From 7648ba30246ca8a692c27328145225535b8f300e Mon Sep 17 00:00:00 2001 From: oy Date: Sun, 3 Jul 2011 00:36:07 +0200 Subject: added a different mouse sens for menus/editor --- src/game/client/components/emoticon.cpp | 1 + src/game/client/components/menus.cpp | 1 + src/game/client/components/spectator.cpp | 1 + src/game/client/ui.cpp | 7 +++++++ src/game/client/ui.h | 1 + src/game/editor/editor.cpp | 1 + src/game/variables.h | 1 + 7 files changed, 13 insertions(+) (limited to 'src') diff --git a/src/game/client/components/emoticon.cpp b/src/game/client/components/emoticon.cpp index 741a604f..bedfaafb 100644 --- a/src/game/client/components/emoticon.cpp +++ b/src/game/client/components/emoticon.cpp @@ -54,6 +54,7 @@ bool CEmoticon::OnMouseMove(float x, float y) if(!m_Active) return false; + UI()->ConvertMouseMove(&x, &y); m_SelectorMouse += vec2(x,y); return true; } diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp index 9826d863..4f3d2da7 100644 --- a/src/game/client/components/menus.cpp +++ b/src/game/client/components/menus.cpp @@ -1348,6 +1348,7 @@ bool CMenus::OnMouseMove(float x, float y) if(!m_MenuActive) return false; + UI()->ConvertMouseMove(&x, &y); m_MousePos.x += x; m_MousePos.y += y; if(m_MousePos.x < 0) m_MousePos.x = 0; diff --git a/src/game/client/components/spectator.cpp b/src/game/client/components/spectator.cpp index e98df118..c69a7669 100644 --- a/src/game/client/components/spectator.cpp +++ b/src/game/client/components/spectator.cpp @@ -139,6 +139,7 @@ bool CSpectator::OnMouseMove(float x, float y) if(!m_Active) return false; + UI()->ConvertMouseMove(&x, &y); m_SelectorMouse += vec2(x,y); return true; } diff --git a/src/game/client/ui.cpp b/src/game/client/ui.cpp index 2161bc77..00a30c15 100644 --- a/src/game/client/ui.cpp +++ b/src/game/client/ui.cpp @@ -53,6 +53,13 @@ int CUI::MouseInside(const CUIRect *r) return 0; } +void CUI::ConvertMouseMove(float *x, float *y) +{ + float Fac = (float)(g_Config.m_UiMousesens)/g_Config.m_InpMousesens; + *x = *x*Fac; + *y = *y*Fac; +} + CUIRect *CUI::Screen() { float Aspect = Graphics()->ScreenAspect(); diff --git a/src/game/client/ui.h b/src/game/client/ui.h index 017abf7c..7cd78d6f 100644 --- a/src/game/client/ui.h +++ b/src/game/client/ui.h @@ -79,6 +79,7 @@ public: const void *LastActiveItem() const { return m_pLastActiveItem; } int MouseInside(const CUIRect *pRect); + void ConvertMouseMove(float *x, float *y); CUIRect *Screen(); void ClipEnable(const CUIRect *pRect); diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index 8c186085..bc00c4a2 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -3337,6 +3337,7 @@ void CEditor::UpdateAndRender() float rx, ry; { Input()->MouseRelative(&rx, &ry); + UI()->ConvertMouseMove(&rx, &ry); m_MouseDeltaX = rx; m_MouseDeltaY = ry; diff --git a/src/game/variables.h b/src/game/variables.h index 3af299cf..d6cf5ac5 100644 --- a/src/game/variables.h +++ b/src/game/variables.h @@ -45,6 +45,7 @@ MACRO_CONFIG_INT(UiPage, ui_page, 5, 0, 10, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Interf MACRO_CONFIG_INT(UiToolboxPage, ui_toolbox_page, 0, 0, 2, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Toolbox page") MACRO_CONFIG_STR(UiServerAddress, ui_server_address, 64, "localhost:8303", CFGFLAG_CLIENT|CFGFLAG_SAVE, "Interface server address") MACRO_CONFIG_INT(UiScale, ui_scale, 100, 50, 150, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Interface scale") +MACRO_CONFIG_INT(UiMousesens, ui_mousesens, 100, 5, 100000, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Mouse sensitivity for menus/editor") MACRO_CONFIG_INT(UiColorHue, ui_color_hue, 160, 0, 255, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Interface color hue") MACRO_CONFIG_INT(UiColorSat, ui_color_sat, 70, 0, 255, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Interface color saturation") -- cgit 1.4.1 From b153003b0b6f08b55fc46645ff522234fe351e67 Mon Sep 17 00:00:00 2001 From: oy Date: Mon, 4 Jul 2011 18:30:24 +0200 Subject: fixed dm wincheck --- src/game/server/gamecontroller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/game/server/gamecontroller.cpp b/src/game/server/gamecontroller.cpp index f0facb8c..fd574d85 100644 --- a/src/game/server/gamecontroller.cpp +++ b/src/game/server/gamecontroller.cpp @@ -662,7 +662,7 @@ bool IGameController::CanChangeTeam(CPlayer *pPlayer, int JoinTeam) void IGameController::DoWincheck() { - if(m_GameOverTick == -1 && !m_Warmup) + if(m_GameOverTick == -1 && !m_Warmup && !GameServer()->m_World.m_ResetRequested) { if(IsTeamplay()) { -- cgit 1.4.1 From 1ae474689d564e1feba9924842f05e06600d83a1 Mon Sep 17 00:00:00 2001 From: oy Date: Tue, 5 Jul 2011 21:54:10 +0200 Subject: added moderator support for the remote console. #518 --- src/engine/console.h | 7 +- src/engine/server/server.cpp | 58 +++++++++++++--- src/engine/server/server.h | 8 +++ src/engine/shared/config_variables.h | 3 +- src/engine/shared/console.cpp | 129 +++++++++++++++++++++++++++-------- src/engine/shared/console.h | 6 ++ 6 files changed, 172 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/engine/console.h b/src/engine/console.h index f8ec67b0..e650ac47 100644 --- a/src/engine/console.h +++ b/src/engine/console.h @@ -14,7 +14,10 @@ public: { OUTPUT_LEVEL_STANDARD=0, OUTPUT_LEVEL_ADDINFO, - OUTPUT_LEVEL_DEBUG + OUTPUT_LEVEL_DEBUG, + + ACCESS_LEVEL_ADMIN=0, + ACCESS_LEVEL_MOD, }; // TODO: rework this interface to reduce the amount of virtual calls @@ -62,6 +65,8 @@ public: virtual void RegisterPrintCallback(FPrintCallback pfnPrintCallback, void *pUserData) = 0; virtual void Print(int Level, const char *pFrom, const char *pStr) = 0; + + virtual void SetAccessLevel(int AccessLevel) = 0; }; extern IConsole *CreateConsole(int FlagMask); diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 0e43e73f..14467b2b 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -1,6 +1,7 @@ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ +#include #include #include @@ -181,6 +182,7 @@ CServer::CServer() : m_DemoRecorder(&m_SnapshotDelta) m_MapReload = 0; m_RconClientID = -1; + m_RconAuthLevel = AUTHED_ADMIN; Init(); } @@ -280,6 +282,11 @@ void CServer::Kick(int ClientID, const char *pReason) Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "you can't kick yourself"); return; } + else if(m_aClients[ClientID].m_Authed > m_RconAuthLevel) + { + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "kick command denied"); + return; + } m_NetServer.Drop(ClientID, pReason); } @@ -571,7 +578,7 @@ int CServer::NewClientCallback(int ClientID, void *pUser) pThis->m_aClients[ClientID].m_aName[0] = 0; pThis->m_aClients[ClientID].m_aClan[0] = 0; pThis->m_aClients[ClientID].m_Country = -1; - pThis->m_aClients[ClientID].m_Authed = 0; + pThis->m_aClients[ClientID].m_Authed = AUTHED_NO; pThis->m_aClients[ClientID].m_AuthTries = 0; pThis->m_aClients[ClientID].Reset(); return 0; @@ -596,7 +603,7 @@ int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser) pThis->m_aClients[ClientID].m_aName[0] = 0; pThis->m_aClients[ClientID].m_aClan[0] = 0; pThis->m_aClients[ClientID].m_Country = -1; - pThis->m_aClients[ClientID].m_Authed = 0; + pThis->m_aClients[ClientID].m_Authed = AUTHED_NO; pThis->m_aClients[ClientID].m_AuthTries = 0; pThis->m_aClients[ClientID].m_Snapshots.PurgeAll(); return 0; @@ -635,7 +642,7 @@ void CServer::SendRconLineAuthed(const char *pLine, void *pUser) for(i = 0; i < MAX_CLIENTS; i++) { - if(pThis->m_aClients[i].m_State != CClient::STATE_EMPTY && pThis->m_aClients[i].m_Authed) + if(pThis->m_aClients[i].m_State != CClient::STATE_EMPTY && pThis->m_aClients[i].m_Authed >= pThis->m_RconAuthLevel) pThis->SendRconLine(i, pLine); } @@ -813,8 +820,12 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) str_format(aBuf, sizeof(aBuf), "ClientID=%d rcon='%s'", ClientID, pCmd); Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBuf); m_RconClientID = ClientID; + m_RconAuthLevel = m_aClients[ClientID].m_Authed; + Console()->SetAccessLevel(m_aClients[ClientID].m_Authed == AUTHED_ADMIN ? IConsole::ACCESS_LEVEL_ADMIN : IConsole::ACCESS_LEVEL_MOD); Console()->ExecuteLine(pCmd); + Console()->SetAccessLevel(IConsole::ACCESS_LEVEL_ADMIN); m_RconClientID = -1; + m_RconAuthLevel = AUTHED_ADMIN; } } else if(Msg == NETMSG_RCON_AUTH) @@ -825,9 +836,9 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) if(Unpacker.Error() == 0) { - if(g_Config.m_SvRconPassword[0] == 0) + if(g_Config.m_SvRconPassword[0] == 0 && g_Config.m_SvRconModPassword[0]) { - SendRconLine(ClientID, "No rcon password set on server. Set sv_rcon_password to enable the remote console."); + SendRconLine(ClientID, "No rcon password set on server. Set sv_rcon_password and/or sv_rcon_mod_password to enable the remote console."); } else if(str_comp(pPw, g_Config.m_SvRconPassword) == 0) { @@ -835,10 +846,22 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) Msg.AddInt(1); SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true); - m_aClients[ClientID].m_Authed = 1; - SendRconLine(ClientID, "Authentication successful. Remote console access granted."); + m_aClients[ClientID].m_Authed = AUTHED_ADMIN; + SendRconLine(ClientID, "Admin authentication successful. Full remote console access granted."); + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (admin)", ClientID); + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); + } + else if(str_comp(pPw, g_Config.m_SvRconModPassword) == 0) + { + CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS); + Msg.AddInt(1); + SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true); + + m_aClients[ClientID].m_Authed = AUTHED_MOD; + SendRconLine(ClientID, "Moderator authentication successful. Limited remote console access granted."); char aBuf[256]; - str_format(aBuf, sizeof(aBuf), "ClientID=%d authed", ClientID); + str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (moderator)", ClientID); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); } else if(g_Config.m_SvRconMaxTries) @@ -1308,6 +1331,20 @@ void CServer::ConBan(IConsole::IResult *pResult, void *pUser) pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "you can't ban yourself"); return; } + + for(int i = 0; i < MAX_CLIENTS; ++i) + { + if(i == pServer->m_RconClientID) + continue; + + AddrCheck = pServer->m_NetServer.ClientAddr(i); + AddrCheck.port = 0; + if(net_addr_comp(&Addr, &AddrCheck) == 0 && pServer->m_aClients[i].m_Authed > pServer->m_RconAuthLevel) + { + pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "ban command denied"); + return; + } + } } pServer->BanAdd(Addr, Minutes*60, pReason); } @@ -1325,6 +1362,11 @@ void CServer::ConBan(IConsole::IResult *pResult, void *pUser) pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "you can't ban yourself"); return; } + else if(pServer->m_aClients[ClientID].m_Authed > pServer->m_RconAuthLevel) + { + pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "ban command denied"); + return; + } Addr = pServer->m_NetServer.ClientAddr(ClientID); pServer->BanAdd(Addr, Minutes*60, pReason); diff --git a/src/engine/server/server.h b/src/engine/server/server.h index be36a856..72c82d4d 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -49,6 +49,13 @@ public: class IConsole *Console() { return m_pConsole; } class IStorage *Storage() { return m_pStorage; } + enum + { + AUTHED_NO=0, + AUTHED_MOD, + AUTHED_ADMIN, + }; + class CClient { public: @@ -110,6 +117,7 @@ public: int m_RunServer; int m_MapReload; int m_RconClientID; + int m_RconAuthLevel; int64 m_Lastheartbeat; //static NETADDR4 master_server; diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index 31a8128a..213ebf26 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -82,7 +82,8 @@ MACRO_CONFIG_INT(SvMaxClients, sv_max_clients, 8, 1, MAX_CLIENTS, CFGFLAG_SERVER MACRO_CONFIG_INT(SvMaxClientsPerIP, sv_max_clients_per_ip, 4, 1, MAX_CLIENTS, CFGFLAG_SERVER, "Maximum number of clients with the same IP that can connect to the server") MACRO_CONFIG_INT(SvHighBandwidth, sv_high_bandwidth, 0, 0, 1, CFGFLAG_SERVER, "Use high bandwidth mode. Doubles the bandwidth required for the server. LAN use only") MACRO_CONFIG_INT(SvRegister, sv_register, 1, 0, 1, CFGFLAG_SERVER, "Register server with master server for public listing") -MACRO_CONFIG_STR(SvRconPassword, sv_rcon_password, 32, "", CFGFLAG_SERVER, "Remote console password") +MACRO_CONFIG_STR(SvRconPassword, sv_rcon_password, 32, "", CFGFLAG_SERVER, "Remote console password (full access)") +MACRO_CONFIG_STR(SvRconModPassword, sv_rcon_mod_password, 32, "", CFGFLAG_SERVER, "Remote console password for moderators (limited access)") MACRO_CONFIG_INT(SvRconMaxTries, sv_rcon_max_tries, 3, 0, 100, CFGFLAG_SERVER, "Maximum number of tries for remote console authentication") MACRO_CONFIG_INT(SvRconBantime, sv_rcon_bantime, 5, 0, 1440, CFGFLAG_SERVER, "The time a client gets banned if remote console authentication fails. 0 makes it just use kick") diff --git a/src/engine/shared/console.cpp b/src/engine/shared/console.cpp index 3fd73543..588abd61 100644 --- a/src/engine/shared/console.cpp +++ b/src/engine/shared/console.cpp @@ -1,11 +1,15 @@ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ #include + +#include #include -#include + #include -#include "console.h" +#include + #include "config.h" +#include "console.h" #include "linereader.h" const char *CConsole::CResult::GetString(unsigned Index) @@ -247,38 +251,47 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr) if(ParseStart(&Result, pStr, (pEnd-pStr) + 1) != 0) return; - if (!*Result.m_pCommand) + if(!*Result.m_pCommand) return; CCommand *pCommand = FindCommand(Result.m_pCommand, m_FlagMask); if(pCommand) { - int IsStrokeCommand = 0; - if(Result.m_pCommand[0] == '+') - { - // insert the stroke direction token - Result.AddArgument(m_paStrokeStr[Stroke]); - IsStrokeCommand = 1; - } - - if(Stroke || IsStrokeCommand) + if(pCommand->m_AccessLevel >= m_AccessLevel) { - if(ParseArgs(&Result, pCommand->m_pParams)) + int IsStrokeCommand = 0; + if(Result.m_pCommand[0] == '+') { - char aBuf[256]; - str_format(aBuf, sizeof(aBuf), "Invalid arguments... Usage: %s %s", pCommand->m_pName, pCommand->m_pParams); - Print(OUTPUT_LEVEL_STANDARD, "Console", aBuf); + // insert the stroke direction token + Result.AddArgument(m_paStrokeStr[Stroke]); + IsStrokeCommand = 1; } - else if(m_StoreCommands && pCommand->m_Flags&CFGFLAG_STORE) + + if(Stroke || IsStrokeCommand) { - m_ExecutionQueue.AddEntry(); - m_ExecutionQueue.m_pLast->m_pfnCommandCallback = pCommand->m_pfnCallback; - m_ExecutionQueue.m_pLast->m_pCommandUserData = pCommand->m_pUserData; - m_ExecutionQueue.m_pLast->m_Result = Result; + if(ParseArgs(&Result, pCommand->m_pParams)) + { + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "Invalid arguments... Usage: %s %s", pCommand->m_pName, pCommand->m_pParams); + Print(OUTPUT_LEVEL_STANDARD, "Console", aBuf); + } + else if(m_StoreCommands && pCommand->m_Flags&CFGFLAG_STORE) + { + m_ExecutionQueue.AddEntry(); + m_ExecutionQueue.m_pLast->m_pfnCommandCallback = pCommand->m_pfnCallback; + m_ExecutionQueue.m_pLast->m_pCommandUserData = pCommand->m_pUserData; + m_ExecutionQueue.m_pLast->m_Result = Result; + } + else + pCommand->m_pfnCallback(&Result, pCommand->m_pUserData); } - else - pCommand->m_pfnCallback(&Result, pCommand->m_pUserData); + } + else if(Stroke) + { + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "Access for command %s denied.", Result.m_pCommand); + Print(OUTPUT_LEVEL_STANDARD, "Console", aBuf); } } else if(Stroke) @@ -294,8 +307,7 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr) void CConsole::PossibleCommands(const char *pStr, int FlagMask, FPossibleCallback pfnCallback, void *pUser) { - CCommand *pCommand; - for(pCommand = m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext) + for(CCommand *pCommand = m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext) { if(pCommand->m_Flags&FlagMask) { @@ -307,8 +319,7 @@ void CConsole::PossibleCommands(const char *pStr, int FlagMask, FPossibleCallbac CConsole::CCommand *CConsole::FindCommand(const char *pName, int FlagMask) { - CCommand *pCommand; - for (pCommand = m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext) + for(CCommand *pCommand = m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext) { if(pCommand->m_Flags&FlagMask) { @@ -383,6 +394,62 @@ void CConsole::Con_Exec(IResult *pResult, void *pUserData) ((CConsole*)pUserData)->ExecuteFile(pResult->GetString(0)); } +void CConsole::ConModCommandAccess(IResult *pResult, void *pUser) +{ + CConsole* pConsole = static_cast(pUser); + char aBuf[128]; + CCommand *pCommand = pConsole->FindCommand(pResult->GetString(0), CFGFLAG_SERVER); + if(pCommand) + { + if(pResult->NumArguments() == 2) + { + pCommand->m_AccessLevel = clamp(pResult->GetInteger(1), (int)(ACCESS_LEVEL_ADMIN), (int)(ACCESS_LEVEL_MOD)); + str_format(aBuf, sizeof(aBuf), "moderator access for '%s' is now %s", pResult->GetString(0), pCommand->m_AccessLevel ? "enabled" : "disabled"); + } + else + str_format(aBuf, sizeof(aBuf), "moderator access for '%s' is %s", pResult->GetString(0), pCommand->m_AccessLevel ? "enabled" : "disabled"); + } + else + str_format(aBuf, sizeof(aBuf), "No such command: '%s'.", pResult->GetString(0)); + + pConsole->Print(OUTPUT_LEVEL_STANDARD, "Console", aBuf); +} + +void CConsole::ConModCommandStatus(IResult *pResult, void *pUser) +{ + CConsole* pConsole = static_cast(pUser); + char aBuf[240]; + mem_zero(aBuf, sizeof(aBuf)); + int Used = 0; + + for(CCommand *pCommand = pConsole->m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext) + { + if(pCommand->m_Flags&pConsole->m_FlagMask && pCommand->m_AccessLevel == ACCESS_LEVEL_MOD) + { + int Length = str_length(pCommand->m_pName); + if(Used + Length + 2 < (int)(sizeof(aBuf))) + { + if(Used > 0) + { + Used += 2; + str_append(aBuf, ", ", sizeof(aBuf)); + } + str_append(aBuf, pCommand->m_pName, sizeof(aBuf)); + Used += Length; + } + else + { + pConsole->Print(OUTPUT_LEVEL_STANDARD, "Console", aBuf); + mem_zero(aBuf, sizeof(aBuf)); + str_copy(aBuf, pCommand->m_pName, sizeof(aBuf)); + Used = Length; + } + } + } + if(Used > 0) + pConsole->Print(OUTPUT_LEVEL_STANDARD, "Console", aBuf); +} + struct CIntVariableData { IConsole *m_pConsole; @@ -463,6 +530,7 @@ static void StrVariableCommand(IConsole::IResult *pResult, void *pUserData) CConsole::CConsole(int FlagMask) { m_FlagMask = FlagMask; + m_AccessLevel = ACCESS_LEVEL_ADMIN; m_StoreCommands = true; m_paStrokeStr[0] = "0"; m_paStrokeStr[1] = "1"; @@ -478,6 +546,9 @@ CConsole::CConsole(int FlagMask) Register("echo", "r", CFGFLAG_SERVER|CFGFLAG_CLIENT, Con_Echo, this, "Echo the text"); Register("exec", "r", CFGFLAG_SERVER|CFGFLAG_CLIENT, Con_Exec, this, "Execute the specified file"); + Register("mod_command", "s?i", CFGFLAG_SERVER, ConModCommandAccess, this, "Specify command accessibility for moderators"); + Register("mod_status", "", CFGFLAG_SERVER, ConModCommandStatus, this, "List all commands which are accessible for moderators"); + // TODO: this should disappear #define MACRO_CONFIG_INT(Name,ScriptName,Def,Min,Max,Flags,Desc) \ { \ @@ -524,14 +595,14 @@ void CConsole::ParseArguments(int NumArgs, const char **ppArguments) void CConsole::Register(const char *pName, const char *pParams, int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp) { - CCommand *pCommand = (CCommand *)mem_alloc(sizeof(CCommand), sizeof(void*)); + CCommand *pCommand = new(mem_alloc(sizeof(CCommand), sizeof(void*))) CCommand; pCommand->m_pfnCallback = pfnFunc; pCommand->m_pUserData = pUser; pCommand->m_pHelp = pHelp; pCommand->m_pName = pName; pCommand->m_pParams = pParams; pCommand->m_Flags = Flags; - + pCommand->m_AccessLevel = ACCESS_LEVEL_ADMIN; pCommand->m_pNext = m_pFirstCommand; m_pFirstCommand = pCommand; diff --git a/src/engine/shared/console.h b/src/engine/shared/console.h index 0866d8e3..14c48581 100644 --- a/src/engine/shared/console.h +++ b/src/engine/shared/console.h @@ -13,6 +13,7 @@ class CConsole : public IConsole public: CCommand *m_pNext; int m_Flags; + int m_AccessLevel; FCommandCallback m_pfnCallback; void *m_pUserData; }; @@ -41,10 +42,13 @@ class CConsole : public IConsole CExecFile *m_pFirstExec; class IStorage *m_pStorage; + int m_AccessLevel; static void Con_Chain(IResult *pResult, void *pUserData); static void Con_Echo(IResult *pResult, void *pUserData); static void Con_Exec(IResult *pResult, void *pUserData); + static void ConModCommandAccess(IResult *pResult, void *pUser); + static void ConModCommandStatus(IConsole::IResult *pResult, void *pUser); void ExecuteFileRecurse(const char *pFilename); void ExecuteLineStroked(int Stroke, const char *pStr); @@ -153,6 +157,8 @@ public: virtual void RegisterPrintCallback(FPrintCallback pfnPrintCallback, void *pUserData); virtual void Print(int Level, const char *pFrom, const char *pStr); + + void SetAccessLevel(int AccessLevel) { m_AccessLevel = clamp(AccessLevel, (int)(ACCESS_LEVEL_ADMIN), (int)(ACCESS_LEVEL_MOD)); } }; #endif -- cgit 1.4.1 From ab1f7d6f95346c7bf86dfbdfa015c7e850097918 Mon Sep 17 00:00:00 2001 From: oy Date: Tue, 5 Jul 2011 22:58:54 +0200 Subject: clamped information flow when moving as spectator in free-view. Closes #551 --- src/game/server/player.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp index 1f822524..3e4d7be5 100644 --- a/src/game/server/player.cpp +++ b/src/game/server/player.cpp @@ -60,6 +60,9 @@ void CPlayer::Tick() } } + if(!m_pCharacter && m_Team == TEAM_SPECTATORS && m_SpectatorID == SPEC_FREEVIEW) + m_ViewPos -= vec2(clamp(m_ViewPos.x-m_LatestActivity.m_TargetX, -5000.0f, 500.0f), clamp(m_ViewPos.y-m_LatestActivity.m_TargetY, -400.0f, 400.0f)); + if(!m_pCharacter && m_DieTick+Server()->TickSpeed()*3 <= Server()->Tick()) m_Spawning = true; @@ -193,9 +196,6 @@ void CPlayer::OnDirectInput(CNetObj_PlayerInput *NewInput) if(!m_pCharacter && m_Team != TEAM_SPECTATORS && (NewInput->m_Fire&1)) m_Spawning = true; - if(!m_pCharacter && m_Team == TEAM_SPECTATORS && m_SpectatorID == SPEC_FREEVIEW) - m_ViewPos = vec2(NewInput->m_TargetX, NewInput->m_TargetY); - // check for activity if(NewInput->m_Direction || m_LatestActivity.m_TargetX != NewInput->m_TargetX || m_LatestActivity.m_TargetY != NewInput->m_TargetY || NewInput->m_Jump || -- cgit 1.4.1 From ac9c3b8f7f26b3b1676345ddca82272fd31fc0ff Mon Sep 17 00:00:00 2001 From: oy Date: Tue, 5 Jul 2011 23:15:24 +0200 Subject: made the dropped flag sign blink faster the last 5 seconds to indicate that it's about to return. Closes #631 --- src/game/client/components/hud.cpp | 4 +++- src/game/client/gameclient.cpp | 16 ++++++++++++++++ src/game/client/gameclient.h | 1 + 3 files changed, 20 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/game/client/components/hud.cpp b/src/game/client/components/hud.cpp index 58fc75b9..11343912 100644 --- a/src/game/client/components/hud.cpp +++ b/src/game/client/components/hud.cpp @@ -108,7 +108,9 @@ void CHud::RenderScoreHud() if(GameFlags&GAMEFLAG_FLAGS) { - if(FlagCarrier[t] == FLAG_ATSTAND || (FlagCarrier[t] == FLAG_TAKEN && ((Client()->GameTick()/10)&1))) + int BlinkTimer = (m_pClient->m_FlagDropTick[t] != 0 && + (Client()->GameTick()-m_pClient->m_FlagDropTick[t])/Client()->GameTickSpeed() >= 25) ? 10 : 20; + if(FlagCarrier[t] == FLAG_ATSTAND || (FlagCarrier[t] == FLAG_TAKEN && ((Client()->GameTick()/BlinkTimer)&1))) { // draw flag Graphics()->BlendNormal(); diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index a3c2dfc2..4618d7dc 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -341,6 +341,8 @@ void CGameClient::OnReset() m_All.m_paComponents[i]->OnReset(); m_DemoSpecID = SPEC_FREEVIEW; + m_FlagDropTick[TEAM_RED] = 0; + m_FlagDropTick[TEAM_BLUE] = 0; } @@ -783,6 +785,20 @@ void CGameClient::OnNewSnapshot() { m_Snap.m_pGameDataObj = (const CNetObj_GameData *)pData; m_Snap.m_GameDataSnapID = Item.m_ID; + if(m_Snap.m_pGameDataObj->m_FlagCarrierRed == FLAG_TAKEN) + { + if(m_FlagDropTick[TEAM_RED] == 0) + m_FlagDropTick[TEAM_RED] = Client()->GameTick(); + } + else if(m_FlagDropTick[TEAM_RED] != 0) + m_FlagDropTick[TEAM_RED] = 0; + if(m_Snap.m_pGameDataObj->m_FlagCarrierBlue == FLAG_TAKEN) + { + if(m_FlagDropTick[TEAM_BLUE] == 0) + m_FlagDropTick[TEAM_BLUE] = Client()->GameTick(); + } + else if(m_FlagDropTick[TEAM_BLUE] != 0) + m_FlagDropTick[TEAM_BLUE] = 0; } else if(Item.m_Type == NETOBJTYPE_FLAG) m_Snap.m_paFlags[Item.m_ID%2] = (const CNetObj_Flag *)pData; diff --git a/src/game/client/gameclient.h b/src/game/client/gameclient.h index 859e1e7b..4783f8b4 100644 --- a/src/game/client/gameclient.h +++ b/src/game/client/gameclient.h @@ -89,6 +89,7 @@ public: bool m_SuppressEvents; bool m_NewTick; bool m_NewPredictedTick; + int m_FlagDropTick[2]; // TODO: move this CTuningParams m_Tuning; -- cgit 1.4.1 From 20fbe2f92c57811bb9f20b084f052339f3f678d0 Mon Sep 17 00:00:00 2001 From: oy Date: Tue, 5 Jul 2011 23:23:33 +0200 Subject: fixed that player friends are marked as online in the friends list if they match a clan friend --- src/game/client/components/menus_browser.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/game/client/components/menus_browser.cpp b/src/game/client/components/menus_browser.cpp index f2926f87..8501c67d 100644 --- a/src/game/client/components/menus_browser.cpp +++ b/src/game/client/components/menus_browser.cpp @@ -252,7 +252,8 @@ void CMenus::RenderServerbrowserServerList(CUIRect View) (!m_lFriends[f].m_pFriendInfo->m_aName[0] || NameHash == m_lFriends[f].m_pFriendInfo->m_NameHash)) { m_lFriends[f].m_NumFound++; - break; + if(m_lFriends[f].m_pFriendInfo->m_aName[0]) + break; } } } -- cgit 1.4.1 From e18390fea86352a98c377781d97bee1a40deae57 Mon Sep 17 00:00:00 2001 From: oy Date: Tue, 5 Jul 2011 23:32:32 +0200 Subject: fixed that client resets tuning. Closes #746 --- src/game/client/gameclient.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index 4618d7dc..7b6b1192 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -343,6 +343,7 @@ void CGameClient::OnReset() m_DemoSpecID = SPEC_FREEVIEW; m_FlagDropTick[TEAM_RED] = 0; m_FlagDropTick[TEAM_BLUE] = 0; + m_Tuning = CTuningParams(); } -- cgit 1.4.1 From 83d8422c4cf3ad2b04b75c7478c92f91c1f8a307 Mon Sep 17 00:00:00 2001 From: oy Date: Wed, 6 Jul 2011 18:20:46 +0200 Subject: added "fixed tcp and added ipv6 tcp support" by SushiTee --- src/base/system.c | 111 +++++++++++++++++++++++++++++++++++------------------- src/base/system.h | 12 +++--- 2 files changed, 78 insertions(+), 45 deletions(-) (limited to 'src') diff --git a/src/base/system.c b/src/base/system.c index 01f0b398..551b3f1b 100644 --- a/src/base/system.c +++ b/src/base/system.c @@ -823,8 +823,6 @@ static int priv_net_close_all_sockets(NETSOCKET sock) static int priv_net_create_socket(int domain, int type, struct sockaddr *addr, int sockaddrlen) { int sock, e; - unsigned long mode = 1; - int broadcast = 1; /* create socket */ sock = socket(domain, type, 0); @@ -852,16 +850,6 @@ static int priv_net_create_socket(int domain, int type, struct sockaddr *addr, i return -1; } - /* set non-blocking */ -#if defined(CONF_FAMILY_WINDOWS) - ioctlsocket(sock, FIONBIO, &mode); -#else - ioctl(sock, FIONBIO, &mode); -#endif - - /* set boardcast */ - setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof(broadcast)); - /* return the newly created socket */ return sock; } @@ -870,6 +858,7 @@ NETSOCKET net_udp_create(NETADDR bindaddr) { NETSOCKET sock = invalid_socket; NETADDR tmpbindaddr = bindaddr; + int broadcast = 1; if(bindaddr.type&NETTYPE_IPV4) { @@ -885,6 +874,12 @@ NETSOCKET net_udp_create(NETADDR bindaddr) sock.type |= NETTYPE_IPV4; sock.ipv4sock = socket; } + + /* set non-blocking */ + net_set_non_blocking(sock); + + /* set boardcast */ + setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof(broadcast)); } if(bindaddr.type&NETTYPE_IPV6) @@ -901,6 +896,12 @@ NETSOCKET net_udp_create(NETADDR bindaddr) sock.type |= NETTYPE_IPV6; sock.ipv6sock = socket; } + + /* set non-blocking */ + net_set_non_blocking(sock); + + /* set boardcast */ + setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof(broadcast)); } /* return */ @@ -1010,32 +1011,48 @@ int net_udp_close(NETSOCKET sock) return priv_net_close_all_sockets(sock); } -// TODO: make TCP stuff work again -NETSOCKET net_tcp_create(const NETADDR *a) +NETSOCKET net_tcp_create(NETADDR bindaddr) { - /* TODO: IPv6 support */ NETSOCKET sock = invalid_socket; + NETADDR tmpbindaddr = bindaddr; - if(a->type&NETTYPE_IPV4) + if(bindaddr.type&NETTYPE_IPV4) { struct sockaddr_in addr; + int socket = -1; - /* create socket */ - sock.type |= NETTYPE_IPV4; - sock.ipv4sock = socket(AF_INET, SOCK_STREAM, 0); - if(sock.ipv4sock < 0) - return invalid_socket; + /* bind, we should check for error */ + tmpbindaddr.type = NETTYPE_IPV4; + netaddr_to_sockaddr_in(&tmpbindaddr, &addr); + socket = priv_net_create_socket(AF_INET, SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr)); + if(socket >= 0) + { + sock.type |= NETTYPE_IPV4; + sock.ipv4sock = socket; + } + } + + if(bindaddr.type&NETTYPE_IPV6) + { + struct sockaddr_in6 addr; + int socket = -1; /* bind, we should check for error */ - netaddr_to_sockaddr_in(a, &addr); - bind(sock.ipv4sock, (struct sockaddr *)&addr, sizeof(addr)); + tmpbindaddr.type = NETTYPE_IPV6; + netaddr_to_sockaddr_in6(&tmpbindaddr, &addr); + socket = priv_net_create_socket(AF_INET6, SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr)); + if(socket >= 0) + { + sock.type |= NETTYPE_IPV6; + sock.ipv6sock = socket; + } } /* return */ return sock; } -int net_tcp_set_non_blocking(NETSOCKET sock) +int net_set_non_blocking(NETSOCKET sock) { unsigned long mode = 1; if(sock.ipv4sock >= 0) @@ -1059,7 +1076,7 @@ int net_tcp_set_non_blocking(NETSOCKET sock) return 0; } -int net_tcp_set_blocking(NETSOCKET sock) +int net_set_blocking(NETSOCKET sock) { unsigned long mode = 0; if(sock.ipv4sock >= 0) @@ -1133,24 +1150,30 @@ int net_tcp_accept(NETSOCKET sock, NETSOCKET *new_sock, NETADDR *a) int net_tcp_connect(NETSOCKET sock, const NETADDR *a) { - /*struct sockaddr addr; - netaddr_to_sockaddr(a, &addr); - return connect(sock, &addr, sizeof(addr)); - */ + if(a->type&NETTYPE_IPV4) + { + struct sockaddr_in addr; + netaddr_to_sockaddr_in(a, &addr); + return connect(sock.ipv4sock, (struct sockaddr *)&addr, sizeof(addr)); + } + + if(a->type&NETTYPE_IPV6) + { + struct sockaddr_in6 addr; + netaddr_to_sockaddr_in6(a, &addr); + return connect(sock.ipv6sock, (struct sockaddr *)&addr, sizeof(addr)); + } + return 0; } -int net_tcp_connect_non_blocking(NETSOCKET sock, const NETADDR *a) +int net_tcp_connect_non_blocking(NETSOCKET sock, NETADDR bindaddr) { - /* struct sockaddr addr; */ int res = 0; - /* - netaddr_to_sockaddr(a, &addr); - net_tcp_set_non_blocking(sock); - res = connect(sock, &addr, sizeof(addr)); - net_tcp_set_blocking(sock); - */ + net_set_non_blocking(sock); + res = net_tcp_connect(sock, &bindaddr); + net_set_blocking(sock); return res; } @@ -1158,14 +1181,24 @@ int net_tcp_connect_non_blocking(NETSOCKET sock, const NETADDR *a) int net_tcp_send(NETSOCKET sock, const void *data, int size) { int bytes = 0; - /* bytes = send((int)sock, (const char*)data, size, 0); */ + + if(sock.ipv4sock >= 0) + bytes = send((int)sock.ipv4sock, (const char*)data, size, 0); + if(sock.ipv6sock >= 0) + bytes = send((int)sock.ipv6sock, (const char*)data, size, 0); + return bytes; } int net_tcp_recv(NETSOCKET sock, void *data, int maxsize) { int bytes = 0; - /* bytes = recv((int)sock, (char*)data, maxsize, 0); */ + + if(sock.ipv4sock >= 0) + bytes = recv((int)sock.ipv4sock, (char*)data, maxsize, 0); + if(sock.ipv6sock >= 0) + bytes = recv((int)sock.ipv6sock, (char*)data, maxsize, 0); + return bytes; } diff --git a/src/base/system.h b/src/base/system.h index de579076..aaa5b43f 100644 --- a/src/base/system.h +++ b/src/base/system.h @@ -591,7 +591,7 @@ int net_udp_close(NETSOCKET sock); Returns: On success it returns an handle to the socket. On failure it returns NETSOCKET_INVALID. */ -NETSOCKET net_tcp_create(const NETADDR *a); +NETSOCKET net_tcp_create(NETADDR bindaddr); /* Function: net_tcp_listen @@ -1094,21 +1094,21 @@ int fs_rename(const char *oldname, const char *newname); DOCTODO: serp */ -int net_tcp_connect_non_blocking(NETSOCKET sock, const NETADDR *a); +int net_tcp_connect_non_blocking(NETSOCKET sock, NETADDR bindaddr); /* - Function: net_tcp_set_non_blocking + Function: net_set_non_blocking DOCTODO: serp */ -int net_tcp_set_non_blocking(NETSOCKET sock); +int net_set_non_blocking(NETSOCKET sock); /* - Function: net_tcp_set_non_blocking + Function: net_set_non_blocking DOCTODO: serp */ -int net_tcp_set_blocking(NETSOCKET sock); +int net_set_blocking(NETSOCKET sock); /* Function: net_errno -- cgit 1.4.1 From e37d536fdfd69bbd04b869e381d64840a185b854 Mon Sep 17 00:00:00 2001 From: oy Date: Thu, 7 Jul 2011 01:48:00 +0200 Subject: fixed some NETTYPE usage based on the socket state --- src/engine/client/client.cpp | 8 ++++---- src/engine/client/client.h | 1 - src/engine/server/server.cpp | 2 +- src/engine/shared/network.h | 2 ++ 4 files changed, 7 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 90cb2011..6949c308 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -693,12 +693,12 @@ void CClient::Connect(const char *pAddress) ServerInfoRequest(); - if(net_host_lookup(m_aServerAddressStr, &m_ServerAddress, NETTYPE_ALL) != 0) + if(net_host_lookup(m_aServerAddressStr, &m_ServerAddress, m_NetClient.NetType()) != 0) { char aBufMsg[256]; str_format(aBufMsg, sizeof(aBufMsg), "could not find the address of %s, connecting to localhost", aBuf); m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client", aBufMsg); - net_host_lookup("localhost", &m_ServerAddress, NETTYPE_ALL); + net_host_lookup("localhost", &m_ServerAddress, m_NetClient.NetType()); } m_RconAuthed = 0; @@ -1799,7 +1799,7 @@ void CClient::VersionUpdate() { if(m_VersionInfo.m_State == CVersionInfo::STATE_INIT) { - Engine()->HostLookup(&m_VersionInfo.m_VersionServeraddr, g_Config.m_ClVersionServer, m_BindAddr.type); + Engine()->HostLookup(&m_VersionInfo.m_VersionServeraddr, g_Config.m_ClVersionServer, m_NetClient.NetType()); m_VersionInfo.m_State = CVersionInfo::STATE_START; } else if(m_VersionInfo.m_State == CVersionInfo::STATE_START) @@ -1881,7 +1881,7 @@ void CClient::Run() Input()->Init(); // start refreshing addresses while we load - MasterServer()->RefreshAddresses(m_BindAddr.type); + MasterServer()->RefreshAddresses(m_NetClient.NetType()); // init the editor m_pEditor->Init(); diff --git a/src/engine/client/client.h b/src/engine/client/client.h index ddcd1167..fa0ddaf7 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -118,7 +118,6 @@ class CClient : public IClient, public CDemoPlayer::IListner float m_FrameTimeHigh; int m_Frames; NETADDR m_ServerAddress; - NETADDR m_BindAddr; int m_WindowMustRefocus; int m_SnapCrcErrors; bool m_AutoScreenshotRecycle; diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 14467b2b..a707b690 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -1246,7 +1246,7 @@ int CServer::Run() } // master server stuff - m_Register.RegisterUpdate(BindAddr.type); + m_Register.RegisterUpdate(m_NetServer.NetType()); PumpNetwork(); diff --git a/src/engine/shared/network.h b/src/engine/shared/network.h index 425d970a..228ba6dd 100644 --- a/src/engine/shared/network.h +++ b/src/engine/shared/network.h @@ -285,6 +285,7 @@ public: // status requests NETADDR ClientAddr(int ClientID) const { return m_aSlots[ClientID].m_Connection.PeerAddress(); } NETSOCKET Socket() const { return m_Socket; } + int NetType() { return m_Socket.type; } int MaxClients() const { return m_MaxClients; } // @@ -320,6 +321,7 @@ public: int ResetErrorString(); // error and state + int NetType() { return m_Socket.type; } int State(); int GotProblems(); const char *ErrorString(); -- cgit 1.4.1 From f44094490549a46781a7d85a137ddf748021d00f Mon Sep 17 00:00:00 2001 From: oy Date: Fri, 8 Jul 2011 00:00:38 +0200 Subject: fixed problem with rcon authentication --- src/engine/server/server.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index a707b690..24d3b317 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -840,7 +840,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) { SendRconLine(ClientID, "No rcon password set on server. Set sv_rcon_password and/or sv_rcon_mod_password to enable the remote console."); } - else if(str_comp(pPw, g_Config.m_SvRconPassword) == 0) + else if(g_Config.m_SvRconPassword[0] && str_comp(pPw, g_Config.m_SvRconPassword) == 0) { CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS); Msg.AddInt(1); @@ -852,7 +852,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (admin)", ClientID); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); } - else if(str_comp(pPw, g_Config.m_SvRconModPassword) == 0) + else if(g_Config.m_SvRconModPassword[0] && str_comp(pPw, g_Config.m_SvRconModPassword) == 0) { CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS); Msg.AddInt(1); -- cgit 1.4.1 From 7bc07b613f9fed3dcef26f63332ea68db1e1f381 Mon Sep 17 00:00:00 2001 From: oy Date: Sat, 9 Jul 2011 01:09:06 +0200 Subject: added auto mapping feature by LordSkelethom --- data/editor/desert_main.rules | 227 ++++++++++++++++++++++++++++++++++++++++ data/editor/grass_main.rules | 225 +++++++++++++++++++++++++++++++++++++++ data/editor/jungle_main.rules | 220 ++++++++++++++++++++++++++++++++++++++ data/editor/winter_main.rules | 177 +++++++++++++++++++++++++++++++ src/game/editor/auto_map.cpp | 202 +++++++++++++++++++++++++++++++++++ src/game/editor/auto_map.h | 54 ++++++++++ src/game/editor/editor.cpp | 12 ++- src/game/editor/editor.h | 19 +++- src/game/editor/io.cpp | 3 + src/game/editor/layer_tiles.cpp | 24 ++++- src/game/editor/popups.cpp | 44 ++++++++ 11 files changed, 1194 insertions(+), 13 deletions(-) create mode 100644 data/editor/desert_main.rules create mode 100644 data/editor/grass_main.rules create mode 100644 data/editor/jungle_main.rules create mode 100644 data/editor/winter_main.rules create mode 100644 src/game/editor/auto_map.cpp create mode 100644 src/game/editor/auto_map.h (limited to 'src') diff --git a/data/editor/desert_main.rules b/data/editor/desert_main.rules new file mode 100644 index 00000000..0102a197 --- /dev/null +++ b/data/editor/desert_main.rules @@ -0,0 +1,227 @@ +[Desert] +Index 1 +BaseTile + +#random +Index 2 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 150 + +Index 3 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 150 + +#top +Index 16 +Pos 0 -1 EMPTY + +#right +Index 17 +Pos 1 0 EMPTY + +#bottom +Index 18 +Pos 0 1 EMPTY + +#left +Index 19 +Pos -1 0 EMPTY + +#corner top-right +Index 33 +Pos 0 -1 EMPTY +Pos 1 0 EMPTY + +#corner top-left +Index 32 +Pos 0 -1 EMPTY +Pos -1 0 EMPTY + +#corner bottom-left +Index 35 +Pos 0 1 EMPTY +Pos -1 0 EMPTY + +#corner bottom-right +Index 34 +Pos 0 1 EMPTY +Pos 1 0 EMPTY + +#inside corner top-right +Index 51 +Pos -1 1 EMPTY +Pos -1 0 FULL +Pos 0 1 FULL + +#inside corner top-left +Index 50 +Pos 1 1 EMPTY +Pos 1 0 FULL +Pos 0 1 FULL + +#inside corner bottom-left +Index 49 +Pos 1 -1 EMPTY +Pos 1 0 FULL +Pos 0 -1 FULL + +#inside corner bottom-right +Index 48 +Pos -1 -1 EMPTY +Pos -1 0 FULL +Pos 0 -1 FULL + +[Mine] +Index 81 +BaseTile + +#random +Index 82 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 500 + +Index 83 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 500 + +Index 84 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 500 + +Index 85 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 500 + +Index 86 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 500 + +Index 100 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 500 + +Index 101 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 500 + +Index 102 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 500 + +Index 117 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 500 + +Index 118 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 500 + +Index 133 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 500 + +Index 134 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 500 + +#top +Index 96 +Pos 0 -1 EMPTY + +#right +Index 97 +Pos 1 0 EMPTY + +#bottom +Index 98 +Pos 0 1 EMPTY + +#left +Index 99 +Pos -1 0 EMPTY + +#corner top-right +Index 113 +Pos 0 -1 EMPTY +Pos 1 0 EMPTY + +#corner top-left +Index 112 +Pos 0 -1 EMPTY +Pos -1 0 EMPTY + +#corner bottom-left +Index 115 +Pos 0 1 EMPTY +Pos -1 0 EMPTY + +#corner bottom-right +Index 114 +Pos 0 1 EMPTY +Pos 1 0 EMPTY + +#inside corner top-right +Index 131 +Pos -1 1 EMPTY +Pos -1 0 FULL +Pos 0 1 FULL + +#inside corner top-left +Index 130 +Pos 1 1 EMPTY +Pos 1 0 FULL +Pos 0 1 FULL + +#inside corner bottom-left +Index 129 +Pos 1 -1 EMPTY +Pos 1 0 FULL +Pos 0 -1 FULL + +#inside corner bottom-right +Index 128 +Pos -1 -1 EMPTY +Pos -1 0 FULL +Pos 0 -1 FULL diff --git a/data/editor/grass_main.rules b/data/editor/grass_main.rules new file mode 100644 index 00000000..b909eb0e --- /dev/null +++ b/data/editor/grass_main.rules @@ -0,0 +1,225 @@ +[Grass] +Index 1 +BaseTile + +#random bones +Index 2 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 150 + +Index 3 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 150 + +Index 66 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 150 + +Index 67 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 150 + +Index 68 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 150 +#--------- + +#top +Index 16 +Pos 0 -1 EMPTY + +#right +Index 21 +Pos 1 0 EMPTY + +#bottom +Index 52 +Pos 0 1 EMPTY + +#left +Index 20 +Pos -1 0 EMPTY + +#corner top-right +Index 5 +Pos 0 -1 EMPTY +Pos 1 0 EMPTY + +#corner top-left +Index 4 +Pos 0 -1 EMPTY +Pos -1 0 EMPTY + +#corner bottom-left +Index 36 +Pos 0 1 EMPTY +Pos -1 0 EMPTY + +#corner bottom-right +Index 37 +Pos 0 1 EMPTY +Pos 1 0 EMPTY + +#inside corner top-right +Index 54 +Pos -1 1 EMPTY +Pos -1 0 FULL +Pos 0 1 FULL + +#inside corner top-left +Index 53 +Pos 1 1 EMPTY +Pos 1 0 FULL +Pos 0 1 FULL + +#inside corner bottom-left +Index 49 +Pos 1 -1 EMPTY +Pos 1 0 FULL +Pos 0 -1 FULL + +#inside corner bottom-right +Index 48 +Pos -1 -1 EMPTY +Pos -1 0 FULL +Pos 0 -1 FULL + +#right bottom +Index 22 +Pos -1 0 EMPTY +Pos -1 1 FULL +Pos 0 1 FULL + +#left bottom +Index 38 +Pos 1 0 EMPTY +Pos 1 1 FULL +Pos 0 1 FULL + +#top corner right 2 +Index 33 +Pos 0 -1 EMPTY +Pos 1 0 EMPTY +Pos 1 1 FULL + +#top corner left 2 +Index 32 +Pos 0 -1 EMPTY +Pos -1 0 EMPTY +Pos -1 1 FULL + +[Cave] +Index 13 +BaseTile + +#random bones +Index 29 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 150 + +Index 42 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 150 + +Index 43 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 150 + +Index 44 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 150 + +Index 45 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 150 +#--------- + +#top +Index 26 +Pos 0 -1 EMPTY + +#right +Index 25 +Pos 1 0 EMPTY + +#bottom +Index 10 +Pos 0 1 EMPTY + +#left +Index 24 +Pos -1 0 EMPTY + +#corner top-right +Index 9 +Pos 0 -1 EMPTY +Pos 1 0 EMPTY + +#corner top-left +Index 8 +Pos 0 -1 EMPTY +Pos -1 0 EMPTY + +#corner bottom-left +Index 40 +Pos 0 1 EMPTY +Pos -1 0 EMPTY + +#corner bottom-right +Index 41 +Pos 0 1 EMPTY +Pos 1 0 EMPTY + +#inside corner top-right +Index 12 +Pos -1 1 EMPTY +Pos -1 0 FULL +Pos 0 1 FULL + +#inside corner top-left +Index 11 +Pos 1 1 EMPTY +Pos 1 0 FULL +Pos 0 1 FULL + +#inside corner bottom-left +Index 27 +Pos 1 -1 EMPTY +Pos 1 0 FULL +Pos 0 -1 FULL + +#inside corner bottom-right +Index 28 +Pos -1 -1 EMPTY +Pos -1 0 FULL +Pos 0 -1 FULL diff --git a/data/editor/jungle_main.rules b/data/editor/jungle_main.rules new file mode 100644 index 00000000..3b967020 --- /dev/null +++ b/data/editor/jungle_main.rules @@ -0,0 +1,220 @@ +[Jungle] +Index 1 +BaseTile + +#random bricks +Index 66 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 150 + +Index 67 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 150 + +#top +Index 16 +Pos 0 -1 EMPTY + +Index 96 +Pos 0 -1 EMPTY +Random 4 + +Index 97 +Pos 0 -1 EMPTY +Random 4 + +Index 98 +Pos 0 -1 EMPTY +Random 4 + +#right +Index 21 +Pos 1 0 EMPTY + +#bottom +Index 52 +Pos 0 1 EMPTY + +Index 99 +Pos 0 1 EMPTY +Random 4 + +Index 100 +Pos 0 1 EMPTY +Random 4 + +Index 101 +Pos 0 1 EMPTY +Random 4 + +#left +Index 21 XFLIP +Pos -1 0 EMPTY + +#corner top-right +Index 5 +Pos 0 -1 EMPTY +Pos 1 0 EMPTY + +#corner top-left +Index 5 XFLIP +Pos 0 -1 EMPTY +Pos -1 0 EMPTY + +#corner bottom-left +Index 37 XFLIP +Pos 0 1 EMPTY +Pos -1 0 EMPTY + +#corner bottom-right +Index 37 +Pos 0 1 EMPTY +Pos 1 0 EMPTY + +#inside corner top-right +Index 54 +Pos -1 1 EMPTY +Pos -1 0 FULL +Pos 0 1 FULL + +#inside corner top-left +Index 54 XFLIP +Pos 1 1 EMPTY +Pos 1 0 FULL +Pos 0 1 FULL + +#inside corner bottom-left +Index 48 XFLIP +Pos 1 -1 EMPTY +Pos 1 0 FULL +Pos 0 -1 FULL + +#inside corner bottom-right +Index 48 +Pos -1 -1 EMPTY +Pos -1 0 FULL +Pos 0 -1 FULL + +#right bottom +Index 22 +Pos -1 0 EMPTY +Pos -1 1 FULL +Pos 0 1 FULL + +#left bottom +Index 22 XFLIP +Pos 1 0 EMPTY +Pos 1 1 FULL +Pos 0 1 FULL + +#top corner right 2 +Index 33 +Pos 0 -1 EMPTY +Pos 1 0 EMPTY +Pos 1 1 FULL + +#top corner left 2 +Index 32 +Pos 0 -1 EMPTY +Pos -1 0 EMPTY +Pos -1 1 FULL + +[Jungle dark] +Index 13 +BaseTile + +#random bricks +Index 42 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 150 + +Index 43 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 150 + +Index 44 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 150 + +Index 45 +Pos 0 1 FULL +Pos 0 -1 FULL +Pos 1 0 FULL +Pos -1 0 FULL +Random 150 +#--------- + +#top +Index 26 +Pos 0 -1 EMPTY + +#right +Index 25 +Pos 1 0 EMPTY + +#bottom +Index 10 +Pos 0 1 EMPTY + +#left +Index 24 +Pos -1 0 EMPTY + +#corner top-right +Index 9 +Pos 0 -1 EMPTY +Pos 1 0 EMPTY + +#corner top-left +Index 8 +Pos 0 -1 EMPTY +Pos -1 0 EMPTY + +#corner bottom-left +Index 40 +Pos 0 1 EMPTY +Pos -1 0 EMPTY + +#corner bottom-right +Index 41 +Pos 0 1 EMPTY +Pos 1 0 EMPTY + +#inside corner top-right +Index 12 +Pos -1 1 EMPTY +Pos -1 0 FULL +Pos 0 1 FULL + +#inside corner top-left +Index 11 +Pos 1 1 EMPTY +Pos 1 0 FULL +Pos 0 1 FULL + +#inside corner bottom-left +Index 27 +Pos 1 -1 EMPTY +Pos 1 0 FULL +Pos 0 -1 FULL + +#inside corner bottom-right +Index 28 +Pos -1 -1 EMPTY +Pos -1 0 FULL +Pos 0 -1 FULL diff --git a/data/editor/winter_main.rules b/data/editor/winter_main.rules new file mode 100644 index 00000000..eaeaec8e --- /dev/null +++ b/data/editor/winter_main.rules @@ -0,0 +1,177 @@ +[Winter] +Index 1 +BaseTile + +#top +Index 17 +Pos 0 -1 EMPTY + +Index 18 +Pos 0 -1 EMPTY +Pos -1 0 INDEX 17 + +Index 19 +Pos 0 -1 EMPTY +Pos -1 0 INDEX 18 + +#bottom +Index 97 +Pos 0 1 EMPTY + +Index 98 +Pos 0 1 EMPTY +Pos -1 0 INDEX 97 + +Index 99 +Pos 0 1 EMPTY +Pos -1 0 INDEX 98 + +#right +Index 2 XFLIP +Pos 1 0 EMPTY + +#left +Index 2 +Pos -1 0 EMPTY + +#corner top right +Index 20 +Pos 0 -1 EMPTY +Pos 1 0 EMPTY + +Index 24 +Pos 0 -1 EMPTY +Pos 1 0 EMPTY +Pos -1 0 INDEX 17 + +#corner top left +Index 16 +Pos 0 -1 EMPTY +Pos -1 0 EMPTY + +#corner bottom right +Index 100 +Pos 0 1 EMPTY +Pos 1 0 EMPTY + +#corner bottom left +Index 96 +Pos 0 1 EMPTY +Pos -1 0 EMPTY + +#inside corner top right +Index 8 +Pos 0 1 FULL +Pos -1 0 FULL +Pos -1 1 EMPTY + +#inside corner top left +Index 7 +Pos 0 1 FULL +Pos 1 0 FULL +Pos 1 1 EMPTY + +#inside corner bottom right +Index 4 +Pos 0 -1 FULL +Pos -1 0 FULL +Pos -1 -1 EMPTY + +#inside corner bottom left +Index 3 +Pos 0 -1 FULL +Pos 1 0 FULL +Pos 1 -1 EMPTY + +#one tile height +Index 113 +Pos 0 1 EMPTY +Pos 0 -1 EMPTY + +Index 114 +Pos 0 1 EMPTY +Pos 0 -1 EMPTY +Pos -1 0 INDEX 113 + +Index 115 +Pos 0 1 EMPTY +Pos 0 -1 EMPTY +Pos -1 0 INDEX 114 + +#one tile height right +Index 116 +Pos 0 1 EMPTY +Pos 0 -1 EMPTY +Pos 1 0 EMPTY + +Index 120 +Pos 0 1 EMPTY +Pos 0 -1 EMPTY +Pos 1 0 EMPTY +Pos -1 0 INDEX 113 + +#one tile height left +Index 112 +Pos 0 1 EMPTY +Pos 0 -1 EMPTY +Pos -1 0 EMPTY + +#one tile height link right +Index 6 +Pos -1 -1 EMPTY +Pos -1 0 FULL +Pos 0 -1 FULL +Pos -1 1 EMPTY + +#one tile height link left +Index 5 +Pos 1 -1 EMPTY +Pos 1 0 FULL +Pos 0 -1 FULL +Pos 1 1 EMPTY + +[Winter dark] +Index 177 +BaseTile + +#bottom +Index 194 +Pos 0 1 EMPTY + +Index 195 +Pos 0 1 EMPTY +Pos -1 0 INDEX 194 + +Index 196 +Pos 0 1 EMPTY +Pos -1 0 INDEX 195 + +#right +Index 178 XFLIP +Pos 1 0 EMPTY + +#left +Index 178 +Pos -1 0 EMPTY + +#corner bottom right +Index 197 +Pos 0 1 EMPTY +Pos 1 0 EMPTY + +#corner bottom left +Index 193 +Pos 0 1 EMPTY +Pos -1 0 EMPTY + +#inside corner top right +Index 180 +Pos 0 1 FULL +Pos -1 0 FULL +Pos -1 1 EMPTY + +#inside corner top left +Index 179 +Pos 0 1 FULL +Pos 1 0 FULL +Pos 1 1 EMPTY diff --git a/src/game/editor/auto_map.cpp b/src/game/editor/auto_map.cpp new file mode 100644 index 00000000..528e459b --- /dev/null +++ b/src/game/editor/auto_map.cpp @@ -0,0 +1,202 @@ +#include // sscanf + +#include +#include +#include + +#include "auto_map.h" +#include "editor.h" + +CAutoMapper::CAutoMapper(CEditor *pEditor) +{ + m_pEditor = pEditor; + m_FileLoaded = false; +} + +void CAutoMapper::Load(const char* pTileName) +{ + char aPath[256]; + str_format(aPath, sizeof(aPath), "editor/%s.rules", pTileName); + IOHANDLE RulesFile = m_pEditor->Storage()->OpenFile(aPath, IOFLAG_READ, IStorage::TYPE_ALL); + if(!RulesFile) + return; + + CLineReader LineReader; + LineReader.Init(RulesFile); + + CConfiguration *pCurrentConf = 0; + CIndexRule *pCurrentIndex = 0; + + char aBuf[256]; + + // read each line + while(char *pLine = LineReader.Get()) + { + // skip blank/empty lines as well as comments + if(str_length(pLine) > 0 && pLine[0] != '#' && pLine[0] != '\n' && pLine[0] != '\r' + && pLine[0] != '\t' && pLine[0] != '\v' && pLine[0] != ' ') + { + if(pLine[0]== '[') + { + // new configuration, get the name + pLine++; + + CConfiguration NewConf; + int ID = m_lConfigs.add(NewConf); + pCurrentConf = &m_lConfigs[ID]; + + str_copy(pCurrentConf->m_aName, pLine, str_length(pLine)); + } + else + { + if(!str_comp_num(pLine, "Index", 5)) + { + // new index + int ID = 0; + char aFlip[128] = ""; + + sscanf(pLine, "Index %d %127s", &ID, aFlip); + + CIndexRule NewIndexRule; + NewIndexRule.m_ID = ID; + NewIndexRule.m_Flag = 0; + NewIndexRule.m_RandomValue = 0; + NewIndexRule.m_BaseTile = false; + + if(str_length(aFlip) > 0) + { + if(!str_comp(aFlip, "XFLIP")) + NewIndexRule.m_Flag = TILEFLAG_VFLIP; + else if(!str_comp(aFlip, "YFLIP")) + NewIndexRule.m_Flag = TILEFLAG_HFLIP; + } + + // add the index rule object and make it current + int ArrayID = pCurrentConf->m_aIndexRules.add(NewIndexRule); + pCurrentIndex = &pCurrentConf->m_aIndexRules[ArrayID]; + } + else if(!str_comp_num(pLine, "BaseTile", 8) && pCurrentIndex) + { + pCurrentIndex->m_BaseTile = true; + } + else if(!str_comp_num(pLine, "Pos", 3) && pCurrentIndex) + { + int x = 0, y = 0; + char aValue[128]; + int Value = CPosRule::EMPTY; + bool IndexValue = false; + + sscanf(pLine, "Pos %d %d %127s", &x, &y, aValue); + + if(!str_comp(aValue, "FULL")) + Value = CPosRule::FULL; + else if(!str_comp_num(aValue, "INDEX", 5)) + { + sscanf(pLine, "Pos %*d %*d INDEX %d", &Value); + IndexValue = true; + } + + CPosRule NewPosRule = {x, y, Value, IndexValue}; + pCurrentIndex->m_aRules.add(NewPosRule); + } + else if(!str_comp_num(pLine, "Random", 6) && pCurrentIndex) + { + sscanf(pLine, "Random %d", &pCurrentIndex->m_RandomValue); + } + } + } + } + + io_close(RulesFile); + + str_format(aBuf, sizeof(aBuf),"loaded %s", aPath); + m_pEditor->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "editor", aBuf); + + m_FileLoaded = true; +} + +const char* CAutoMapper::GetConfigName(int Index) +{ + if(Index < 0 || Index >= m_lConfigs.size()) + return ""; + + return m_lConfigs[Index].m_aName; +} + +void CAutoMapper::Proceed(CLayerTiles *pLayer, int ConfigID) +{ + if(!m_FileLoaded || pLayer->m_Readonly || ConfigID < 0 || ConfigID >= m_lConfigs.size()) + return; + + CConfiguration *pConf = &m_lConfigs[ConfigID]; + + if(!pConf->m_aIndexRules.size()) + return; + + int BaseTile = 1; + + // find base tile if there is one + for(int i = 0; i < pConf->m_aIndexRules.size(); ++i) + { + if(pConf->m_aIndexRules[i].m_BaseTile) + { + BaseTile = pConf->m_aIndexRules[i].m_ID; + break; + } + } + + // auto map ! + int MaxIndex = pLayer->m_Width*pLayer->m_Height; + for(int y = 0; y < pLayer->m_Height; y++) + for(int x = 0; x < pLayer->m_Width; x++) + { + CTile *pTile = &(pLayer->m_pTiles[y*pLayer->m_Width+x]); + if(pTile->m_Index == 0) + continue; + + pTile->m_Index = BaseTile; + m_pEditor->m_Map.m_Modified = true; + + if(y == 0 || y == pLayer->m_Height-1 || x == 0 || x == pLayer->m_Width-1) + continue; + + for(int i = 0; i < pConf->m_aIndexRules.size(); ++i) + { + if(pConf->m_aIndexRules[i].m_BaseTile) + continue; + + bool RespectRules = true; + for(int j = 0; j < pConf->m_aIndexRules[i].m_aRules.size() && RespectRules; ++j) + { + CPosRule *pRule = &pConf->m_aIndexRules[i].m_aRules[j]; + int CheckIndex = (y+pRule->m_Y)*pLayer->m_Width+(x+pRule->m_X); + + if(CheckIndex < 0 || CheckIndex >= MaxIndex) + RespectRules = false; + else + { + if(pRule->m_IndexValue) + { + if(pLayer->m_pTiles[CheckIndex].m_Index != pRule->m_Value) + RespectRules = false; + } + else + { + if(pLayer->m_pTiles[CheckIndex].m_Index > 0 && pRule->m_Value == CPosRule::EMPTY) + RespectRules = false; + + if(pLayer->m_pTiles[CheckIndex].m_Index == 0 && pRule->m_Value == CPosRule::FULL) + RespectRules = false; + } + } + } + + if(RespectRules && + (pConf->m_aIndexRules[i].m_RandomValue <= 1 || (int)((float)rand() / ((float)RAND_MAX + 1) * pConf->m_aIndexRules[i].m_RandomValue) == 1)) + { + pTile->m_Index = pConf->m_aIndexRules[i].m_ID; + pTile->m_Flags = pConf->m_aIndexRules[i].m_Flag; + } + } + } +} diff --git a/src/game/editor/auto_map.h b/src/game/editor/auto_map.h new file mode 100644 index 00000000..4f4cf92e --- /dev/null +++ b/src/game/editor/auto_map.h @@ -0,0 +1,54 @@ +#ifndef GAME_EDITOR_ED_AUTO_MAP_H +#define GAME_EDITOR_ED_AUTO_MAP_H + +#include + +class CAutoMapper +{ + struct CPosRule + { + int m_X; + int m_Y; + int m_Value; + bool m_IndexValue; + + enum + { + EMPTY=0, + FULL + }; + }; + + struct CIndexRule + { + int m_ID; + array m_aRules; + int m_Flag; + int m_RandomValue; + bool m_BaseTile; + }; + + struct CConfiguration + { + array m_aIndexRules; + char m_aName[128]; + }; + +public: + CAutoMapper(class CEditor *pEditor); + + void Load(const char* pTileName); + void Proceed(class CLayerTiles *pLayer, int ConfigID); + + int ConfigNamesNum() { return m_lConfigs.size(); } + const char* GetConfigName(int Index); + + const bool IsLoaded() { return m_FileLoaded; } +private: + array m_lConfigs; + class CEditor *m_pEditor; + bool m_FileLoaded; +}; + + +#endif diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index bc00c4a2..907552dc 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -8,20 +8,20 @@ #include #include #include -#include #include #include #include +#include -#include #include +#include +#include #include +#include #include +#include "auto_map.h" #include "editor.h" -#include - -#include int CEditor::ms_CheckerTexture; int CEditor::ms_BackgroundTexture; @@ -1899,6 +1899,7 @@ void CEditor::ReplaceImage(const char *pFileName, int StorageType, void *pUser) *pImg = ImgInfo; pImg->m_External = External; pEditor->ExtractName(pFileName, pImg->m_aName, sizeof(pImg->m_aName)); + pImg->m_AutoMapper.Load(pImg->m_aName); pImg->m_TexID = pEditor->Graphics()->LoadTextureRaw(ImgInfo.m_Width, ImgInfo.m_Height, ImgInfo.m_Format, ImgInfo.m_pData, CImageInfo::FORMAT_AUTO, 0); pEditor->SortImages(); for(int i = 0; i < pEditor->m_Map.m_lImages.size(); ++i) @@ -1930,6 +1931,7 @@ void CEditor::AddImage(const char *pFileName, int StorageType, void *pUser) pImg->m_TexID = pEditor->Graphics()->LoadTextureRaw(ImgInfo.m_Width, ImgInfo.m_Height, ImgInfo.m_Format, ImgInfo.m_pData, CImageInfo::FORMAT_AUTO, 0); pImg->m_External = 1; // external by default str_copy(pImg->m_aName, aBuf, sizeof(pImg->m_aName)); + pImg->m_AutoMapper.Load(pImg->m_aName); pEditor->m_Map.m_lImages.add(pImg); pEditor->SortImages(); if(pEditor->m_SelectedImage > -1 && pEditor->m_SelectedImage < pEditor->m_Map.m_lImages.size()) diff --git a/src/game/editor/editor.h b/src/game/editor/editor.h index c7779954..353b0774 100644 --- a/src/game/editor/editor.h +++ b/src/game/editor/editor.h @@ -3,23 +3,26 @@ #ifndef GAME_EDITOR_EDITOR_H #define GAME_EDITOR_EDITOR_H -#include +#include + #include -#include +#include + #include +#include #include #include -#include +#include #include #include -#include #include +#include #include #include -#include +#include "auto_map.h" typedef void (*INDEX_MODIFY_FUNC)(int *pIndex); @@ -230,6 +233,7 @@ public: CEditor *m_pEditor; CEditorImage(CEditor *pEditor) + : m_AutoMapper(pEditor) { m_pEditor = pEditor; m_TexID = -1; @@ -249,6 +253,7 @@ public: int m_External; char m_aName[128]; unsigned char m_aTileFlags[256]; + class CAutoMapper m_AutoMapper; }; class CEditorMap @@ -684,6 +689,7 @@ public: static int PopupSelectGametileOp(CEditor *pEditor, CUIRect View); static int PopupImage(CEditor *pEditor, CUIRect View); static int PopupMenuFile(CEditor *pEditor, CUIRect View); + static int PopupSelectConfigAutoMap(CEditor *pEditor, CUIRect View); static void CallbackOpenMap(const char *pFileName, int StorageType, void *pUser); static void CallbackAppendMap(const char *pFileName, int StorageType, void *pUser); @@ -694,6 +700,9 @@ public: void PopupSelectGametileOpInvoke(float x, float y); int PopupSelectGameTileOpResult(); + + void PopupSelectConfigAutoMapInvoke(float x, float y); + int PopupSelectConfigAutoMapResult(); vec4 ButtonColorMul(const void *pID); diff --git a/src/game/editor/io.cpp b/src/game/editor/io.cpp index 7207e49f..987404b8 100644 --- a/src/game/editor/io.cpp +++ b/src/game/editor/io.cpp @@ -449,6 +449,9 @@ int CEditorMap::Load(class IStorage *pStorage, const char *pFileName, int Storag if(pName) str_copy(pImg->m_aName, pName, 128); + // load auto mapper file + pImg->m_AutoMapper.Load(pImg->m_aName); + m_lImages.add(pImg); // unload image diff --git a/src/game/editor/layer_tiles.cpp b/src/game/editor/layer_tiles.cpp index b792eda9..81944636 100644 --- a/src/game/editor/layer_tiles.cpp +++ b/src/game/editor/layer_tiles.cpp @@ -360,14 +360,32 @@ void CLayerTiles::ShowInfo() int CLayerTiles::RenderProperties(CUIRect *pToolBox) { CUIRect Button; - pToolBox->HSplitBottom(12.0f, pToolBox, &Button); - + bool InGameGroup = !find_linear(m_pEditor->m_Map.m_pGameGroup->m_lLayers.all(), this).empty(); - if(m_pEditor->m_Map.m_pGameLayer == this) + if(m_pEditor->m_Map.m_pGameLayer != this) + { + if(m_Image >= 0 && m_Image < m_pEditor->m_Map.m_lImages.size() && m_pEditor->m_Map.m_lImages[m_Image]->m_AutoMapper.IsLoaded()) + { + static int s_AutoMapperButton = 0; + pToolBox->HSplitBottom(12.0f, pToolBox, &Button); + if(m_pEditor->DoButton_Editor(&s_AutoMapperButton, "Auto map", 0, &Button, 0, "")) + m_pEditor->PopupSelectConfigAutoMapInvoke(m_pEditor->UI()->MouseX(), m_pEditor->UI()->MouseY()); + + int Result = m_pEditor->PopupSelectConfigAutoMapResult(); + if(Result > -1) + { + m_pEditor->m_Map.m_lImages[m_Image]->m_AutoMapper.Proceed(this, Result); + return 1; + } + } + } + else InGameGroup = false; if(InGameGroup) { + pToolBox->HSplitBottom(2.0f, pToolBox, 0); + pToolBox->HSplitBottom(12.0f, pToolBox, &Button); static int s_ColclButton = 0; if(m_pEditor->DoButton_Editor(&s_ColclButton, "Game tiles", 0, &Button, 0, "Constructs game tiles from this layer")) m_pEditor->PopupSelectGametileOpInvoke(m_pEditor->UI()->MouseX(), m_pEditor->UI()->MouseY()); diff --git a/src/game/editor/popups.cpp b/src/game/editor/popups.cpp index 3ae29725..0a691fdf 100644 --- a/src/game/editor/popups.cpp +++ b/src/game/editor/popups.cpp @@ -1,10 +1,14 @@ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ + +#include + #include #include #include #include #include + #include "editor.h" @@ -737,3 +741,43 @@ int CEditor::PopupSelectGameTileOpResult() s_GametileOpSelected = -1; return Result; } + +static int s_AutoMapConfigSelected = -1; + +int CEditor::PopupSelectConfigAutoMap(CEditor *pEditor, CUIRect View) +{ + CLayerTiles *pLayer = static_cast(pEditor->GetSelectedLayer(0)); + CUIRect Button; + static int s_AutoMapperConfigButtons[256]; + CAutoMapper *pAutoMapper = &pEditor->m_Map.m_lImages[pLayer->m_Image]->m_AutoMapper; + + for(int i = 0; i < pAutoMapper->ConfigNamesNum(); ++i) + { + View.HSplitTop(2.0f, 0, &View); + View.HSplitTop(12.0f, &Button, &View); + if(pEditor->DoButton_Editor(&s_AutoMapperConfigButtons[i], pAutoMapper->GetConfigName(i), 0, &Button, 0, 0)) + s_AutoMapConfigSelected = i; + } + + return 0; +} + +void CEditor::PopupSelectConfigAutoMapInvoke(float x, float y) +{ + static int s_AutoMapConfigSelectID = 0; + s_AutoMapConfigSelected = -1; + CLayerTiles *pLayer = static_cast(GetSelectedLayer(0)); + if(pLayer && pLayer->m_Image >= 0 && pLayer->m_Image < m_Map.m_lImages.size() && + m_Map.m_lImages[pLayer->m_Image]->m_AutoMapper.ConfigNamesNum()) + UiInvokePopupMenu(&s_AutoMapConfigSelectID, 0, x, y, 120.0f, 12.0f+14.0f*m_Map.m_lImages[pLayer->m_Image]->m_AutoMapper.ConfigNamesNum(), PopupSelectConfigAutoMap); +} + +int CEditor::PopupSelectConfigAutoMapResult() +{ + if(s_AutoMapConfigSelected < 0) + return -1; + + int Result = s_AutoMapConfigSelected; + s_AutoMapConfigSelected = -1; + return Result; +} -- cgit 1.4.1 From 1058fe27f2411f08918fc39183a6101b8d3c9f72 Mon Sep 17 00:00:00 2001 From: Romain Labolle Date: Sat, 9 Jul 2011 11:45:01 +0200 Subject: Allow multi-file input for dilate and tilset_borderfix commands --- src/tools/dilate.cpp | 24 +++++++++++++++++++----- src/tools/tileset_borderfix.cpp | 24 +++++++++++++++++++----- 2 files changed, 38 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/tools/dilate.cpp b/src/tools/dilate.cpp index ef862270..a4853e1c 100644 --- a/src/tools/dilate.cpp +++ b/src/tools/dilate.cpp @@ -48,18 +48,18 @@ static void CopyAlpha(int w, int h, CPixel *pSrc, CPixel *pDest) pDest[m].a = pSrc[m].a; } -int main(int argc, char **argv) +int DilateFile(const char *FileName) { png_t Png; CPixel *pBuffer[3] = {0,0,0}; png_init(0, 0); - png_open_file(&Png, argv[1]); + png_open_file(&Png, FileName); if(Png.color_type != PNG_TRUECOLOR_ALPHA) { - dbg_msg("dilate", "not an RGBA image"); - return -1; + dbg_msg("dilate", "%s : not an RGBA image", FileName); + return 1; } pBuffer[0] = (CPixel*)mem_alloc(Png.width*Png.height*sizeof(CPixel), 1); @@ -81,9 +81,23 @@ int main(int argc, char **argv) CopyAlpha(w, h, pBuffer[0], pBuffer[1]); // save here - png_open_file_write(&Png, argv[1]); + png_open_file_write(&Png, FileName); png_set_data(&Png, w, h, 8, PNG_TRUECOLOR_ALPHA, (unsigned char *)pBuffer[1]); png_close_file(&Png); return 0; } + +int main(int argc, const char **argv) +{ + dbg_logger_stdout(); + if(argc == 1) + { + dbg_msg("Usage", "%s FILE1 [ FILE2... ]", argv[0]); + return -1; + } + int errors=0; + for(int i=1;i Date: Mon, 11 Jul 2011 11:26:41 +0200 Subject: cleaned up last commit --- src/tools/dilate.cpp | 16 ++++++++-------- src/tools/tileset_borderfix.cpp | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/tools/dilate.cpp b/src/tools/dilate.cpp index a4853e1c..eb770a90 100644 --- a/src/tools/dilate.cpp +++ b/src/tools/dilate.cpp @@ -48,17 +48,17 @@ static void CopyAlpha(int w, int h, CPixel *pSrc, CPixel *pDest) pDest[m].a = pSrc[m].a; } -int DilateFile(const char *FileName) +int DilateFile(const char *pFileName) { png_t Png; CPixel *pBuffer[3] = {0,0,0}; png_init(0, 0); - png_open_file(&Png, FileName); + png_open_file(&Png, pFileName); if(Png.color_type != PNG_TRUECOLOR_ALPHA) { - dbg_msg("dilate", "%s : not an RGBA image", FileName); + dbg_msg("dilate", "%s: not an RGBA image", pFileName); return 1; } @@ -81,7 +81,7 @@ int DilateFile(const char *FileName) CopyAlpha(w, h, pBuffer[0], pBuffer[1]); // save here - png_open_file_write(&Png, FileName); + png_open_file_write(&Png, pFileName); png_set_data(&Png, w, h, 8, PNG_TRUECOLOR_ALPHA, (unsigned char *)pBuffer[1]); png_close_file(&Png); @@ -96,8 +96,8 @@ int main(int argc, const char **argv) dbg_msg("Usage", "%s FILE1 [ FILE2... ]", argv[0]); return -1; } - int errors=0; - for(int i=1;i Date: Sun, 10 Jul 2011 13:02:13 +0200 Subject: Display a message when an admin forces a vote. Closes #759 --- src/game/server/gamecontext.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index a8b2f379..52eaca89 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -1264,6 +1264,8 @@ void CGameContext::ConForceVote(IConsole::IResult *pResult, void *pUserData) return; } + str_format(aBuf, sizeof(aBuf), "admin moved '%s' to spectator (%s)", pSelf->Server()->ClientName(SpectateID), pReason); + pSelf->SendChatTarget(-1, aBuf); str_format(aBuf, sizeof(aBuf), "set_team %d -1 %d", SpectateID, g_Config.m_SvVoteSpectateRejoindelay); pSelf->Console()->ExecuteLine(aBuf); } @@ -1290,6 +1292,8 @@ void CGameContext::ConVote(IConsole::IResult *pResult, void *pUserData) else if(str_comp_nocase(pResult->GetString(0), "no") == 0) pSelf->m_VoteEnforce = CGameContext::VOTE_ENFORCE_NO; char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "admin forced vote %s", pResult->GetString(0)); + pSelf->SendChatTarget(-1, aBuf); str_format(aBuf, sizeof(aBuf), "forcing vote %s", pResult->GetString(0)); pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); } -- cgit 1.4.1 From d28108b8ad25476ea5fc05836bea6a35205c7213 Mon Sep 17 00:00:00 2001 From: oy Date: Mon, 11 Jul 2011 12:00:13 +0200 Subject: fixed few issues with masters.cfg --- src/engine/masterserver.h | 1 - src/engine/shared/masterserver.cpp | 90 +++++++++++++++++++++----------------- 2 files changed, 49 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/engine/masterserver.h b/src/engine/masterserver.h index 74a394dc..57433993 100644 --- a/src/engine/masterserver.h +++ b/src/engine/masterserver.h @@ -23,7 +23,6 @@ public: virtual int RefreshAddresses(int Nettype) = 0; virtual void Update() = 0; virtual int IsRefreshing() = 0; - virtual void DumpServers() = 0; virtual NETADDR GetAddr(int Index) = 0; virtual const char *GetName(int Index) = 0; virtual bool IsValid(int Index) = 0; diff --git a/src/engine/shared/masterserver.cpp b/src/engine/shared/masterserver.cpp index 1bf402ca..1271eeaf 100644 --- a/src/engine/shared/masterserver.cpp +++ b/src/engine/shared/masterserver.cpp @@ -21,51 +21,57 @@ public: bool m_Valid; CHostLookup m_Lookup; - } ; + }; + + enum + { + STATE_INIT, + STATE_UPDATE, + STATE_READY, + }; CMasterInfo m_aMasterServers[MAX_MASTERSERVERS]; - int m_NeedsUpdate; + int m_State; IEngine *m_pEngine; IStorage *m_pStorage; CMasterServer() { SetDefault(); - m_NeedsUpdate = -1; + m_State = STATE_INIT; m_pEngine = 0; + m_pStorage = 0; } virtual int RefreshAddresses(int Nettype) { - int i; - - if(m_NeedsUpdate != -1) - return 0; + if(m_State != STATE_INIT) + return -1; dbg_msg("engine/mastersrv", "refreshing master server addresses"); // add lookup jobs - for(i = 0; i < MAX_MASTERSERVERS; i++) + for(int i = 0; i < MAX_MASTERSERVERS; i++) { m_pEngine->HostLookup(&m_aMasterServers[i].m_Lookup, m_aMasterServers[i].m_aHostname, Nettype); m_aMasterServers[i].m_Valid = false; } - m_NeedsUpdate = 1; + m_State = STATE_UPDATE; return 0; } virtual void Update() { // check if we need to update - if(m_NeedsUpdate != 1) + if(m_State != STATE_UPDATE) return; - m_NeedsUpdate = 0; + m_State = STATE_READY; for(int i = 0; i < MAX_MASTERSERVERS; i++) { if(m_aMasterServers[i].m_Lookup.m_Job.Status() != CJob::STATE_DONE) - m_NeedsUpdate = 1; + m_State = STATE_UPDATE; else { if(m_aMasterServers[i].m_Lookup.m_Job.Result() == 0) @@ -79,7 +85,7 @@ public: } } - if(!m_NeedsUpdate) + if(m_State == STATE_READY) { dbg_msg("engine/mastersrv", "saving addresses"); Save(); @@ -88,7 +94,7 @@ public: virtual int IsRefreshing() { - return m_NeedsUpdate; + return m_State != STATE_READY; } virtual NETADDR GetAddr(int Index) @@ -106,16 +112,6 @@ public: return m_aMasterServers[Index].m_Valid; } - virtual void DumpServers() - { - for(int i = 0; i < MAX_MASTERSERVERS; i++) - { - char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(&m_aMasterServers[i].m_Addr, aAddrStr, sizeof(aAddrStr)); - dbg_msg("mastersrv", "#%d = %s", i, aAddrStr); - } - } - virtual void Init() { m_pEngine = Kernel()->RequestInterface(); @@ -131,17 +127,15 @@ public: virtual int Load() { - CLineReader LineReader; - IOHANDLE File; - int Count = 0; if(!m_pStorage) return -1; // try to open file - File = m_pStorage->OpenFile("masters.cfg", IOFLAG_READ, IStorage::TYPE_SAVE); + IOHANDLE File = m_pStorage->OpenFile("masters.cfg", IOFLAG_READ, IStorage::TYPE_SAVE); if(!File) return -1; + CLineReader LineReader; LineReader.Init(File); while(1) { @@ -152,19 +146,32 @@ public: // parse line char aAddrStr[NETADDR_MAXSTRSIZE]; - if(sscanf(pLine, "%s %s", Info.m_aHostname, aAddrStr) == 2 && net_addr_from_str(&Info.m_Addr, aAddrStr) == 0) + if(sscanf(pLine, "%127s %47s", Info.m_aHostname, aAddrStr) == 2 && net_addr_from_str(&Info.m_Addr, aAddrStr) == 0) { Info.m_Addr.port = 8300; - if(Count != MAX_MASTERSERVERS) + bool Added = false; + for(int i = 0; i < MAX_MASTERSERVERS; ++i) + if(str_comp(m_aMasterServers[i].m_aHostname, Info.m_aHostname) == 0) + { + m_aMasterServers[i] = Info; + Added = true; + break; + } + + if(!Added) { - m_aMasterServers[Count] = Info; - Count++; + for(int i = 0; i < MAX_MASTERSERVERS; ++i) + if(m_aMasterServers[i].m_Addr.type == NETTYPE_INVALID) + { + m_aMasterServers[i] = Info; + Added = true; + break; + } } - //else - // dbg_msg("engine/mastersrv", "warning: skipped master server '%s' due to limit of %d", pLine, MAX_MASTERSERVERS); + + if(!Added) + break; } - //else - // dbg_msg("engine/mastersrv", "warning: couldn't parse master server '%s'", pLine); } io_close(File); @@ -173,21 +180,22 @@ public: virtual int Save() { - IOHANDLE File; - if(!m_pStorage) return -1; // try to open file - File = m_pStorage->OpenFile("masters.cfg", IOFLAG_WRITE, IStorage::TYPE_SAVE); + IOHANDLE File = m_pStorage->OpenFile("masters.cfg", IOFLAG_WRITE, IStorage::TYPE_SAVE); if(!File) return -1; for(int i = 0; i < MAX_MASTERSERVERS; i++) { char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(&m_aMasterServers[i].m_Addr, aAddrStr, sizeof(aAddrStr)); - char aBuf[1024]; + if(m_aMasterServers[i].m_Addr.type != NETTYPE_INVALID) + net_addr_str(&m_aMasterServers[i].m_Addr, aAddrStr, sizeof(aAddrStr)); + else + aAddrStr[0] = 0; + char aBuf[256]; str_format(aBuf, sizeof(aBuf), "%s %s\n", m_aMasterServers[i].m_aHostname, aAddrStr); io_write(File, aBuf, str_length(aBuf)); -- cgit 1.4.1 From f4ce34f01c87e4edbfc085ea60ccec1e3b386f60 Mon Sep 17 00:00:00 2001 From: oy Date: Mon, 11 Jul 2011 12:02:45 +0200 Subject: close spectator/emoticon menu when changing to team/spectator via bind. Closes #768 --- src/game/client/components/emoticon.cpp | 7 +++++++ src/game/client/components/spectator.cpp | 7 +++++++ 2 files changed, 14 insertions(+) (limited to 'src') diff --git a/src/game/client/components/emoticon.cpp b/src/game/client/components/emoticon.cpp index bedfaafb..b2f48b80 100644 --- a/src/game/client/components/emoticon.cpp +++ b/src/game/client/components/emoticon.cpp @@ -102,6 +102,13 @@ void CEmoticon::OnRender() return; } + if(m_pClient->m_Snap.m_SpecInfo.m_Active) + { + m_Active = false; + m_WasActive = false; + return; + } + m_WasActive = true; if (length(m_SelectorMouse) > 140) diff --git a/src/game/client/components/spectator.cpp b/src/game/client/components/spectator.cpp index c69a7669..c09b2ee2 100644 --- a/src/game/client/components/spectator.cpp +++ b/src/game/client/components/spectator.cpp @@ -162,6 +162,13 @@ void CSpectator::OnRender() return; } + if(!m_pClient->m_Snap.m_SpecInfo.m_Active) + { + m_Active = false; + m_WasActive = false; + return; + } + m_WasActive = true; m_SelectedSpectatorID = NO_SELECTION; -- cgit 1.4.1 From 6cd2ab38878cda02a6ff18bc87d8a694e43781bb Mon Sep 17 00:00:00 2001 From: SushiTee Date: Sun, 10 Jul 2011 22:16:16 +0200 Subject: added grid to editor --- src/game/editor/editor.cpp | 173 ++++++++++++++++++++++++++++++++++++++++++--- src/game/editor/editor.h | 10 +++ 2 files changed, 173 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index 907552dc..94a5d837 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -466,6 +466,49 @@ int CEditor::DoButton_ButtonDec(const void *pID, const char *pText, int Checked, return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip); } +void CEditor::RenderGrid(CLayerGroup *pGroup) +{ + if(!m_GridActive) + return; + + float aGroupPoints[4]; + pGroup->Mapping(aGroupPoints); + + float w = UI()->Screen()->w; + float h = UI()->Screen()->h; + + int LineDistance = GetLineDistance(); + + int XOffset = aGroupPoints[0]/LineDistance; + int YOffset = aGroupPoints[1]/LineDistance; + int XGridOffset = XOffset % m_GridFactor; + int YGridOffset = YOffset % m_GridFactor; + + Graphics()->TextureSet(-1); + Graphics()->LinesBegin(); + + for(int i = 0; i < (int)w; i++) + { + if((i+YGridOffset) % m_GridFactor == 0) + Graphics()->SetColor(1.0f, 0.3f, 0.3f, 0.3f); + else + Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.15f); + + IGraphics::CLineItem Line = IGraphics::CLineItem(LineDistance*XOffset, LineDistance*i+LineDistance*YOffset, w+aGroupPoints[2], LineDistance*i+LineDistance*YOffset); + Graphics()->LinesDraw(&Line, 1); + + if((i+XGridOffset) % m_GridFactor == 0) + Graphics()->SetColor(1.0f, 0.3f, 0.3f, 0.3f); + else + Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.15f); + + Line = IGraphics::CLineItem(LineDistance*i+LineDistance*XOffset, LineDistance*YOffset, LineDistance*i+LineDistance*XOffset, h+aGroupPoints[3]); + Graphics()->LinesDraw(&Line, 1); + } + Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f); + Graphics()->LinesEnd(); +} + void CEditor::RenderBackground(CUIRect View, int Texture, float Size, float Brightness) { Graphics()->TextureSet(Texture); @@ -857,6 +900,41 @@ void CEditor::DoToolbar(CUIRect ToolBar) m_WorldOffsetX = 0; m_WorldOffsetY = 0; } + + TB_Bottom.VSplitLeft(5.0f, 0, &TB_Bottom); + + // grid button + TB_Bottom.VSplitLeft(50.0f, &Button, &TB_Bottom); + static int s_GridButton = 0; + if(DoButton_Editor(&s_GridButton, "Grid", m_GridActive, &Button, 0, "Toggle Grid")) + { + m_GridActive = !m_GridActive; + } + + TB_Bottom.VSplitLeft(30.0f, 0, &TB_Bottom); + + // grid zoom + TB_Bottom.VSplitLeft(30.0f, &Button, &TB_Bottom); + static int s_GridIncreaseButton = 0; + if(DoButton_Ex(&s_GridIncreaseButton, "G-", 0, &Button, 0, "Decrease grid", CUI::CORNER_L)) + { + if(m_GridFactor > 1) + m_GridFactor--; + } + + TB_Bottom.VSplitLeft(30.0f, &Button, &TB_Bottom); + static int s_GridNormalButton = 0; + if(DoButton_Ex(&s_GridNormalButton, "1", 0, &Button, 0, "Normal grid", 0)) + m_GridFactor = 1; + + TB_Bottom.VSplitLeft(30.0f, &Button, &TB_Bottom); + + static int s_GridDecreaseButton = 0; + if(DoButton_Ex(&s_GridDecreaseButton, "G+", 0, &Button, 0, "Increase grid", CUI::CORNER_R)) + { + if(m_GridFactor < 15) + m_GridFactor++; + } } static void Rotate(CPoint *pCenter, CPoint *pPoint, float Rotation) @@ -916,10 +994,41 @@ void CEditor::DoQuad(CQuad *q, int Index) else if(s_Operation == OP_MOVE_ALL) { // move all points including pivot - for(int v = 0; v < 5; v++) + if(m_GridActive) + { + int LineDistance = GetLineDistance(); + + float x = 0.0f; + float y = 0.0f; + if(wx >= 0) + x = (int)((wx+(LineDistance/2)*m_GridFactor)/(LineDistance*m_GridFactor)) * (LineDistance*m_GridFactor); + else + x = (int)((wx-(LineDistance/2)*m_GridFactor)/(LineDistance*m_GridFactor)) * (LineDistance*m_GridFactor); + if(wy >= 0) + y = (int)((wy+(LineDistance/2)*m_GridFactor)/(LineDistance*m_GridFactor)) * (LineDistance*m_GridFactor); + else + y = (int)((wy-(LineDistance/2)*m_GridFactor)/(LineDistance*m_GridFactor)) * (LineDistance*m_GridFactor); + + int OldX = q->m_aPoints[4].x; + int OldY = q->m_aPoints[4].y; + q->m_aPoints[4].x = f2fx(x); + q->m_aPoints[4].y = f2fx(y); + int DiffX = q->m_aPoints[4].x - OldX; + int DiffY = q->m_aPoints[4].y - OldY; + + for(int v = 0; v < 4; v++) + { + q->m_aPoints[v].x += DiffX; + q->m_aPoints[v].y += DiffY; + } + } + else { - q->m_aPoints[v].x += f2fx(wx-s_LastWx); - q->m_aPoints[v].y += f2fx(wy-s_LastWy); + for(int v = 0; v < 5; v++) + { + q->m_aPoints[v].x += f2fx(wx-s_LastWx); + q->m_aPoints[v].y += f2fx(wy-s_LastWy); + } } } else if(s_Operation == OP_ROTATE) @@ -1050,12 +1159,37 @@ void CEditor::DoQuadPoint(CQuad *pQuad, int QuadIndex, int V) { if(s_Operation == OP_MOVEPOINT) { - for(int m = 0; m < 4; m++) - if(m_SelectedPoints&(1<m_aPoints[m].x += f2fx(dx); - pQuad->m_aPoints[m].y += f2fx(dy); - } + if(m_GridActive) + { + for(int m = 0; m < 4; m++) + if(m_SelectedPoints&(1<= 0) + x = (int)((wx+(LineDistance/2)*m_GridFactor)/(LineDistance*m_GridFactor)) * (LineDistance*m_GridFactor); + else + x = (int)((wx-(LineDistance/2)*m_GridFactor)/(LineDistance*m_GridFactor)) * (LineDistance*m_GridFactor); + if(wy >= 0) + y = (int)((wy+(LineDistance/2)*m_GridFactor)/(LineDistance*m_GridFactor)) * (LineDistance*m_GridFactor); + else + y = (int)((wy-(LineDistance/2)*m_GridFactor)/(LineDistance*m_GridFactor)) * (LineDistance*m_GridFactor); + + pQuad->m_aPoints[m].x = f2fx(x); + pQuad->m_aPoints[m].y = f2fx(y); + } + } + else + { + for(int m = 0; m < 4; m++) + if(m_SelectedPoints&(1<m_aPoints[m].x += f2fx(dx); + pQuad->m_aPoints[m].y += f2fx(dy); + } + } } else if(s_Operation == OP_MOVEUV) { @@ -1248,6 +1382,8 @@ void CEditor::DoMapEditor(CUIRect View, CUIRect ToolBar) { g->MapScreen(); + RenderGrid(g); + for(int i = 0; i < NumEditLayers; i++) { if(pEditLayers[i]->m_Type != LAYERTYPE_TILES) @@ -3154,7 +3290,6 @@ void CEditor::Render() Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); } - } void CEditor::Reset(bool CreateDefault) @@ -3192,6 +3327,24 @@ void CEditor::Reset(bool CreateDefault) m_Map.m_Modified = false; } +int CEditor::GetLineDistance() +{ + int LineDistance = 512; + + if(m_ZoomLevel <= 100) + LineDistance = 16; + else if(m_ZoomLevel <= 250) + LineDistance = 32; + else if(m_ZoomLevel <= 450) + LineDistance = 64; + else if(m_ZoomLevel <= 850) + LineDistance = 128; + else if(m_ZoomLevel <= 1550) + LineDistance = 256; + + return LineDistance; +} + void CEditorMap::DeleteEnvelope(int Index) { if(Index < 0 || Index >= m_lEnvelopes.size()) diff --git a/src/game/editor/editor.h b/src/game/editor/editor.h index 353b0774..92ec7b2b 100644 --- a/src/game/editor/editor.h +++ b/src/game/editor/editor.h @@ -475,6 +475,9 @@ public: m_Dialog = 0; m_pTooltip = 0; + m_GridActive = false; + m_GridFactor = 1; + m_aFileName[0] = 0; m_aFileSaveName[0] = 0; m_ValidSaveFilename = false; @@ -556,6 +559,9 @@ public: int m_Dialog; const char *m_pTooltip; + bool m_GridActive; + int m_GridFactor; + char m_aFileName[512]; char m_aFileSaveName[512]; bool m_ValidSaveFilename; @@ -674,6 +680,8 @@ public: void RenderBackground(CUIRect View, int Texture, float Size, float Brightness); + void RenderGrid(CLayerGroup *pGroup); + void UiInvokePopupMenu(void *pID, int Flags, float X, float Y, float W, float H, int (*pfnFunc)(CEditor *pEditor, CUIRect Rect), void *pExtra=0); void UiDoPopupMenu(); @@ -742,6 +750,8 @@ public: int Length = pEnd > pExtractedName ? min(BufferSize, (int)(pEnd-pExtractedName+1)) : BufferSize; str_copy(pName, pExtractedName, Length); } + + int GetLineDistance(); }; // make sure to inline this function -- cgit 1.4.1 From 5f4a5b3366aebf55abc1112d9cac8325d3f082ce Mon Sep 17 00:00:00 2001 From: oy Date: Tue, 12 Jul 2011 20:33:53 +0200 Subject: added country flags to language selectors --- data/languages/index.txt | 21 ++++++++++++ src/game/client/components/menus_settings.cpp | 46 +++++++++++++++++++++++---- 2 files changed, 60 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/data/languages/index.txt b/data/languages/index.txt index 3e8d9f91..3a0c3a34 100644 --- a/data/languages/index.txt +++ b/data/languages/index.txt @@ -3,63 +3,84 @@ bosnian == Bosanski +== 70 brazilian_portuguese == Português brasileiro +== 76 bulgarian == Български +== 100 czech == Česky +== 203 danish == Dansk +== 208 dutch == Nederlands +== 528 finnish == Suomi +== 246 french == Français +== 250 german == Deutsch +== 276 italian == Italiano +== 380 norwegian == Norsk +== 578 polish == Polski +== 616 portuguese == Português +== 620 romanian == Română +== 642 russian == Русский +== 643 serbian == Srpski +== 688 slovak == Slovensky +== 703 spanish == Español +== 724 swedish == Svenska +== 752 turkish == Türkçe +== 792 ukrainian == Українська +== 804 diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp index 3fb0ab94..c2fab00f 100644 --- a/src/game/client/components/menus_settings.cpp +++ b/src/game/client/components/menus_settings.cpp @@ -812,10 +812,11 @@ class CLanguage { public: CLanguage() {} - CLanguage(const char *n, const char *f) : m_Name(n), m_FileName(f) {} + CLanguage(const char *n, const char *f, int Code) : m_Name(n), m_FileName(f), m_CountryCode(Code) {} string m_Name; string m_FileName; + int m_CountryCode; bool operator<(const CLanguage &Other) { return m_Name < Other.m_Name; } }; @@ -830,6 +831,7 @@ void LoadLanguageIndexfile(IStorage *pStorage, IConsole *pConsole, sorted_array< } char aOrigin[128]; + char aReplacement[128]; CLineReader LineReader; LineReader.Init(File); char *pLine; @@ -839,14 +841,32 @@ void LoadLanguageIndexfile(IStorage *pStorage, IConsole *pConsole, sorted_array< continue; str_copy(aOrigin, pLine, sizeof(aOrigin)); - char *pReplacement = LineReader.Get(); - if(!pReplacement) + + pLine = LineReader.Get(); + if(!pLine) + { + pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "localization", "unexpected end of index file"); + break; + } + + if(pLine[0] != '=' || pLine[1] != '=' || pLine[2] != ' ') + { + char aBuf[128]; + str_format(aBuf, sizeof(aBuf), "malform replacement for index '%s'", aOrigin); + pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "localization", aBuf); + (void)LineReader.Get(); + continue; + } + str_copy(aReplacement, pLine+3, sizeof(aReplacement)); + + pLine = LineReader.Get(); + if(!pLine) { pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "localization", "unexpected end of index file"); break; } - if(pReplacement[0] != '=' || pReplacement[1] != '=' || pReplacement[2] != ' ') + if(pLine[0] != '=' || pLine[1] != '=' || pLine[2] != ' ') { char aBuf[128]; str_format(aBuf, sizeof(aBuf), "malform replacement for index '%s'", aOrigin); @@ -856,7 +876,7 @@ void LoadLanguageIndexfile(IStorage *pStorage, IConsole *pConsole, sorted_array< char aFileName[128]; str_format(aFileName, sizeof(aFileName), "languages/%s.txt", aOrigin); - pLanguages->add(CLanguage(pReplacement+3, aFileName)); + pLanguages->add(CLanguage(aReplacement, aFileName, str_toint(pLine+3))); } io_close(File); } @@ -870,7 +890,7 @@ void CMenus::RenderLanguageSelection(CUIRect MainView) if(s_Languages.size() == 0) { - s_Languages.add(CLanguage("English", "")); + s_Languages.add(CLanguage("English", "", 826)); LoadLanguageIndexfile(Storage(), Console(), &s_Languages); for(int i = 0; i < s_Languages.size(); i++) if(str_comp(s_Languages[i].m_FileName, g_Config.m_ClLanguagefile) == 0) @@ -889,7 +909,19 @@ void CMenus::RenderLanguageSelection(CUIRect MainView) CListboxItem Item = UiDoListboxNextItem(&r.front()); if(Item.m_Visible) - UI()->DoLabelScaled(&Item.m_Rect, r.front().m_Name, 16.0f, -1); + { + CUIRect Rect; + Item.m_Rect.VSplitLeft(Item.m_Rect.h*2.0f, &Rect, &Item.m_Rect); + Rect.VMargin(6.0f, &Rect); + Rect.HMargin(3.0f, &Rect); + Graphics()->TextureSet(m_pClient->m_pCountryFlags->GetByCountryCode(r.front().m_CountryCode)->m_Texture); + Graphics()->QuadsBegin(); + IGraphics::CQuadItem QuadItem(Rect.x, Rect.y, Rect.w, Rect.h); + Graphics()->QuadsDrawTL(&QuadItem, 1); + Graphics()->QuadsEnd(); + Item.m_Rect.HSplitTop(2.0f, 0, &Item.m_Rect); + UI()->DoLabelScaled(&Item.m_Rect, r.front().m_Name, 16.0f, -1); + } } s_SelectedLanguage = UiDoListboxEnd(&s_ScrollValue, 0); -- cgit 1.4.1 From 571dff6216562387ff020407c147fe8000177c15 Mon Sep 17 00:00:00 2001 From: oy Date: Thu, 14 Jul 2011 22:07:21 +0200 Subject: made rcon auto completion serverside. Closes #97 --- scripts/cmd5.py | 2 +- src/engine/client.h | 1 + src/engine/client/client.cpp | 24 ++++- src/engine/client/client.h | 4 +- src/engine/console.h | 24 ++++- src/engine/server/server.cpp | 95 +++++++++++++++--- src/engine/server/server.h | 9 ++ src/engine/shared/console.cpp | 171 ++++++++++++++++++++++++++++++--- src/engine/shared/console.h | 18 +++- src/engine/shared/protocol.h | 6 +- src/game/client/components/console.cpp | 30 ++++-- src/game/client/components/console.h | 5 +- src/game/server/gamecontext.cpp | 32 +++--- 13 files changed, 356 insertions(+), 65 deletions(-) (limited to 'src') diff --git a/scripts/cmd5.py b/scripts/cmd5.py index a06d45a7..07e35bb1 100644 --- a/scripts/cmd5.py +++ b/scripts/cmd5.py @@ -30,6 +30,6 @@ for filename in sys.argv[1:]: hash = hashlib.md5(f).hexdigest().lower()[16:] #TODO 0.7: improve nethash creation -if hash == "5c1e637ffddf3a37": +if hash == "71de0f4d82688970": hash = "626fce9a778df4d4" print('#define GAME_NETVERSION_HASH "%s"' % hash) diff --git a/src/engine/client.h b/src/engine/client.h index 65ab761e..966e8f61 100644 --- a/src/engine/client.h +++ b/src/engine/client.h @@ -95,6 +95,7 @@ public: // remote console virtual void RconAuth(const char *pUsername, const char *pPassword) = 0; virtual bool RconAuthed() = 0; + virtual bool UseTempRconCommands() = 0; virtual void Rcon(const char *pLine) = 0; // server info diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 6949c308..90131703 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -536,11 +536,6 @@ void CClient::SendReady() SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH); } -bool CClient::RconAuthed() -{ - return m_RconAuthed; -} - void CClient::RconAuth(const char *pName, const char *pPassword) { if(RconAuthed()) @@ -549,6 +544,7 @@ void CClient::RconAuth(const char *pName, const char *pPassword) CMsgPacker Msg(NETMSG_RCON_AUTH); Msg.AddString(pName, 32); Msg.AddString(pPassword, 32); + Msg.AddInt(1); SendMsgEx(&Msg, MSGFLAG_VITAL); } @@ -726,6 +722,7 @@ void CClient::DisconnectWithReason(const char *pReason) // m_RconAuthed = 0; + m_pConsole->DeregisterTempAll(); m_NetClient.Disconnect(pReason); SetState(IClient::STATE_OFFLINE); m_pMap->Unload(); @@ -1313,11 +1310,28 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket) CMsgPacker Msg(NETMSG_PING_REPLY); SendMsgEx(&Msg, 0); } + else if(Msg == NETMSG_RCON_CMD_ADD) + { + const char *pName = Unpacker.GetString(CUnpacker::SANITIZE_CC); + const char *pHelp = Unpacker.GetString(CUnpacker::SANITIZE_CC); + const char *pParams = Unpacker.GetString(CUnpacker::SANITIZE_CC); + if(Unpacker.Error() == 0) + m_pConsole->RegisterTemp(pName, pParams, CFGFLAG_SERVER, pHelp); + } + else if(Msg == NETMSG_RCON_CMD_REM) + { + const char *pName = Unpacker.GetString(CUnpacker::SANITIZE_CC); + if(Unpacker.Error() == 0) + m_pConsole->DeregisterTemp(pName); + } else if(Msg == NETMSG_RCON_AUTH_STATUS) { int Result = Unpacker.GetInt(); if(Unpacker.Error() == 0) m_RconAuthed = Result; + m_UseTempRconCommands = Unpacker.GetInt(); + if(Unpacker.Error() != 0) + m_UseTempRconCommands = 0; } else if(Msg == NETMSG_RCON_LINE) { diff --git a/src/engine/client/client.h b/src/engine/client/client.h index fa0ddaf7..3d81f073 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -128,6 +128,7 @@ class CClient : public IClient, public CDemoPlayer::IListner int m_AckGameTick; int m_CurrentRecvTick; int m_RconAuthed; + int m_UseTempRconCommands; // version-checking char m_aVersionStr[10]; @@ -220,7 +221,8 @@ public: void SendEnterGame(); void SendReady(); - virtual bool RconAuthed(); + virtual bool RconAuthed() { return m_RconAuthed != 0; } + virtual bool UseTempRconCommands() { return m_UseTempRconCommands != 0; } void RconAuth(const char *pName, const char *pPassword); virtual void Rcon(const char *pCmd); diff --git a/src/engine/console.h b/src/engine/console.h index e650ac47..7c39cf49 100644 --- a/src/engine/console.h +++ b/src/engine/console.h @@ -10,6 +10,7 @@ class IConsole : public IInterface MACRO_INTERFACE("console", 0) public: + // TODO: rework/cleanup enum { OUTPUT_LEVEL_STANDARD=0, @@ -18,6 +19,10 @@ public: ACCESS_LEVEL_ADMIN=0, ACCESS_LEVEL_MOD, + + TEMPCMD_NAME_LENGTH=32, + TEMPCMD_HELP_LENGTH=64, + TEMPCMD_PARAMS_LENGTH=16, }; // TODO: rework this interface to reduce the amount of virtual calls @@ -38,10 +43,18 @@ public: class CCommandInfo { + protected: + int m_AccessLevel; public: + CCommandInfo() { m_AccessLevel = ACCESS_LEVEL_ADMIN; } + virtual ~CCommandInfo() {} const char *m_pName; const char *m_pHelp; const char *m_pParams; + + virtual const CCommandInfo *NextCommandInfo(int AccessLevel, int FlagMask) const = 0; + + int GetAccessLevel() const { return m_AccessLevel; } }; typedef void (*FPrintCallback)(const char *pStr, void *pUser); @@ -49,12 +62,15 @@ public: typedef void (*FCommandCallback)(IResult *pResult, void *pUserData); typedef void (*FChainCommandCallback)(IResult *pResult, void *pUserData, FCommandCallback pfnCallback, void *pCallbackUserData); - virtual CCommandInfo *GetCommandInfo(const char *pName, int FlagMask) = 0; - virtual void PossibleCommands(const char *pStr, int FlagMask, FPossibleCallback pfnCallback, void *pUser) = 0; + virtual const CCommandInfo *FirstCommandInfo(int AccessLevel, int Flagmask) const = 0; + virtual const CCommandInfo *GetCommandInfo(const char *pName, int FlagMask, bool Temp) = 0; + virtual void PossibleCommands(const char *pStr, int FlagMask, bool Temp, FPossibleCallback pfnCallback, void *pUser) = 0; virtual void ParseArguments(int NumArgs, const char **ppArguments) = 0; - virtual void Register(const char *pName, const char *pParams, - int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp) = 0; + virtual void Register(const char *pName, const char *pParams, int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp) = 0; + virtual void RegisterTemp(const char *pName, const char *pParams, int Flags, const char *pHelp) = 0; + virtual void DeregisterTemp(const char *pName) = 0; + virtual void DeregisterTempAll() = 0; virtual void Chain(const char *pName, FChainCommandCallback pfnChainFunc, void *pUser) = 0; virtual void StoreCommands(bool Store) = 0; diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 24d3b317..17df19ed 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -580,6 +580,7 @@ int CServer::NewClientCallback(int ClientID, void *pUser) pThis->m_aClients[ClientID].m_Country = -1; pThis->m_aClients[ClientID].m_Authed = AUTHED_NO; pThis->m_aClients[ClientID].m_AuthTries = 0; + pThis->m_aClients[ClientID].m_pRconCmdToSend = 0; pThis->m_aClients[ClientID].Reset(); return 0; } @@ -605,6 +606,7 @@ int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser) pThis->m_aClients[ClientID].m_Country = -1; pThis->m_aClients[ClientID].m_Authed = AUTHED_NO; pThis->m_aClients[ClientID].m_AuthTries = 0; + pThis->m_aClients[ClientID].m_pRconCmdToSend = 0; pThis->m_aClients[ClientID].m_Snapshots.PurgeAll(); return 0; } @@ -649,6 +651,37 @@ void CServer::SendRconLineAuthed(const char *pLine, void *pUser) ReentryGuard--; } +void CServer::SendRconCmdAdd(const IConsole::CCommandInfo *pCommandInfo, int ClientID) +{ + CMsgPacker Msg(NETMSG_RCON_CMD_ADD); + Msg.AddString(pCommandInfo->m_pName, 32); + Msg.AddString(pCommandInfo->m_pHelp, 64); + Msg.AddString(pCommandInfo->m_pParams, 16); + SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true); +} + +void CServer::SendRconCmdRem(const IConsole::CCommandInfo *pCommandInfo, int ClientID) +{ + CMsgPacker Msg(NETMSG_RCON_CMD_REM); + Msg.AddString(pCommandInfo->m_pName, 256); + SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true); +} + +void CServer::UpdateClientRconCommands() +{ + int ClientID = Tick() % MAX_CLIENTS; + + if(m_aClients[ClientID].m_State != CClient::STATE_EMPTY && m_aClients[ClientID].m_Authed) + { + int ConsoleAccessLevel = m_aClients[ClientID].m_Authed == AUTHED_ADMIN ? IConsole::ACCESS_LEVEL_ADMIN : IConsole::ACCESS_LEVEL_MOD; + for(int i = 0; i < MAX_RCONCMD_SEND && m_aClients[ClientID].m_pRconCmdToSend; ++i) + { + SendRconCmdAdd(m_aClients[ClientID].m_pRconCmdToSend, ClientID); + m_aClients[ClientID].m_pRconCmdToSend = m_aClients[ClientID].m_pRconCmdToSend->NextCommandInfo(ConsoleAccessLevel, CFGFLAG_SERVER); + } + } +} + void CServer::ProcessClientPacket(CNetChunk *pPacket) { int ClientID = pPacket->m_ClientID; @@ -843,10 +876,14 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) else if(g_Config.m_SvRconPassword[0] && str_comp(pPw, g_Config.m_SvRconPassword) == 0) { CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS); - Msg.AddInt(1); + Msg.AddInt(1); //authed + Msg.AddInt(1); //cmdlist SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true); m_aClients[ClientID].m_Authed = AUTHED_ADMIN; + int SendRconCmds = Unpacker.GetInt(); + if(Unpacker.Error() == 0 && SendRconCmds) + m_aClients[ClientID].m_pRconCmdToSend = Console()->FirstCommandInfo(IConsole::ACCESS_LEVEL_ADMIN, CFGFLAG_SERVER); SendRconLine(ClientID, "Admin authentication successful. Full remote console access granted."); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (admin)", ClientID); @@ -855,10 +892,14 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) else if(g_Config.m_SvRconModPassword[0] && str_comp(pPw, g_Config.m_SvRconModPassword) == 0) { CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS); - Msg.AddInt(1); + Msg.AddInt(1); //authed + Msg.AddInt(1); //cmdlist SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true); m_aClients[ClientID].m_Authed = AUTHED_MOD; + int SendRconCmds = Unpacker.GetInt(); + if(Unpacker.Error() == 0 && SendRconCmds) + m_aClients[ClientID].m_pRconCmdToSend = Console()->FirstCommandInfo(IConsole::ACCESS_LEVEL_MOD, CFGFLAG_SERVER); SendRconLine(ClientID, "Moderator authentication successful. Limited remote console access granted."); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (moderator)", ClientID); @@ -1243,6 +1284,8 @@ int CServer::Run() { if(g_Config.m_SvHighBandwidth || (m_CurrentGameTick%2) == 0) DoSnapshot(); + + UpdateClientRconCommands(); } // master server stuff @@ -1512,26 +1555,56 @@ void CServer::ConchainMaxclientsperipUpdate(IConsole::IResult *pResult, void *pU ((CServer *)pUserData)->m_NetServer.SetMaxClientsPerIP(pResult->GetInteger(0)); } +void CServer::ConchainModCommandUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData) +{ + if(pResult->NumArguments() == 2) + { + CServer *pThis = static_cast(pUserData); + const IConsole::CCommandInfo *pInfo = pThis->Console()->GetCommandInfo(pResult->GetString(0), CFGFLAG_SERVER, false); + int OldAccessLevel; + if(pInfo) + OldAccessLevel = pInfo->GetAccessLevel(); + pfnCallback(pResult, pCallbackUserData); + if(pInfo && OldAccessLevel != pInfo->GetAccessLevel()) + { + for(int i = 0; i < MAX_CLIENTS; ++i) + { + if(pThis->m_aClients[i].m_State == CServer::CClient::STATE_EMPTY || pThis->m_aClients[i].m_Authed != CServer::AUTHED_MOD || + (pThis->m_aClients[i].m_pRconCmdToSend && str_comp(pResult->GetString(0), pThis->m_aClients[i].m_pRconCmdToSend->m_pName) >= 0)) + continue; + + if(OldAccessLevel == IConsole::ACCESS_LEVEL_ADMIN) + pThis->SendRconCmdAdd(pInfo, i); + else + pThis->SendRconCmdRem(pInfo, i); + } + } + } + else + pfnCallback(pResult, pCallbackUserData); +} + void CServer::RegisterCommands() { m_pConsole = Kernel()->RequestInterface(); - Console()->Register("kick", "i?r", CFGFLAG_SERVER, ConKick, this, ""); - Console()->Register("ban", "s?ir", CFGFLAG_SERVER|CFGFLAG_STORE, ConBan, this, ""); - Console()->Register("unban", "s", CFGFLAG_SERVER|CFGFLAG_STORE, ConUnban, this, ""); - Console()->Register("bans", "", CFGFLAG_SERVER|CFGFLAG_STORE, ConBans, this, ""); - Console()->Register("status", "", CFGFLAG_SERVER, ConStatus, this, ""); - Console()->Register("shutdown", "", CFGFLAG_SERVER, ConShutdown, this, ""); + Console()->Register("kick", "i?r", CFGFLAG_SERVER, ConKick, this, "Kick player with specified id for any reason"); + Console()->Register("ban", "s?ir", CFGFLAG_SERVER|CFGFLAG_STORE, ConBan, this, "Ban player with ip/id for x minutes for any reason"); + Console()->Register("unban", "s", CFGFLAG_SERVER|CFGFLAG_STORE, ConUnban, this, "Unban ip"); + Console()->Register("bans", "", CFGFLAG_SERVER|CFGFLAG_STORE, ConBans, this, "Show banlist"); + Console()->Register("status", "", CFGFLAG_SERVER, ConStatus, this, "List players"); + Console()->Register("shutdown", "", CFGFLAG_SERVER, ConShutdown, this, "Shut down"); - Console()->Register("record", "?s", CFGFLAG_SERVER|CFGFLAG_STORE, ConRecord, this, ""); - Console()->Register("stoprecord", "", CFGFLAG_SERVER, ConStopRecord, this, ""); + Console()->Register("record", "?s", CFGFLAG_SERVER|CFGFLAG_STORE, ConRecord, this, "Record to a file"); + Console()->Register("stoprecord", "", CFGFLAG_SERVER, ConStopRecord, this, "Stop recording"); - Console()->Register("reload", "", CFGFLAG_SERVER, ConMapReload, this, ""); + Console()->Register("reload", "", CFGFLAG_SERVER, ConMapReload, this, "Reload the map"); Console()->Chain("sv_name", ConchainSpecialInfoupdate, this); Console()->Chain("password", ConchainSpecialInfoupdate, this); Console()->Chain("sv_max_clients_per_ip", ConchainMaxclientsperipUpdate, this); + Console()->Chain("mod_command", ConchainModCommandUpdate, this); } diff --git a/src/engine/server/server.h b/src/engine/server/server.h index 72c82d4d..5b6e038d 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -54,6 +54,8 @@ public: AUTHED_NO=0, AUTHED_MOD, AUTHED_ADMIN, + + MAX_RCONCMD_SEND=16, }; class CClient @@ -100,6 +102,8 @@ public: int m_Authed; int m_AuthTries; + const IConsole::CCommandInfo *m_pRconCmdToSend; + void Reset(); }; @@ -169,6 +173,10 @@ public: void SendRconLine(int ClientID, const char *pLine); static void SendRconLineAuthed(const char *pLine, void *pUser); + void SendRconCmdAdd(const IConsole::CCommandInfo *pCommandInfo, int ClientID); + void SendRconCmdRem(const IConsole::CCommandInfo *pCommandInfo, int ClientID); + void UpdateClientRconCommands(); + void ProcessClientPacket(CNetChunk *pPacket); void SendServerInfo(NETADDR *pAddr, int Token); @@ -197,6 +205,7 @@ public: static void ConMapReload(IConsole::IResult *pResult, void *pUser); static void ConchainSpecialInfoupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); static void ConchainMaxclientsperipUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); + static void ConchainModCommandUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); void RegisterCommands(); diff --git a/src/engine/shared/console.cpp b/src/engine/shared/console.cpp index 588abd61..847fb140 100644 --- a/src/engine/shared/console.cpp +++ b/src/engine/shared/console.cpp @@ -33,6 +33,29 @@ float CConsole::CResult::GetFloat(unsigned Index) return str_tofloat(m_apArgs[Index]); } +const IConsole::CCommandInfo *CConsole::CCommand::NextCommandInfo(int AccessLevel, int FlagMask) const +{ + const CCommand *pInfo = m_pNext; + while(pInfo) + { + if(pInfo->m_Flags&FlagMask && pInfo->m_AccessLevel >= AccessLevel) + break; + pInfo = pInfo->m_pNext; + } + return pInfo; +} + +const IConsole::CCommandInfo *CConsole::FirstCommandInfo(int AccessLevel, int FlagMask) const +{ + for(const CCommand *pCommand = m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext) + { + if(pCommand->m_Flags&FlagMask && pCommand->GetAccessLevel() >= AccessLevel) + return pCommand; + } + + return 0; +} + // the maximum number of tokens occurs in a string of length CONSOLE_MAX_STR_LENGTH with tokens size 1 separated by single spaces @@ -258,7 +281,7 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr) if(pCommand) { - if(pCommand->m_AccessLevel >= m_AccessLevel) + if(pCommand->GetAccessLevel() >= m_AccessLevel) { int IsStrokeCommand = 0; if(Result.m_pCommand[0] == '+') @@ -305,11 +328,11 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr) } } -void CConsole::PossibleCommands(const char *pStr, int FlagMask, FPossibleCallback pfnCallback, void *pUser) +void CConsole::PossibleCommands(const char *pStr, int FlagMask, bool Temp, FPossibleCallback pfnCallback, void *pUser) { for(CCommand *pCommand = m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext) { - if(pCommand->m_Flags&FlagMask) + if(pCommand->m_Flags&FlagMask && pCommand->m_Temp == Temp) { if(str_find_nocase(pCommand->m_pName, pStr)) pfnCallback(pCommand->m_pName, pUser); @@ -403,11 +426,11 @@ void CConsole::ConModCommandAccess(IResult *pResult, void *pUser) { if(pResult->NumArguments() == 2) { - pCommand->m_AccessLevel = clamp(pResult->GetInteger(1), (int)(ACCESS_LEVEL_ADMIN), (int)(ACCESS_LEVEL_MOD)); - str_format(aBuf, sizeof(aBuf), "moderator access for '%s' is now %s", pResult->GetString(0), pCommand->m_AccessLevel ? "enabled" : "disabled"); + pCommand->SetAccessLevel(pResult->GetInteger(1)); + str_format(aBuf, sizeof(aBuf), "moderator access for '%s' is now %s", pResult->GetString(0), pCommand->GetAccessLevel() ? "enabled" : "disabled"); } else - str_format(aBuf, sizeof(aBuf), "moderator access for '%s' is %s", pResult->GetString(0), pCommand->m_AccessLevel ? "enabled" : "disabled"); + str_format(aBuf, sizeof(aBuf), "moderator access for '%s' is %s", pResult->GetString(0), pCommand->GetAccessLevel() ? "enabled" : "disabled"); } else str_format(aBuf, sizeof(aBuf), "No such command: '%s'.", pResult->GetString(0)); @@ -424,7 +447,7 @@ void CConsole::ConModCommandStatus(IResult *pResult, void *pUser) for(CCommand *pCommand = pConsole->m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext) { - if(pCommand->m_Flags&pConsole->m_FlagMask && pCommand->m_AccessLevel == ACCESS_LEVEL_MOD) + if(pCommand->m_Flags&pConsole->m_FlagMask && pCommand->GetAccessLevel() == ACCESS_LEVEL_MOD) { int Length = str_length(pCommand->m_pName); if(Used + Length + 2 < (int)(sizeof(aBuf))) @@ -531,6 +554,8 @@ CConsole::CConsole(int FlagMask) { m_FlagMask = FlagMask; m_AccessLevel = ACCESS_LEVEL_ADMIN; + m_pRecycleList = 0; + m_TempCommands.Reset(); m_StoreCommands = true; m_paStrokeStr[0] = "0"; m_paStrokeStr[1] = "1"; @@ -592,20 +617,131 @@ void CConsole::ParseArguments(int NumArgs, const char **ppArguments) } } +void CConsole::AddCommandSorted(CCommand *pCommand) +{ + if(!m_pFirstCommand || str_comp(pCommand->m_pName, m_pFirstCommand->m_pName) < 0) + { + if(m_pFirstCommand && m_pFirstCommand->m_pNext) + pCommand->m_pNext = m_pFirstCommand; + else + pCommand->m_pNext = 0; + m_pFirstCommand = pCommand; + } + else + { + for(CCommand *p = m_pFirstCommand; p; p = p->m_pNext) + { + if(!p->m_pNext || str_comp(pCommand->m_pName, p->m_pNext->m_pName) < 0) + { + pCommand->m_pNext = p->m_pNext; + p->m_pNext = pCommand; + break; + } + } + } +} + void CConsole::Register(const char *pName, const char *pParams, int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp) { CCommand *pCommand = new(mem_alloc(sizeof(CCommand), sizeof(void*))) CCommand; pCommand->m_pfnCallback = pfnFunc; pCommand->m_pUserData = pUser; - pCommand->m_pHelp = pHelp; + pCommand->m_pName = pName; + pCommand->m_pHelp = pHelp; pCommand->m_pParams = pParams; + + pCommand->m_Flags = Flags; + pCommand->m_Temp = false; + + AddCommandSorted(pCommand); +} + +void CConsole::RegisterTemp(const char *pName, const char *pParams, int Flags, const char *pHelp) +{ + CCommand *pCommand; + if(m_pRecycleList) + { + pCommand = m_pRecycleList; + str_copy(const_cast(pCommand->m_pName), pName, TEMPCMD_NAME_LENGTH); + str_copy(const_cast(pCommand->m_pHelp), pHelp, TEMPCMD_HELP_LENGTH); + str_copy(const_cast(pCommand->m_pParams), pParams, TEMPCMD_PARAMS_LENGTH); + + m_pRecycleList = m_pRecycleList->m_pNext; + } + else + { + pCommand = new(m_TempCommands.Allocate(sizeof(CCommand))) CCommand; + char *pMem = static_cast(m_TempCommands.Allocate(TEMPCMD_NAME_LENGTH)); + str_copy(pMem, pName, TEMPCMD_NAME_LENGTH); + pCommand->m_pName = pMem; + pMem = static_cast(m_TempCommands.Allocate(TEMPCMD_HELP_LENGTH)); + str_copy(pMem, pHelp, TEMPCMD_HELP_LENGTH); + pCommand->m_pHelp = pMem; + pMem = static_cast(m_TempCommands.Allocate(TEMPCMD_PARAMS_LENGTH)); + str_copy(pMem, pParams, TEMPCMD_PARAMS_LENGTH); + pCommand->m_pParams = pMem; + } + + pCommand->m_pfnCallback = 0; + pCommand->m_pUserData = 0; pCommand->m_Flags = Flags; - pCommand->m_AccessLevel = ACCESS_LEVEL_ADMIN; + pCommand->m_Temp = true; + + AddCommandSorted(pCommand); +} + +void CConsole::DeregisterTemp(const char *pName) +{ + if(!m_pFirstCommand) + return; + + CCommand *pRemoved = 0; + + // remove temp entry from command list + if(m_pFirstCommand->m_Temp && str_comp(m_pFirstCommand->m_pName, pName) == 0) + { + pRemoved = m_pFirstCommand; + m_pFirstCommand = m_pFirstCommand->m_pNext; + } + else + { + for(CCommand *pCommand = m_pFirstCommand; pCommand->m_pNext; pCommand = pCommand->m_pNext) + if(pCommand->m_pNext->m_Temp && str_comp(pCommand->m_pNext->m_pName, pName) == 0) + { + pRemoved = pCommand->m_pNext; + pCommand->m_pNext = pCommand->m_pNext->m_pNext; + break; + } + } + + // add to recycle list + if(pRemoved) + { + pRemoved->m_pNext = m_pRecycleList; + m_pRecycleList = pRemoved; + } +} + +void CConsole::DeregisterTempAll() +{ + // set non temp as first one + for(; m_pFirstCommand && m_pFirstCommand->m_Temp; m_pFirstCommand = m_pFirstCommand->m_pNext); + + // remove temp entries from command list + for(CCommand *pCommand = m_pFirstCommand; pCommand && pCommand->m_pNext; pCommand = pCommand->m_pNext) + { + CCommand *pNext = pCommand->m_pNext; + if(pNext->m_Temp) + { + for(; pNext && pNext->m_Temp; pNext = pNext->m_pNext); + pCommand->m_pNext = pNext; + } + } - pCommand->m_pNext = m_pFirstCommand; - m_pFirstCommand = pCommand; + m_TempCommands.Reset(); + m_pRecycleList = 0; } void CConsole::Con_Chain(IResult *pResult, void *pUserData) @@ -651,9 +787,18 @@ void CConsole::StoreCommands(bool Store) } -IConsole::CCommandInfo *CConsole::GetCommandInfo(const char *pName, int FlagMask) +const IConsole::CCommandInfo *CConsole::GetCommandInfo(const char *pName, int FlagMask, bool Temp) { - return FindCommand(pName, FlagMask); + for(CCommand *pCommand = m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext) + { + if(pCommand->m_Flags&FlagMask && pCommand->m_Temp == Temp) + { + if(str_comp_nocase(pCommand->m_pName, pName) == 0) + return pCommand; + } + } + + return 0; } diff --git a/src/engine/shared/console.h b/src/engine/shared/console.h index 14c48581..b29f3202 100644 --- a/src/engine/shared/console.h +++ b/src/engine/shared/console.h @@ -13,9 +13,13 @@ class CConsole : public IConsole public: CCommand *m_pNext; int m_Flags; - int m_AccessLevel; + bool m_Temp; FCommandCallback m_pfnCallback; void *m_pUserData; + + virtual const CCommandInfo *NextCommandInfo(int AccessLevel, int FlagMask) const; + + void SetAccessLevel(int AccessLevel) { m_AccessLevel = clamp(AccessLevel, (int)(ACCESS_LEVEL_ADMIN), (int)(ACCESS_LEVEL_MOD)); } }; @@ -44,6 +48,9 @@ class CConsole : public IConsole class IStorage *m_pStorage; int m_AccessLevel; + CCommand *m_pRecycleList; + CHeap m_TempCommands; + static void Con_Chain(IResult *pResult, void *pUserData); static void Con_Echo(IResult *pResult, void *pUserData); static void Con_Exec(IResult *pResult, void *pUserData); @@ -138,16 +145,21 @@ class CConsole : public IConsole } } m_ExecutionQueue; + void AddCommandSorted(CCommand *pCommand); CCommand *FindCommand(const char *pName, int FlagMask); public: CConsole(int FlagMask); - virtual CCommandInfo *GetCommandInfo(const char *pName, int FlagMask); - virtual void PossibleCommands(const char *pStr, int FlagMask, FPossibleCallback pfnCallback, void *pUser) ; + virtual const CCommandInfo *FirstCommandInfo(int AccessLevel, int Flagmask) const; + virtual const CCommandInfo *GetCommandInfo(const char *pName, int FlagMask, bool Temp); + virtual void PossibleCommands(const char *pStr, int FlagMask, bool Temp, FPossibleCallback pfnCallback, void *pUser); virtual void ParseArguments(int NumArgs, const char **ppArguments); virtual void Register(const char *pName, const char *pParams, int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp); + virtual void RegisterTemp(const char *pName, const char *pParams, int Flags, const char *pHelp); + virtual void DeregisterTemp(const char *pName); + virtual void DeregisterTempAll(); virtual void Chain(const char *pName, FChainCommandCallback pfnChainFunc, void *pUser); virtual void StoreCommands(bool Store); diff --git a/src/engine/shared/protocol.h b/src/engine/shared/protocol.h index 4a4895ad..ba04da8a 100644 --- a/src/engine/shared/protocol.h +++ b/src/engine/shared/protocol.h @@ -65,7 +65,11 @@ enum // sent by both NETMSG_PING, NETMSG_PING_REPLY, - NETMSG_ERROR + NETMSG_ERROR, + + // sent by server (todo: move it up) + NETMSG_RCON_CMD_ADD, + NETMSG_RCON_CMD_REM, }; // this should be revised diff --git a/src/game/client/components/console.cpp b/src/game/client/components/console.cpp index 2f5c49ad..9b16ce0d 100644 --- a/src/game/client/components/console.cpp +++ b/src/game/client/components/console.cpp @@ -51,7 +51,7 @@ CGameConsole::CInstance::CInstance(int Type) m_CompletionChosen = -1; m_CompletionRenderOffset = 0.0f; - m_pCommand = 0x0; + m_IsCommand = false; } void CGameConsole::CInstance::Init(CGameConsole *pGameConsole) @@ -147,14 +147,16 @@ void CGameConsole::CInstance::OnInput(IInput::CEvent Event) { m_CompletionChosen++; m_CompletionEnumerationCount = 0; - m_pGameConsole->m_pConsole->PossibleCommands(m_aCompletionBuffer, m_CompletionFlagmask, PossibleCommandsCompleteCallback, this); + m_pGameConsole->m_pConsole->PossibleCommands(m_aCompletionBuffer, m_CompletionFlagmask, m_Type != CGameConsole::CONSOLETYPE_LOCAL && + m_pGameConsole->Client()->RconAuthed() && m_pGameConsole->Client()->UseTempRconCommands(), PossibleCommandsCompleteCallback, this); // handle wrapping if(m_CompletionEnumerationCount && m_CompletionChosen >= m_CompletionEnumerationCount) { m_CompletionChosen %= m_CompletionEnumerationCount; m_CompletionEnumerationCount = 0; - m_pGameConsole->m_pConsole->PossibleCommands(m_aCompletionBuffer, m_CompletionFlagmask, PossibleCommandsCompleteCallback, this); + m_pGameConsole->m_pConsole->PossibleCommands(m_aCompletionBuffer, m_CompletionFlagmask, m_Type != CGameConsole::CONSOLETYPE_LOCAL && + m_pGameConsole->Client()->RconAuthed() && m_pGameConsole->Client()->UseTempRconCommands(), PossibleCommandsCompleteCallback, this); } } } @@ -190,7 +192,17 @@ void CGameConsole::CInstance::OnInput(IInput::CEvent Event) aBuf[i] = *pSrc; aBuf[i] = 0; - m_pCommand = m_pGameConsole->m_pConsole->GetCommandInfo(aBuf, m_CompletionFlagmask); + const IConsole::CCommandInfo *pCommand = m_pGameConsole->m_pConsole->GetCommandInfo(aBuf, m_CompletionFlagmask, + m_Type != CGameConsole::CONSOLETYPE_LOCAL && m_pGameConsole->Client()->RconAuthed() && m_pGameConsole->Client()->UseTempRconCommands()); + if(pCommand) + { + m_IsCommand = true; + str_copy(m_aCommandName, pCommand->m_pName, IConsole::TEMPCMD_NAME_LENGTH); + str_copy(m_aCommandHelp, pCommand->m_pHelp, IConsole::TEMPCMD_HELP_LENGTH); + str_copy(m_aCommandParams, pCommand->m_pParams, IConsole::TEMPCMD_PARAMS_LENGTH); + } + else + m_IsCommand = false; } } } @@ -449,19 +461,19 @@ void CGameConsole::OnRender() { if(pConsole->m_Input.GetString()[0] != 0) { - m_pConsole->PossibleCommands(pConsole->m_aCompletionBuffer, pConsole->m_CompletionFlagmask, PossibleCommandsRenderCallback, &Info); + m_pConsole->PossibleCommands(pConsole->m_aCompletionBuffer, pConsole->m_CompletionFlagmask, m_ConsoleType != CGameConsole::CONSOLETYPE_LOCAL && + Client()->RconAuthed() && Client()->UseTempRconCommands(), PossibleCommandsRenderCallback, &Info); pConsole->m_CompletionRenderOffset = Info.m_Offset; if(Info.m_EnumCount <= 0) { - if(pConsole->m_pCommand) + if(pConsole->m_IsCommand) { - char aBuf[512]; - str_format(aBuf, sizeof(aBuf), "Help: %s ", pConsole->m_pCommand->m_pHelp); + str_format(aBuf, sizeof(aBuf), "Help: %s ", pConsole->m_aCommandHelp); TextRender()->TextEx(&Info.m_Cursor, aBuf, -1); TextRender()->TextColor(0.75f, 0.75f, 0.75f, 1); - str_format(aBuf, sizeof(aBuf), "Syntax: %s %s", pConsole->m_pCommand->m_pName, pConsole->m_pCommand->m_pParams); + str_format(aBuf, sizeof(aBuf), "Syntax: %s %s", pConsole->m_aCommandName, pConsole->m_aCommandParams); TextRender()->TextEx(&Info.m_Cursor, aBuf, -1); } } diff --git a/src/game/client/components/console.h b/src/game/client/components/console.h index 003a9423..326fb076 100644 --- a/src/game/client/components/console.h +++ b/src/game/client/components/console.h @@ -33,7 +33,10 @@ class CGameConsole : public CComponent int m_CompletionFlagmask; float m_CompletionRenderOffset; - IConsole::CCommandInfo *m_pCommand; + bool m_IsCommand; + char m_aCommandName[IConsole::TEMPCMD_NAME_LENGTH]; + char m_aCommandHelp[IConsole::TEMPCMD_HELP_LENGTH]; + char m_aCommandParams[IConsole::TEMPCMD_PARAMS_LENGTH]; CInstance(int t); void Init(CGameConsole *pGameConsole); diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index 52eaca89..6b029bbd 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -1317,22 +1317,22 @@ void CGameContext::OnConsoleInit() m_pServer = Kernel()->RequestInterface(); m_pConsole = Kernel()->RequestInterface(); - Console()->Register("tune", "si", CFGFLAG_SERVER, ConTuneParam, this, ""); - Console()->Register("tune_reset", "", CFGFLAG_SERVER, ConTuneReset, this, ""); - Console()->Register("tune_dump", "", CFGFLAG_SERVER, ConTuneDump, this, ""); - - Console()->Register("change_map", "?r", CFGFLAG_SERVER|CFGFLAG_STORE, ConChangeMap, this, ""); - Console()->Register("restart", "?i", CFGFLAG_SERVER|CFGFLAG_STORE, ConRestart, this, ""); - Console()->Register("broadcast", "r", CFGFLAG_SERVER, ConBroadcast, this, ""); - Console()->Register("say", "r", CFGFLAG_SERVER, ConSay, this, ""); - Console()->Register("set_team", "ii?i", CFGFLAG_SERVER, ConSetTeam, this, ""); - Console()->Register("set_team_all", "i", CFGFLAG_SERVER, ConSetTeamAll, this, ""); - - Console()->Register("add_vote", "sr", CFGFLAG_SERVER, ConAddVote, this, ""); - Console()->Register("remove_vote", "s", CFGFLAG_SERVER, ConRemoveVote, this, ""); - Console()->Register("force_vote", "ss?r", CFGFLAG_SERVER, ConForceVote, this, ""); - Console()->Register("clear_votes", "", CFGFLAG_SERVER, ConClearVotes, this, ""); - Console()->Register("vote", "r", CFGFLAG_SERVER, ConVote, this, ""); + Console()->Register("tune", "si", CFGFLAG_SERVER, ConTuneParam, this, "Tune variable to value"); + Console()->Register("tune_reset", "", CFGFLAG_SERVER, ConTuneReset, this, "Reset tuning"); + Console()->Register("tune_dump", "", CFGFLAG_SERVER, ConTuneDump, this, "Dump tuning"); + + Console()->Register("change_map", "?r", CFGFLAG_SERVER|CFGFLAG_STORE, ConChangeMap, this, "Change map"); + Console()->Register("restart", "?i", CFGFLAG_SERVER|CFGFLAG_STORE, ConRestart, this, "Restart in x seconds"); + Console()->Register("broadcast", "r", CFGFLAG_SERVER, ConBroadcast, this, "Broadcast message"); + Console()->Register("say", "r", CFGFLAG_SERVER, ConSay, this, "Say in chat"); + Console()->Register("set_team", "ii?i", CFGFLAG_SERVER, ConSetTeam, this, "Set team of player to team"); + Console()->Register("set_team_all", "i", CFGFLAG_SERVER, ConSetTeamAll, this, "Set team of all players to team"); + + Console()->Register("add_vote", "sr", CFGFLAG_SERVER, ConAddVote, this, "Add a voting option"); + Console()->Register("remove_vote", "s", CFGFLAG_SERVER, ConRemoveVote, this, "remove a voting option"); + Console()->Register("force_vote", "ss?r", CFGFLAG_SERVER, ConForceVote, this, "Force a voting option"); + Console()->Register("clear_votes", "", CFGFLAG_SERVER, ConClearVotes, this, "Clears the voting options"); + Console()->Register("vote", "r", CFGFLAG_SERVER, ConVote, this, "Force a vote to yes/no"); Console()->Chain("sv_motd", ConchainSpecialMotdupdate, this); } -- cgit 1.4.1 From a3fec2f9f384f82ec631bbfc43bce456b20a2e0e Mon Sep 17 00:00:00 2001 From: SushiTee Date: Tue, 12 Jul 2011 05:26:52 +0200 Subject: fixed clipping on some machines --- src/engine/client/graphics.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/engine/client/graphics.cpp b/src/engine/client/graphics.cpp index 76fd3400..d1f0b8a8 100644 --- a/src/engine/client/graphics.cpp +++ b/src/engine/client/graphics.cpp @@ -179,7 +179,16 @@ CGraphics_OpenGL::CGraphics_OpenGL() void CGraphics_OpenGL::ClipEnable(int x, int y, int w, int h) { - //if(no_gfx) return; + if(x < 0) + w += x; + if(y < 0) + h += y; + + x = clamp(x, 0, ScreenWidth()); + y = clamp(y, 0, ScreenHeight()); + w = clamp(w, 0, ScreenWidth()-x); + h = clamp(h, 0, ScreenHeight()-y); + glScissor(x, ScreenHeight()-(y+h), w, h); glEnable(GL_SCISSOR_TEST); } -- cgit 1.4.1 From d78c0d66e5108f0316f3bcac2a2119aa3a680ff9 Mon Sep 17 00:00:00 2001 From: SushiTee Date: Tue, 12 Jul 2011 03:14:46 +0200 Subject: ability to name groups and layers --- src/game/editor/editor.cpp | 125 +++++++++++++++++++++++++++++++--------- src/game/editor/editor.h | 10 ++-- src/game/editor/io.cpp | 28 ++++++++- src/game/editor/layer_game.cpp | 2 +- src/game/editor/layer_quads.cpp | 2 +- src/game/editor/layer_tiles.cpp | 2 +- src/game/editor/popups.cpp | 26 ++++++++- src/game/mapitems.h | 8 ++- 8 files changed, 163 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index 94a5d837..630bad8d 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -41,7 +41,7 @@ CEditorImage::~CEditorImage() CLayerGroup::CLayerGroup() { - m_pName = ""; + m_aName[0] = 0; m_Visible = true; m_SaveToMap = true; m_GameGroup = false; @@ -196,32 +196,59 @@ void CEditorImage::AnalyseTileFlags() // copied from gc_menu.cpp, should be more generalized //extern int ui_do_edit_box(void *id, const CUIRect *rect, char *str, int str_size, float font_size, bool hidden=false); -int CEditor::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, bool Hidden) +int CEditor::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, float *Offset, bool Hidden, int Corners) { - int Inside = UI()->MouseInside(pRect); + int Inside = UI()->MouseInside(pRect); bool ReturnValue = false; + bool UpdateOffset = false; static int s_AtIndex = 0; + static bool s_DoScroll = false; + static float s_ScrollStart = 0.0f; + + FontSize *= UI()->Scale(); if(UI()->LastActiveItem() == pID) { int Len = str_length(pStr); + if(Len == 0) + s_AtIndex = 0; if(Inside && UI()->MouseButton(0)) { + s_DoScroll = true; + s_ScrollStart = UI()->MouseX(); int MxRel = (int)(UI()->MouseX() - pRect->x); - for (int i = 1; i <= Len; i++) + for(int i = 1; i <= Len; i++) { - if (TextRender()->TextWidth(0, FontSize, pStr, i) + 10 > MxRel) + if(TextRender()->TextWidth(0, FontSize, pStr, i) - *Offset > MxRel) { s_AtIndex = i - 1; break; } - if (i == Len) + if(i == Len) s_AtIndex = Len; } } + else if(!UI()->MouseButton(0)) + s_DoScroll = false; + else if(s_DoScroll) + { + // do scrolling + if(UI()->MouseX() < pRect->x && s_ScrollStart-UI()->MouseX() > 10.0f) + { + s_AtIndex = max(0, s_AtIndex-1); + s_ScrollStart = UI()->MouseX(); + UpdateOffset = true; + } + else if(UI()->MouseX() > pRect->x+pRect->w && UI()->MouseX()-s_ScrollStart > 10.0f) + { + s_AtIndex = min(Len, s_AtIndex+1); + s_ScrollStart = UI()->MouseX(); + UpdateOffset = true; + } + } for(int i = 0; i < Input()->NumEvents(); i++) { @@ -235,7 +262,11 @@ int CEditor::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned Str if(UI()->ActiveItem() == pID) { if(!UI()->MouseButton(0)) + { + s_AtIndex = min(s_AtIndex, str_length(pStr)); + s_DoScroll = false; UI()->SetActiveItem(0); + } } else if(UI()->HotItem() == pID) { @@ -251,8 +282,8 @@ int CEditor::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned Str UI()->SetHotItem(pID); CUIRect Textbox = *pRect; - RenderTools()->DrawUIRect(&Textbox, vec4(1,1,1,0.5f), CUI::CORNER_ALL, 3.0f); - Textbox.VMargin(3.0f, &Textbox); + RenderTools()->DrawUIRect(&Textbox, vec4(1, 1, 1, 0.5f), Corners, 3.0f); + Textbox.VMargin(2.0f, &Textbox); const char *pDisplayStr = pStr; char aStars[128]; @@ -268,19 +299,47 @@ int CEditor::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned Str pDisplayStr = aStars; } + // check if the text has to be moved + if(UI()->LastActiveItem() == pID && !JustGotActive && (UpdateOffset || Input()->NumEvents())) + { + float w = TextRender()->TextWidth(0, FontSize, pDisplayStr, s_AtIndex); + if(w-*Offset > Textbox.w) + { + // move to the left + float wt = TextRender()->TextWidth(0, FontSize, pDisplayStr, -1); + do + { + *Offset += min(wt-*Offset-Textbox.w, Textbox.w/3); + } + while(w-*Offset > Textbox.w); + } + else if(w-*Offset < 0.0f) + { + // move to the right + do + { + *Offset = max(0.0f, *Offset-Textbox.w/3); + } + while(w-*Offset < 0.0f); + } + } + UI()->ClipEnable(pRect); + Textbox.x -= *Offset; + UI()->DoLabel(&Textbox, pDisplayStr, FontSize, -1); - - //TODO: make it blink + + // render the cursor if(UI()->LastActiveItem() == pID && !JustGotActive) { float w = TextRender()->TextWidth(0, FontSize, pDisplayStr, s_AtIndex); Textbox = *pRect; Textbox.VSplitLeft(2.0f, 0, &Textbox); - Textbox.x += w*UI()->Scale(); - Textbox.y -= FontSize/10.f; - - UI()->DoLabel(&Textbox, "|", FontSize*1.1f, -1); + Textbox.x += (w-*Offset-TextRender()->TextWidth(0, FontSize, "|", -1)/2); + + if((2*time_get()/time_freq()) % 2) // make it blink + UI()->DoLabel(&Textbox, "|", FontSize, -1); } + UI()->ClipDisable(); return ReturnValue; } @@ -443,12 +502,12 @@ int CEditor::DoButton_Tab(const void *pID, const char *pText, int Checked, const return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip); } -int CEditor::DoButton_Ex(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip, int Corners) +int CEditor::DoButton_Ex(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip, int Corners, float FontSize) { RenderTools()->DrawUIRect(pRect, GetButtonColor(pID, Checked), Corners, 3.0f); CUIRect NewRect = *pRect; - NewRect.y += NewRect.h/2.0f-7.0f; - UI()->DoLabel(&NewRect, pText, 10, 0, -1); + NewRect.HMargin(NewRect.h/2.0f-FontSize/2.0f-1.0f, &NewRect); + UI()->DoLabel(&NewRect, pText, FontSize, 0, -1); return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip); } @@ -1951,16 +2010,19 @@ void CEditor::RenderLayers(CUIRect ToolBox, CUIRect ToolBar, CUIRect View) if(!m_Map.m_lGroups[g]->m_GameGroup) m_Map.m_lGroups[g]->m_SaveToMap = !m_Map.m_lGroups[g]->m_SaveToMap; - str_format(aBuf, sizeof(aBuf),"#%d %s", g, m_Map.m_lGroups[g]->m_pName); + str_format(aBuf, sizeof(aBuf),"#%d %s", g, m_Map.m_lGroups[g]->m_aName); + float FontSize = 10.0f; + while(TextRender()->TextWidth(0, FontSize, aBuf, -1) > Slot.w) + FontSize--; if(int Result = DoButton_Ex(&m_Map.m_lGroups[g], aBuf, g==m_SelectedGroup, &Slot, - BUTTON_CONTEXT, "Select group. Right click for properties.", 0)) + BUTTON_CONTEXT, "Select group. Right click for properties.", 0, FontSize)) { m_SelectedGroup = g; m_SelectedLayer = 0; static int s_GroupPopupId = 0; if(Result == 2) - UiInvokePopupMenu(&s_GroupPopupId, 0, UI()->MouseX(), UI()->MouseY(), 120, 200, PopupGroup); + UiInvokePopupMenu(&s_GroupPopupId, 0, UI()->MouseX(), UI()->MouseY(), 120, 220, PopupGroup); } LayersBox.HSplitTop(2.0f, &Slot, &LayersBox); } @@ -1989,9 +2051,18 @@ void CEditor::RenderLayers(CUIRect ToolBox, CUIRect ToolBar, CUIRect View) if(m_Map.m_lGroups[g]->m_lLayers[i] != m_Map.m_pGameLayer) m_Map.m_lGroups[g]->m_lLayers[i]->m_SaveToMap = !m_Map.m_lGroups[g]->m_lLayers[i]->m_SaveToMap; - str_format(aBuf, sizeof(aBuf),"#%d %s ", i, m_Map.m_lGroups[g]->m_lLayers[i]->m_pTypeName); + if(m_Map.m_lGroups[g]->m_lLayers[i]->m_aName[0]) + str_format(aBuf, sizeof(aBuf), "%s", m_Map.m_lGroups[g]->m_lLayers[i]->m_aName); + else if(m_Map.m_lGroups[g]->m_lLayers[i]->m_Type == LAYERTYPE_TILES) + str_copy(aBuf, "Tiles", sizeof(aBuf)); + else + str_copy(aBuf, "Quads", sizeof(aBuf)); + + float FontSize = 10.0f; + while(TextRender()->TextWidth(0, FontSize, aBuf, -1) > Button.w) + FontSize--; if(int Result = DoButton_Ex(m_Map.m_lGroups[g]->m_lLayers[i], aBuf, g==m_SelectedGroup&&i==m_SelectedLayer, &Button, - BUTTON_CONTEXT, "Select layer. Right click for properties.", 0)) + BUTTON_CONTEXT, "Select layer. Right click for properties.", 0, FontSize)) { m_SelectedLayer = i; m_SelectedGroup = g; @@ -2382,9 +2453,9 @@ void CEditor::RenderFileDialog() // filebox if(m_FileDialogStorageType == IStorage::TYPE_SAVE) { - static int s_FileBoxID = 0; + static float s_FileBoxID = 0; UI()->DoLabel(&FileBoxLabel, "Filename:", 10.0f, -1, -1); - if(DoEditBox(&s_FileBoxID, &FileBox, m_aFileDialogFileName, sizeof(m_aFileDialogFileName), 10.0f)) + if(DoEditBox(&s_FileBoxID, &FileBox, m_aFileDialogFileName, sizeof(m_aFileDialogFileName), 10.0f, &s_FileBoxID)) { // remove '/' and '\' for(int i = 0; m_aFileDialogFileName[i]; ++i) @@ -2733,8 +2804,8 @@ void CEditor::RenderEnvelopeEditor(CUIRect View) ToolBar.VSplitLeft(80.0f, &Button, &ToolBar); - static int s_NameBox = 0; - if(DoEditBox(&s_NameBox, &Button, pEnvelope->m_aName, sizeof(pEnvelope->m_aName), 10.0f)) + static float s_NameBox = 0; + if(DoEditBox(&s_NameBox, &Button, pEnvelope->m_aName, sizeof(pEnvelope->m_aName), 10.0f, &s_NameBox)) m_Map.m_Modified = true; } } @@ -3385,7 +3456,7 @@ void CEditorMap::MakeGameGroup(CLayerGroup *pGroup) { m_pGameGroup = pGroup; m_pGameGroup->m_GameGroup = true; - m_pGameGroup->m_pName = "Game"; + str_copy(m_pGameGroup->m_aName, "Game", sizeof(m_pGameGroup->m_aName)); } diff --git a/src/game/editor/editor.h b/src/game/editor/editor.h index 92ec7b2b..1139562e 100644 --- a/src/game/editor/editor.h +++ b/src/game/editor/editor.h @@ -126,7 +126,7 @@ public: CLayer() { m_Type = LAYERTYPE_INVALID; - m_pTypeName = "(invalid)"; + str_copy(m_aName, "(invalid)", sizeof(m_aName)); m_Visible = true; m_Readonly = false; m_SaveToMap = true; @@ -156,7 +156,7 @@ public: virtual void GetSize(float *w, float *h) { *w = 0; *h = 0;} - const char *m_pTypeName; + char m_aName[12]; int m_Type; int m_Flags; @@ -184,7 +184,7 @@ public: int m_ClipW; int m_ClipH; - const char *m_pName; + char m_aName[12]; bool m_GameGroup; bool m_Visible; bool m_SaveToMap; @@ -667,7 +667,7 @@ public: int DoButton_Editor(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip); int DoButton_Tab(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip); - int DoButton_Ex(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip, int Corners); + int DoButton_Ex(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip, int Corners, float FontSize=10.0f); int DoButton_ButtonDec(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip); int DoButton_ButtonInc(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip); @@ -676,7 +676,7 @@ public: int DoButton_Menu(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip); int DoButton_MenuItem(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags=0, const char *pToolTip=0); - int DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, bool Hidden=false); + int DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, float *Offset, bool Hidden=false, int Corners=CUI::CORNER_ALL); void RenderBackground(CUIRect View, int Texture, float Size, float Brightness); diff --git a/src/game/editor/io.cpp b/src/game/editor/io.cpp index 987404b8..9ce6d1f1 100644 --- a/src/game/editor/io.cpp +++ b/src/game/editor/io.cpp @@ -266,6 +266,9 @@ int CEditorMap::Save(class IStorage *pStorage, const char *pFileName) GItem.m_StartLayer = LayerCount; GItem.m_NumLayers = 0; + // save group name + StrToInts(GItem.m_aName, sizeof(GItem.m_aName)/sizeof(int), pGroup->m_aName); + for(int l = 0; l < pGroup->m_lLayers.size(); l++) { if(!pGroup->m_lLayers[l]->m_SaveToMap) @@ -278,7 +281,7 @@ int CEditorMap::Save(class IStorage *pStorage, const char *pFileName) pLayer->PrepareForSave(); CMapItemLayerTilemap Item; - Item.m_Version = 2; + Item.m_Version = 3; Item.m_Layer.m_Flags = pLayer->m_Flags; Item.m_Layer.m_Type = pLayer->m_Type; @@ -295,6 +298,10 @@ int CEditorMap::Save(class IStorage *pStorage, const char *pFileName) Item.m_Flags = pLayer->m_Game; Item.m_Image = pLayer->m_Image; Item.m_Data = df.AddData(pLayer->m_Width*pLayer->m_Height*sizeof(CTile), pLayer->m_pTiles); + + // save layer name + StrToInts(Item.m_aName, sizeof(Item.m_aName)/sizeof(int), pLayer->m_aName); + df.AddItem(MAPITEMTYPE_LAYER, LayerCount, sizeof(Item), &Item); GItem.m_NumLayers++; @@ -307,7 +314,7 @@ int CEditorMap::Save(class IStorage *pStorage, const char *pFileName) if(pLayer->m_lQuads.size()) { CMapItemLayerQuads Item; - Item.m_Version = 1; + Item.m_Version = 2; Item.m_Layer.m_Flags = pLayer->m_Flags; Item.m_Layer.m_Type = pLayer->m_Type; Item.m_Image = pLayer->m_Image; @@ -315,6 +322,10 @@ int CEditorMap::Save(class IStorage *pStorage, const char *pFileName) // add the data Item.m_NumQuads = pLayer->m_lQuads.size(); Item.m_Data = df.AddDataSwapped(pLayer->m_lQuads.size()*sizeof(CQuad), pLayer->m_lQuads.base_ptr()); + + // save layer name + StrToInts(Item.m_aName, sizeof(Item.m_aName)/sizeof(int), pLayer->m_aName); + df.AddItem(MAPITEMTYPE_LAYER, LayerCount, sizeof(Item), &Item); // clean up @@ -489,6 +500,10 @@ int CEditorMap::Load(class IStorage *pStorage, const char *pFileName, int Storag pGroup->m_ClipH = pGItem->m_ClipH; } + // load group name + if(pGItem->m_Version >= 3) + IntsToStr(pGItem->m_aName, sizeof(pGroup->m_aName)/sizeof(int), pGroup->m_aName); + for(int l = 0; l < pGItem->m_NumLayers; l++) { CLayer *pLayer = 0; @@ -524,6 +539,10 @@ int CEditorMap::Load(class IStorage *pStorage, const char *pFileName, int Storag pTiles->m_Image = pTilemapItem->m_Image; pTiles->m_Game = pTilemapItem->m_Flags&1; + // load layer name + if(pTilemapItem->m_Version >= 3) + IntsToStr(pTilemapItem->m_aName, sizeof(pTiles->m_aName)/sizeof(int), pTiles->m_aName); + mem_copy(pTiles->m_pTiles, pData, pTiles->m_Width*pTiles->m_Height*sizeof(CTile)); if(pTiles->m_Game && pTilemapItem->m_Version == MakeVersion(1, *pTilemapItem)) @@ -546,6 +565,11 @@ int CEditorMap::Load(class IStorage *pStorage, const char *pFileName, int Storag pQuads->m_Image = pQuadsItem->m_Image; if(pQuads->m_Image < -1 || pQuads->m_Image >= m_lImages.size()) pQuads->m_Image = -1; + + // load layer name + if(pQuadsItem->m_Version >= 2) + IntsToStr(pQuadsItem->m_aName, sizeof(pQuads->m_aName)/sizeof(int), pQuads->m_aName); + void *pData = DataFile.GetDataSwapped(pQuadsItem->m_Data); pGroup->AddLayer(pQuads); pQuads->m_lQuads.set_size(pQuadsItem->m_NumQuads); diff --git a/src/game/editor/layer_game.cpp b/src/game/editor/layer_game.cpp index f4a5fb76..7e879c3e 100644 --- a/src/game/editor/layer_game.cpp +++ b/src/game/editor/layer_game.cpp @@ -6,7 +6,7 @@ CLayerGame::CLayerGame(int w, int h) : CLayerTiles(w, h) { - m_pTypeName = "Game"; + str_copy(m_aName, "Game", sizeof(m_aName)); m_Game = 1; } diff --git a/src/game/editor/layer_quads.cpp b/src/game/editor/layer_quads.cpp index d2a8a1e5..a0c0d544 100644 --- a/src/game/editor/layer_quads.cpp +++ b/src/game/editor/layer_quads.cpp @@ -13,7 +13,7 @@ CLayerQuads::CLayerQuads() { m_Type = LAYERTYPE_QUADS; - m_pTypeName = "Quads"; + str_copy(m_aName, "Quads", sizeof(m_aName)); m_Image = -1; } diff --git a/src/game/editor/layer_tiles.cpp b/src/game/editor/layer_tiles.cpp index 81944636..ebaa640a 100644 --- a/src/game/editor/layer_tiles.cpp +++ b/src/game/editor/layer_tiles.cpp @@ -15,7 +15,7 @@ CLayerTiles::CLayerTiles(int w, int h) { m_Type = LAYERTYPE_TILES; - m_pTypeName = "Tiles"; + str_copy(m_aName, "Tiles", sizeof(m_aName)); m_Width = w; m_Height = h; m_Image = -1; diff --git a/src/game/editor/popups.cpp b/src/game/editor/popups.cpp index 0a691fdf..00c9f043 100644 --- a/src/game/editor/popups.cpp +++ b/src/game/editor/popups.cpp @@ -167,6 +167,17 @@ int CEditor::PopupGroup(CEditor *pEditor, CUIRect View) return 1; } + // group name + if(!pEditor->GetSelectedGroup()->m_GameGroup) + { + View.HSplitBottom(5.0f, &View, &Button); + View.HSplitBottom(12.0f, &View, &Button); + static float s_Name = 0; + pEditor->UI()->DoLabel(&Button, "Name:", 10.0f, -1, -1); + Button.VSplitLeft(40.0f, 0, &Button); + pEditor->DoEditBox(&s_Name, &Button, pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_aName, sizeof(pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_aName), 10.0f, &s_Name); + } + enum { PROP_ORDER=0, @@ -243,6 +254,17 @@ int CEditor::PopupLayer(CEditor *pEditor, CUIRect View) return 1; } + // layer name + if(pEditor->m_Map.m_pGameLayer != pEditor->GetSelectedLayer(0)) + { + View.HSplitBottom(5.0f, &View, &Button); + View.HSplitBottom(12.0f, &View, &Button); + static float s_Name = 0; + pEditor->UI()->DoLabel(&Button, "Name:", 10.0f, -1, -1); + Button.VSplitLeft(40.0f, 0, &Button); + pEditor->DoEditBox(&s_Name, &Button, pEditor->GetSelectedLayer(0)->m_aName, sizeof(pEditor->GetSelectedLayer(0)->m_aName), 10.0f, &s_Name); + } + View.HSplitBottom(10.0f, &View, 0); CLayerGroup *pCurrentGroup = pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]; @@ -532,8 +554,8 @@ int CEditor::PopupNewFolder(CEditor *pEditor, CUIRect View) View.HSplitBottom(40.0f, &View, 0); View.VMargin(40.0f, &View); View.HSplitBottom(20.0f, &View, &Label); - static int s_FolderBox = 0; - pEditor->DoEditBox(&s_FolderBox, &Label, pEditor->m_FileDialogNewFolderName, sizeof(pEditor->m_FileDialogNewFolderName), 15.0f); + static float s_FolderBox = 0; + pEditor->DoEditBox(&s_FolderBox, &Label, pEditor->m_FileDialogNewFolderName, sizeof(pEditor->m_FileDialogNewFolderName), 15.0f, &s_FolderBox); View.HSplitBottom(20.0f, &View, &Label); pEditor->UI()->DoLabel(&Label, "Name:", 10.0f, -1); diff --git a/src/game/mapitems.h b/src/game/mapitems.h index d99d6724..4daf139b 100644 --- a/src/game/mapitems.h +++ b/src/game/mapitems.h @@ -114,13 +114,15 @@ struct CMapItemGroup_v1 struct CMapItemGroup : public CMapItemGroup_v1 { - enum { CURRENT_VERSION=2 }; + enum { CURRENT_VERSION=3 }; int m_UseClipping; int m_ClipX; int m_ClipY; int m_ClipW; int m_ClipH; + + int m_aName[3]; } ; struct CMapItemLayer @@ -145,6 +147,8 @@ struct CMapItemLayerTilemap int m_Image; int m_Data; + + int m_aName[3]; } ; struct CMapItemLayerQuads @@ -155,6 +159,8 @@ struct CMapItemLayerQuads int m_NumQuads; int m_Data; int m_Image; + + int m_aName[3]; } ; struct CMapItemVersion -- cgit 1.4.1 From ef881a532147c512b08faedf34b982ce6ebc1921 Mon Sep 17 00:00:00 2001 From: SushiTee Date: Tue, 12 Jul 2011 18:38:33 +0200 Subject: added layer/image scrolling via mouse wheel --- src/game/editor/editor.cpp | 47 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index 630bad8d..8e1c81ec 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -840,13 +840,6 @@ void CEditor::DoToolbar(CUIRect ToolBar) m_AnimateSpeed -= 0.5f; } - if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP) && m_Dialog == DIALOG_NONE) - m_ZoomLevel -= 20; - - if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN) && m_Dialog == DIALOG_NONE) - m_ZoomLevel += 20; - - m_ZoomLevel = clamp(m_ZoomLevel, 50, 2000); m_WorldZoom = m_ZoomLevel/100.0f; TB_Top.VSplitLeft(10.0f, &Button, &TB_Top); @@ -1976,6 +1969,20 @@ void CEditor::RenderLayers(CUIRect ToolBox, CUIRect ToolBar, CUIRect View) LayersBox.VSplitRight(3.0f, &LayersBox, 0); // extra spacing Scroll.HMargin(5.0f, &Scroll); s_ScrollValue = UiDoScrollbarV(&s_ScrollBar, &Scroll, s_ScrollValue); + + if(UI()->MouseInside(&Scroll) || UI()->MouseInside(&LayersBox)) + { + int ScrollNum = (int)((LayersHeight-LayersBox.h)/15.0f)+1; + if(ScrollNum > 0) + { + if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP)) + s_ScrollValue = clamp(s_ScrollValue - 1.0f/ScrollNum, 0.0f, 1.0f); + if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN)) + s_ScrollValue = clamp(s_ScrollValue + 1.0f/ScrollNum, 0.0f, 1.0f); + } + else + ScrollNum = 0; + } } float LayerStartAt = ScrollDifference * s_ScrollValue; @@ -2272,6 +2279,20 @@ void CEditor::RenderImages(CUIRect ToolBox, CUIRect ToolBar, CUIRect View) ToolBox.VSplitRight(3.0f, &ToolBox, 0); // extra spacing Scroll.HMargin(5.0f, &Scroll); s_ScrollValue = UiDoScrollbarV(&s_ScrollBar, &Scroll, s_ScrollValue); + + if(UI()->MouseInside(&Scroll) || UI()->MouseInside(&ToolBox)) + { + int ScrollNum = (int)((ImagesHeight-ToolBox.h)/14.0f)+1; + if(ScrollNum > 0) + { + if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP)) + s_ScrollValue = clamp(s_ScrollValue - 1.0f/ScrollNum, 0.0f, 1.0f); + if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN)) + s_ScrollValue = clamp(s_ScrollValue + 1.0f/ScrollNum, 0.0f, 1.0f); + } + else + ScrollNum = 0; + } } float ImageStartAt = ScrollDifference * s_ScrollValue; @@ -3264,6 +3285,18 @@ void CEditor::Render() if(m_Mode == MODE_LAYERS) DoMapEditor(View, ToolBar); + // do the scrolling + if(m_Dialog == DIALOG_NONE && UI()->MouseInside(&View)) + { + if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP)) + m_ZoomLevel -= 20; + + if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN)) + m_ZoomLevel += 20; + + m_ZoomLevel = clamp(m_ZoomLevel, 50, 2000); + } + if(m_GuiActive) { float Brightness = 0.25f; -- cgit 1.4.1 From f7a9e80163af47ef4ad1bc9df1cf635610ebe2eb Mon Sep 17 00:00:00 2001 From: SushiTee Date: Tue, 12 Jul 2011 17:54:59 +0200 Subject: added possibility to collapse groups by double clicking them --- src/game/editor/editor.cpp | 19 +++++++++++++++---- src/game/editor/editor.h | 1 + src/game/editor/popups.cpp | 2 ++ 3 files changed, 18 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index 8e1c81ec..ecb38444 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -44,6 +44,7 @@ CLayerGroup::CLayerGroup() m_aName[0] = 0; m_Visible = true; m_SaveToMap = true; + m_Collapse = false; m_GameGroup = false; m_OffsetX = 0; m_OffsetY = 0; @@ -1956,9 +1957,13 @@ void CEditor::RenderLayers(CUIRect ToolBox, CUIRect ToolBar, CUIRect View) static float s_ScrollValue = 0; for(int g = 0; g < m_Map.m_lGroups.size(); g++) + { // Each group is 19.0f // Each layer is 14.0f - LayersHeight += 19.0f + m_Map.m_lGroups[g]->m_lLayers.size() * 14.0f; + LayersHeight += 19.0f; + if(!m_Map.m_lGroups[g]->m_Collapse) + LayersHeight += m_Map.m_lGroups[g]->m_lLayers.size() * 14.0f; + } float ScrollDifference = LayersHeight - LayersBox.h; @@ -2009,7 +2014,7 @@ void CEditor::RenderLayers(CUIRect ToolBox, CUIRect ToolBar, CUIRect View) { LayersBox.HSplitTop(12.0f, &Slot, &LayersBox); Slot.VSplitLeft(12, &VisibleToggle, &Slot); - if(DoButton_Ex(&m_Map.m_lGroups[g]->m_Visible, m_Map.m_lGroups[g]->m_Visible?"V":"H", 0, &VisibleToggle, 0, "Toggle group visibility", CUI::CORNER_L)) + if(DoButton_Ex(&m_Map.m_lGroups[g]->m_Visible, m_Map.m_lGroups[g]->m_Visible?"V":"H", m_Map.m_lGroups[g]->m_Collapse ? 1 : 0, &VisibleToggle, 0, "Toggle group visibility", CUI::CORNER_L)) m_Map.m_lGroups[g]->m_Visible = !m_Map.m_lGroups[g]->m_Visible; Slot.VSplitRight(12.0f, &Slot, &SaveCheck); @@ -2022,7 +2027,7 @@ void CEditor::RenderLayers(CUIRect ToolBox, CUIRect ToolBar, CUIRect View) while(TextRender()->TextWidth(0, FontSize, aBuf, -1) > Slot.w) FontSize--; if(int Result = DoButton_Ex(&m_Map.m_lGroups[g], aBuf, g==m_SelectedGroup, &Slot, - BUTTON_CONTEXT, "Select group. Right click for properties.", 0, FontSize)) + BUTTON_CONTEXT, m_Map.m_lGroups[g]->m_Collapse ? "Select group. Double click to expand." : "Select group. Double click to collapse.", 0, FontSize)) { m_SelectedGroup = g; m_SelectedLayer = 0; @@ -2030,6 +2035,9 @@ void CEditor::RenderLayers(CUIRect ToolBox, CUIRect ToolBar, CUIRect View) static int s_GroupPopupId = 0; if(Result == 2) UiInvokePopupMenu(&s_GroupPopupId, 0, UI()->MouseX(), UI()->MouseY(), 120, 220, PopupGroup); + + if(m_Map.m_lGroups[g]->m_lLayers.size() && Input()->MouseDoubleClick()) + m_Map.m_lGroups[g]->m_Collapse ^= 1; } LayersBox.HSplitTop(2.0f, &Slot, &LayersBox); } @@ -2045,6 +2053,9 @@ void CEditor::RenderLayers(CUIRect ToolBox, CUIRect ToolBar, CUIRect View) continue; } + if(m_Map.m_lGroups[g]->m_Collapse) + continue; + //visible LayersBox.HSplitTop(12.0f, &Slot, &LayersBox); Slot.VSplitLeft(12.0f, 0, &Button); @@ -2069,7 +2080,7 @@ void CEditor::RenderLayers(CUIRect ToolBox, CUIRect ToolBar, CUIRect View) while(TextRender()->TextWidth(0, FontSize, aBuf, -1) > Button.w) FontSize--; if(int Result = DoButton_Ex(m_Map.m_lGroups[g]->m_lLayers[i], aBuf, g==m_SelectedGroup&&i==m_SelectedLayer, &Button, - BUTTON_CONTEXT, "Select layer. Right click for properties.", 0, FontSize)) + BUTTON_CONTEXT, "Select layer.", 0, FontSize)) { m_SelectedLayer = i; m_SelectedGroup = g; diff --git a/src/game/editor/editor.h b/src/game/editor/editor.h index 1139562e..d282f5e1 100644 --- a/src/game/editor/editor.h +++ b/src/game/editor/editor.h @@ -188,6 +188,7 @@ public: bool m_GameGroup; bool m_Visible; bool m_SaveToMap; + bool m_Collapse; CLayerGroup(); ~CLayerGroup(); diff --git a/src/game/editor/popups.cpp b/src/game/editor/popups.cpp index 00c9f043..d8b8a91e 100644 --- a/src/game/editor/popups.cpp +++ b/src/game/editor/popups.cpp @@ -151,6 +151,7 @@ int CEditor::PopupGroup(CEditor *pEditor, CUIRect View) l->m_pEditor = pEditor; pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->AddLayer(l); pEditor->m_SelectedLayer = pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_lLayers.size()-1; + pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_Collapse = false; return 1; } @@ -164,6 +165,7 @@ int CEditor::PopupGroup(CEditor *pEditor, CUIRect View) l->m_pEditor = pEditor; pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->AddLayer(l); pEditor->m_SelectedLayer = pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_lLayers.size()-1; + pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_Collapse = false; return 1; } -- cgit 1.4.1 From 6b2dc40570492baf8492d54d513da969c82f4a78 Mon Sep 17 00:00:00 2001 From: Choupom Date: Wed, 20 Jul 2011 10:32:37 +0200 Subject: fixed a rcon authentication issue --- src/engine/server/server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 17df19ed..2b174610 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -869,7 +869,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) if(Unpacker.Error() == 0) { - if(g_Config.m_SvRconPassword[0] == 0 && g_Config.m_SvRconModPassword[0]) + if(g_Config.m_SvRconPassword[0] == 0 && g_Config.m_SvRconModPassword[0] == 0) { SendRconLine(ClientID, "No rcon password set on server. Set sv_rcon_password and/or sv_rcon_mod_password to enable the remote console."); } -- cgit 1.4.1 From 188e6223730e577a1cdfc5891f832c53c23cc146 Mon Sep 17 00:00:00 2001 From: Choupom Date: Mon, 18 Jul 2011 10:34:30 +0200 Subject: fixed auto_map.h header guard --- src/game/editor/auto_map.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/game/editor/auto_map.h b/src/game/editor/auto_map.h index 4f4cf92e..ee570378 100644 --- a/src/game/editor/auto_map.h +++ b/src/game/editor/auto_map.h @@ -1,5 +1,5 @@ -#ifndef GAME_EDITOR_ED_AUTO_MAP_H -#define GAME_EDITOR_ED_AUTO_MAP_H +#ifndef GAME_EDITOR_AUTO_MAP_H +#define GAME_EDITOR_AUTO_MAP_H #include -- cgit 1.4.1 From c2e8bf5035cbe3f41a71c454e348fc408f17a991 Mon Sep 17 00:00:00 2001 From: Choupom Date: Mon, 18 Jul 2011 10:31:57 +0200 Subject: made a constant for game layer flag --- src/game/editor/io.cpp | 6 +++--- src/game/mapitems.h | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/game/editor/io.cpp b/src/game/editor/io.cpp index 9ce6d1f1..768f0fa5 100644 --- a/src/game/editor/io.cpp +++ b/src/game/editor/io.cpp @@ -295,7 +295,7 @@ int CEditorMap::Save(class IStorage *pStorage, const char *pFileName) Item.m_Width = pLayer->m_Width; Item.m_Height = pLayer->m_Height; - Item.m_Flags = pLayer->m_Game; + Item.m_Flags = pLayer->m_Game ? TILESLAYERFLAG_GAME : 0; Item.m_Image = pLayer->m_Image; Item.m_Data = df.AddData(pLayer->m_Width*pLayer->m_Height*sizeof(CTile), pLayer->m_pTiles); @@ -516,7 +516,7 @@ int CEditorMap::Load(class IStorage *pStorage, const char *pFileName, int Storag CMapItemLayerTilemap *pTilemapItem = (CMapItemLayerTilemap *)pLayerItem; CLayerTiles *pTiles = 0; - if(pTilemapItem->m_Flags&1) + if(pTilemapItem->m_Flags&TILESLAYERFLAG_GAME) { pTiles = new CLayerGame(pTilemapItem->m_Width, pTilemapItem->m_Height); MakeGameLayer(pTiles); @@ -537,7 +537,7 @@ int CEditorMap::Load(class IStorage *pStorage, const char *pFileName, int Storag pGroup->AddLayer(pTiles); void *pData = DataFile.GetData(pTilemapItem->m_Data); pTiles->m_Image = pTilemapItem->m_Image; - pTiles->m_Game = pTilemapItem->m_Flags&1; + pTiles->m_Game = pTilemapItem->m_Flags&TILESLAYERFLAG_GAME; // load layer name if(pTilemapItem->m_Version >= 3) diff --git a/src/game/mapitems.h b/src/game/mapitems.h index 4daf139b..fb66e12d 100644 --- a/src/game/mapitems.h +++ b/src/game/mapitems.h @@ -53,6 +53,7 @@ enum TILEFLAG_ROTATE=8, LAYERFLAG_DETAIL=1, + TILESLAYERFLAG_GAME=1, ENTITY_OFFSET=255-16*4, }; -- cgit 1.4.1 From 84e5c534322940a696d9a915829a5e69e5679a28 Mon Sep 17 00:00:00 2001 From: Choupom Date: Mon, 18 Jul 2011 12:05:12 +0200 Subject: added color envelope feature for tilemaps --- src/game/client/components/maplayers.cpp | 6 ++++-- src/game/client/render.h | 5 +++-- src/game/client/render_map.cpp | 18 +++++++++++++++--- src/game/editor/editor.cpp | 20 +++++++++++++++++++- src/game/editor/editor.h | 4 ++++ src/game/editor/io.cpp | 16 ++++++---------- src/game/editor/layer_quads.cpp | 20 +------------------- src/game/editor/layer_tiles.cpp | 13 ++++++++++++- 8 files changed, 64 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/game/client/components/maplayers.cpp b/src/game/client/components/maplayers.cpp index b9a2af16..096f9cc5 100644 --- a/src/game/client/components/maplayers.cpp +++ b/src/game/client/components/maplayers.cpp @@ -190,9 +190,11 @@ void CMapLayers::OnRender() CTile *pTiles = (CTile *)m_pLayers->Map()->GetData(pTMap->m_Data); Graphics()->BlendNone(); vec4 Color = vec4(pTMap->m_Color.r/255.0f, pTMap->m_Color.g/255.0f, pTMap->m_Color.b/255.0f, pTMap->m_Color.a/255.0f); - RenderTools()->RenderTilemap(pTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_OPAQUE); + RenderTools()->RenderTilemap(pTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_OPAQUE, + EnvelopeEval, this, pTMap->m_ColorEnv, pTMap->m_ColorEnvOffset); Graphics()->BlendNormal(); - RenderTools()->RenderTilemap(pTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_TRANSPARENT); + RenderTools()->RenderTilemap(pTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_TRANSPARENT, + EnvelopeEval, this, pTMap->m_ColorEnv, pTMap->m_ColorEnvOffset); } else if(pLayer->m_Type == LAYERTYPE_QUADS) { diff --git a/src/game/client/render.h b/src/game/client/render.h index dc7207be..d3d7fc40 100644 --- a/src/game/client/render.h +++ b/src/game/client/render.h @@ -39,6 +39,7 @@ enum TILERENDERFLAG_EXTEND=4, }; +typedef void (*ENVELOPE_EVAL)(float TimeOffset, int Env, float *pChannels, void *pUser); class CRenderTools { @@ -70,8 +71,8 @@ public: // map render methods (gc_render_map.cpp) static void RenderEvalEnvelope(CEnvPoint *pPoints, int NumPoints, int Channels, float Time, float *pResult); - void RenderQuads(CQuad *pQuads, int NumQuads, int Flags, void (*pfnEval)(float TimeOffset, int Env, float *pChannels, void *pUser), void *pUser); - void RenderTilemap(CTile *pTiles, int w, int h, float Scale, vec4 Color, int Flags); + void RenderQuads(CQuad *pQuads, int NumQuads, int Flags, ENVELOPE_EVAL pfnEval, void *pUser); + void RenderTilemap(CTile *pTiles, int w, int h, float Scale, vec4 Color, int RenderFlags, ENVELOPE_EVAL pfnEval, void *pUser, int ColorEnv, int ColorEnvOffset); // helpers void MapscreenToWorld(float CenterX, float CenterY, float ParallaxX, float ParallaxY, diff --git a/src/game/client/render_map.cpp b/src/game/client/render_map.cpp index 33cc1c7d..23fa42e0 100644 --- a/src/game/client/render_map.cpp +++ b/src/game/client/render_map.cpp @@ -78,7 +78,7 @@ static void Rotate(CPoint *pCenter, CPoint *pPoint, float Rotation) pPoint->y = (int)(x * sinf(Rotation) + y * cosf(Rotation) + pCenter->y); } -void CRenderTools::RenderQuads(CQuad *pQuads, int NumQuads, int RenderFlags, void (*pfnEval)(float TimeOffset, int Env, float *pChannels, void *pUser), void *pUser) +void CRenderTools::RenderQuads(CQuad *pQuads, int NumQuads, int RenderFlags, ENVELOPE_EVAL pfnEval, void *pUser) { Graphics()->QuadsBegin(); float Conv = 1/255.0f; @@ -162,7 +162,8 @@ void CRenderTools::RenderQuads(CQuad *pQuads, int NumQuads, int RenderFlags, voi Graphics()->QuadsEnd(); } -void CRenderTools::RenderTilemap(CTile *pTiles, int w, int h, float Scale, vec4 Color, int RenderFlags) +void CRenderTools::RenderTilemap(CTile *pTiles, int w, int h, float Scale, vec4 Color, int RenderFlags, + ENVELOPE_EVAL pfnEval, void *pUser, int ColorEnv, int ColorEnvOffset) { //Graphics()->TextureSet(img_get(tmap->image)); float ScreenX0, ScreenY0, ScreenX1, ScreenY1; @@ -174,8 +175,19 @@ void CRenderTools::RenderTilemap(CTile *pTiles, int w, int h, float Scale, vec4 float FinalTileSize = Scale/(ScreenX1-ScreenX0) * Graphics()->ScreenWidth(); float FinalTilesetScale = FinalTileSize/TilePixelSize; + float r=1, g=1, b=1, a=1; + if(ColorEnv >= 0) + { + float aChannels[4]; + pfnEval(ColorEnvOffset/1000.0f, ColorEnv, aChannels, pUser); + r = aChannels[0]; + g = aChannels[1]; + b = aChannels[2]; + a = aChannels[3]; + } + Graphics()->QuadsBegin(); - Graphics()->SetColor(Color.r, Color.g, Color.b, Color.a); + Graphics()->SetColor(Color.r*r, Color.g*g, Color.b*b, Color.a*a); int StartY = (int)(ScreenY0/Scale)-1; int StartX = (int)(ScreenX0/Scale)-1; diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index ecb38444..7453472a 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -190,6 +190,24 @@ void CEditorImage::AnalyseTileFlags() } +void CEditor::EnvelopeEval(float TimeOffset, int Env, float *pChannels, void *pUser) +{ + CEditor *pThis = (CEditor *)pUser; + if(Env < 0 || Env > pThis->m_Map.m_lEnvelopes.size()) + { + pChannels[0] = 0; + pChannels[1] = 0; + pChannels[2] = 0; + pChannels[3] = 0; + return; + } + + CEnvelope *e = pThis->m_Map.m_lEnvelopes[Env]; + float t = pThis->m_AnimateTime+TimeOffset; + t *= pThis->m_AnimateSpeed; + e->Eval(t, pChannels); +} + /******************************************************** OTHER *********************************************************/ @@ -2086,7 +2104,7 @@ void CEditor::RenderLayers(CUIRect ToolBox, CUIRect ToolBar, CUIRect View) m_SelectedGroup = g; static int s_LayerPopupID = 0; if(Result == 2) - UiInvokePopupMenu(&s_LayerPopupID, 0, UI()->MouseX(), UI()->MouseY(), 120, 220, PopupLayer); + UiInvokePopupMenu(&s_LayerPopupID, 0, UI()->MouseX(), UI()->MouseY(), 120, 245, PopupLayer); } LayerCur += 14.0f; diff --git a/src/game/editor/editor.h b/src/game/editor/editor.h index d282f5e1..1a904953 100644 --- a/src/game/editor/editor.h +++ b/src/game/editor/editor.h @@ -406,6 +406,8 @@ public: int m_Width; int m_Height; CColor m_Color; + int m_ColorEnv; + int m_ColorEnvOffset; CTile *m_pTiles; }; @@ -663,6 +665,8 @@ public: CEditorMap m_Map; + static void EnvelopeEval(float TimeOffset, int Env, float *pChannels, void *pUser); + void DoMapBorder(); int DoButton_Editor_Common(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip); int DoButton_Editor(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip); diff --git a/src/game/editor/io.cpp b/src/game/editor/io.cpp index 768f0fa5..68330f03 100644 --- a/src/game/editor/io.cpp +++ b/src/game/editor/io.cpp @@ -286,12 +286,9 @@ int CEditorMap::Save(class IStorage *pStorage, const char *pFileName) Item.m_Layer.m_Flags = pLayer->m_Flags; Item.m_Layer.m_Type = pLayer->m_Type; - Item.m_Color.r = pLayer->m_Color.r; - Item.m_Color.g = pLayer->m_Color.g; - Item.m_Color.b = pLayer->m_Color.b; - Item.m_Color.a = pLayer->m_Color.a; - Item.m_ColorEnv = -1; // not in use right now - Item.m_ColorEnvOffset = 0; + Item.m_Color = pLayer->m_Color; + Item.m_ColorEnv = pLayer->m_ColorEnv; + Item.m_ColorEnvOffset = pLayer->m_ColorEnvOffset; Item.m_Width = pLayer->m_Width; Item.m_Height = pLayer->m_Height; @@ -526,10 +523,9 @@ int CEditorMap::Load(class IStorage *pStorage, const char *pFileName, int Storag { pTiles = new CLayerTiles(pTilemapItem->m_Width, pTilemapItem->m_Height); pTiles->m_pEditor = m_pEditor; - pTiles->m_Color.r = pTilemapItem->m_Color.r; - pTiles->m_Color.g = pTilemapItem->m_Color.g; - pTiles->m_Color.b = pTilemapItem->m_Color.b; - pTiles->m_Color.a = pTilemapItem->m_Color.a; + pTiles->m_Color = pTilemapItem->m_Color; + pTiles->m_ColorEnv = pTilemapItem->m_ColorEnv; + pTiles->m_ColorEnvOffset = pTilemapItem->m_ColorEnvOffset; } pLayer = pTiles; diff --git a/src/game/editor/layer_quads.cpp b/src/game/editor/layer_quads.cpp index a0c0d544..d0b66405 100644 --- a/src/game/editor/layer_quads.cpp +++ b/src/game/editor/layer_quads.cpp @@ -21,31 +21,13 @@ CLayerQuads::~CLayerQuads() { } -static void EnvelopeEval(float TimeOffset, int Env, float *pChannels, void *pUser) -{ - CEditor *pEditor = (CEditor *)pUser; - if(Env < 0 || Env > pEditor->m_Map.m_lEnvelopes.size()) - { - pChannels[0] = 0; - pChannels[1] = 0; - pChannels[2] = 0; - pChannels[3] = 0; - return; - } - - CEnvelope *e = pEditor->m_Map.m_lEnvelopes[Env]; - float t = pEditor->m_AnimateTime+TimeOffset; - t *= pEditor->m_AnimateSpeed; - e->Eval(t, pChannels); -} - void CLayerQuads::Render() { Graphics()->TextureSet(-1); if(m_Image >= 0 && m_Image < m_pEditor->m_Map.m_lImages.size()) Graphics()->TextureSet(m_pEditor->m_Map.m_lImages[m_Image]->m_TexID); - m_pEditor->RenderTools()->RenderQuads(m_lQuads.base_ptr(), m_lQuads.size(), LAYERRENDERFLAG_OPAQUE|LAYERRENDERFLAG_TRANSPARENT, EnvelopeEval, m_pEditor); + m_pEditor->RenderTools()->RenderQuads(m_lQuads.base_ptr(), m_lQuads.size(), LAYERRENDERFLAG_OPAQUE|LAYERRENDERFLAG_TRANSPARENT, m_pEditor->EnvelopeEval, m_pEditor); } CQuad *CLayerQuads::NewQuad() diff --git a/src/game/editor/layer_tiles.cpp b/src/game/editor/layer_tiles.cpp index ebaa640a..5662613c 100644 --- a/src/game/editor/layer_tiles.cpp +++ b/src/game/editor/layer_tiles.cpp @@ -25,6 +25,8 @@ CLayerTiles::CLayerTiles(int w, int h) m_Color.g = 255; m_Color.b = 255; m_Color.a = 255; + m_ColorEnv = -1; + m_ColorEnvOffset = 0; m_pTiles = new CTile[m_Width*m_Height]; mem_zero(m_pTiles, m_Width*m_Height*sizeof(CTile)); @@ -62,7 +64,8 @@ void CLayerTiles::Render() m_TexID = m_pEditor->m_Map.m_lImages[m_Image]->m_TexID; Graphics()->TextureSet(m_TexID); vec4 Color = vec4(m_Color.r/255.0f, m_Color.g/255.0f, m_Color.b/255.0f, m_Color.a/255.0f); - m_pEditor->RenderTools()->RenderTilemap(m_pTiles, m_Width, m_Height, 32.0f, Color, LAYERRENDERFLAG_OPAQUE|LAYERRENDERFLAG_TRANSPARENT); + m_pEditor->RenderTools()->RenderTilemap(m_pTiles, m_Width, m_Height, 32.0f, Color, LAYERRENDERFLAG_OPAQUE|LAYERRENDERFLAG_TRANSPARENT, + m_pEditor->EnvelopeEval, m_pEditor, m_ColorEnv, m_ColorEnvOffset); } int CLayerTiles::ConvertX(float x) const { return (int)(x/32.0f); } @@ -412,6 +415,8 @@ int CLayerTiles::RenderProperties(CUIRect *pToolBox) PROP_SHIFT, PROP_IMAGE, PROP_COLOR, + PROP_COLOR_ENV, + PROP_COLOR_ENV_OFFSET, NUM_PROPS, }; @@ -427,6 +432,8 @@ int CLayerTiles::RenderProperties(CUIRect *pToolBox) {"Shift", 0, PROPTYPE_SHIFT, 0, 0}, {"Image", m_Image, PROPTYPE_IMAGE, 0, 0}, {"Color", Color, PROPTYPE_COLOR, 0, 0}, + {"Color Env", m_ColorEnv+1, PROPTYPE_INT_STEP, 0, m_pEditor->m_Map.m_lEnvelopes.size()+1}, + {"Color TO", m_ColorEnvOffset, PROPTYPE_INT_SCROLL, -1000000, 1000000}, {0}, }; @@ -465,6 +472,10 @@ int CLayerTiles::RenderProperties(CUIRect *pToolBox) m_Color.b = (NewVal>>8)&0xff; m_Color.a = NewVal&0xff; } + if(Prop == PROP_COLOR_ENV) + m_ColorEnv = clamp(NewVal-1, -1, m_pEditor->m_Map.m_lEnvelopes.size()-1); + if(Prop == PROP_COLOR_ENV_OFFSET) + m_ColorEnvOffset = NewVal; return 0; } -- cgit 1.4.1 From 6312a2d71ca35cd925602bf978ef7c9483d6f78f Mon Sep 17 00:00:00 2001 From: oy Date: Wed, 20 Jul 2011 22:18:31 +0200 Subject: fixed few things in th editor --- src/game/editor/editor.cpp | 2 +- src/game/editor/popups.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index 7453472a..500e600b 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -193,7 +193,7 @@ void CEditorImage::AnalyseTileFlags() void CEditor::EnvelopeEval(float TimeOffset, int Env, float *pChannels, void *pUser) { CEditor *pThis = (CEditor *)pUser; - if(Env < 0 || Env > pThis->m_Map.m_lEnvelopes.size()) + if(Env < 0 || Env >= pThis->m_Map.m_lEnvelopes.size()) { pChannels[0] = 0; pChannels[1] = 0; diff --git a/src/game/editor/popups.cpp b/src/game/editor/popups.cpp index d8b8a91e..f29ae7e2 100644 --- a/src/game/editor/popups.cpp +++ b/src/game/editor/popups.cpp @@ -177,7 +177,8 @@ int CEditor::PopupGroup(CEditor *pEditor, CUIRect View) static float s_Name = 0; pEditor->UI()->DoLabel(&Button, "Name:", 10.0f, -1, -1); Button.VSplitLeft(40.0f, 0, &Button); - pEditor->DoEditBox(&s_Name, &Button, pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_aName, sizeof(pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_aName), 10.0f, &s_Name); + if(pEditor->DoEditBox(&s_Name, &Button, pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_aName, sizeof(pEditor->m_Map.m_lGroups[pEditor->m_SelectedGroup]->m_aName), 10.0f, &s_Name)) + pEditor->m_Map.m_Modified = true; } enum @@ -264,7 +265,8 @@ int CEditor::PopupLayer(CEditor *pEditor, CUIRect View) static float s_Name = 0; pEditor->UI()->DoLabel(&Button, "Name:", 10.0f, -1, -1); Button.VSplitLeft(40.0f, 0, &Button); - pEditor->DoEditBox(&s_Name, &Button, pEditor->GetSelectedLayer(0)->m_aName, sizeof(pEditor->GetSelectedLayer(0)->m_aName), 10.0f, &s_Name); + if(pEditor->DoEditBox(&s_Name, &Button, pEditor->GetSelectedLayer(0)->m_aName, sizeof(pEditor->GetSelectedLayer(0)->m_aName), 10.0f, &s_Name)) + pEditor->m_Map.m_Modified = true; } View.HSplitBottom(10.0f, &View, 0); -- cgit 1.4.1 From b7aa8af7aada959f3cb1d57df4a7d8d83965c4ad Mon Sep 17 00:00:00 2001 From: Choupom Date: Sat, 23 Jul 2011 12:03:15 +0200 Subject: thats why magic values sux --- src/game/server/player.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp index 3e4d7be5..38baad75 100644 --- a/src/game/server/player.cpp +++ b/src/game/server/player.cpp @@ -61,7 +61,7 @@ void CPlayer::Tick() } if(!m_pCharacter && m_Team == TEAM_SPECTATORS && m_SpectatorID == SPEC_FREEVIEW) - m_ViewPos -= vec2(clamp(m_ViewPos.x-m_LatestActivity.m_TargetX, -5000.0f, 500.0f), clamp(m_ViewPos.y-m_LatestActivity.m_TargetY, -400.0f, 400.0f)); + m_ViewPos -= vec2(clamp(m_ViewPos.x-m_LatestActivity.m_TargetX, -500.0f, 500.0f), clamp(m_ViewPos.y-m_LatestActivity.m_TargetY, -400.0f, 400.0f)); if(!m_pCharacter && m_DieTick+Server()->TickSpeed()*3 <= Server()->Tick()) m_Spawning = true; -- cgit 1.4.1 From 65d312fd06ef7730cb6699923e17d8b05bd764d0 Mon Sep 17 00:00:00 2001 From: oy Date: Thu, 28 Jul 2011 22:01:14 +0200 Subject: fixed problem with lineinput. Closes #802 --- src/game/client/lineinput.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/game/client/lineinput.cpp b/src/game/client/lineinput.cpp index 29b891c2..2de85d66 100644 --- a/src/game/client/lineinput.cpp +++ b/src/game/client/lineinput.cpp @@ -42,7 +42,7 @@ bool CLineInput::Manipulate(IInput::CEvent e, char *pStr, int StrMaxSize, int *p if (Len < StrMaxSize - CharSize && CursorPos < StrMaxSize - CharSize) { - mem_move(pStr + CursorPos + CharSize, pStr + CursorPos, Len - CursorPos + CharSize); + mem_move(pStr + CursorPos + CharSize, pStr + CursorPos, Len-CursorPos+1); // +1 == null term for(int i = 0; i < CharSize; i++) pStr[CursorPos+i] = Tmp[i]; CursorPos += CharSize; -- cgit 1.4.1 From 2ba6fbd7314bfce9cedf93e6f2b1e7f8b5ac7a84 Mon Sep 17 00:00:00 2001 From: heinrich5991 Date: Sat, 2 Jul 2011 08:36:14 +0200 Subject: added econ functionality --- src/engine/server/econ.cpp | 0 src/engine/server/econ.h | 0 src/engine/server/server.cpp | 116 ++++++++++++++++++- src/engine/server/server.h | 25 +++- src/engine/shared/config_variables.h | 4 + src/engine/shared/network.h | 78 +++++++++++++ src/engine/shared/network_console.cpp | 144 +++++++++++++++++++++++ src/engine/shared/network_console_conn.cpp | 176 +++++++++++++++++++++++++++++ 8 files changed, 539 insertions(+), 4 deletions(-) create mode 100644 src/engine/server/econ.cpp create mode 100644 src/engine/server/econ.h create mode 100644 src/engine/shared/network_console.cpp create mode 100644 src/engine/shared/network_console_conn.cpp (limited to 'src') diff --git a/src/engine/server/econ.cpp b/src/engine/server/econ.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/engine/server/econ.h b/src/engine/server/econ.h new file mode 100644 index 00000000..e69de29b diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 2b174610..8e151035 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -317,8 +317,15 @@ int CServer::Init() m_aClients[i].m_Snapshots.Init(); } + for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) + { + m_aEconClients[i].m_State = CEconClient::STATE_EMPTY; + } + m_CurrentGameTick = 0; + m_UseEcon = 0; + return 0; } @@ -611,6 +618,30 @@ int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser) return 0; } +int CServer::NewConsoleClientCallback(int EconID, void *pUser) +{ + CServer *pThis = (CServer *)pUser; + pThis->m_aEconClients[EconID].m_State = CEconClient::STATE_CONNECTED; + pThis->m_NetConsole.SetTimeout(EconID, g_Config.m_SvEconAuthTimeout); + return 0; +} + +int CServer::DelConsoleClientCallback(int EconID, const char *pReason, void *pUser) +{ + CServer *pThis = (CServer *)pUser; + + NETADDR Addr = pThis->m_NetConsole.ClientAddr(EconID); + char aAddrStr[NETADDR_MAXSTRSIZE]; + net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr)); + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "econ client dropped. eid=%d addr=%s reason='%s'", EconID, aAddrStr, pReason); + pThis->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBuf); + + pThis->m_aEconClients[EconID].m_State = CEconClient::STATE_EMPTY; + return 0; +} + + void CServer::SendMap(int ClientID) { CMsgPacker Msg(NETMSG_MAP_CHANGE); @@ -633,7 +664,12 @@ void CServer::SendRconLine(int ClientID, const char *pLine) SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true); } -void CServer::SendRconLineAuthed(const char *pLine, void *pUser) +void CServer::SendEconLine(int EconID, const char *pLine) +{ + m_NetConsole.Send(EconID, pLine); +} + +void CServer::SendConsoleLineAuthed(const char *pLine, void *pUser) { CServer *pThis = (CServer *)pUser; static volatile int ReentryGuard = 0; @@ -648,6 +684,15 @@ void CServer::SendRconLineAuthed(const char *pLine, void *pUser) pThis->SendRconLine(i, pLine); } + if(pThis->m_UseEcon) + { + for(i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) + { + if(pThis->m_aEconClients[i].m_State == CEconClient::STATE_AUTHED) + pThis->SendEconLine(i, pLine); + } + } + ReentryGuard--; } @@ -1084,6 +1129,47 @@ void CServer::PumpNetwork() else ProcessClientPacket(&Packet); } + + if(m_UseEcon) + EconPumpNetwork(); +} + +void CServer::EconPumpNetwork() +{ + m_NetConsole.Update(); + + char aBuf[NET_MAX_PACKETSIZE]; + int EconID; + + while(m_NetConsole.Recv(aBuf, sizeof(aBuf) - 1, &EconID)) + { + dbg_assert(m_aEconClients[EconID].m_State != CEconClient::STATE_EMPTY, "got message from empty slot"); + if(m_aEconClients[EconID].m_State == CEconClient::STATE_CONNECTED) + { + if(str_comp(aBuf, g_Config.m_SvRconPassword) == 0) + { + m_aEconClients[EconID].m_State = CEconClient::STATE_AUTHED; + m_NetConsole.Send(EconID, "Authentication successful. Remote console access granted."); + m_NetConsole.SetTimeout(EconID, g_Config.m_SvEconTimeout); + + str_format(aBuf, sizeof(aBuf), "EconID=%d authed", EconID); + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); + } + else + { + m_NetConsole.Send(EconID, "Wrong password"); + } + } + else if(m_aEconClients[EconID].m_State == CEconClient::STATE_AUTHED) + { + char aFormatted[256]; + str_format(aFormatted, sizeof(aBuf), "eid=%d cmd='%s'", EconID, aBuf); + Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aFormatted); + m_RconClientID = EconID; + Console()->ExecuteLine(aBuf); + m_RconClientID = -1; + } + } } char *CServer::GetMapName() @@ -1158,7 +1244,7 @@ int CServer::Run() m_pStorage = Kernel()->RequestInterface(); // - Console()->RegisterPrintCallback(SendRconLineAuthed, this); + Console()->RegisterPrintCallback(SendConsoleLineAuthed, this); // load map if(!LoadMap(g_Config.m_SvMap)) @@ -1181,7 +1267,6 @@ int CServer::Run() BindAddr.port = g_Config.m_SvPort; } - if(!m_NetServer.Open(BindAddr, g_Config.m_SvMaxClients, g_Config.m_SvMaxClientsPerIP, 0)) { dbg_msg("server", "couldn't open socket. port might already be in use"); @@ -1190,6 +1275,31 @@ int CServer::Run() m_NetServer.SetCallbacks(NewClientCallback, DelClientCallback, this); + if(g_Config.m_SvEconPort && g_Config.m_SvRconPassword[0]) + { + dbg_msg("econ", "binding econ to %s:%d", g_Config.m_SvEconBindaddr, g_Config.m_SvEconPort); + if(g_Config.m_SvEconBindaddr[0] && net_host_lookup(g_Config.m_SvEconBindaddr, &BindAddr, NETTYPE_ALL) == 0) + { + BindAddr.port = g_Config.m_SvEconPort; + } + else + { + mem_zero(&BindAddr, sizeof(BindAddr)); + BindAddr.type = NETTYPE_ALL; + BindAddr.port = g_Config.m_SvEconPort; + } + + if(m_NetConsole.Open(BindAddr, 0)) + { + m_NetConsole.SetCallbacks(NewConsoleClientCallback, DelConsoleClientCallback, this); + m_UseEcon = 1; + } + else + { + dbg_msg("econ", "couldn't open econ socket. port might already be in use"); + } + } + char aBuf[256]; str_format(aBuf, sizeof(aBuf), "server name is '%s'", g_Config.m_SvName); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); diff --git a/src/engine/server/server.h b/src/engine/server/server.h index 5b6e038d..d744b9ff 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -109,10 +109,26 @@ public: CClient m_aClients[MAX_CLIENTS]; + class CEconClient + { + public: + enum + { + STATE_EMPTY=0, + STATE_CONNECTED, + STATE_AUTHED + }; + + int m_State; + }; + + CEconClient m_aEconClients[NET_MAX_CONSOLE_CLIENTS]; + CSnapshotDelta m_SnapshotDelta; CSnapshotBuilder m_SnapshotBuilder; CSnapIDPool m_IDPool; CNetServer m_NetServer; + CNetConsole m_NetConsole; IEngineMap *m_pMap; @@ -123,6 +139,8 @@ public: int m_RconClientID; int m_RconAuthLevel; + int m_UseEcon; + int64 m_Lastheartbeat; //static NETADDR4 master_server; @@ -168,10 +186,14 @@ public: static int NewClientCallback(int ClientID, void *pUser); static int DelClientCallback(int ClientID, const char *pReason, void *pUser); + static int NewConsoleClientCallback(int EconID, void *pUser); + static int DelConsoleClientCallback(int EconID, const char *pReason, void *pUser); + void SendMap(int ClientID); void SendConnectionReady(int ClientID); void SendRconLine(int ClientID, const char *pLine); - static void SendRconLineAuthed(const char *pLine, void *pUser); + void SendEconLine(int EconID, const char *pLine); + static void SendConsoleLineAuthed(const char *pLine, void *pUser); void SendRconCmdAdd(const IConsole::CCommandInfo *pCommandInfo, int ClientID); void SendRconCmdRem(const IConsole::CCommandInfo *pCommandInfo, int ClientID); @@ -185,6 +207,7 @@ public: int BanAdd(NETADDR Addr, int Seconds, const char *pReason); int BanRemove(NETADDR Addr); + void EconPumpNetwork(); void PumpNetwork(); diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index 213ebf26..fd318a7d 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -86,6 +86,10 @@ MACRO_CONFIG_STR(SvRconPassword, sv_rcon_password, 32, "", CFGFLAG_SERVER, "Remo MACRO_CONFIG_STR(SvRconModPassword, sv_rcon_mod_password, 32, "", CFGFLAG_SERVER, "Remote console password for moderators (limited access)") MACRO_CONFIG_INT(SvRconMaxTries, sv_rcon_max_tries, 3, 0, 100, CFGFLAG_SERVER, "Maximum number of tries for remote console authentication") MACRO_CONFIG_INT(SvRconBantime, sv_rcon_bantime, 5, 0, 1440, CFGFLAG_SERVER, "The time a client gets banned if remote console authentication fails. 0 makes it just use kick") +MACRO_CONFIG_STR(SvEconBindaddr, sv_econ_bindaddr, 128, "localhost", CFGFLAG_SERVER, "Address to bind the external console to. Anything but 'localhost' is dangerous") +MACRO_CONFIG_INT(SvEconPort, sv_econ_port, 0, 0, 0, CFGFLAG_SERVER, "Port to use for the external console") +MACRO_CONFIG_INT(SvEconAuthTimeout, sv_econ_auth_timeout, 30, 1, 120, CFGFLAG_SERVER, "Time in seconds before the the econ authentification times out") +MACRO_CONFIG_INT(SvEconTimeout, sv_econ_timeout, 300, 1, 3600, CFGFLAG_SERVER, "Time in seconds before the econ connection times out") MACRO_CONFIG_INT(Debug, debug, 0, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SERVER, "Debug mode") MACRO_CONFIG_INT(DbgStress, dbg_stress, 0, 0, 0, CFGFLAG_CLIENT|CFGFLAG_SERVER, "Stress systems") diff --git a/src/engine/shared/network.h b/src/engine/shared/network.h index 228ba6dd..d0b78d05 100644 --- a/src/engine/shared/network.h +++ b/src/engine/shared/network.h @@ -49,6 +49,7 @@ enum NET_MAX_CHUNKHEADERSIZE = 5, NET_PACKETHEADERSIZE = 3, NET_MAX_CLIENTS = 16, + NET_MAX_CONSOLE_CLIENTS = 16, NET_MAX_SEQUENCE = 1<<10, NET_SEQUENCE_MASK = NET_MAX_SEQUENCE-1, @@ -192,6 +193,41 @@ public: int AckSequence() const { return m_Ack; } }; +class CConsoleNetConnection +{ +private: + unsigned m_State; + + NETADDR m_PeerAddr; + NETSOCKET m_Socket; + + char m_aBuffer[NET_MAX_PACKETSIZE]; + char *m_pBufferPos; + + char m_aErrorString[256]; + + int m_Timeout; + int64 m_LastRecvTime; + +public: + void Init(NETSOCKET Socket); + void Init(NETSOCKET Socket, const NETADDR *pAddr); + int Connect(const NETADDR *pAddr); + void Disconnect(const char *pReason); + + int State() const { return m_State; } + NETADDR PeerAddress() const { return m_PeerAddr; } + const char *ErrorString() const { return m_aErrorString; } + + void SetTimeout(int Timeout) { m_Timeout = Timeout; } + int Timeout() const { return m_Timeout; } + + void Reset(); + int Update(); + int Send(const char *pLine); + int Recv(char *pLine, int MaxLength); +}; + class CNetRecvUnpacker { public: @@ -292,6 +328,48 @@ public: void SetMaxClientsPerIP(int Max); }; +class CNetConsole +{ +private: + struct CSlot + { + CConsoleNetConnection m_Connection; + }; + + NETSOCKET m_Socket; + CSlot m_aSlots[NET_MAX_CLIENTS]; + + NETFUNC_NEWCLIENT m_pfnNewClient; + NETFUNC_DELCLIENT m_pfnDelClient; + void *m_UserPtr; + + CNetRecvUnpacker m_RecvUnpacker; + +public: + int SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser); + + // + bool Open(NETADDR BindAddr, int Flags); + int Close(); + + // + int Broadcast(const char *pLine); + int Recv(char *pLine, int MaxLength, int *pClientID = 0); + int Send(int ClientID, const char *pLine); + int Update(); + + // + int AcceptClient(NETSOCKET Socket, const NETADDR *pAddr); + int Drop(int ClientID, const char *pReason); + + // + void SetTimeout(int ClientID, int Timeout) { m_aSlots[ClientID].m_Connection.SetTimeout(Timeout); } + + // status requests + int Timeout(int ClientID) { return m_aSlots[ClientID].m_Connection.Timeout(); } + NETADDR ClientAddr(int ClientID) const { return m_aSlots[ClientID].m_Connection.PeerAddress(); } +}; + // client side diff --git a/src/engine/shared/network_console.cpp b/src/engine/shared/network_console.cpp new file mode 100644 index 00000000..3e50a1ac --- /dev/null +++ b/src/engine/shared/network_console.cpp @@ -0,0 +1,144 @@ +/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ +/* If you are missing that file, acquire a complete release at teeworlds.com. */ +#include +#include "network.h" + +bool CNetConsole::Open(NETADDR BindAddr, int Flags) +{ + // zero out the whole structure + mem_zero(this, sizeof(*this)); + + // open socket + m_Socket = net_tcp_create(&BindAddr); + if(!m_Socket.type) + return false; + if(net_tcp_listen(m_Socket, NET_MAX_CONSOLE_CLIENTS)) + return false; + net_tcp_set_non_blocking(m_Socket); + + for(int i = 0; i < NET_MAX_CLIENTS; i++) + m_aSlots[i].m_Connection.Init(m_Socket); + + return true; +} + +int CNetConsole::SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser) +{ + m_pfnNewClient = pfnNewClient; + m_pfnDelClient = pfnDelClient; + m_UserPtr = pUser; + return 0; +} + +int CNetConsole::Close() +{ + // TODO: implement me + return 0; +} + +int CNetConsole::Drop(int ClientID, const char *pReason) +{ + NETADDR Addr = ClientAddr(ClientID); + + char aAddrStr[NETADDR_MAXSTRSIZE]; + net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr)); + + if(m_pfnDelClient) + m_pfnDelClient(ClientID, pReason, m_UserPtr); + + m_aSlots[ClientID].m_Connection.Disconnect(pReason); + + return 0; +} + +int CNetConsole::AcceptClient(NETSOCKET Socket, const NETADDR *pAddr) +{ + char aError[256] = { 0 }; + int FreeSlot = -1; + + for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) + { + if(FreeSlot == -1 && m_aSlots[i].m_Connection.State() == NET_CONNSTATE_OFFLINE) + FreeSlot = i; + if(m_aSlots[i].m_Connection.State() != NET_CONNSTATE_OFFLINE) + { + NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress();; + if(net_addr_comp(pAddr, &PeerAddr) == 0) + { + str_copy(aError, "Only one client per IP allowed", sizeof(aError)); + break; + } + } + } + + if(!aError[0] && FreeSlot != -1) + { + m_aSlots[FreeSlot].m_Connection.Init(Socket, pAddr); + if(m_pfnNewClient) + m_pfnNewClient(FreeSlot, m_UserPtr); + return 1; + } + + if(!aError[0]) + { + str_copy(aError, "No free slot available", sizeof(aError)); + } + + dbg_msg("netconsole", "refused client, reason=\"%s\"", aError); + + net_tcp_send(Socket, aError, str_length(aError)); + net_tcp_close(Socket); + + return 0; +} + +int CNetConsole::Update() +{ + NETSOCKET Socket; + NETADDR Addr; + + while(net_tcp_accept(m_Socket, &Socket, &Addr) > 0) + { + AcceptClient(Socket, &Addr); + } + + for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) + { + if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ONLINE) + m_aSlots[i].m_Connection.Update(); + if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ERROR) + Drop(i, m_aSlots[i].m_Connection.ErrorString()); + } + + return 0; +} + +int CNetConsole::Recv(char *pLine, int MaxLength, int *pClientID) +{ + for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) + { + if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ONLINE && m_aSlots[i].m_Connection.Recv(pLine, MaxLength)) + { + if(pClientID) + *pClientID = i; + return 1; + } + } + return 0; +} + +int CNetConsole::Broadcast(const char *pLine) +{ + for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) + { + if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ONLINE) + Send(i, pLine); + } + return 0; +} + +int CNetConsole::Send(int ClientID, const char *pLine) +{ + return m_aSlots[ClientID].m_Connection.Send(pLine); +} + diff --git a/src/engine/shared/network_console_conn.cpp b/src/engine/shared/network_console_conn.cpp new file mode 100644 index 00000000..4dd971a6 --- /dev/null +++ b/src/engine/shared/network_console_conn.cpp @@ -0,0 +1,176 @@ +/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ +/* If you are missing that file, acquire a complete release at teeworlds.com. */ +#include +#include "config.h" +#include "network.h" + +void CConsoleNetConnection::Reset() +{ + m_State = NET_CONNSTATE_OFFLINE; + mem_zero(&m_PeerAddr, sizeof(m_PeerAddr)); + m_aErrorString[0] = 0; + + m_aBuffer[0] = 0; + m_pBufferPos = 0; + m_Timeout = 0; +} + +void CConsoleNetConnection::Init(NETSOCKET Socket, const NETADDR *pAddr) +{ + Reset(); + + m_Socket = Socket; + net_tcp_set_non_blocking(m_Socket); + + m_LastRecvTime = time_get(); + + m_PeerAddr = *pAddr; + m_State = NET_CONNSTATE_ONLINE; +} + +void CConsoleNetConnection::Init(NETSOCKET Socket) +{ + Reset(); + + m_Socket = Socket; + net_tcp_set_non_blocking(m_Socket); + + m_LastRecvTime = time_get(); +} + +int CConsoleNetConnection::Connect(const NETADDR *pAddr) +{ + if(State() != NET_CONNSTATE_OFFLINE) + return -1; + + // init connection + Reset(); + m_PeerAddr = *pAddr; + net_tcp_connect(m_Socket, pAddr); + m_State = NET_CONNSTATE_ONLINE; + return 0; +} + +void CConsoleNetConnection::Disconnect(const char *pReason) +{ + if(State() == NET_CONNSTATE_OFFLINE) + return; + + if(pReason) + { + char aBuf[sizeof(pReason) + 4]; + str_format(aBuf, sizeof(aBuf), "%s", pReason); + Send(aBuf); + } + + net_tcp_close(m_Socket); + + Reset(); +} + +int CConsoleNetConnection::Update() +{ + if(m_Timeout && time_get() > m_LastRecvTime + m_Timeout * time_freq()) + { + m_State = NET_CONNSTATE_ERROR; + str_copy(m_aErrorString, "timeout", sizeof(m_aErrorString)); + return -1; + } + + if(State() == NET_CONNSTATE_ONLINE) + { + char aBuf[NET_MAX_PACKETSIZE]; + + int Bytes = net_tcp_recv(m_Socket, aBuf, sizeof(aBuf) - 1); + + if(Bytes > 0) + { + aBuf[Bytes - 1] = 0; + + if(!m_pBufferPos) + m_aBuffer[0] = 0; + else if(m_pBufferPos != m_aBuffer) + mem_move(m_pBufferPos, m_aBuffer, str_length(m_pBufferPos) + 1); // +1 for the \0 + m_pBufferPos = m_aBuffer; + + str_append(m_aBuffer, aBuf, sizeof(m_aBuffer)); + + m_LastRecvTime = time_get(); + } + else if(Bytes < 0) + { + if(net_would_block()) // no data received + return 0; + + m_State = NET_CONNSTATE_ERROR; // error + str_copy(m_aErrorString, "connection failure", sizeof(m_aErrorString)); + return -1; + } + else + { + m_State = NET_CONNSTATE_ERROR; + str_copy(m_aErrorString, "remote end closed the connection", sizeof(m_aErrorString)); + return -1; + } + } + + return 0; +} + +int CConsoleNetConnection::Recv(char *pLine, int MaxLength) +{ + if(State() == NET_CONNSTATE_ONLINE) + { + if(m_pBufferPos && *m_pBufferPos) + { + char *pResult = m_pBufferPos; + + while(*m_pBufferPos && *m_pBufferPos != '\r' && *m_pBufferPos != '\n') + m_pBufferPos++; + + if(*m_pBufferPos) // haven't reached the end of the buffer? + { + if(*m_pBufferPos == '\r' && *(m_pBufferPos + 1) == '\n') + { + *m_pBufferPos = 0; + m_pBufferPos += 2; + } + else + { + *m_pBufferPos = 0; + m_pBufferPos++; + } + } + else + { + m_pBufferPos = 0; + } + + str_copy(pLine, pResult, MaxLength); + return 1; + } + } + return 0; +} + +int CConsoleNetConnection::Send(const char *pLine) +{ + if(State() != NET_CONNSTATE_ONLINE) + return -1; + + int Length = str_length(pLine); + char aBuf[1024]; + str_copy(aBuf, pLine, sizeof(aBuf) - 2); + aBuf[Length + 1] = '\n'; + aBuf[Length + 2] = '\0'; + + if(net_tcp_send(m_Socket, aBuf, Length + 2) < 0) + { + m_State = NET_CONNSTATE_ERROR; + str_copy(m_aErrorString, "Failed to send packet", sizeof(m_aErrorString)); + return -1; + } + + return 0; +} + -- cgit 1.4.1 From b0fdc4095988ed5bd8bda4b94ce35bc506f31653 Mon Sep 17 00:00:00 2001 From: heinrich5991 Date: Sun, 24 Jul 2011 12:13:33 +0200 Subject: deleted unnecessary empty files --- src/engine/server/econ.cpp | 0 src/engine/server/econ.h | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/engine/server/econ.cpp delete mode 100644 src/engine/server/econ.h (limited to 'src') diff --git a/src/engine/server/econ.cpp b/src/engine/server/econ.cpp deleted file mode 100644 index e69de29b..00000000 diff --git a/src/engine/server/econ.h b/src/engine/server/econ.h deleted file mode 100644 index e69de29b..00000000 -- cgit 1.4.1 From a0a62bcd70d1d8c0874d5ff52e443b5fb417854c Mon Sep 17 00:00:00 2001 From: oy Date: Sat, 30 Jul 2011 13:40:01 +0200 Subject: fixed econ feature and tcp --- src/base/system.c | 44 +++++--- src/engine/console.h | 5 +- src/engine/server/server.cpp | 127 +++------------------ src/engine/server/server.h | 29 +---- src/engine/shared/config_variables.h | 10 +- src/engine/shared/console.cpp | 32 ++++-- src/engine/shared/console.h | 12 +- src/engine/shared/econ.cpp | 147 ++++++++++++++++++++++++ src/engine/shared/econ.h | 43 ++++++++ src/engine/shared/network.h | 24 ++-- src/engine/shared/network_console.cpp | 49 +++----- src/engine/shared/network_console_conn.cpp | 172 +++++++++++++++-------------- src/game/client/components/console.cpp | 14 ++- src/game/client/components/console.h | 2 + 14 files changed, 408 insertions(+), 302 deletions(-) create mode 100644 src/engine/shared/econ.cpp create mode 100644 src/engine/shared/econ.h (limited to 'src') diff --git a/src/base/system.c b/src/base/system.c index 551b3f1b..466e3ca6 100644 --- a/src/base/system.c +++ b/src/base/system.c @@ -42,10 +42,6 @@ #include #include #include - - #ifndef EWOULDBLOCK - #define EWOULDBLOCK WSAEWOULDBLOCK - #endif #else #error NOT IMPLEMENTED #endif @@ -1102,30 +1098,31 @@ int net_set_blocking(NETSOCKET sock) int net_tcp_listen(NETSOCKET sock, int backlog) { + int err = -1; if(sock.ipv4sock >= 0) - listen(sock.ipv4sock, backlog); + err = listen(sock.ipv4sock, backlog); if(sock.ipv6sock >= 0) - listen(sock.ipv6sock, backlog); - return 0; + err = listen(sock.ipv6sock, backlog); + return err; } int net_tcp_accept(NETSOCKET sock, NETSOCKET *new_sock, NETADDR *a) { int s; socklen_t sockaddr_len; - struct sockaddr addr; *new_sock = invalid_socket; - sockaddr_len = sizeof(addr); - if(sock.ipv4sock >= 0) { - s = accept(sock.ipv4sock, &addr, &sockaddr_len); + struct sockaddr_in addr; + sockaddr_len = sizeof(addr); + s = accept(sock.ipv4sock, (struct sockaddr *)&addr, &sockaddr_len); + if (s != -1) { - sockaddr_to_netaddr(&addr, a); + sockaddr_to_netaddr((const struct sockaddr *)&addr, a); new_sock->type = NETTYPE_IPV4; new_sock->ipv4sock = s; return s; @@ -1134,18 +1131,21 @@ int net_tcp_accept(NETSOCKET sock, NETSOCKET *new_sock, NETADDR *a) if(sock.ipv6sock >= 0) { - s = accept(sock.ipv6sock, &addr, &sockaddr_len); + struct sockaddr_in6 addr; + sockaddr_len = sizeof(addr); + s = accept(sock.ipv6sock, (struct sockaddr *)&addr, &sockaddr_len); + if (s != -1) { - sockaddr_to_netaddr(&addr, a); + sockaddr_to_netaddr((const struct sockaddr *)&addr, a); new_sock->type = NETTYPE_IPV6; new_sock->ipv6sock = s; return s; } } - return 0; + return -1; } int net_tcp_connect(NETSOCKET sock, const NETADDR *a) @@ -1164,7 +1164,7 @@ int net_tcp_connect(NETSOCKET sock, const NETADDR *a) return connect(sock.ipv6sock, (struct sockaddr *)&addr, sizeof(addr)); } - return 0; + return -1; } int net_tcp_connect_non_blocking(NETSOCKET sock, NETADDR bindaddr) @@ -1180,7 +1180,7 @@ int net_tcp_connect_non_blocking(NETSOCKET sock, NETADDR bindaddr) int net_tcp_send(NETSOCKET sock, const void *data, int size) { - int bytes = 0; + int bytes = -1; if(sock.ipv4sock >= 0) bytes = send((int)sock.ipv4sock, (const char*)data, size, 0); @@ -1192,7 +1192,7 @@ int net_tcp_send(NETSOCKET sock, const void *data, int size) int net_tcp_recv(NETSOCKET sock, void *data, int maxsize) { - int bytes = 0; + int bytes = -1; if(sock.ipv4sock >= 0) bytes = recv((int)sock.ipv4sock, (char*)data, maxsize, 0); @@ -1209,12 +1209,20 @@ int net_tcp_close(NETSOCKET sock) int net_errno() { +#if defined(CONF_FAMILY_WINDOWS) + return WSAGetLastError(); +#else return errno; +#endif } int net_would_block() { +#if defined(CONF_FAMILY_WINDOWS) + return net_errno() == WSAEWOULDBLOCK; +#else return net_errno() == EWOULDBLOCK; +#endif } int net_init() diff --git a/src/engine/console.h b/src/engine/console.h index 7c39cf49..5d3f2811 100644 --- a/src/engine/console.h +++ b/src/engine/console.h @@ -23,6 +23,8 @@ public: TEMPCMD_NAME_LENGTH=32, TEMPCMD_HELP_LENGTH=64, TEMPCMD_PARAMS_LENGTH=16, + + MAX_PRINT_CB=4, }; // TODO: rework this interface to reduce the amount of virtual calls @@ -79,7 +81,8 @@ public: virtual void ExecuteLineStroked(int Stroke, const char *pStr) = 0; virtual void ExecuteFile(const char *pFilename) = 0; - virtual void RegisterPrintCallback(FPrintCallback pfnPrintCallback, void *pUserData) = 0; + virtual int RegisterPrintCallback(int OutputLevel, FPrintCallback pfnPrintCallback, void *pUserData) = 0; + virtual void SetPrintOutputLevel(int Index, int OutputLevel) = 0; virtual void Print(int Level, const char *pFrom, const char *pStr) = 0; virtual void SetAccessLevel(int AccessLevel) = 0; diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 8e151035..ee7de31b 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -317,15 +318,8 @@ int CServer::Init() m_aClients[i].m_Snapshots.Init(); } - for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) - { - m_aEconClients[i].m_State = CEconClient::STATE_EMPTY; - } - m_CurrentGameTick = 0; - m_UseEcon = 0; - return 0; } @@ -618,30 +612,6 @@ int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser) return 0; } -int CServer::NewConsoleClientCallback(int EconID, void *pUser) -{ - CServer *pThis = (CServer *)pUser; - pThis->m_aEconClients[EconID].m_State = CEconClient::STATE_CONNECTED; - pThis->m_NetConsole.SetTimeout(EconID, g_Config.m_SvEconAuthTimeout); - return 0; -} - -int CServer::DelConsoleClientCallback(int EconID, const char *pReason, void *pUser) -{ - CServer *pThis = (CServer *)pUser; - - NETADDR Addr = pThis->m_NetConsole.ClientAddr(EconID); - char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr)); - char aBuf[256]; - str_format(aBuf, sizeof(aBuf), "econ client dropped. eid=%d addr=%s reason='%s'", EconID, aAddrStr, pReason); - pThis->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBuf); - - pThis->m_aEconClients[EconID].m_State = CEconClient::STATE_EMPTY; - return 0; -} - - void CServer::SendMap(int ClientID) { CMsgPacker Msg(NETMSG_MAP_CHANGE); @@ -664,12 +634,7 @@ void CServer::SendRconLine(int ClientID, const char *pLine) SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true); } -void CServer::SendEconLine(int EconID, const char *pLine) -{ - m_NetConsole.Send(EconID, pLine); -} - -void CServer::SendConsoleLineAuthed(const char *pLine, void *pUser) +void CServer::SendRconLineAuthed(const char *pLine, void *pUser) { CServer *pThis = (CServer *)pUser; static volatile int ReentryGuard = 0; @@ -684,15 +649,6 @@ void CServer::SendConsoleLineAuthed(const char *pLine, void *pUser) pThis->SendRconLine(i, pLine); } - if(pThis->m_UseEcon) - { - for(i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) - { - if(pThis->m_aEconClients[i].m_State == CEconClient::STATE_AUTHED) - pThis->SendEconLine(i, pLine); - } - } - ReentryGuard--; } @@ -1130,46 +1086,7 @@ void CServer::PumpNetwork() ProcessClientPacket(&Packet); } - if(m_UseEcon) - EconPumpNetwork(); -} - -void CServer::EconPumpNetwork() -{ - m_NetConsole.Update(); - - char aBuf[NET_MAX_PACKETSIZE]; - int EconID; - - while(m_NetConsole.Recv(aBuf, sizeof(aBuf) - 1, &EconID)) - { - dbg_assert(m_aEconClients[EconID].m_State != CEconClient::STATE_EMPTY, "got message from empty slot"); - if(m_aEconClients[EconID].m_State == CEconClient::STATE_CONNECTED) - { - if(str_comp(aBuf, g_Config.m_SvRconPassword) == 0) - { - m_aEconClients[EconID].m_State = CEconClient::STATE_AUTHED; - m_NetConsole.Send(EconID, "Authentication successful. Remote console access granted."); - m_NetConsole.SetTimeout(EconID, g_Config.m_SvEconTimeout); - - str_format(aBuf, sizeof(aBuf), "EconID=%d authed", EconID); - Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); - } - else - { - m_NetConsole.Send(EconID, "Wrong password"); - } - } - else if(m_aEconClients[EconID].m_State == CEconClient::STATE_AUTHED) - { - char aFormatted[256]; - str_format(aFormatted, sizeof(aBuf), "eid=%d cmd='%s'", EconID, aBuf); - Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aFormatted); - m_RconClientID = EconID; - Console()->ExecuteLine(aBuf); - m_RconClientID = -1; - } - } + m_Econ.Update(); } char *CServer::GetMapName() @@ -1244,7 +1161,7 @@ int CServer::Run() m_pStorage = Kernel()->RequestInterface(); // - Console()->RegisterPrintCallback(SendConsoleLineAuthed, this); + m_PrintCBIndex = Console()->RegisterPrintCallback(g_Config.m_ConsoleOutputLevel, SendRconLineAuthed, this); // load map if(!LoadMap(g_Config.m_SvMap)) @@ -1275,30 +1192,7 @@ int CServer::Run() m_NetServer.SetCallbacks(NewClientCallback, DelClientCallback, this); - if(g_Config.m_SvEconPort && g_Config.m_SvRconPassword[0]) - { - dbg_msg("econ", "binding econ to %s:%d", g_Config.m_SvEconBindaddr, g_Config.m_SvEconPort); - if(g_Config.m_SvEconBindaddr[0] && net_host_lookup(g_Config.m_SvEconBindaddr, &BindAddr, NETTYPE_ALL) == 0) - { - BindAddr.port = g_Config.m_SvEconPort; - } - else - { - mem_zero(&BindAddr, sizeof(BindAddr)); - BindAddr.type = NETTYPE_ALL; - BindAddr.port = g_Config.m_SvEconPort; - } - - if(m_NetConsole.Open(BindAddr, 0)) - { - m_NetConsole.SetCallbacks(NewConsoleClientCallback, DelConsoleClientCallback, this); - m_UseEcon = 1; - } - else - { - dbg_msg("econ", "couldn't open econ socket. port might already be in use"); - } - } + m_Econ.Init(Console()); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "server name is '%s'", g_Config.m_SvName); @@ -1694,6 +1588,16 @@ void CServer::ConchainModCommandUpdate(IConsole::IResult *pResult, void *pUserDa pfnCallback(pResult, pCallbackUserData); } +void CServer::ConchainConsoleOutputLevelUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData) +{ + pfnCallback(pResult, pCallbackUserData); + if(pResult->NumArguments() == 1) + { + CServer *pThis = static_cast(pUserData); + pThis->Console()->SetPrintOutputLevel(pThis->m_PrintCBIndex, pResult->GetInteger(0)); + } +} + void CServer::RegisterCommands() { m_pConsole = Kernel()->RequestInterface(); @@ -1715,6 +1619,7 @@ void CServer::RegisterCommands() Console()->Chain("sv_max_clients_per_ip", ConchainMaxclientsperipUpdate, this); Console()->Chain("mod_command", ConchainModCommandUpdate, this); + Console()->Chain("console_output_level", ConchainConsoleOutputLevelUpdate, this); } diff --git a/src/engine/server/server.h b/src/engine/server/server.h index d744b9ff..4e575055 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -109,26 +109,11 @@ public: CClient m_aClients[MAX_CLIENTS]; - class CEconClient - { - public: - enum - { - STATE_EMPTY=0, - STATE_CONNECTED, - STATE_AUTHED - }; - - int m_State; - }; - - CEconClient m_aEconClients[NET_MAX_CONSOLE_CLIENTS]; - CSnapshotDelta m_SnapshotDelta; CSnapshotBuilder m_SnapshotBuilder; CSnapIDPool m_IDPool; CNetServer m_NetServer; - CNetConsole m_NetConsole; + CEcon m_Econ; IEngineMap *m_pMap; @@ -138,8 +123,7 @@ public: int m_MapReload; int m_RconClientID; int m_RconAuthLevel; - - int m_UseEcon; + int m_PrintCBIndex; int64 m_Lastheartbeat; //static NETADDR4 master_server; @@ -186,14 +170,10 @@ public: static int NewClientCallback(int ClientID, void *pUser); static int DelClientCallback(int ClientID, const char *pReason, void *pUser); - static int NewConsoleClientCallback(int EconID, void *pUser); - static int DelConsoleClientCallback(int EconID, const char *pReason, void *pUser); - void SendMap(int ClientID); void SendConnectionReady(int ClientID); void SendRconLine(int ClientID, const char *pLine); - void SendEconLine(int EconID, const char *pLine); - static void SendConsoleLineAuthed(const char *pLine, void *pUser); + static void SendRconLineAuthed(const char *pLine, void *pUser); void SendRconCmdAdd(const IConsole::CCommandInfo *pCommandInfo, int ClientID); void SendRconCmdRem(const IConsole::CCommandInfo *pCommandInfo, int ClientID); @@ -207,8 +187,6 @@ public: int BanAdd(NETADDR Addr, int Seconds, const char *pReason); int BanRemove(NETADDR Addr); - void EconPumpNetwork(); - void PumpNetwork(); char *GetMapName(); @@ -229,6 +207,7 @@ public: static void ConchainSpecialInfoupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); static void ConchainMaxclientsperipUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); static void ConchainModCommandUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); + static void ConchainConsoleOutputLevelUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); void RegisterCommands(); diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index fd318a7d..cb8f5f15 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -86,10 +86,12 @@ MACRO_CONFIG_STR(SvRconPassword, sv_rcon_password, 32, "", CFGFLAG_SERVER, "Remo MACRO_CONFIG_STR(SvRconModPassword, sv_rcon_mod_password, 32, "", CFGFLAG_SERVER, "Remote console password for moderators (limited access)") MACRO_CONFIG_INT(SvRconMaxTries, sv_rcon_max_tries, 3, 0, 100, CFGFLAG_SERVER, "Maximum number of tries for remote console authentication") MACRO_CONFIG_INT(SvRconBantime, sv_rcon_bantime, 5, 0, 1440, CFGFLAG_SERVER, "The time a client gets banned if remote console authentication fails. 0 makes it just use kick") -MACRO_CONFIG_STR(SvEconBindaddr, sv_econ_bindaddr, 128, "localhost", CFGFLAG_SERVER, "Address to bind the external console to. Anything but 'localhost' is dangerous") -MACRO_CONFIG_INT(SvEconPort, sv_econ_port, 0, 0, 0, CFGFLAG_SERVER, "Port to use for the external console") -MACRO_CONFIG_INT(SvEconAuthTimeout, sv_econ_auth_timeout, 30, 1, 120, CFGFLAG_SERVER, "Time in seconds before the the econ authentification times out") -MACRO_CONFIG_INT(SvEconTimeout, sv_econ_timeout, 300, 1, 3600, CFGFLAG_SERVER, "Time in seconds before the econ connection times out") + +MACRO_CONFIG_STR(EcBindaddr, ec_bindaddr, 128, "localhost", CFGFLAG_SERVER, "Address to bind the external console to. Anything but 'localhost' is dangerous") +MACRO_CONFIG_INT(EcPort, ec_port, 0, 0, 0, CFGFLAG_SERVER, "Port to use for the external console") +MACRO_CONFIG_STR(EcPassword, ec_password, 32, "", CFGFLAG_SERVER, "External console password") +MACRO_CONFIG_INT(EcAuthTimeout, ec_auth_timeout, 30, 1, 120, CFGFLAG_SERVER, "Time in seconds before the the econ authentification times out") +MACRO_CONFIG_INT(EcOutputLevel, ec_output_level, 1, 0, 2, CFGFLAG_SERVER, "Adjusts the amount of information in the external console") MACRO_CONFIG_INT(Debug, debug, 0, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SERVER, "Debug mode") MACRO_CONFIG_INT(DbgStress, dbg_stress, 0, 0, 0, CFGFLAG_CLIENT|CFGFLAG_SERVER, "Stress systems") diff --git a/src/engine/shared/console.cpp b/src/engine/shared/console.cpp index 847fb140..e4cb1991 100644 --- a/src/engine/shared/console.cpp +++ b/src/engine/shared/console.cpp @@ -173,20 +173,34 @@ int CConsole::ParseArgs(CResult *pResult, const char *pFormat) return Error; } -void CConsole::RegisterPrintCallback(FPrintCallback pfnPrintCallback, void *pUserData) +int CConsole::RegisterPrintCallback(int OutputLevel, FPrintCallback pfnPrintCallback, void *pUserData) { - m_pfnPrintCallback = pfnPrintCallback; - m_pPrintCallbackUserdata = pUserData; + if(m_NumPrintCB == MAX_PRINT_CB) + return -1; + + m_aPrintCB[m_NumPrintCB].m_OutputLevel = clamp(OutputLevel, (int)(OUTPUT_LEVEL_STANDARD), (int)(OUTPUT_LEVEL_DEBUG)); + m_aPrintCB[m_NumPrintCB].m_pfnPrintCallback = pfnPrintCallback; + m_aPrintCB[m_NumPrintCB].m_pPrintCallbackUserdata = pUserData; + return m_NumPrintCB++; +} + +void CConsole::SetPrintOutputLevel(int Index, int OutputLevel) +{ + if(Index >= 0 && Index < MAX_PRINT_CB) + m_aPrintCB[Index].m_OutputLevel = clamp(OutputLevel, (int)(OUTPUT_LEVEL_STANDARD), (int)(OUTPUT_LEVEL_DEBUG)); } void CConsole::Print(int Level, const char *pFrom, const char *pStr) { dbg_msg(pFrom ,"%s", pStr); - if(Level <= g_Config.m_ConsoleOutputLevel && m_pfnPrintCallback) + for(int i = 0; i < m_NumPrintCB; ++i) { - char aBuf[1024]; - str_format(aBuf, sizeof(aBuf), "[%s]: %s", pFrom, pStr); - m_pfnPrintCallback(aBuf, m_pPrintCallbackUserdata); + if(Level <= m_aPrintCB[i].m_OutputLevel && m_aPrintCB[i].m_pfnPrintCallback) + { + char aBuf[1024]; + str_format(aBuf, sizeof(aBuf), "[%s]: %s", pFrom, pStr); + m_aPrintCB[i].m_pfnPrintCallback(aBuf, m_aPrintCB[i].m_pPrintCallbackUserdata); + } } } @@ -562,8 +576,8 @@ CConsole::CConsole(int FlagMask) m_ExecutionQueue.Reset(); m_pFirstCommand = 0; m_pFirstExec = 0; - m_pPrintCallbackUserdata = 0; - m_pfnPrintCallback = 0; + mem_zero(m_aPrintCB, sizeof(m_aPrintCB)); + m_NumPrintCB = 0; m_pStorage = 0; diff --git a/src/engine/shared/console.h b/src/engine/shared/console.h index b29f3202..6989c696 100644 --- a/src/engine/shared/console.h +++ b/src/engine/shared/console.h @@ -60,8 +60,13 @@ class CConsole : public IConsole void ExecuteFileRecurse(const char *pFilename); void ExecuteLineStroked(int Stroke, const char *pStr); - FPrintCallback m_pfnPrintCallback; - void *m_pPrintCallbackUserdata; + struct + { + int m_OutputLevel; + FPrintCallback m_pfnPrintCallback; + void *m_pPrintCallbackUserdata; + } m_aPrintCB[MAX_PRINT_CB]; + int m_NumPrintCB; enum { @@ -167,7 +172,8 @@ public: virtual void ExecuteLine(const char *pStr); virtual void ExecuteFile(const char *pFilename); - virtual void RegisterPrintCallback(FPrintCallback pfnPrintCallback, void *pUserData); + virtual int RegisterPrintCallback(int OutputLevel, FPrintCallback pfnPrintCallback, void *pUserData); + virtual void SetPrintOutputLevel(int Index, int OutputLevel); virtual void Print(int Level, const char *pFrom, const char *pStr); void SetAccessLevel(int AccessLevel) { m_AccessLevel = clamp(AccessLevel, (int)(ACCESS_LEVEL_ADMIN), (int)(ACCESS_LEVEL_MOD)); } diff --git a/src/engine/shared/econ.cpp b/src/engine/shared/econ.cpp new file mode 100644 index 00000000..ba86e5c0 --- /dev/null +++ b/src/engine/shared/econ.cpp @@ -0,0 +1,147 @@ +#include +#include + +#include "econ.h" + +int CEcon::NewClientCallback(int ClientID, void *pUser) +{ + CEcon *pThis = (CEcon *)pUser; + + NETADDR Addr = pThis->m_NetConsole.ClientAddr(ClientID); + char aAddrStr[NETADDR_MAXSTRSIZE]; + net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr)); + char aBuf[128]; + str_format(aBuf, sizeof(aBuf), "client accepted. cid=%d addr=%s'", ClientID, aAddrStr); + pThis->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "econ", aBuf); + + pThis->m_aClients[ClientID].m_State = CClient::STATE_CONNECTED; + pThis->m_aClients[ClientID].m_TimeConnected = time_get(); + return 0; +} + +int CEcon::DelClientCallback(int ClientID, const char *pReason, void *pUser) +{ + CEcon *pThis = (CEcon *)pUser; + + NETADDR Addr = pThis->m_NetConsole.ClientAddr(ClientID); + char aAddrStr[NETADDR_MAXSTRSIZE]; + net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr)); + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "client dropped. cid=%d addr=%s reason='%s'", ClientID, aAddrStr, pReason); + pThis->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "econ", aBuf); + + pThis->m_aClients[ClientID].m_State = CClient::STATE_EMPTY; + return 0; +} + +void CEcon::SendLineCB(const char *pLine, void *pUserData) +{ + static_cast(pUserData)->Send(-1, pLine); +} + +void CEcon::ConchainEconOutputLevelUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData) +{ + pfnCallback(pResult, pCallbackUserData); + if(pResult->NumArguments() == 1) + { + CEcon *pThis = static_cast(pUserData); + pThis->Console()->SetPrintOutputLevel(pThis->m_PrintCBIndex, pResult->GetInteger(0)); + } +} + +void CEcon::Init(IConsole *pConsole) +{ + m_pConsole = pConsole; + + for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) + m_aClients[i].m_State = CClient::STATE_EMPTY; + + m_Ready = false; + + if(g_Config.m_EcPort == 0 || g_Config.m_EcPassword[0] == 0) + return; + + NETADDR BindAddr; + if(g_Config.m_EcBindaddr[0] && net_host_lookup(g_Config.m_EcBindaddr, &BindAddr, NETTYPE_ALL) == 0) + BindAddr.port = g_Config.m_EcPort; + else + { + mem_zero(&BindAddr, sizeof(BindAddr)); + BindAddr.type = NETTYPE_ALL; + BindAddr.port = g_Config.m_EcPort; + } + + if(m_NetConsole.Open(BindAddr, 0)) + { + m_NetConsole.SetCallbacks(NewClientCallback, DelClientCallback, this); + m_Ready = true; + char aBuf[128]; + str_format(aBuf, sizeof(aBuf), "bound to %s:%d", g_Config.m_EcBindaddr, g_Config.m_EcPort); + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD,"econ", aBuf); + + Console()->Chain("ec_output_level", ConchainEconOutputLevelUpdate, this); + m_PrintCBIndex = Console()->RegisterPrintCallback(g_Config.m_EcOutputLevel, SendLineCB, this); + } + else + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD,"econ", "couldn't open socket. port might already be in use"); +} + +void CEcon::Update() +{ + if(!m_Ready) + return; + + m_NetConsole.Update(); + + char aBuf[NET_MAX_PACKETSIZE]; + int ClientID; + + while(m_NetConsole.Recv(aBuf, (int)(sizeof(aBuf))-1, &ClientID)) + { + dbg_assert(m_aClients[ClientID].m_State != CClient::STATE_EMPTY, "got message from empty slot"); + if(m_aClients[ClientID].m_State == CClient::STATE_CONNECTED) + { + if(str_comp(aBuf, g_Config.m_EcPassword) == 0) + { + m_aClients[ClientID].m_State = CClient::STATE_AUTHED; + m_NetConsole.Send(ClientID, "Authentication successful. External console access granted."); + + str_format(aBuf, sizeof(aBuf), "cid=%d authed", ClientID); + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "econ", aBuf); + } + else + m_NetConsole.Send(ClientID, "Wrong password"); + } + else if(m_aClients[ClientID].m_State == CClient::STATE_AUTHED) + { + char aFormatted[256]; + str_format(aFormatted, sizeof(aBuf), "cid=%d cmd='%s'", ClientID, aBuf); + Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aFormatted); + Console()->ExecuteLine(aBuf); + } + } + + for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; ++i) + { + if(m_aClients[i].m_State == CClient::STATE_CONNECTED && + time_get() > m_aClients[i].m_TimeConnected + g_Config.m_EcAuthTimeout * time_freq()) + m_NetConsole.Drop(i, "authentication timeout"); + } +} + +void CEcon::Send(int ClientID, const char *pLine) +{ + if(!m_Ready) + return; + + if(ClientID == -1) + { + for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) + { + if(m_aClients[i].m_State == CClient::STATE_AUTHED) + m_NetConsole.Send(i, pLine); + } + } + else if(ClientID >= 0 && ClientID < NET_MAX_CONSOLE_CLIENTS && m_aClients[ClientID].m_State == CClient::STATE_AUTHED) + m_NetConsole.Send(ClientID, pLine); +} diff --git a/src/engine/shared/econ.h b/src/engine/shared/econ.h new file mode 100644 index 00000000..33b23ea6 --- /dev/null +++ b/src/engine/shared/econ.h @@ -0,0 +1,43 @@ +#ifndef ENGINE_SHARED_ECON_H +#define ENGINE_SHARED_ECON_H + +#include "network.h" + +class CEcon +{ + class CClient + { + public: + enum + { + STATE_EMPTY=0, + STATE_CONNECTED, + STATE_AUTHED, + }; + + int m_State; + int64 m_TimeConnected; + }; + CClient m_aClients[NET_MAX_CONSOLE_CLIENTS]; + + IConsole *m_pConsole; + CNetConsole m_NetConsole; + + bool m_Ready; + int m_PrintCBIndex; + + static void SendLineCB(const char *pLine, void *pUserData); + static void ConchainEconOutputLevelUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); + + static int NewClientCallback(int ClientID, void *pUser); + static int DelClientCallback(int ClientID, const char *pReason, void *pUser); + +public: + IConsole *Console() { return m_pConsole; } + + void Init(IConsole *pConsole); + void Update(); + void Send(int ClientID, const char *pLine); +}; + +#endif diff --git a/src/engine/shared/network.h b/src/engine/shared/network.h index d0b78d05..94e2824c 100644 --- a/src/engine/shared/network.h +++ b/src/engine/shared/network.h @@ -49,7 +49,7 @@ enum NET_MAX_CHUNKHEADERSIZE = 5, NET_PACKETHEADERSIZE = 3, NET_MAX_CLIENTS = 16, - NET_MAX_CONSOLE_CLIENTS = 16, + NET_MAX_CONSOLE_CLIENTS = 4, NET_MAX_SEQUENCE = 1<<10, NET_SEQUENCE_MASK = NET_MAX_SEQUENCE-1, @@ -196,32 +196,27 @@ public: class CConsoleNetConnection { private: - unsigned m_State; + int m_State; NETADDR m_PeerAddr; NETSOCKET m_Socket; char m_aBuffer[NET_MAX_PACKETSIZE]; - char *m_pBufferPos; + int m_BufferOffset; char m_aErrorString[256]; - int m_Timeout; - int64 m_LastRecvTime; + bool m_LineEndingDetected; + char m_aLineEnding[3]; public: - void Init(NETSOCKET Socket); void Init(NETSOCKET Socket, const NETADDR *pAddr); - int Connect(const NETADDR *pAddr); void Disconnect(const char *pReason); int State() const { return m_State; } NETADDR PeerAddress() const { return m_PeerAddr; } const char *ErrorString() const { return m_aErrorString; } - void SetTimeout(int Timeout) { m_Timeout = Timeout; } - int Timeout() const { return m_Timeout; } - void Reset(); int Update(); int Send(const char *pLine); @@ -337,7 +332,7 @@ private: }; NETSOCKET m_Socket; - CSlot m_aSlots[NET_MAX_CLIENTS]; + CSlot m_aSlots[NET_MAX_CONSOLE_CLIENTS]; NETFUNC_NEWCLIENT m_pfnNewClient; NETFUNC_DELCLIENT m_pfnDelClient; @@ -346,14 +341,13 @@ private: CNetRecvUnpacker m_RecvUnpacker; public: - int SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser); + void SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser); // bool Open(NETADDR BindAddr, int Flags); int Close(); // - int Broadcast(const char *pLine); int Recv(char *pLine, int MaxLength, int *pClientID = 0); int Send(int ClientID, const char *pLine); int Update(); @@ -362,11 +356,7 @@ public: int AcceptClient(NETSOCKET Socket, const NETADDR *pAddr); int Drop(int ClientID, const char *pReason); - // - void SetTimeout(int ClientID, int Timeout) { m_aSlots[ClientID].m_Connection.SetTimeout(Timeout); } - // status requests - int Timeout(int ClientID) { return m_aSlots[ClientID].m_Connection.Timeout(); } NETADDR ClientAddr(int ClientID) const { return m_aSlots[ClientID].m_Connection.PeerAddress(); } }; diff --git a/src/engine/shared/network_console.cpp b/src/engine/shared/network_console.cpp index 3e50a1ac..0cf2a718 100644 --- a/src/engine/shared/network_console.cpp +++ b/src/engine/shared/network_console.cpp @@ -9,25 +9,24 @@ bool CNetConsole::Open(NETADDR BindAddr, int Flags) mem_zero(this, sizeof(*this)); // open socket - m_Socket = net_tcp_create(&BindAddr); + m_Socket = net_tcp_create(BindAddr); if(!m_Socket.type) return false; if(net_tcp_listen(m_Socket, NET_MAX_CONSOLE_CLIENTS)) return false; - net_tcp_set_non_blocking(m_Socket); + net_set_non_blocking(m_Socket); - for(int i = 0; i < NET_MAX_CLIENTS; i++) - m_aSlots[i].m_Connection.Init(m_Socket); + for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) + m_aSlots[i].m_Connection.Reset(); return true; } -int CNetConsole::SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser) +void CNetConsole::SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser) { m_pfnNewClient = pfnNewClient; m_pfnDelClient = pfnDelClient; m_UserPtr = pUser; - return 0; } int CNetConsole::Close() @@ -38,11 +37,6 @@ int CNetConsole::Close() int CNetConsole::Drop(int ClientID, const char *pReason) { - NETADDR Addr = ClientAddr(ClientID); - - char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr)); - if(m_pfnDelClient) m_pfnDelClient(ClientID, pReason, m_UserPtr); @@ -56,40 +50,39 @@ int CNetConsole::AcceptClient(NETSOCKET Socket, const NETADDR *pAddr) char aError[256] = { 0 }; int FreeSlot = -1; + // look for free slot or multiple client for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) { if(FreeSlot == -1 && m_aSlots[i].m_Connection.State() == NET_CONNSTATE_OFFLINE) FreeSlot = i; if(m_aSlots[i].m_Connection.State() != NET_CONNSTATE_OFFLINE) { - NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress();; + NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress(); if(net_addr_comp(pAddr, &PeerAddr) == 0) { - str_copy(aError, "Only one client per IP allowed", sizeof(aError)); + str_copy(aError, "only one client per IP allowed", sizeof(aError)); break; } } } + // accept client if(!aError[0] && FreeSlot != -1) { m_aSlots[FreeSlot].m_Connection.Init(Socket, pAddr); if(m_pfnNewClient) m_pfnNewClient(FreeSlot, m_UserPtr); - return 1; + return 0; } + // reject client if(!aError[0]) - { - str_copy(aError, "No free slot available", sizeof(aError)); - } - - dbg_msg("netconsole", "refused client, reason=\"%s\"", aError); + str_copy(aError, "no free slot available", sizeof(aError)); net_tcp_send(Socket, aError, str_length(aError)); net_tcp_close(Socket); - return 0; + return -1; } int CNetConsole::Update() @@ -127,18 +120,10 @@ int CNetConsole::Recv(char *pLine, int MaxLength, int *pClientID) return 0; } -int CNetConsole::Broadcast(const char *pLine) -{ - for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) - { - if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ONLINE) - Send(i, pLine); - } - return 0; -} - int CNetConsole::Send(int ClientID, const char *pLine) { - return m_aSlots[ClientID].m_Connection.Send(pLine); + if(m_aSlots[ClientID].m_Connection.State() == NET_CONNSTATE_ONLINE) + return m_aSlots[ClientID].m_Connection.Send(pLine); + else + return -1; } - diff --git a/src/engine/shared/network_console_conn.cpp b/src/engine/shared/network_console_conn.cpp index 4dd971a6..75b581fa 100644 --- a/src/engine/shared/network_console_conn.cpp +++ b/src/engine/shared/network_console_conn.cpp @@ -1,7 +1,6 @@ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ #include -#include "config.h" #include "network.h" void CConsoleNetConnection::Reset() @@ -10,9 +9,22 @@ void CConsoleNetConnection::Reset() mem_zero(&m_PeerAddr, sizeof(m_PeerAddr)); m_aErrorString[0] = 0; + m_Socket.type = NETTYPE_INVALID; + m_Socket.ipv4sock = -1; + m_Socket.ipv6sock = -1; m_aBuffer[0] = 0; - m_pBufferPos = 0; - m_Timeout = 0; + m_BufferOffset = 0; + + m_LineEndingDetected = false; + #if defined(CONF_FAMILY_WINDOWS) + m_aLineEnding[0] = '\r'; + m_aLineEnding[1] = '\n'; + m_aLineEnding[2] = 0; + #else + m_aLineEnding[0] = '\n'; + m_aLineEnding[1] = 0; + m_aLineEnding[2] = 0; + #endif } void CConsoleNetConnection::Init(NETSOCKET Socket, const NETADDR *pAddr) @@ -20,48 +32,19 @@ void CConsoleNetConnection::Init(NETSOCKET Socket, const NETADDR *pAddr) Reset(); m_Socket = Socket; - net_tcp_set_non_blocking(m_Socket); - - m_LastRecvTime = time_get(); + net_set_non_blocking(m_Socket); m_PeerAddr = *pAddr; m_State = NET_CONNSTATE_ONLINE; } -void CConsoleNetConnection::Init(NETSOCKET Socket) -{ - Reset(); - - m_Socket = Socket; - net_tcp_set_non_blocking(m_Socket); - - m_LastRecvTime = time_get(); -} - -int CConsoleNetConnection::Connect(const NETADDR *pAddr) -{ - if(State() != NET_CONNSTATE_OFFLINE) - return -1; - - // init connection - Reset(); - m_PeerAddr = *pAddr; - net_tcp_connect(m_Socket, pAddr); - m_State = NET_CONNSTATE_ONLINE; - return 0; -} - void CConsoleNetConnection::Disconnect(const char *pReason) { if(State() == NET_CONNSTATE_OFFLINE) return; - if(pReason) - { - char aBuf[sizeof(pReason) + 4]; - str_format(aBuf, sizeof(aBuf), "%s", pReason); - Send(aBuf); - } + if(pReason && pReason[0]) + Send(pReason); net_tcp_close(m_Socket); @@ -70,32 +53,20 @@ void CConsoleNetConnection::Disconnect(const char *pReason) int CConsoleNetConnection::Update() { - if(m_Timeout && time_get() > m_LastRecvTime + m_Timeout * time_freq()) - { - m_State = NET_CONNSTATE_ERROR; - str_copy(m_aErrorString, "timeout", sizeof(m_aErrorString)); - return -1; - } - if(State() == NET_CONNSTATE_ONLINE) { - char aBuf[NET_MAX_PACKETSIZE]; + if((int)(sizeof(m_aBuffer)) <= m_BufferOffset) + { + m_State = NET_CONNSTATE_ERROR; + str_copy(m_aErrorString, "too weak connection (out of buffer)", sizeof(m_aErrorString)); + return -1; + } - int Bytes = net_tcp_recv(m_Socket, aBuf, sizeof(aBuf) - 1); + int Bytes = net_tcp_recv(m_Socket, m_aBuffer+m_BufferOffset, (int)(sizeof(m_aBuffer))-m_BufferOffset); if(Bytes > 0) { - aBuf[Bytes - 1] = 0; - - if(!m_pBufferPos) - m_aBuffer[0] = 0; - else if(m_pBufferPos != m_aBuffer) - mem_move(m_pBufferPos, m_aBuffer, str_length(m_pBufferPos) + 1); // +1 for the \0 - m_pBufferPos = m_aBuffer; - - str_append(m_aBuffer, aBuf, sizeof(m_aBuffer)); - - m_LastRecvTime = time_get(); + m_BufferOffset += Bytes; } else if(Bytes < 0) { @@ -121,32 +92,59 @@ int CConsoleNetConnection::Recv(char *pLine, int MaxLength) { if(State() == NET_CONNSTATE_ONLINE) { - if(m_pBufferPos && *m_pBufferPos) + if(m_BufferOffset) { - char *pResult = m_pBufferPos; - - while(*m_pBufferPos && *m_pBufferPos != '\r' && *m_pBufferPos != '\n') - m_pBufferPos++; - - if(*m_pBufferPos) // haven't reached the end of the buffer? + // find message start + int StartOffset = 0; + while(m_aBuffer[StartOffset] == '\r' || m_aBuffer[StartOffset] == '\n') { - if(*m_pBufferPos == '\r' && *(m_pBufferPos + 1) == '\n') + // detect clients line ending format + if(!m_LineEndingDetected) { - *m_pBufferPos = 0; - m_pBufferPos += 2; + m_aLineEnding[0] = m_aBuffer[StartOffset]; + if(StartOffset+1 < m_BufferOffset && (m_aBuffer[StartOffset+1] == '\r' || m_aBuffer[StartOffset+1] == '\n') && + m_aBuffer[StartOffset] != m_aBuffer[StartOffset+1]) + m_aLineEnding[1] = m_aBuffer[StartOffset+1]; + m_LineEndingDetected = true; } - else + + if(++StartOffset >= m_BufferOffset) { - *m_pBufferPos = 0; - m_pBufferPos++; + m_BufferOffset = 0; + return 0; } } - else + + // find message end + int EndOffset = StartOffset; + while(m_aBuffer[EndOffset] != '\r' && m_aBuffer[EndOffset] != '\n') { - m_pBufferPos = 0; + if(++EndOffset >= m_BufferOffset) + { + if(StartOffset > 0) + { + mem_move(m_aBuffer, m_aBuffer+StartOffset, m_BufferOffset-StartOffset); + m_BufferOffset -= StartOffset; + } + return 0; + } } - str_copy(pLine, pResult, MaxLength); + // extract message and update buffer + if(MaxLength-1 < EndOffset-StartOffset) + { + if(StartOffset > 0) + { + mem_move(m_aBuffer, m_aBuffer+StartOffset, m_BufferOffset-StartOffset); + m_BufferOffset -= StartOffset; + } + return 0; + } + mem_copy(pLine, m_aBuffer+StartOffset, EndOffset-StartOffset); + pLine[EndOffset-StartOffset] = 0; + str_sanitize_cc(pLine); + mem_move(m_aBuffer, m_aBuffer+EndOffset, m_BufferOffset-EndOffset); + m_BufferOffset -= EndOffset; return 1; } } @@ -158,19 +156,31 @@ int CConsoleNetConnection::Send(const char *pLine) if(State() != NET_CONNSTATE_ONLINE) return -1; - int Length = str_length(pLine); char aBuf[1024]; - str_copy(aBuf, pLine, sizeof(aBuf) - 2); - aBuf[Length + 1] = '\n'; - aBuf[Length + 2] = '\0'; - - if(net_tcp_send(m_Socket, aBuf, Length + 2) < 0) + str_copy(aBuf, pLine, (int)(sizeof(aBuf))-2); + int Length = str_length(aBuf); + aBuf[Length] = m_aLineEnding[0]; + aBuf[Length+1] = m_aLineEnding[1]; + aBuf[Length+2] = m_aLineEnding[2]; + Length += 3; + const char *pData = aBuf; + + while(true) { - m_State = NET_CONNSTATE_ERROR; - str_copy(m_aErrorString, "Failed to send packet", sizeof(m_aErrorString)); - return -1; + int Send = net_tcp_send(m_Socket, pData, Length); + if(Send < 0) + { + m_State = NET_CONNSTATE_ERROR; + str_copy(m_aErrorString, "failed to send packet", sizeof(m_aErrorString)); + return -1; + } + + if(Send >= Length) + break; + + pData += Send; + Length -= Send; } return 0; } - diff --git a/src/game/client/components/console.cpp b/src/game/client/components/console.cpp index 9b16ce0d..f2e9e65d 100644 --- a/src/game/client/components/console.cpp +++ b/src/game/client/components/console.cpp @@ -662,6 +662,16 @@ void CGameConsole::ClientConsolePrintCallback(const char *pStr, void *pUserData) ((CGameConsole *)pUserData)->m_LocalConsole.PrintLine(pStr); } +void CGameConsole::ConchainConsoleOutputLevelUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData) +{ + pfnCallback(pResult, pCallbackUserData); + if(pResult->NumArguments() == 1) + { + CGameConsole *pThis = static_cast(pUserData); + pThis->Console()->SetPrintOutputLevel(pThis->m_PrintCBIndex, pResult->GetInteger(0)); + } +} + void CGameConsole::PrintLine(int Type, const char *pLine) { if(Type == CONSOLETYPE_LOCAL) @@ -679,7 +689,7 @@ void CGameConsole::OnConsoleInit() m_pConsole = Kernel()->RequestInterface(); // - Console()->RegisterPrintCallback(ClientConsolePrintCallback, this); + m_PrintCBIndex = Console()->RegisterPrintCallback(g_Config.m_ConsoleOutputLevel, ClientConsolePrintCallback, this); Console()->Register("toggle_local_console", "", CFGFLAG_CLIENT, ConToggleLocalConsole, this, "Toggle local console"); Console()->Register("toggle_remote_console", "", CFGFLAG_CLIENT, ConToggleRemoteConsole, this, "Toggle remote console"); @@ -687,6 +697,8 @@ void CGameConsole::OnConsoleInit() Console()->Register("clear_remote_console", "", CFGFLAG_CLIENT, ConClearRemoteConsole, this, "Clear remote console"); Console()->Register("dump_local_console", "", CFGFLAG_CLIENT, ConDumpLocalConsole, this, "Dump local console"); Console()->Register("dump_remote_console", "", CFGFLAG_CLIENT, ConDumpRemoteConsole, this, "Dump remote console"); + + Console()->Chain("console_output_level", ConchainConsoleOutputLevelUpdate, this); } void CGameConsole::OnStateChange(int NewState, int OldState) diff --git a/src/game/client/components/console.h b/src/game/client/components/console.h index 326fb076..6bcc75a6 100644 --- a/src/game/client/components/console.h +++ b/src/game/client/components/console.h @@ -60,6 +60,7 @@ class CGameConsole : public CComponent CInstance *CurrentConsole(); float TimeNow(); + int m_PrintCBIndex; int m_ConsoleType; int m_ConsoleState; @@ -77,6 +78,7 @@ class CGameConsole : public CComponent static void ConClearRemoteConsole(IConsole::IResult *pResult, void *pUserData); static void ConDumpLocalConsole(IConsole::IResult *pResult, void *pUserData); static void ConDumpRemoteConsole(IConsole::IResult *pResult, void *pUserData); + static void ConchainConsoleOutputLevelUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); public: enum -- cgit 1.4.1 From b3e8506f20ac42902e575c4522502da94bace3ed Mon Sep 17 00:00:00 2001 From: oy Date: Sat, 30 Jul 2011 13:50:22 +0200 Subject: create client on heap. Closes #744 --- src/engine/client/client.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 90131703..37fda6c2 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -2342,7 +2342,7 @@ void CClient::RegisterCommands() m_pConsole->Chain("br_filter_serveraddress", ConchainServerBrowserUpdate, this); } -static CClient m_Client; +static CClient *CreateClient() { return new CClient(); } /* Server Time @@ -2373,9 +2373,10 @@ int main(int argc, const char **argv) // ignore_convention } #endif + CClient *pClient = CreateClient(); IKernel *pKernel = IKernel::Create(); - pKernel->RegisterInterface(&m_Client); - m_Client.RegisterInterfaces(); + pKernel->RegisterInterface(pClient); + pClient->RegisterInterfaces(); // create the components IEngine *pEngine = CreateEngine("Teeworlds"); @@ -2428,12 +2429,12 @@ int main(int argc, const char **argv) // ignore_convention pEngineMasterServer->Load(); // register all console commands - m_Client.RegisterCommands(); + pClient->RegisterCommands(); pKernel->RequestInterface()->OnConsoleInit(); // init client's interfaces - m_Client.InitInterfaces(); + pClient->InitInterfaces(); // execute config file pConsole->ExecuteFile("settings.cfg"); @@ -2448,11 +2449,11 @@ int main(int argc, const char **argv) // ignore_convention // restore empty config strings to their defaults pConfig->RestoreStrings(); - m_Client.Engine()->InitLogfile(); + pClient->Engine()->InitLogfile(); // run the client dbg_msg("client", "starting..."); - m_Client.Run(); + pClient->Run(); // write down the config and quit pConfig->Save(); -- cgit 1.4.1 From 7db6d1e0567ee439e67c83a0ef670db9b419cfb6 Mon Sep 17 00:00:00 2001 From: oy Date: Sat, 30 Jul 2011 18:08:24 +0200 Subject: fixed problem with player collision. Closes #722 --- src/game/gamecore.cpp | 48 ++++++++++++++++++---------------- src/game/server/entities/character.cpp | 2 +- 2 files changed, 26 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/game/gamecore.cpp b/src/game/gamecore.cpp index d2a1652c..af086df2 100644 --- a/src/game/gamecore.cpp +++ b/src/game/gamecore.cpp @@ -362,35 +362,37 @@ void CCharacterCore::Move() m_Vel.x = m_Vel.x*RampValue; - vec2 NewPos = m_Pos; + vec2 NewPos = m_Pos; m_pCollision->MoveBox(&NewPos, &m_Vel, vec2(28.0f, 28.0f), 0); m_Vel.x = m_Vel.x*(1.0f/RampValue); if(m_pWorld && m_pWorld->m_Tuning.m_PlayerCollision) { - // check player collision - float Distance = distance(m_Pos, NewPos); - int End = Distance+1; - for(int i = 0; i < End; i++) - { - float a = i/Distance; - vec2 Pos = mix(m_Pos, NewPos, a); - for(int p = 0; p < MAX_CLIENTS; p++) - { - CCharacterCore *pCharCore = m_pWorld->m_apCharacters[p]; - if(!pCharCore || pCharCore == this) - continue; - float D = distance(Pos, pCharCore->m_Pos); - if(D < 28.0f*1.25f && D > 0.0f) - { - if(a > 0.0f) - m_Pos = Pos; - else - m_Pos = NewPos; - return; - } - } + // check player collision + float Distance = distance(m_Pos, NewPos); + int End = Distance+1; + vec2 LastPos = m_Pos; + for(int i = 0; i < End; i++) + { + float a = i/Distance; + vec2 Pos = mix(m_Pos, NewPos, a); + for(int p = 0; p < MAX_CLIENTS; p++) + { + CCharacterCore *pCharCore = m_pWorld->m_apCharacters[p]; + if(!pCharCore || pCharCore == this) + continue; + float D = distance(Pos, pCharCore->m_Pos); + if(D < 28.0f && D > 0.0f) + { + if(a > 0.0f) + m_Pos = LastPos; + else if(distance(NewPos, pCharCore->m_Pos) > D) + m_Pos = NewPos; + return; + } + } + LastPos = Pos; } } diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index 9e2033b2..e926c305 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -179,7 +179,7 @@ void CCharacter::HandleNinja() if(m_NumObjectsHit < 10) m_apHitObjects[m_NumObjectsHit++] = aEnts[i]; - aEnts[i]->TakeDamage(vec2(0, 10.0f), g_pData->m_Weapons.m_Ninja.m_pBase->m_Damage, m_pPlayer->GetCID(), WEAPON_NINJA); + aEnts[i]->TakeDamage(vec2(0, -10.0f), g_pData->m_Weapons.m_Ninja.m_pBase->m_Damage, m_pPlayer->GetCID(), WEAPON_NINJA); } } -- cgit 1.4.1 From 0f11cf014c7a53c20d4432ea26af41123f9f2436 Mon Sep 17 00:00:00 2001 From: oy Date: Sat, 30 Jul 2011 18:19:15 +0200 Subject: increased length for help string of temporary commands --- src/engine/console.h | 2 +- src/engine/server/server.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/engine/console.h b/src/engine/console.h index 5d3f2811..0abf4ad2 100644 --- a/src/engine/console.h +++ b/src/engine/console.h @@ -21,7 +21,7 @@ public: ACCESS_LEVEL_MOD, TEMPCMD_NAME_LENGTH=32, - TEMPCMD_HELP_LENGTH=64, + TEMPCMD_HELP_LENGTH=96, TEMPCMD_PARAMS_LENGTH=16, MAX_PRINT_CB=4, diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index ee7de31b..46f87840 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -655,9 +655,9 @@ void CServer::SendRconLineAuthed(const char *pLine, void *pUser) void CServer::SendRconCmdAdd(const IConsole::CCommandInfo *pCommandInfo, int ClientID) { CMsgPacker Msg(NETMSG_RCON_CMD_ADD); - Msg.AddString(pCommandInfo->m_pName, 32); - Msg.AddString(pCommandInfo->m_pHelp, 64); - Msg.AddString(pCommandInfo->m_pParams, 16); + Msg.AddString(pCommandInfo->m_pName, IConsole::TEMPCMD_NAME_LENGTH); + Msg.AddString(pCommandInfo->m_pHelp, IConsole::TEMPCMD_HELP_LENGTH); + Msg.AddString(pCommandInfo->m_pParams, IConsole::TEMPCMD_PARAMS_LENGTH); SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true); } -- cgit 1.4.1 From e2664c1b00e24158c3e9cee02ab517935be2f8c9 Mon Sep 17 00:00:00 2001 From: Johannes Loher Date: Fri, 22 Jul 2011 23:17:16 +0200 Subject: Added server sided automatic demo recording --- src/engine/client/client.cpp | 180 +-------------------------------- src/engine/client/client.h | 30 ------ src/engine/server.h | 2 + src/engine/server/server.cpp | 20 ++++ src/engine/server/server.h | 2 + src/engine/shared/config_variables.h | 2 + src/engine/shared/filecollection.cpp | 186 +++++++++++++++++++++++++++++++++++ src/engine/shared/filecollection.h | 35 +++++++ src/game/server/gamecontroller.cpp | 1 + 9 files changed, 249 insertions(+), 209 deletions(-) create mode 100644 src/engine/shared/filecollection.cpp create mode 100644 src/engine/shared/filecollection.h (limited to 'src') diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 37fda6c2..5029fe1e 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -231,185 +232,6 @@ void CSmoothTime::Update(CGraph *pGraph, int64 Target, int TimeLeft, int AdjustD } -bool CFileCollection::IsFilenameValid(const char *pFilename) -{ - if(str_length(pFilename) != m_FileDescLength+TIMESTAMP_LENGTH+m_FileExtLength || - str_comp_num(pFilename, m_aFileDesc, m_FileDescLength) || - str_comp(pFilename+m_FileDescLength+TIMESTAMP_LENGTH, m_aFileExt)) - return false; - - pFilename += m_FileDescLength; - if(pFilename[0] == '_' && - pFilename[1] >= '0' && pFilename[1] <= '9' && - pFilename[2] >= '0' && pFilename[2] <= '9' && - pFilename[3] >= '0' && pFilename[3] <= '9' && - pFilename[4] >= '0' && pFilename[4] <= '9' && - pFilename[5] == '-' && - pFilename[6] >= '0' && pFilename[6] <= '9' && - pFilename[7] >= '0' && pFilename[7] <= '9' && - pFilename[8] == '-' && - pFilename[9] >= '0' && pFilename[9] <= '9' && - pFilename[10] >= '0' && pFilename[10] <= '9' && - pFilename[11] == '_' && - pFilename[12] >= '0' && pFilename[12] <= '9' && - pFilename[13] >= '0' && pFilename[13] <= '9' && - pFilename[14] == '-' && - pFilename[15] >= '0' && pFilename[15] <= '9' && - pFilename[16] >= '0' && pFilename[16] <= '9' && - pFilename[17] == '-' && - pFilename[18] >= '0' && pFilename[18] <= '9' && - pFilename[19] >= '0' && pFilename[19] <= '9') - return true; - - return false; -} - -int64 CFileCollection::ExtractTimestamp(const char *pTimestring) -{ - int64 Timestamp = pTimestring[0]-'0'; Timestamp <<= 4; - Timestamp += pTimestring[1]-'0'; Timestamp <<= 4; - Timestamp += pTimestring[2]-'0'; Timestamp <<= 4; - Timestamp += pTimestring[3]-'0'; Timestamp <<= 4; - Timestamp += pTimestring[5]-'0'; Timestamp <<= 4; - Timestamp += pTimestring[6]-'0'; Timestamp <<= 4; - Timestamp += pTimestring[8]-'0'; Timestamp <<= 4; - Timestamp += pTimestring[9]-'0'; Timestamp <<= 4; - Timestamp += pTimestring[11]-'0'; Timestamp <<= 4; - Timestamp += pTimestring[12]-'0'; Timestamp <<= 4; - Timestamp += pTimestring[14]-'0'; Timestamp <<= 4; - Timestamp += pTimestring[15]-'0'; Timestamp <<= 4; - Timestamp += pTimestring[17]-'0'; Timestamp <<= 4; - Timestamp += pTimestring[18]-'0'; - - return Timestamp; -} - -void CFileCollection::BuildTimestring(int64 Timestamp, char *pTimestring) -{ - pTimestring[19] = 0; - pTimestring[18] = (Timestamp&0xF)+'0'; Timestamp >>= 4; - pTimestring[17] = (Timestamp&0xF)+'0'; Timestamp >>= 4; - pTimestring[16] = '-'; - pTimestring[15] = (Timestamp&0xF)+'0'; Timestamp >>= 4; - pTimestring[14] = (Timestamp&0xF)+'0'; Timestamp >>= 4; - pTimestring[13] = '-'; - pTimestring[12] = (Timestamp&0xF)+'0'; Timestamp >>= 4; - pTimestring[11] = (Timestamp&0xF)+'0'; Timestamp >>= 4; - pTimestring[10] = '_'; - pTimestring[9] = (Timestamp&0xF)+'0'; Timestamp >>= 4; - pTimestring[8] = (Timestamp&0xF)+'0'; Timestamp >>= 4; - pTimestring[7] = '-'; - pTimestring[6] = (Timestamp&0xF)+'0'; Timestamp >>= 4; - pTimestring[5] = (Timestamp&0xF)+'0'; Timestamp >>= 4; - pTimestring[4] = '-'; - pTimestring[3] = (Timestamp&0xF)+'0'; Timestamp >>= 4; - pTimestring[2] = (Timestamp&0xF)+'0'; Timestamp >>= 4; - pTimestring[1] = (Timestamp&0xF)+'0'; Timestamp >>= 4; - pTimestring[0] = (Timestamp&0xF)+'0'; -} - -void CFileCollection::Init(IStorage *pStorage, const char *pPath, const char *pFileDesc, const char *pFileExt, int MaxEntries) -{ - mem_zero(m_aTimestamps, sizeof(m_aTimestamps)); - m_NumTimestamps = 0; - m_MaxEntries = clamp(MaxEntries, 1, static_cast(MAX_ENTRIES)); - str_copy(m_aFileDesc, pFileDesc, sizeof(m_aFileDesc)); - m_FileDescLength = str_length(m_aFileDesc); - str_copy(m_aFileExt, pFileExt, sizeof(m_aFileExt)); - m_FileExtLength = str_length(m_aFileExt); - str_copy(m_aPath, pPath, sizeof(m_aPath)); - m_pStorage = pStorage; - - m_pStorage->ListDirectory(IStorage::TYPE_SAVE, m_aPath, FilelistCallback, this); -} - -void CFileCollection::AddEntry(int64 Timestamp) -{ - if(m_NumTimestamps == 0) - { - // empty list - m_aTimestamps[m_NumTimestamps++] = Timestamp; - } - else - { - // remove old file - if(m_NumTimestamps == m_MaxEntries) - { - char aBuf[512]; - char aTimestring[TIMESTAMP_LENGTH]; - BuildTimestring(m_aTimestamps[0], aTimestring); - str_format(aBuf, sizeof(aBuf), "%s/%s_%s%s", m_aPath, m_aFileDesc, aTimestring, m_aFileExt); - m_pStorage->RemoveFile(aBuf, IStorage::TYPE_SAVE); - } - - // add entry to the sorted list - if(m_aTimestamps[0] > Timestamp) - { - // first entry - if(m_NumTimestamps < m_MaxEntries) - { - mem_move(m_aTimestamps+1, m_aTimestamps, m_NumTimestamps*sizeof(int64)); - m_aTimestamps[0] = Timestamp; - ++m_NumTimestamps; - } - } - else if(m_aTimestamps[m_NumTimestamps-1] <= Timestamp) - { - // last entry - if(m_NumTimestamps == m_MaxEntries) - { - mem_move(m_aTimestamps, m_aTimestamps+1, (m_NumTimestamps-1)*sizeof(int64)); - m_aTimestamps[m_NumTimestamps-1] = Timestamp; - } - else - m_aTimestamps[m_NumTimestamps++] = Timestamp; - } - else - { - // middle entry - int Left = 0, Right = m_NumTimestamps-1; - while(Right-Left > 1) - { - int Mid = (Left+Right)/2; - if(m_aTimestamps[Mid] > Timestamp) - Right = Mid; - else - Left = Mid; - } - - if(m_NumTimestamps == m_MaxEntries) - { - mem_move(m_aTimestamps, m_aTimestamps+1, (Right-1)*sizeof(int64)); - m_aTimestamps[Right-1] = Timestamp; - } - else - { - mem_move(m_aTimestamps+Right+1, m_aTimestamps+Right, (m_NumTimestamps-Right)*sizeof(int64)); - m_aTimestamps[Right] = Timestamp; - ++m_NumTimestamps; - } - } - } -} - -int CFileCollection::FilelistCallback(const char *pFilename, int IsDir, int StorageType, void *pUser) -{ - CFileCollection *pThis = static_cast(pUser); - - // check for valid file name format - if(IsDir || !pThis->IsFilenameValid(pFilename)) - return 0; - - // extract the timestamp - int64 Timestamp = pThis->ExtractTimestamp(pFilename+pThis->m_FileDescLength+1); - - // add the entry - pThis->AddEntry(Timestamp); - - return 0; -} - - CClient::CClient() : m_DemoPlayer(&m_SnapshotDelta), m_DemoRecorder(&m_SnapshotDelta) { m_pEditor = 0; diff --git a/src/engine/client/client.h b/src/engine/client/client.h index 3d81f073..1504a4e4 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -51,36 +51,6 @@ public: }; -class CFileCollection -{ - enum - { - MAX_ENTRIES=1000, - TIMESTAMP_LENGTH=20, // _YYYY-MM-DD_HH-MM-SS - }; - - int64 m_aTimestamps[MAX_ENTRIES]; - int m_NumTimestamps; - int m_MaxEntries; - char m_aFileDesc[128]; - int m_FileDescLength; - char m_aFileExt[32]; - int m_FileExtLength; - char m_aPath[512]; - IStorage *m_pStorage; - - bool IsFilenameValid(const char *pFilename); - int64 ExtractTimestamp(const char *pTimestring); - void BuildTimestring(int64 Timestamp, char *pTimestring); - -public: - void Init(IStorage *pStorage, const char *pPath, const char *pFileDesc, const char *pFileExt, int MaxEntries); - void AddEntry(int64 Timestamp); - - static int FilelistCallback(const char *pFilename, int IsDir, int StorageType, void *pUser); -}; - - class CClient : public IClient, public CDemoPlayer::IListner { // needed interfaces diff --git a/src/engine/server.h b/src/engine/server.h index 28a97ecc..31134ca9 100644 --- a/src/engine/server.h +++ b/src/engine/server.h @@ -56,6 +56,8 @@ public: virtual bool IsAuthed(int ClientID) = 0; virtual void Kick(int ClientID, const char *pReason) = 0; + + virtual void DemoRecorder_HandleAutoStart() = 0; }; class IGameServer : public IInterface diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 46f87840..57be060b 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -1519,6 +1520,25 @@ void CServer::ConShutdown(IConsole::IResult *pResult, void *pUser) ((CServer *)pUser)->m_RunServer = 0; } +void CServer::DemoRecorder_HandleAutoStart() +{ + if(g_Config.m_SvAutoDemoRecord) + { + m_DemoRecorder.Stop(); + char aFilename[128]; + char aDate[20]; + str_timestamp(aDate, sizeof(aDate)); + str_format(aFilename, sizeof(aFilename), "demos/%s_%s.demo", "auto/autorecord", aDate); + m_DemoRecorder.Start(Storage(), m_pConsole, aFilename, GameServer()->NetVersion(), m_aCurrentMap, m_CurrentMapCrc, "server"); + if(g_Config.m_SvAutoDemoMax) + { + // clean up auto recorded demos + CFileCollection AutoDemos; + AutoDemos.Init(Storage(), "demos/server", "autorecord", ".demo", g_Config.m_SvAutoDemoMax); + } + } +} + void CServer::ConRecord(IConsole::IResult *pResult, void *pUser) { CServer* pServer = (CServer *)pUser; diff --git a/src/engine/server/server.h b/src/engine/server/server.h index 4e575055..d8fdd8fa 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -148,6 +148,8 @@ public: void Kick(int ClientID, const char *pReason); + void DemoRecorder_HandleAutoStart(); + //int Tick() int64 TickStartTime(int Tick); //int TickSpeed() diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index cb8f5f15..0789476e 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -86,6 +86,8 @@ MACRO_CONFIG_STR(SvRconPassword, sv_rcon_password, 32, "", CFGFLAG_SERVER, "Remo MACRO_CONFIG_STR(SvRconModPassword, sv_rcon_mod_password, 32, "", CFGFLAG_SERVER, "Remote console password for moderators (limited access)") MACRO_CONFIG_INT(SvRconMaxTries, sv_rcon_max_tries, 3, 0, 100, CFGFLAG_SERVER, "Maximum number of tries for remote console authentication") MACRO_CONFIG_INT(SvRconBantime, sv_rcon_bantime, 5, 0, 1440, CFGFLAG_SERVER, "The time a client gets banned if remote console authentication fails. 0 makes it just use kick") +MACRO_CONFIG_INT(SvAutoDemoRecord, sv_auto_demo_record, 0, 0, 1, CFGFLAG_SERVER, "Automatically record demos") +MACRO_CONFIG_INT(SvAutoDemoMax, sv_auto_demo_max, 10, 0, 1000, CFGFLAG_SERVER, "Maximum number of automatically recorded demos (0 = no limit)") MACRO_CONFIG_STR(EcBindaddr, ec_bindaddr, 128, "localhost", CFGFLAG_SERVER, "Address to bind the external console to. Anything but 'localhost' is dangerous") MACRO_CONFIG_INT(EcPort, ec_port, 0, 0, 0, CFGFLAG_SERVER, "Port to use for the external console") diff --git a/src/engine/shared/filecollection.cpp b/src/engine/shared/filecollection.cpp new file mode 100644 index 00000000..c7db92a6 --- /dev/null +++ b/src/engine/shared/filecollection.cpp @@ -0,0 +1,186 @@ +/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ +/* If you are missing that file, acquire a complete release at teeworlds.com. */ + +#include + +#include + +#include "filecollection.h" + +bool CFileCollection::IsFilenameValid(const char *pFilename) +{ + if(str_length(pFilename) != m_FileDescLength+TIMESTAMP_LENGTH+m_FileExtLength || + str_comp_num(pFilename, m_aFileDesc, m_FileDescLength) || + str_comp(pFilename+m_FileDescLength+TIMESTAMP_LENGTH, m_aFileExt)) + return false; + + pFilename += m_FileDescLength; + if(pFilename[0] == '_' && + pFilename[1] >= '0' && pFilename[1] <= '9' && + pFilename[2] >= '0' && pFilename[2] <= '9' && + pFilename[3] >= '0' && pFilename[3] <= '9' && + pFilename[4] >= '0' && pFilename[4] <= '9' && + pFilename[5] == '-' && + pFilename[6] >= '0' && pFilename[6] <= '9' && + pFilename[7] >= '0' && pFilename[7] <= '9' && + pFilename[8] == '-' && + pFilename[9] >= '0' && pFilename[9] <= '9' && + pFilename[10] >= '0' && pFilename[10] <= '9' && + pFilename[11] == '_' && + pFilename[12] >= '0' && pFilename[12] <= '9' && + pFilename[13] >= '0' && pFilename[13] <= '9' && + pFilename[14] == '-' && + pFilename[15] >= '0' && pFilename[15] <= '9' && + pFilename[16] >= '0' && pFilename[16] <= '9' && + pFilename[17] == '-' && + pFilename[18] >= '0' && pFilename[18] <= '9' && + pFilename[19] >= '0' && pFilename[19] <= '9') + return true; + + return false; +} + +int64 CFileCollection::ExtractTimestamp(const char *pTimestring) +{ + int64 Timestamp = pTimestring[0]-'0'; Timestamp <<= 4; + Timestamp += pTimestring[1]-'0'; Timestamp <<= 4; + Timestamp += pTimestring[2]-'0'; Timestamp <<= 4; + Timestamp += pTimestring[3]-'0'; Timestamp <<= 4; + Timestamp += pTimestring[5]-'0'; Timestamp <<= 4; + Timestamp += pTimestring[6]-'0'; Timestamp <<= 4; + Timestamp += pTimestring[8]-'0'; Timestamp <<= 4; + Timestamp += pTimestring[9]-'0'; Timestamp <<= 4; + Timestamp += pTimestring[11]-'0'; Timestamp <<= 4; + Timestamp += pTimestring[12]-'0'; Timestamp <<= 4; + Timestamp += pTimestring[14]-'0'; Timestamp <<= 4; + Timestamp += pTimestring[15]-'0'; Timestamp <<= 4; + Timestamp += pTimestring[17]-'0'; Timestamp <<= 4; + Timestamp += pTimestring[18]-'0'; + + return Timestamp; +} + +void CFileCollection::BuildTimestring(int64 Timestamp, char *pTimestring) +{ + pTimestring[19] = 0; + pTimestring[18] = (Timestamp&0xF)+'0'; Timestamp >>= 4; + pTimestring[17] = (Timestamp&0xF)+'0'; Timestamp >>= 4; + pTimestring[16] = '-'; + pTimestring[15] = (Timestamp&0xF)+'0'; Timestamp >>= 4; + pTimestring[14] = (Timestamp&0xF)+'0'; Timestamp >>= 4; + pTimestring[13] = '-'; + pTimestring[12] = (Timestamp&0xF)+'0'; Timestamp >>= 4; + pTimestring[11] = (Timestamp&0xF)+'0'; Timestamp >>= 4; + pTimestring[10] = '_'; + pTimestring[9] = (Timestamp&0xF)+'0'; Timestamp >>= 4; + pTimestring[8] = (Timestamp&0xF)+'0'; Timestamp >>= 4; + pTimestring[7] = '-'; + pTimestring[6] = (Timestamp&0xF)+'0'; Timestamp >>= 4; + pTimestring[5] = (Timestamp&0xF)+'0'; Timestamp >>= 4; + pTimestring[4] = '-'; + pTimestring[3] = (Timestamp&0xF)+'0'; Timestamp >>= 4; + pTimestring[2] = (Timestamp&0xF)+'0'; Timestamp >>= 4; + pTimestring[1] = (Timestamp&0xF)+'0'; Timestamp >>= 4; + pTimestring[0] = (Timestamp&0xF)+'0'; +} + +void CFileCollection::Init(IStorage *pStorage, const char *pPath, const char *pFileDesc, const char *pFileExt, int MaxEntries) +{ + mem_zero(m_aTimestamps, sizeof(m_aTimestamps)); + m_NumTimestamps = 0; + m_MaxEntries = clamp(MaxEntries, 1, static_cast(MAX_ENTRIES)); + str_copy(m_aFileDesc, pFileDesc, sizeof(m_aFileDesc)); + m_FileDescLength = str_length(m_aFileDesc); + str_copy(m_aFileExt, pFileExt, sizeof(m_aFileExt)); + m_FileExtLength = str_length(m_aFileExt); + str_copy(m_aPath, pPath, sizeof(m_aPath)); + m_pStorage = pStorage; + + m_pStorage->ListDirectory(IStorage::TYPE_SAVE, m_aPath, FilelistCallback, this); +} + +void CFileCollection::AddEntry(int64 Timestamp) +{ + if(m_NumTimestamps == 0) + { + // empty list + m_aTimestamps[m_NumTimestamps++] = Timestamp; + } + else + { + // remove old file + if(m_NumTimestamps == m_MaxEntries) + { + char aBuf[512]; + char aTimestring[TIMESTAMP_LENGTH]; + BuildTimestring(m_aTimestamps[0], aTimestring); + str_format(aBuf, sizeof(aBuf), "%s/%s_%s%s", m_aPath, m_aFileDesc, aTimestring, m_aFileExt); + m_pStorage->RemoveFile(aBuf, IStorage::TYPE_SAVE); + } + + // add entry to the sorted list + if(m_aTimestamps[0] > Timestamp) + { + // first entry + if(m_NumTimestamps < m_MaxEntries) + { + mem_move(m_aTimestamps+1, m_aTimestamps, m_NumTimestamps*sizeof(int64)); + m_aTimestamps[0] = Timestamp; + ++m_NumTimestamps; + } + } + else if(m_aTimestamps[m_NumTimestamps-1] <= Timestamp) + { + // last entry + if(m_NumTimestamps == m_MaxEntries) + { + mem_move(m_aTimestamps, m_aTimestamps+1, (m_NumTimestamps-1)*sizeof(int64)); + m_aTimestamps[m_NumTimestamps-1] = Timestamp; + } + else + m_aTimestamps[m_NumTimestamps++] = Timestamp; + } + else + { + // middle entry + int Left = 0, Right = m_NumTimestamps-1; + while(Right-Left > 1) + { + int Mid = (Left+Right)/2; + if(m_aTimestamps[Mid] > Timestamp) + Right = Mid; + else + Left = Mid; + } + + if(m_NumTimestamps == m_MaxEntries) + { + mem_move(m_aTimestamps, m_aTimestamps+1, (Right-1)*sizeof(int64)); + m_aTimestamps[Right-1] = Timestamp; + } + else + { + mem_move(m_aTimestamps+Right+1, m_aTimestamps+Right, (m_NumTimestamps-Right)*sizeof(int64)); + m_aTimestamps[Right] = Timestamp; + ++m_NumTimestamps; + } + } + } +} + +int CFileCollection::FilelistCallback(const char *pFilename, int IsDir, int StorageType, void *pUser) +{ + CFileCollection *pThis = static_cast(pUser); + + // check for valid file name format + if(IsDir || !pThis->IsFilenameValid(pFilename)) + return 0; + + // extract the timestamp + int64 Timestamp = pThis->ExtractTimestamp(pFilename+pThis->m_FileDescLength+1); + + // add the entry + pThis->AddEntry(Timestamp); + + return 0; +} \ No newline at end of file diff --git a/src/engine/shared/filecollection.h b/src/engine/shared/filecollection.h new file mode 100644 index 00000000..c7548a8b --- /dev/null +++ b/src/engine/shared/filecollection.h @@ -0,0 +1,35 @@ +/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ +/* If you are missing that file, acquire a complete release at teeworlds.com. */ +#ifndef ENGINE_SHARED_FILECOLLECTION_H +#define ENGINE_SHARED_FILECOLLECTION_H + +class CFileCollection +{ + enum + { + MAX_ENTRIES=1000, + TIMESTAMP_LENGTH=20, // _YYYY-MM-DD_HH-MM-SS + }; + + int64 m_aTimestamps[MAX_ENTRIES]; + int m_NumTimestamps; + int m_MaxEntries; + char m_aFileDesc[128]; + int m_FileDescLength; + char m_aFileExt[32]; + int m_FileExtLength; + char m_aPath[512]; + IStorage *m_pStorage; + + bool IsFilenameValid(const char *pFilename); + int64 ExtractTimestamp(const char *pTimestring); + void BuildTimestring(int64 Timestamp, char *pTimestring); + +public: + void Init(IStorage *pStorage, const char *pPath, const char *pFileDesc, const char *pFileExt, int MaxEntries); + void AddEntry(int64 Timestamp); + + static int FilelistCallback(const char *pFilename, int IsDir, int StorageType, void *pUser); +}; + +#endif \ No newline at end of file diff --git a/src/game/server/gamecontroller.cpp b/src/game/server/gamecontroller.cpp index fd574d85..f8d418c3 100644 --- a/src/game/server/gamecontroller.cpp +++ b/src/game/server/gamecontroller.cpp @@ -217,6 +217,7 @@ void IGameController::StartRound() m_aTeamscore[TEAM_RED] = 0; m_aTeamscore[TEAM_BLUE] = 0; m_ForceBalanced = false; + Server()->DemoRecorder_HandleAutoStart(); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "start round type='%s' teamplay='%d'", m_pGameType, m_GameFlags&GAMEFLAG_TEAMS); GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf); -- cgit 1.4.1 From 94bdd95957af0f66da06275df2bcd041a75a3014 Mon Sep 17 00:00:00 2001 From: oy Date: Sat, 30 Jul 2011 18:29:40 +0200 Subject: added missing newlines at end of 2 files --- src/engine/client/client.cpp | 2 +- src/engine/server/server.cpp | 3 +-- src/engine/shared/filecollection.cpp | 2 +- src/engine/shared/filecollection.h | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 5029fe1e..3d1a5a23 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -26,13 +26,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include #include diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 57be060b..55208caa 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -1,7 +1,6 @@ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ -#include #include #include @@ -17,12 +16,12 @@ #include #include #include +#include #include #include #include #include #include -#include #include diff --git a/src/engine/shared/filecollection.cpp b/src/engine/shared/filecollection.cpp index c7db92a6..622534f2 100644 --- a/src/engine/shared/filecollection.cpp +++ b/src/engine/shared/filecollection.cpp @@ -183,4 +183,4 @@ int CFileCollection::FilelistCallback(const char *pFilename, int IsDir, int Stor pThis->AddEntry(Timestamp); return 0; -} \ No newline at end of file +} diff --git a/src/engine/shared/filecollection.h b/src/engine/shared/filecollection.h index c7548a8b..ac633892 100644 --- a/src/engine/shared/filecollection.h +++ b/src/engine/shared/filecollection.h @@ -32,4 +32,4 @@ public: static int FilelistCallback(const char *pFilename, int IsDir, int StorageType, void *pUser); }; -#endif \ No newline at end of file +#endif -- cgit 1.4.1 From 34132ce2443f286fdfd36220fcd2ed53199e9199 Mon Sep 17 00:00:00 2001 From: oy Date: Sun, 31 Jul 2011 01:38:45 +0200 Subject: fixed client crash in debug --- src/engine/client/friends.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/engine/client/friends.cpp b/src/engine/client/friends.cpp index 99f82b50..eca39edb 100644 --- a/src/engine/client/friends.cpp +++ b/src/engine/client/friends.cpp @@ -12,6 +12,7 @@ CFriends::CFriends() { mem_zero(m_aFriends, sizeof(m_aFriends)); + m_NumFriends = 0; } void CFriends::ConAddFriend(IConsole::IResult *pResult, void *pUserData) -- cgit 1.4.1 From 8d0cc2a825b39b58d9a9dc3d884159fb9255fea2 Mon Sep 17 00:00:00 2001 From: oy Date: Sun, 31 Jul 2011 01:40:28 +0200 Subject: reduced stack memory usage of CDataFileWriter --- src/engine/shared/datafile.cpp | 113 ++++++++++++++++++++++++----------------- src/engine/shared/datafile.h | 16 ++++-- 2 files changed, 78 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/engine/shared/datafile.cpp b/src/engine/shared/datafile.cpp index 00410038..e2215635 100644 --- a/src/engine/shared/datafile.cpp +++ b/src/engine/shared/datafile.cpp @@ -422,6 +422,25 @@ unsigned CDataFileReader::Crc() return m_pDataFile->m_Crc; } + +CDataFileWriter::CDataFileWriter() +{ + m_File = 0; + m_pItemTypes = static_cast(mem_alloc(sizeof(CItemTypeInfo) * MAX_ITEM_TYPES, 1)); + m_pItems = static_cast(mem_alloc(sizeof(CItemInfo) * MAX_ITEMS, 1)); + m_pDatas = static_cast(mem_alloc(sizeof(CDataInfo) * MAX_DATAS, 1)); +} + +CDataFileWriter::~CDataFileWriter() +{ + mem_free(m_pItemTypes); + m_pItemTypes = 0; + mem_free(m_pItems); + m_pItems = 0; + mem_free(m_pDatas); + m_pDatas = 0; +} + bool CDataFileWriter::Open(class IStorage *pStorage, const char *pFilename) { dbg_assert(!m_File, "a file already exists"); @@ -432,12 +451,12 @@ bool CDataFileWriter::Open(class IStorage *pStorage, const char *pFilename) m_NumItems = 0; m_NumDatas = 0; m_NumItemTypes = 0; - mem_zero(&m_aItemTypes, sizeof(m_aItemTypes)); + mem_zero(m_pItemTypes, sizeof(CItemTypeInfo) * MAX_ITEM_TYPES); - for(int i = 0; i < 0xffff; i++) + for(int i = 0; i < MAX_ITEM_TYPES; i++) { - m_aItemTypes[i].m_First = -1; - m_aItemTypes[i].m_Last = -1; + m_pItemTypes[i].m_First = -1; + m_pItemTypes[i].m_Last = -1; } return true; @@ -451,29 +470,29 @@ int CDataFileWriter::AddItem(int Type, int ID, int Size, void *pData) dbg_assert(m_NumItems < 1024, "too many items"); dbg_assert(Size%sizeof(int) == 0, "incorrect boundary"); - m_aItems[m_NumItems].m_Type = Type; - m_aItems[m_NumItems].m_ID = ID; - m_aItems[m_NumItems].m_Size = Size; + m_pItems[m_NumItems].m_Type = Type; + m_pItems[m_NumItems].m_ID = ID; + m_pItems[m_NumItems].m_Size = Size; // copy data - m_aItems[m_NumItems].m_pData = mem_alloc(Size, 1); - mem_copy(m_aItems[m_NumItems].m_pData, pData, Size); + m_pItems[m_NumItems].m_pData = mem_alloc(Size, 1); + mem_copy(m_pItems[m_NumItems].m_pData, pData, Size); - if(!m_aItemTypes[Type].m_Num) // count item types + if(!m_pItemTypes[Type].m_Num) // count item types m_NumItemTypes++; // link - m_aItems[m_NumItems].m_Prev = m_aItemTypes[Type].m_Last; - m_aItems[m_NumItems].m_Next = -1; + m_pItems[m_NumItems].m_Prev = m_pItemTypes[Type].m_Last; + m_pItems[m_NumItems].m_Next = -1; - if(m_aItemTypes[Type].m_Last != -1) - m_aItems[m_aItemTypes[Type].m_Last].m_Next = m_NumItems; - m_aItemTypes[Type].m_Last = m_NumItems; + if(m_pItemTypes[Type].m_Last != -1) + m_pItems[m_pItemTypes[Type].m_Last].m_Next = m_NumItems; + m_pItemTypes[Type].m_Last = m_NumItems; - if(m_aItemTypes[Type].m_First == -1) - m_aItemTypes[Type].m_First = m_NumItems; + if(m_pItemTypes[Type].m_First == -1) + m_pItemTypes[Type].m_First = m_NumItems; - m_aItemTypes[Type].m_Num++; + m_pItemTypes[Type].m_Num++; m_NumItems++; return m_NumItems-1; @@ -485,7 +504,7 @@ int CDataFileWriter::AddData(int Size, void *pData) dbg_assert(m_NumDatas < 1024, "too much data"); - CDataInfo *pInfo = &m_aDatas[m_NumDatas]; + CDataInfo *pInfo = &m_pDatas[m_NumDatas]; unsigned long s = compressBound(Size); void *pCompData = mem_alloc(s, 1); // temporary buffer that we use during compression @@ -540,13 +559,13 @@ int CDataFileWriter::Finish() for(int i = 0; i < m_NumItems; i++) { if(DEBUG) - dbg_msg("datafile", "item=%d size=%d (%d)", i, m_aItems[i].m_Size, m_aItems[i].m_Size+sizeof(CDatafileItem)); - ItemSize += m_aItems[i].m_Size + sizeof(CDatafileItem); + dbg_msg("datafile", "item=%d size=%d (%d)", i, m_pItems[i].m_Size, m_pItems[i].m_Size+sizeof(CDatafileItem)); + ItemSize += m_pItems[i].m_Size + sizeof(CDatafileItem); } for(int i = 0; i < m_NumDatas; i++) - DataSize += m_aDatas[i].m_CompressedSize; + DataSize += m_pDatas[i].m_CompressedSize; // calculate the complete size TypesSize = m_NumItemTypes*sizeof(CDatafileItemType); @@ -587,30 +606,30 @@ int CDataFileWriter::Finish() // write types for(int i = 0, Count = 0; i < 0xffff; i++) { - if(m_aItemTypes[i].m_Num) + if(m_pItemTypes[i].m_Num) { // write info CDatafileItemType Info; Info.m_Type = i; Info.m_Start = Count; - Info.m_Num = m_aItemTypes[i].m_Num; + Info.m_Num = m_pItemTypes[i].m_Num; if(DEBUG) dbg_msg("datafile", "writing type=%x start=%d num=%d", Info.m_Type, Info.m_Start, Info.m_Num); #if defined(CONF_ARCH_ENDIAN_BIG) swap_endian(&Info, sizeof(int), sizeof(CDatafileItemType)/sizeof(int)); #endif io_write(m_File, &Info, sizeof(Info)); - Count += m_aItemTypes[i].m_Num; + Count += m_pItemTypes[i].m_Num; } } // write item offsets for(int i = 0, Offset = 0; i < 0xffff; i++) { - if(m_aItemTypes[i].m_Num) + if(m_pItemTypes[i].m_Num) { - // write all m_aItems in of this type - int k = m_aItemTypes[i].m_First; + // write all m_pItems in of this type + int k = m_pItemTypes[i].m_First; while(k != -1) { if(DEBUG) @@ -620,10 +639,10 @@ int CDataFileWriter::Finish() swap_endian(&Temp, sizeof(int), sizeof(Temp)/sizeof(int)); #endif io_write(m_File, &Temp, sizeof(Temp)); - Offset += m_aItems[k].m_Size + sizeof(CDatafileItem); + Offset += m_pItems[k].m_Size + sizeof(CDatafileItem); // next - k = m_aItems[k].m_Next; + k = m_pItems[k].m_Next; } } } @@ -638,45 +657,45 @@ int CDataFileWriter::Finish() swap_endian(&Temp, sizeof(int), sizeof(Temp)/sizeof(int)); #endif io_write(m_File, &Temp, sizeof(Temp)); - Offset += m_aDatas[i].m_CompressedSize; + Offset += m_pDatas[i].m_CompressedSize; } // write data uncompressed sizes for(int i = 0; i < m_NumDatas; i++) { if(DEBUG) - dbg_msg("datafile", "writing data uncompressed size num=%d size=%d", i, m_aDatas[i].m_UncompressedSize); - int UncompressedSize = m_aDatas[i].m_UncompressedSize; + dbg_msg("datafile", "writing data uncompressed size num=%d size=%d", i, m_pDatas[i].m_UncompressedSize); + int UncompressedSize = m_pDatas[i].m_UncompressedSize; #if defined(CONF_ARCH_ENDIAN_BIG) swap_endian(&UncompressedSize, sizeof(int), sizeof(UncompressedSize)/sizeof(int)); #endif io_write(m_File, &UncompressedSize, sizeof(UncompressedSize)); } - // write m_aItems + // write m_pItems for(int i = 0; i < 0xffff; i++) { - if(m_aItemTypes[i].m_Num) + if(m_pItemTypes[i].m_Num) { - // write all m_aItems in of this type - int k = m_aItemTypes[i].m_First; + // write all m_pItems in of this type + int k = m_pItemTypes[i].m_First; while(k != -1) { CDatafileItem Item; - Item.m_TypeAndID = (i<<16)|m_aItems[k].m_ID; - Item.m_Size = m_aItems[k].m_Size; + Item.m_TypeAndID = (i<<16)|m_pItems[k].m_ID; + Item.m_Size = m_pItems[k].m_Size; if(DEBUG) - dbg_msg("datafile", "writing item type=%x idx=%d id=%d size=%d", i, k, m_aItems[k].m_ID, m_aItems[k].m_Size); + dbg_msg("datafile", "writing item type=%x idx=%d id=%d size=%d", i, k, m_pItems[k].m_ID, m_pItems[k].m_Size); #if defined(CONF_ARCH_ENDIAN_BIG) swap_endian(&Item, sizeof(int), sizeof(Item)/sizeof(int)); - swap_endian(m_aItems[k].m_pData, sizeof(int), m_aItems[k].m_Size/sizeof(int)); + swap_endian(m_pItems[k].m_pData, sizeof(int), m_pItems[k].m_Size/sizeof(int)); #endif io_write(m_File, &Item, sizeof(Item)); - io_write(m_File, m_aItems[k].m_pData, m_aItems[k].m_Size); + io_write(m_File, m_pItems[k].m_pData, m_pItems[k].m_Size); // next - k = m_aItems[k].m_Next; + k = m_pItems[k].m_Next; } } } @@ -685,15 +704,15 @@ int CDataFileWriter::Finish() for(int i = 0; i < m_NumDatas; i++) { if(DEBUG) - dbg_msg("datafile", "writing data id=%d size=%d", i, m_aDatas[i].m_CompressedSize); - io_write(m_File, m_aDatas[i].m_pCompressedData, m_aDatas[i].m_CompressedSize); + dbg_msg("datafile", "writing data id=%d size=%d", i, m_pDatas[i].m_CompressedSize); + io_write(m_File, m_pDatas[i].m_pCompressedData, m_pDatas[i].m_CompressedSize); } // free data for(int i = 0; i < m_NumItems; i++) - mem_free(m_aItems[i].m_pData); + mem_free(m_pItems[i].m_pData); for(int i = 0; i < m_NumDatas; ++i) - mem_free(m_aDatas[i].m_pCompressedData); + mem_free(m_pDatas[i].m_pCompressedData); io_close(m_File); m_File = 0; diff --git a/src/engine/shared/datafile.h b/src/engine/shared/datafile.h index 9f27f968..cafce20e 100644 --- a/src/engine/shared/datafile.h +++ b/src/engine/shared/datafile.h @@ -61,16 +61,24 @@ class CDataFileWriter int m_Last; }; + enum + { + MAX_ITEM_TYPES=0xffff, + MAX_ITEMS=1024, + MAX_DATAS=1024, + }; + IOHANDLE m_File; int m_NumItems; int m_NumDatas; int m_NumItemTypes; - CItemTypeInfo m_aItemTypes[0xffff]; - CItemInfo m_aItems[1024]; - CDataInfo m_aDatas[1024]; + CItemTypeInfo *m_pItemTypes; + CItemInfo *m_pItems; + CDataInfo *m_pDatas; public: - CDataFileWriter() : m_File(0) {} + CDataFileWriter(); + ~CDataFileWriter(); bool Open(class IStorage *pStorage, const char *Filename); int AddData(int Size, void *pData); int AddDataSwapped(int Size, void *pData); -- cgit 1.4.1 From 10c3e844d77996f6a383791edc673bd7855dd321 Mon Sep 17 00:00:00 2001 From: oy Date: Sun, 31 Jul 2011 02:04:46 +0200 Subject: show alpha2 country code strings next to the flag in the country code selectors. Closes #805 --- src/game/client/components/countryflags.cpp | 1 + src/game/client/components/countryflags.h | 3 ++- src/game/client/components/menus.cpp | 5 ++++- src/game/client/components/menus_settings.cpp | 5 ++++- 4 files changed, 11 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/game/client/components/countryflags.cpp b/src/game/client/components/countryflags.cpp index d6b30fe0..ef350cd7 100644 --- a/src/game/client/components/countryflags.cpp +++ b/src/game/client/components/countryflags.cpp @@ -69,6 +69,7 @@ void CCountryFlags::LoadCountryflagsIndexfile() // add entry CCountryFlag CountryFlag; CountryFlag.m_CountryCode = CountryCode; + str_copy(CountryFlag.m_aCountryCodeString, aOrigin, sizeof(CountryFlag.m_aCountryCodeString)); CountryFlag.m_Texture = Graphics()->LoadTextureRaw(Info.m_Width, Info.m_Height, Info.m_Format, Info.m_pData, Info.m_Format, 0); mem_free(Info.m_pData); str_format(aBuf, sizeof(aBuf), "loaded country flag '%s'", aOrigin); diff --git a/src/game/client/components/countryflags.h b/src/game/client/components/countryflags.h index 15eb8598..ad24a762 100644 --- a/src/game/client/components/countryflags.h +++ b/src/game/client/components/countryflags.h @@ -12,9 +12,10 @@ public: struct CCountryFlag { int m_CountryCode; + char m_aCountryCodeString[8]; int m_Texture; - bool operator<(const CCountryFlag &Other) { return m_CountryCode < Other.m_CountryCode; } + bool operator<(const CCountryFlag &Other) { return str_comp(m_aCountryCodeString, Other.m_aCountryCodeString) < 0; } }; void OnInit(); diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp index 4f3d2da7..8f330f78 100644 --- a/src/game/client/components/menus.cpp +++ b/src/game/client/components/menus.cpp @@ -1125,7 +1125,9 @@ int CMenus::Render() CListboxItem Item = UiDoListboxNextItem(&pEntry->m_CountryCode, OldSelected == i); if(Item.m_Visible) { - Item.m_Rect.Margin(10.0f, &Item.m_Rect); + CUIRect Label; + Item.m_Rect.Margin(5.0f, &Item.m_Rect); + Item.m_Rect.HSplitBottom(10.0f, &Item.m_Rect, &Label); float OldWidth = Item.m_Rect.w; Item.m_Rect.w = Item.m_Rect.h*2; Item.m_Rect.x += (OldWidth-Item.m_Rect.w)/ 2.0f; @@ -1135,6 +1137,7 @@ int CMenus::Render() IGraphics::CQuadItem QuadItem(Item.m_Rect.x, Item.m_Rect.y, Item.m_Rect.w, Item.m_Rect.h); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); + UI()->DoLabel(&Label, pEntry->m_aCountryCodeString, 10.0f, 0); } } diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp index c2fab00f..51fdbd29 100644 --- a/src/game/client/components/menus_settings.cpp +++ b/src/game/client/components/menus_settings.cpp @@ -215,7 +215,9 @@ void CMenus::RenderSettingsPlayer(CUIRect MainView) CListboxItem Item = UiDoListboxNextItem(&pEntry->m_CountryCode, OldSelected == i); if(Item.m_Visible) { - Item.m_Rect.Margin(10.0f, &Item.m_Rect); + CUIRect Label; + Item.m_Rect.Margin(5.0f, &Item.m_Rect); + Item.m_Rect.HSplitBottom(10.0f, &Item.m_Rect, &Label); float OldWidth = Item.m_Rect.w; Item.m_Rect.w = Item.m_Rect.h*2; Item.m_Rect.x += (OldWidth-Item.m_Rect.w)/ 2.0f; @@ -225,6 +227,7 @@ void CMenus::RenderSettingsPlayer(CUIRect MainView) IGraphics::CQuadItem QuadItem(Item.m_Rect.x, Item.m_Rect.y, Item.m_Rect.w, Item.m_Rect.h); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); + UI()->DoLabel(&Label, pEntry->m_aCountryCodeString, 10.0f, 0); } } -- cgit 1.4.1 From 9349af008572efe573ec435cf70d02c2f5db9821 Mon Sep 17 00:00:00 2001 From: oy Date: Sun, 31 Jul 2011 02:20:46 +0200 Subject: clean up econ sockets on shutdown. Closes #804 --- src/engine/server/server.cpp | 2 ++ src/engine/shared/econ.cpp | 8 ++++++++ src/engine/shared/econ.h | 1 + src/engine/shared/network_console.cpp | 9 ++++++++- 4 files changed, 19 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 55208caa..2d288740 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -1331,6 +1331,8 @@ int CServer::Run() { if(m_aClients[i].m_State != CClient::STATE_EMPTY) m_NetServer.Drop(i, "Server shutdown"); + + m_Econ.Shutdown(); } GameServer()->OnShutdown(); diff --git a/src/engine/shared/econ.cpp b/src/engine/shared/econ.cpp index ba86e5c0..0bc3a988 100644 --- a/src/engine/shared/econ.cpp +++ b/src/engine/shared/econ.cpp @@ -145,3 +145,11 @@ void CEcon::Send(int ClientID, const char *pLine) else if(ClientID >= 0 && ClientID < NET_MAX_CONSOLE_CLIENTS && m_aClients[ClientID].m_State == CClient::STATE_AUTHED) m_NetConsole.Send(ClientID, pLine); } + +void CEcon::Shutdown() +{ + if(!m_Ready) + return; + + m_NetConsole.Close(); +} diff --git a/src/engine/shared/econ.h b/src/engine/shared/econ.h index 33b23ea6..3ec19e28 100644 --- a/src/engine/shared/econ.h +++ b/src/engine/shared/econ.h @@ -38,6 +38,7 @@ public: void Init(IConsole *pConsole); void Update(); void Send(int ClientID, const char *pLine); + void Shutdown(); }; #endif diff --git a/src/engine/shared/network_console.cpp b/src/engine/shared/network_console.cpp index 0cf2a718..f77e40f2 100644 --- a/src/engine/shared/network_console.cpp +++ b/src/engine/shared/network_console.cpp @@ -7,6 +7,9 @@ bool CNetConsole::Open(NETADDR BindAddr, int Flags) { // zero out the whole structure mem_zero(this, sizeof(*this)); + m_Socket.type = NETTYPE_INVALID; + m_Socket.ipv4sock = -1; + m_Socket.ipv6sock = -1; // open socket m_Socket = net_tcp_create(BindAddr); @@ -31,7 +34,11 @@ void CNetConsole::SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT int CNetConsole::Close() { - // TODO: implement me + for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) + m_aSlots[i].m_Connection.Disconnect("closing console"); + + net_tcp_close(m_Socket); + return 0; } -- cgit 1.4.1 From aabac3dcfce42ee1bf04cd4f428f7e52e9aa26b1 Mon Sep 17 00:00:00 2001 From: oy Date: Sun, 31 Jul 2011 02:25:55 +0200 Subject: send notification to enter a password when a client connects to econ. Closes #803 --- src/engine/shared/econ.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/engine/shared/econ.cpp b/src/engine/shared/econ.cpp index 0bc3a988..18a551e7 100644 --- a/src/engine/shared/econ.cpp +++ b/src/engine/shared/econ.cpp @@ -16,6 +16,8 @@ int CEcon::NewClientCallback(int ClientID, void *pUser) pThis->m_aClients[ClientID].m_State = CClient::STATE_CONNECTED; pThis->m_aClients[ClientID].m_TimeConnected = time_get(); + + pThis->m_NetConsole.Send(ClientID, "Enter password:"); return 0; } -- cgit 1.4.1 From 1705c90e148d680c4b8002d12ac15a7d228f6408 Mon Sep 17 00:00:00 2001 From: oy Date: Sun, 31 Jul 2011 12:43:35 +0200 Subject: fixed ban for life on the server --- src/engine/server/server.cpp | 2 +- src/engine/shared/network_server.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 2d288740..65bb231a 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -1364,7 +1364,7 @@ void CServer::ConBan(IConsole::IResult *pResult, void *pUser) const char *pReason = "No reason given"; if(pResult->NumArguments() > 1) - Minutes = pResult->GetInteger(1); + Minutes = max(0, pResult->GetInteger(1)); if(pResult->NumArguments() > 2) pReason = pResult->GetString(2); diff --git a/src/engine/shared/network_server.cpp b/src/engine/shared/network_server.cpp index f3fbfa32..b100e1a2 100644 --- a/src/engine/shared/network_server.cpp +++ b/src/engine/shared/network_server.cpp @@ -221,10 +221,10 @@ int CNetServer::BanAdd(NETADDR Addr, int Seconds, const char *pReason) char Buf[128]; NETADDR BanAddr; - int Mins = (Seconds + 59) / 60; - if(Mins) + if(Stamp > -1) { - if(Mins == 1) + int Mins = (Seconds + 59) / 60; + if(Mins <= 1) str_format(Buf, sizeof(Buf), "You have been banned for 1 minute (%s)", pReason); else str_format(Buf, sizeof(Buf), "You have been banned for %d minutes (%s)", Mins, pReason); @@ -255,7 +255,7 @@ int CNetServer::Update() } // remove expired bans - while(m_BanPool_FirstUsed && m_BanPool_FirstUsed->m_Info.m_Expires < Now) + while(m_BanPool_FirstUsed && m_BanPool_FirstUsed->m_Info.m_Expires > -1 && m_BanPool_FirstUsed->m_Info.m_Expires < Now) { CBan *pBan = m_BanPool_FirstUsed; BanRemoveByObject(pBan); @@ -307,10 +307,10 @@ int CNetServer::Recv(CNetChunk *pChunk) { // banned, reply with a message char BanStr[128]; - if(pBan->m_Info.m_Expires) + if(pBan->m_Info.m_Expires > -1) { int Mins = ((pBan->m_Info.m_Expires - Now)+59)/60; - if(Mins == 1) + if(Mins <= 1) str_format(BanStr, sizeof(BanStr), "Banned for 1 minute (%s)", pBan->m_Info.m_Reason); else str_format(BanStr, sizeof(BanStr), "Banned for %d minutes (%s)", Mins, pBan->m_Info.m_Reason); -- cgit 1.4.1 From 94188021509a376fc352b7707d9a324335a97eba Mon Sep 17 00:00:00 2001 From: oy Date: Sun, 31 Jul 2011 13:05:12 +0200 Subject: protected econ authentication against brute force --- src/engine/shared/config_variables.h | 1 + src/engine/shared/econ.cpp | 18 +++++++- src/engine/shared/econ.h | 6 +++ src/engine/shared/network.h | 18 +++++++- src/engine/shared/network_console.cpp | 87 ++++++++++++++++++++++++++++++++++- 5 files changed, 126 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index 0789476e..c812063a 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -92,6 +92,7 @@ MACRO_CONFIG_INT(SvAutoDemoMax, sv_auto_demo_max, 10, 0, 1000, CFGFLAG_SERVER, " MACRO_CONFIG_STR(EcBindaddr, ec_bindaddr, 128, "localhost", CFGFLAG_SERVER, "Address to bind the external console to. Anything but 'localhost' is dangerous") MACRO_CONFIG_INT(EcPort, ec_port, 0, 0, 0, CFGFLAG_SERVER, "Port to use for the external console") MACRO_CONFIG_STR(EcPassword, ec_password, 32, "", CFGFLAG_SERVER, "External console password") +MACRO_CONFIG_INT(EcBantime, ec_bantime, 0, 0, 1440, CFGFLAG_SERVER, "The time a client gets banned if econ authentication fails. 0 just closes the connection") MACRO_CONFIG_INT(EcAuthTimeout, ec_auth_timeout, 30, 1, 120, CFGFLAG_SERVER, "Time in seconds before the the econ authentification times out") MACRO_CONFIG_INT(EcOutputLevel, ec_output_level, 1, 0, 2, CFGFLAG_SERVER, "Adjusts the amount of information in the external console") diff --git a/src/engine/shared/econ.cpp b/src/engine/shared/econ.cpp index 18a551e7..617cdbd6 100644 --- a/src/engine/shared/econ.cpp +++ b/src/engine/shared/econ.cpp @@ -16,6 +16,7 @@ int CEcon::NewClientCallback(int ClientID, void *pUser) pThis->m_aClients[ClientID].m_State = CClient::STATE_CONNECTED; pThis->m_aClients[ClientID].m_TimeConnected = time_get(); + pThis->m_aClients[ClientID].m_AuthTries = 0; pThis->m_NetConsole.Send(ClientID, "Enter password:"); return 0; @@ -112,7 +113,22 @@ void CEcon::Update() Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "econ", aBuf); } else - m_NetConsole.Send(ClientID, "Wrong password"); + { + m_aClients[ClientID].m_AuthTries++; + char aBuf[128]; + str_format(aBuf, sizeof(aBuf), "Wrong password %d/%d.", m_aClients[ClientID].m_AuthTries, MAX_AUTH_TRIES); + m_NetConsole.Send(ClientID, aBuf); + if(m_aClients[ClientID].m_AuthTries >= MAX_AUTH_TRIES) + { + if(!g_Config.m_EcBantime) + m_NetConsole.Drop(ClientID, "Too many authentication tries"); + else + { + NETADDR Addr = m_NetConsole.ClientAddr(ClientID); + m_NetConsole.AddBan(Addr, g_Config.m_EcBantime*60); + } + } + } } else if(m_aClients[ClientID].m_State == CClient::STATE_AUTHED) { diff --git a/src/engine/shared/econ.h b/src/engine/shared/econ.h index 3ec19e28..daec34c4 100644 --- a/src/engine/shared/econ.h +++ b/src/engine/shared/econ.h @@ -5,6 +5,11 @@ class CEcon { + enum + { + MAX_AUTH_TRIES=3, + }; + class CClient { public: @@ -17,6 +22,7 @@ class CEcon int m_State; int64 m_TimeConnected; + int m_AuthTries; }; CClient m_aClients[NET_MAX_CONSOLE_CLIENTS]; diff --git a/src/engine/shared/network.h b/src/engine/shared/network.h index 94e2824c..d10c03b6 100644 --- a/src/engine/shared/network.h +++ b/src/engine/shared/network.h @@ -325,7 +325,21 @@ public: class CNetConsole { -private: + enum + { + MAX_BANS=128, + }; + + int FindBan(NETADDR Addr); + void UpdateBans(); + + struct CBanEntry + { + NETADDR m_Addr; + int m_Expires; + } m_aBans[MAX_BANS]; + int m_NumBans; + struct CSlot { CConsoleNetConnection m_Connection; @@ -356,6 +370,8 @@ public: int AcceptClient(NETSOCKET Socket, const NETADDR *pAddr); int Drop(int ClientID, const char *pReason); + bool AddBan(NETADDR Addr, int Seconds); + // status requests NETADDR ClientAddr(int ClientID) const { return m_aSlots[ClientID].m_Connection.PeerAddress(); } }; diff --git a/src/engine/shared/network_console.cpp b/src/engine/shared/network_console.cpp index f77e40f2..13ed3751 100644 --- a/src/engine/shared/network_console.cpp +++ b/src/engine/shared/network_console.cpp @@ -97,9 +97,28 @@ int CNetConsole::Update() NETSOCKET Socket; NETADDR Addr; - while(net_tcp_accept(m_Socket, &Socket, &Addr) > 0) + if(net_tcp_accept(m_Socket, &Socket, &Addr) > 0) { - AcceptClient(Socket, &Addr); + int Index = FindBan(Addr); + if(Index == -1) + AcceptClient(Socket, &Addr); + else + { + char aBuf[128]; + if(m_aBans[Index].m_Expires > -1) + { + int Mins = (m_aBans[Index].m_Expires-time_timestamp()+ 59) / 60; + if(Mins <= 1) + str_format(aBuf, sizeof(aBuf), "You have been banned for 1 minute"); + else + str_format(aBuf, sizeof(aBuf), "You have been banned for %d minutes", Mins); + } + else + str_format(aBuf, sizeof(aBuf), "You have been banned for life"); + + net_tcp_send(Socket, aBuf, str_length(aBuf)); + net_tcp_close(Socket); + } } for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) @@ -110,6 +129,8 @@ int CNetConsole::Update() Drop(i, m_aSlots[i].m_Connection.ErrorString()); } + UpdateBans(); + return 0; } @@ -134,3 +155,65 @@ int CNetConsole::Send(int ClientID, const char *pLine) else return -1; } + +int CNetConsole::FindBan(NETADDR Addr) +{ + Addr.port = 0; + for(int i = 0; i < m_NumBans; i++) + if(net_addr_comp(&m_aBans[i].m_Addr, &Addr) == 0) + return i; + + return -1; +} + +bool CNetConsole::AddBan(NETADDR Addr, int Seconds) +{ + if(m_NumBans == MAX_BANS) + return false; + + Addr.port = 0; + int Index = FindBan(Addr); + if(Index == -1) + { + Index = m_NumBans++; + m_aBans[Index].m_Addr = Addr; + } + m_aBans[Index].m_Expires = Seconds>0 ? time_timestamp()+Seconds : -1; + + for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) + { + if(m_aSlots[i].m_Connection.State() != NET_CONNSTATE_OFFLINE) + { + NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress(); + PeerAddr.port = 0; + if(net_addr_comp(&Addr, &PeerAddr) == 0) + { + char aBuf[128]; + if(Seconds>0) + { + int Mins = (Seconds + 59) / 60; + if(Mins <= 1) + str_format(aBuf, sizeof(aBuf), "You have been banned for 1 minute"); + else + str_format(aBuf, sizeof(aBuf), "You have been banned for %d minutes", Mins); + } + else + str_format(aBuf, sizeof(aBuf), "You have been banned for life"); + Drop(i, aBuf); + } + } + } + return true; +} + +void CNetConsole::UpdateBans() +{ + int Now = time_timestamp(); + for(int i = 0; i < m_NumBans; ++i) + if(m_aBans[i].m_Expires > 0 && m_aBans[i].m_Expires < Now) + { + m_aBans[i] = m_aBans[m_NumBans-1]; + --m_NumBans; + break; + } +} -- cgit 1.4.1 From 3209aec45f61a16423c02545b8b4e34eb6324b60 Mon Sep 17 00:00:00 2001 From: oy Date: Sun, 31 Jul 2011 13:17:38 +0200 Subject: fixed compiling error on osx --- src/engine/server/server.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 65bb231a..193547cc 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -1,6 +1,7 @@ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ +#include #include #include -- cgit 1.4.1 From 9cf4facd05a07c457d41624390965c801fe4d325 Mon Sep 17 00:00:00 2001 From: oy Date: Sun, 31 Jul 2011 17:07:10 +0200 Subject: fixed a client crash in debug. Closes #806 --- src/engine/client/client.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 3d1a5a23..c8bcc83b 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -289,6 +289,7 @@ CClient::CClient() : m_DemoPlayer(&m_SnapshotDelta), m_DemoRecorder(&m_SnapshotD m_aServerAddressStr[0] = 0; mem_zero(m_aSnapshots, sizeof(m_aSnapshots)); + m_SnapshotStorage.Init(); m_RecivedSnapshots = 0; m_VersionInfo.m_State = CVersionInfo::STATE_INIT; -- cgit 1.4.1 From b25fc26c1cad561bcb4c94a17405058b82dc9e8e Mon Sep 17 00:00:00 2001 From: oy Date: Sun, 31 Jul 2011 18:39:48 +0200 Subject: zero out client memory on startup to prevent more bad surprises --- src/engine/client/client.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index c8bcc83b..bec7d4d6 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -1,5 +1,6 @@ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ +#include #include // qsort #include @@ -2165,7 +2166,12 @@ void CClient::RegisterCommands() m_pConsole->Chain("br_filter_serveraddress", ConchainServerBrowserUpdate, this); } -static CClient *CreateClient() { return new CClient(); } +static CClient *CreateClient() +{ + CClient *pClient = static_cast(mem_alloc(sizeof(CClient), 1)); + mem_zero(pClient, sizeof(CClient)); + return new(pClient) CClient; +} /* Server Time -- cgit 1.4.1 From 50edfd37c0ed57ff793b79d06edd0bde1f6cf1bd Mon Sep 17 00:00:00 2001 From: oy Date: Sun, 31 Jul 2011 23:17:00 +0200 Subject: made 0.6.1 release --- src/game/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/game/version.h b/src/game/version.h index c7f04b75..76b6d4ab 100644 --- a/src/game/version.h +++ b/src/game/version.h @@ -3,6 +3,6 @@ #ifndef GAME_VERSION_H #define GAME_VERSION_H #include "generated/nethash.cpp" -#define GAME_VERSION "0.6 trunk" +#define GAME_VERSION "0.6.1" #define GAME_NETVERSION "0.6 " GAME_NETVERSION_HASH #endif -- cgit 1.4.1