Merge pull request #296 from heinrich5991/pr_ddnet_map_settings

Automatically store map configs in maps, add tools for storing and retrieving these configs
This commit is contained in:
Dennis Felsing 2015-08-27 13:15:18 +02:00
commit 628a10bcaa
23 changed files with 748 additions and 53 deletions

View file

@ -26,6 +26,9 @@ public:
TEMPCMD_PARAMS_LENGTH=16,
MAX_PRINT_CB=4,
CLIENT_ID_GAME=-2,
CLIENT_ID_NO_GAME=-3,
};
// TODO: rework this interface to reduce the amount of virtual calls
@ -94,6 +97,8 @@ public:
virtual void SetAccessLevel(int AccessLevel) = 0;
virtual void ResetServerGameSettings() = 0;
// DDRace
bool m_Cheated;

View file

@ -14,6 +14,7 @@ public:
virtual void *GetDataSwapped(int Index) = 0;
virtual void UnloadData(int Index) = 0;
virtual void *GetItem(int Index, int *Type, int *pID) = 0;
virtual int GetItemSize(int Index) = 0;
virtual void GetType(int Type, int *pStart, int *pNum) = 0;
virtual void *FindItem(int Type, int ID) = 0;
virtual int NumItems() = 0;

View file

@ -174,6 +174,7 @@ protected:
public:
virtual void OnInit() = 0;
virtual void OnConsoleInit() = 0;
virtual void OnMapChange(char *pNewMapName, int MapNameSize) = 0;
virtual void OnShutdown() = 0;
virtual void OnTick() = 0;

View file

@ -1477,6 +1477,7 @@ int CServer::LoadMap(const char *pMapName)
//DATAFILE *df;
char aBuf[512];
str_format(aBuf, sizeof(aBuf), "maps/%s.map", pMapName);
GameServer()->OnMapChange(aBuf, sizeof(aBuf));
/*df = datafile_load(buf);
if(!df)

View file

@ -30,7 +30,8 @@ enum
// DDRace
CMDFLAG_TEST=64,
CFGFLAG_CHAT = 128
CFGFLAG_CHAT=128,
CFGFLAG_GAME=256,
};
#endif

View file

@ -166,16 +166,16 @@ MACRO_CONFIG_INT(DbgResizable, dbg_resizable, 0, 0, 0, CFGFLAG_CLIENT, "Enables
MACRO_CONFIG_STR(SvWelcome, sv_welcome, 64, "", CFGFLAG_SERVER, "Message that will be displayed to players who join the server")
MACRO_CONFIG_INT(SvReservedSlots, sv_reserved_slots, 0, 0, 16, CFGFLAG_SERVER, "The number of slots that are reserved for special players")
MACRO_CONFIG_STR(SvReservedSlotsPass, sv_reserved_slots_pass, 32, "", CFGFLAG_SERVER, "The password that is required to use a reserved slot")
MACRO_CONFIG_INT(SvHit, sv_hit, 1, 0, 1, CFGFLAG_SERVER, "Whether players can hammer/grenade/laser eachother or not")
MACRO_CONFIG_INT(SvEndlessDrag, sv_endless_drag, 0, 0, 1, CFGFLAG_SERVER, "Turns endless hooking on/off")
MACRO_CONFIG_INT(SvHit, sv_hit, 1, 0, 1, CFGFLAG_SERVER|CFGFLAG_GAME, "Whether players can hammer/grenade/laser eachother or not")
MACRO_CONFIG_INT(SvEndlessDrag, sv_endless_drag, 0, 0, 1, CFGFLAG_SERVER|CFGFLAG_GAME, "Turns endless hooking on/off")
MACRO_CONFIG_INT(SvTestingCommands, sv_test_cmds, 0, 0, 1, CFGFLAG_SERVER, "Turns testing commands aka cheats on/off")
MACRO_CONFIG_INT(SvFreezeDelay, sv_freeze_delay, 3, 1, 30, CFGFLAG_SERVER, "How many seconds the players will remain frozen (applies to all except delayed freeze in switch layer & deepfreeze)")
MACRO_CONFIG_INT(SvFreezeDelay, sv_freeze_delay, 3, 1, 30, CFGFLAG_SERVER|CFGFLAG_GAME, "How many seconds the players will remain frozen (applies to all except delayed freeze in switch layer & deepfreeze)")
MACRO_CONFIG_INT(ClDDRaceBinds, cl_race_binds, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Enable Default DDRace builds when pressing the reset binds button")
MACRO_CONFIG_INT(ClDDRaceBindsSet, cl_race_binds_set, 0, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Whether the DDRace binds set or not (this is automated you don't need to use this)")
MACRO_CONFIG_INT(SvEndlessSuperHook, sv_endless_super_hook, 0, 0, 1, CFGFLAG_SERVER, "Endless hook for super players on/off")
MACRO_CONFIG_INT(SvHideScore, sv_hide_score, 0, 0, 1, CFGFLAG_SERVER, "Whether players scores will be announced or not")
MACRO_CONFIG_INT(SvSaveWorseScores, sv_save_worse_scores, 1, 0, 1, CFGFLAG_SERVER, "Whether to save worse scores when you already have a better one")
MACRO_CONFIG_INT(SvPauseable, sv_pauseable, 1, 0, 1, CFGFLAG_SERVER, "Whether players can pause their char or not")
MACRO_CONFIG_INT(SvSaveWorseScores, sv_save_worse_scores, 1, 0, 1, CFGFLAG_SERVER|CFGFLAG_GAME, "Whether to save worse scores when you already have a better one")
MACRO_CONFIG_INT(SvPauseable, sv_pauseable, 1, 0, 1, CFGFLAG_SERVER|CFGFLAG_GAME, "Whether players can pause their char or not")
MACRO_CONFIG_INT(SvPauseMessages, sv_pause_messages, 0, 0, 1, CFGFLAG_SERVER, "Whether to show messages when a player pauses and resumes")
MACRO_CONFIG_INT(SvPauseTime, sv_pause_time, 0, 0, 1, CFGFLAG_SERVER, "Whether '/pause' and 'sv_max_dc_restore' pauses the time of player or not")
MACRO_CONFIG_INT(SvPauseFrequency, sv_pause_frequency, 1, 0, 9999, CFGFLAG_SERVER, "The minimum allowed delay between pauses")
@ -233,16 +233,16 @@ MACRO_CONFIG_STR(SvRulesLine8, sv_rules_line8, 40, "", CFGFLAG_SERVER, "Rules li
MACRO_CONFIG_STR(SvRulesLine9, sv_rules_line9, 40, "", CFGFLAG_SERVER, "Rules line 9")
MACRO_CONFIG_STR(SvRulesLine10, sv_rules_line10, 40, "", CFGFLAG_SERVER, "Rules line 10")
MACRO_CONFIG_INT(SvTeam, sv_team, 1, 0, 3, CFGFLAG_SERVER, "Teams configuration (0 = off, 1 = on but optional, 2 = must play only with teams, 3 = forced random team only for you)")
MACRO_CONFIG_INT(SvTeamMaxSize, sv_max_team_size, MAX_CLIENTS, 1, MAX_CLIENTS, CFGFLAG_SERVER, "Maximum team size (from 2 to 16)")
MACRO_CONFIG_INT(SvTeamLock, sv_team_lock, 1, 0, 1, CFGFLAG_SERVER, "Enable team lock")
MACRO_CONFIG_INT(SvMapVote, sv_map_vote, 1, 0, 1, CFGFLAG_SERVER, "Whether to allow /map")
MACRO_CONFIG_INT(SvTeam, sv_team, 1, 0, 3, CFGFLAG_SERVER|CFGFLAG_GAME, "Teams configuration (0 = off, 1 = on but optional, 2 = must play only with teams, 3 = forced random team only for you)")
MACRO_CONFIG_INT(SvTeamMaxSize, sv_max_team_size, MAX_CLIENTS, 1, MAX_CLIENTS, CFGFLAG_SERVER|CFGFLAG_GAME, "Maximum team size (from 2 to 16)")
MACRO_CONFIG_INT(SvTeamLock, sv_team_lock, 1, 0, 1, CFGFLAG_SERVER|CFGFLAG_GAME, "Enable team lock")
MACRO_CONFIG_INT(SvMapVote, sv_map_vote, 1, 0, 1, CFGFLAG_SERVER|CFGFLAG_GAME, "Whether to allow /map")
MACRO_CONFIG_STR(SvAnnouncementFileName, sv_announcement_filename, 24, "announcement.txt", CFGFLAG_SERVER, "file which will have the announcement, each one at a line")
MACRO_CONFIG_INT(SvAnnouncementInterval, sv_announcement_interval, 300, 1, 9999, CFGFLAG_SERVER, "time(minutes) in which the announcement will be displayed from the announcement file")
MACRO_CONFIG_INT(SvAnnouncementRandom, sv_announcement_random, 1, 0, 1, CFGFLAG_SERVER, "Whether announcements are sequential or random")
MACRO_CONFIG_INT(SvOldLaser, sv_old_laser, 0, 0, 1, CFGFLAG_SERVER, "Whether lasers can hit you if you shot them and that they pull you towards the bounce origin (0 for DDRace Beta) or lasers can't hit you if you shot them, and they pull others towards the shooter")
MACRO_CONFIG_INT(SvOldLaser, sv_old_laser, 0, 0, 1, CFGFLAG_SERVER|CFGFLAG_GAME, "Whether lasers can hit you if you shot them and that they pull you towards the bounce origin (0 for DDRace Beta) or lasers can't hit you if you shot them, and they pull others towards the shooter")
MACRO_CONFIG_INT(SvSlashMe, sv_slash_me, 0, 0, 1, CFGFLAG_SERVER, "Whether /me is active on the server or not")
MACRO_CONFIG_INT(SvRejoinTeam0, sv_rejoin_team_0, 1, 0, 1, CFGFLAG_SERVER, "Make a team automatically rejoin team 0 after finish (only if not locked)")
@ -287,7 +287,7 @@ MACRO_CONFIG_INT(ClRaceShowGhost, cl_race_show_ghost, 1, 0, 1, CFGFLAG_CLIENT|CF
MACRO_CONFIG_INT(ClRaceSaveGhost, cl_race_save_ghost, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Save ghost")
MACRO_CONFIG_INT(ClDDRaceScoreBoard, cl_ddrace_scoreboard, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Enable DDRace Scoreboard ")
MACRO_CONFIG_INT(ClShowDecisecs, cl_show_decisecs, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Show deciseconds in game time")
MACRO_CONFIG_INT(SvResetPickups, sv_reset_pickups, 0, 0, 1, CFGFLAG_SERVER, "Whether the weapons are reset on passing the start tile or not")
MACRO_CONFIG_INT(SvResetPickups, sv_reset_pickups, 0, 0, 1, CFGFLAG_SERVER|CFGFLAG_GAME, "Whether the weapons are reset on passing the start tile or not")
MACRO_CONFIG_INT(ClShowOthers, cl_show_others, 0, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Show players in other teams")
MACRO_CONFIG_INT(ClShowOthersAlpha, cl_show_others_alpha, 40, 0, 100, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Show players in other teams (alpha value, 0 invisible, 100 fully visible)")
MACRO_CONFIG_INT(ClOverlayEntities, cl_overlay_entities, 0, 0, 100, CFGFLAG_CLIENT, "Overlay game tiles with a percentage of opacity")
@ -304,8 +304,8 @@ MACRO_CONFIG_INT(SvShowOthersDefault, sv_show_others_default, 0, 0, 1, CFGFLAG_S
MACRO_CONFIG_INT(SvShowAllDefault, sv_show_all_default, 0, 0, 1, CFGFLAG_SERVER, "Whether players see all tees by default")
MACRO_CONFIG_INT(SvMaxAfkTime, sv_max_afk_time, 0, 0, 9999, CFGFLAG_SERVER, "The time in seconds a player is allowed to be afk (0 = disabled)")
MACRO_CONFIG_INT(SvMaxAfkVoteTime, sv_max_afk_vote_time, 300, 0, 9999, CFGFLAG_SERVER, "The time in seconds a player can be afk and his votes still count (0 = disabled)")
MACRO_CONFIG_INT(SvPlasmaRange, sv_plasma_range, 700, 1, 99999, CFGFLAG_SERVER, "How far will the plasma gun track tees")
MACRO_CONFIG_INT(SvPlasmaPerSec, sv_plasma_per_sec, 3, 0, 50, CFGFLAG_SERVER, "How many shots does the plasma gun fire per seconds")
MACRO_CONFIG_INT(SvPlasmaRange, sv_plasma_range, 700, 1, 99999, CFGFLAG_SERVER|CFGFLAG_GAME, "How far will the plasma gun track tees")
MACRO_CONFIG_INT(SvPlasmaPerSec, sv_plasma_per_sec, 3, 0, 50, CFGFLAG_SERVER|CFGFLAG_GAME, "How many shots does the plasma gun fire per seconds")
MACRO_CONFIG_INT(SvVotePause, sv_vote_pause, 1, 0, 1, CFGFLAG_SERVER, "Allow voting to pause players (instead of moving to spectators)")
MACRO_CONFIG_INT(SvVotePauseTime, sv_vote_pause_time, 10, 0, 360, CFGFLAG_SERVER, "The time (in seconds) players have to wait in pause when paused by vote")
MACRO_CONFIG_INT(SvTuneReset, sv_tune_reset, 1, 0, 1, CFGFLAG_SERVER, "Whether tuning is reset after each map change or not")
@ -326,7 +326,7 @@ MACRO_CONFIG_INT(SvEvents, sv_events, 1, 0, 1, CFGFLAG_SERVER, "Enable triggerin
MACRO_CONFIG_INT(SvRankCheats, sv_rank_cheats, 0, 0, 1, CFGFLAG_SERVER, "Enable ranks after cheats have been used (file based server only)")
MACRO_CONFIG_INT(SvShutdownWhenEmpty, sv_shutdown_when_empty, 0, 0, 1, CFGFLAG_SERVER, "Shutdown server as soon as noone is on it anymore")
MACRO_CONFIG_INT(SvKillProtection, sv_kill_protection, 20, 0, 9999, CFGFLAG_SERVER, "0 - Disable, 1-9999 minutes")
MACRO_CONFIG_INT(SvSoloServer, sv_solo_server, 0, 0, 1, CFGFLAG_SERVER, "Set server to solo mode (no player interactions, has to be set before loading the map)")
MACRO_CONFIG_INT(SvSoloServer, sv_solo_server, 0, 0, 1, CFGFLAG_SERVER|CFGFLAG_GAME, "Set server to solo mode (no player interactions, has to be set before loading the map)")
MACRO_CONFIG_STR(SvClientSuggestion, sv_client_suggestion, 128, "Get DDNet client from DDNet.tw to use all features on DDNet!", CFGFLAG_SERVER, "Broadcast to display to players without DDNet client")
MACRO_CONFIG_STR(SvClientSuggestionOld, sv_client_suggestion_old, 128, "Your DDNet client is old, update it on DDNet.tw!", CFGFLAG_SERVER, "Broadcast to display to players with an old version of DDNet client")
MACRO_CONFIG_STR(SvClientSuggestionBot, sv_client_suggestion_bot, 128, "Your client has bots and can be remote controlled!\nPlease use another client like DDNet client from DDNet.tw", CFGFLAG_SERVER, "Broadcast to display to players with a known botting client")

View file

@ -323,7 +323,29 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr, int ClientID)
if(pCommand)
{
if(pCommand->GetAccessLevel() >= m_AccessLevel)
if(ClientID == IConsole::CLIENT_ID_GAME
&& !(pCommand->m_Flags & CFGFLAG_GAME))
{
if(Stroke)
{
char aBuf[96];
str_format(aBuf, sizeof(aBuf), "Command '%s' cannot be executed from a map.", Result.m_pCommand);
Print(OUTPUT_LEVEL_STANDARD, "console", aBuf);
}
}
else if(ClientID == IConsole::CLIENT_ID_NO_GAME
&& pCommand->m_Flags & CFGFLAG_GAME)
{
if(Stroke)
{
char aBuf[96];
str_format(aBuf, sizeof(aBuf), "Command '%s' cannot be executed from a non-map config file.", Result.m_pCommand);
Print(OUTPUT_LEVEL_STANDARD, "console", aBuf);
str_format(aBuf, sizeof(aBuf), "Hint: Put the command in '%s.cfg' instead of '%s.map.cfg' ", g_Config.m_SvMap, g_Config.m_SvMap);
Print(OUTPUT_LEVEL_STANDARD, "console", aBuf);
}
}
else if(pCommand->GetAccessLevel() >= m_AccessLevel)
{
int IsStrokeCommand = 0;
if(Result.m_pCommand[0] == '+')
@ -458,7 +480,7 @@ void CConsole::ExecuteFile(const char *pFilename, int ClientID)
// exec the file
IOHANDLE File = m_pStorage->OpenFile(pFilename, IOFLAG_READ, IStorage::TYPE_ALL);
char aBuf[8192];
char aBuf[128];
if(File)
{
char *pLine;
@ -560,6 +582,7 @@ struct CIntVariableData
int *m_pVariable;
int m_Min;
int m_Max;
int m_OldValue;
};
struct CStrVariableData
@ -567,6 +590,7 @@ struct CStrVariableData
IConsole *m_pConsole;
char *m_pStr;
int m_MaxSize;
char *m_pOldValue;
};
static void IntVariableCommand(IConsole::IResult *pResult, void *pUserData)
@ -587,10 +611,12 @@ static void IntVariableCommand(IConsole::IResult *pResult, void *pUserData)
}
*(pData->m_pVariable) = Val;
if(pResult->m_ClientID != IConsole::CLIENT_ID_GAME)
pData->m_OldValue = Val;
}
else
{
char aBuf[1024];
char aBuf[32];
str_format(aBuf, sizeof(aBuf), "Value: %d", *(pData->m_pVariable));
pData->m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "console", aBuf);
}
@ -622,6 +648,9 @@ static void StrVariableCommand(IConsole::IResult *pResult, void *pUserData)
}
else
str_copy(pData->m_pStr, pString, pData->m_MaxSize);
if(pResult->m_ClientID != IConsole::CLIENT_ID_GAME)
str_copy(pData->m_pOldValue, pData->m_pStr, pData->m_MaxSize);
}
else
{
@ -732,13 +761,14 @@ CConsole::CConsole(int FlagMask)
// TODO: this should disappear
#define MACRO_CONFIG_INT(Name,ScriptName,Def,Min,Max,Flags,Desc) \
{ \
static CIntVariableData Data = { this, &g_Config.m_##Name, Min, Max }; \
static CIntVariableData Data = { this, &g_Config.m_##Name, Min, Max, Def }; \
Register(#ScriptName, "?i", Flags, IntVariableCommand, &Data, Desc); \
}
#define MACRO_CONFIG_STR(Name,ScriptName,Len,Def,Flags,Desc) \
{ \
static CStrVariableData Data = { this, g_Config.m_##Name, Len }; \
static char OldValue[Len] = Def; \
static CStrVariableData Data = { this, g_Config.m_##Name, Len, OldValue }; \
Register(#ScriptName, "?r", Flags, StrVariableCommand, &Data, Desc); \
}
@ -1008,6 +1038,50 @@ void CConsole::ConUserCommandStatus(IResult *pResult, void *pUser)
pConsole->Print(OUTPUT_LEVEL_STANDARD, "console", aBuf);
}
void CConsole::ResetServerGameSettings()
{
#define MACRO_CONFIG_INT(Name,ScriptName,Def,Min,Max,Flags,Desc) \
{ \
if(((Flags) & (CFGFLAG_SERVER|CFGFLAG_GAME)) == (CFGFLAG_SERVER|CFGFLAG_GAME)) \
{ \
CCommand *pCommand = FindCommand(#ScriptName, CFGFLAG_SERVER); \
void *pUserData = pCommand->m_pUserData; \
FCommandCallback pfnCallback = pCommand->m_pfnCallback; \
while(pfnCallback == Con_Chain) \
{ \
CChain *pChainInfo = (CChain *)pUserData; \
pUserData = pChainInfo->m_pCallbackUserData; \
pfnCallback = pChainInfo->m_pfnCallback; \
} \
CIntVariableData *pData = (CIntVariableData *)pUserData; \
*pData->m_pVariable = pData->m_OldValue; \
} \
}
#define MACRO_CONFIG_STR(Name,ScriptName,Len,Def,Flags,Desc) \
{ \
if(((Flags) & (CFGFLAG_SERVER|CFGFLAG_GAME)) == (CFGFLAG_SERVER|CFGFLAG_GAME)) \
{ \
CCommand *pCommand = FindCommand(#ScriptName, CFGFLAG_SERVER); \
void *pUserData = pCommand->m_pUserData; \
FCommandCallback pfnCallback = pCommand->m_pfnCallback; \
while(pfnCallback == Con_Chain) \
{ \
CChain *pChainInfo = (CChain *)pUserData; \
pUserData = pChainInfo->m_pCallbackUserData; \
pfnCallback = pChainInfo->m_pfnCallback; \
} \
CStrVariableData *pData = (CStrVariableData *)pUserData; \
str_copy(pData->m_pOldValue, pData->m_pStr, pData->m_MaxSize); \
} \
}
#include "config_variables.h"
#undef MACRO_CONFIG_INT
#undef MACRO_CONFIG_STR
}
int CConsole::CResult::GetVictim()
{
return m_Victim;

View file

@ -195,7 +195,7 @@ public:
virtual void Print(int Level, const char *pFrom, const char *pStr, bool Highlighted = false);
void SetAccessLevel(int AccessLevel) { m_AccessLevel = clamp(AccessLevel, (int)(ACCESS_LEVEL_ADMIN), (int)(ACCESS_LEVEL_USER)); }
void ResetServerGameSettings();
// DDRace
static void ConUserCommandStatus(IConsole::IResult *pResult, void *pUser);

View file

@ -452,13 +452,16 @@ CDataFileWriter::~CDataFileWriter()
m_pDatas = 0;
}
bool CDataFileWriter::Open(class IStorage *pStorage, const char *pFilename)
bool CDataFileWriter::OpenFile(class IStorage *pStorage, const char *pFilename)
{
dbg_assert(!m_File, "a file already exists");
m_File = pStorage->OpenFile(pFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE);
if(!m_File)
return false;
return m_File != 0;
}
void CDataFileWriter::Init()
{
dbg_assert(!m_File, "a file already exists");
m_NumItems = 0;
m_NumDatas = 0;
m_NumItemTypes = 0;
@ -469,14 +472,16 @@ bool CDataFileWriter::Open(class IStorage *pStorage, const char *pFilename)
m_pItemTypes[i].m_First = -1;
m_pItemTypes[i].m_Last = -1;
}
}
return true;
bool CDataFileWriter::Open(class IStorage *pStorage, const char *pFilename)
{
Init();
return OpenFile(pStorage, pFilename);
}
int CDataFileWriter::AddItem(int Type, int ID, int Size, void *pData)
{
if(!m_File) return 0;
dbg_assert(Type >= 0 && Type < 0xFFFF, "incorrect type");
dbg_assert(m_NumItems < 1024, "too many items");
dbg_assert(Size%sizeof(int) == 0, "incorrect boundary");
@ -511,8 +516,6 @@ int CDataFileWriter::AddItem(int Type, int ID, int Size, void *pData)
int CDataFileWriter::AddData(int Size, void *pData)
{
if(!m_File) return 0;
dbg_assert(m_NumDatas < 1024, "too much data");
CDataInfo *pInfo = &m_pDatas[m_NumDatas];

View file

@ -80,6 +80,8 @@ class CDataFileWriter
public:
CDataFileWriter();
~CDataFileWriter();
void Init();
bool OpenFile(class IStorage *pStorage, const char *pFilename);
bool Open(class IStorage *pStorage, const char *Filename);
int AddData(int Size, void *pData);
int AddDataSwapped(int Size, void *pData);

View file

@ -16,6 +16,7 @@ public:
virtual void *GetDataSwapped(int Index) { return m_DataFile.GetDataSwapped(Index); }
virtual void UnloadData(int Index) { m_DataFile.UnloadData(Index); }
virtual void *GetItem(int Index, int *pType, int *pID) { return m_DataFile.GetItem(Index, pType, pID); }
virtual int GetItemSize(int Index) { return m_DataFile.GetItemSize(Index); }
virtual void GetType(int Type, int *pStart, int *pNum) { m_DataFile.GetType(Type, pStart, pNum); }
virtual void *FindItem(int Type, int ID) { return m_DataFile.FindItem(Type, ID); }
virtual int NumItems() { return m_DataFile.NumItems(); }

View file

@ -433,3 +433,18 @@ public:
};
IStorage *CreateStorage(const char *pApplicationName, int StorageType, int NumArgs, const char **ppArguments) { return CStorage::Create(pApplicationName, StorageType, NumArgs, ppArguments); }
IStorage *CreateLocalStorage()
{
CStorage *pStorage = new CStorage();
if(pStorage)
{
if(!fs_getcwd(pStorage->m_aCurrentdir, sizeof(pStorage->m_aCurrentdir)))
{
delete pStorage;
return NULL;
}
pStorage->AddPath("$CURRENTDIR");
}
return pStorage;
}

View file

@ -33,6 +33,7 @@ public:
};
extern IStorage *CreateStorage(const char *pApplicationName, int StorageType, int NumArgs, const char **ppArguments);
extern IStorage *CreateLocalStorage();
#endif

View file

@ -4098,6 +4098,20 @@ void CEditor::RenderStatusbar(CUIRect View)
else if(MouseButton == 1)
m_ShowEnvelopeEditor = (m_ShowEnvelopeEditor+1)%4;
if(MouseButton)
{
m_ShowServerSettingsEditor = false;
}
View.VSplitRight(100.0f, &View, &Button);
Button.VSplitRight(10.0f, &Button, 0);
static int s_SettingsButton = 0;
if(DoButton_Editor(&s_SettingsButton, "Server settings", m_ShowServerSettingsEditor, &Button, 0, "Toggles the server settings editor."))
{
m_ShowEnvelopeEditor = 0;
m_ShowServerSettingsEditor ^= 1;
}
if (g_Config.m_ClEditorUndo)
{
View.VSplitRight(5.0f, &View, &Button);
@ -4707,6 +4721,126 @@ void CEditor::RenderEnvelopeEditor(CUIRect View)
}
}
void CEditor::RenderServerSettingsEditor(CUIRect View)
{
static int s_CommandSelectedIndex = -1;
CUIRect ToolBar;
View.HSplitTop(20.0f, &ToolBar, &View);
ToolBar.Margin(2.0f, &ToolBar);
// do the toolbar
{
CUIRect Button;
// command line
ToolBar.VSplitLeft(5.0f, 0, &Button);
UI()->DoLabel(&Button, "Command:", 12.0f, -1);
Button.VSplitLeft(70.0f, 0, &Button);
Button.VSplitLeft(180.0f, &Button, 0);
DoEditBox(&m_CommandBox, &Button, m_aSettingsCommand, sizeof(m_aSettingsCommand), 12.0f, &m_CommandBox);
// buttons
ToolBar.VSplitRight(50.0f, &ToolBar, &Button);
static int s_AddButton = 0;
if(DoButton_Editor(&s_AddButton, "Add", 0, &Button, 0, "Add a command to command list.")
|| ((Input()->KeyDown(KEY_RETURN) || Input()->KeyDown(KEY_KP_ENTER)) && UI()->LastActiveItem() == &m_CommandBox))
{
if(m_aSettingsCommand[0] != 0 && str_find(m_aSettingsCommand, " "))
{
bool Found = false;
for(int i = 0; i < m_Map.m_lSettings.size(); i++)
if(!str_comp(m_Map.m_lSettings[i].m_aCommand, m_aSettingsCommand))
{
Found = true;
break;
}
if(!Found)
{
CEditorMap::CSetting Setting;
str_copy(Setting.m_aCommand, m_aSettingsCommand, sizeof(Setting.m_aCommand));
m_Map.m_lSettings.add(Setting);
}
}
}
if(m_Map.m_lSettings.size())
{
ToolBar.VSplitRight(50.0f, &ToolBar, &Button);
Button.VSplitRight(5.0f, &Button, 0);
static int s_AddButton = 0;
if(DoButton_Editor(&s_AddButton, "Del", 0, &Button, 0, "Delete a command from the command list.")
|| Input()->KeyDown(KEY_DELETE))
if(s_CommandSelectedIndex > -1 && s_CommandSelectedIndex < m_Map.m_lSettings.size())
m_Map.m_lSettings.remove_index(s_CommandSelectedIndex);
}
}
View.HSplitTop(2.0f, 0, &View);
RenderBackground(View, ms_CheckerTexture, 32.0f, 0.1f);
CUIRect ListBox;
View.Margin(1.0f, &ListBox);
float ListHeight = 17.0f * m_Map.m_lSettings.size();
static int s_ScrollBar = 0;
static float s_ScrollValue = 0;
float ScrollDifference = ListHeight - ListBox.h;
if(ListHeight > ListBox.h) // Do we even need a scrollbar?
{
CUIRect Scroll;
ListBox.VSplitRight(15.0f, &ListBox, &Scroll);
ListBox.VSplitRight(3.0f, &ListBox, 0); // extra spacing
Scroll.HMargin(5.0f, &Scroll);
s_ScrollValue = UiDoScrollbarV(&s_ScrollBar, &Scroll, s_ScrollValue);
if(UI()->MouseInside(&Scroll) || UI()->MouseInside(&ListBox))
{
int ScrollNum = (int)((ListHeight-ListBox.h)/17.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 ListStartAt = ScrollDifference * s_ScrollValue;
if(ListStartAt < 0.0f)
ListStartAt = 0.0f;
float ListStopAt = ListHeight - ScrollDifference * (1 - s_ScrollValue);
float ListCur = 0;
UI()->ClipEnable(&ListBox);
for(int i = 0; i < m_Map.m_lSettings.size(); i++)
{
if(ListCur > ListStopAt)
break;
if(ListCur >= ListStartAt)
{
CUIRect Button;
ListBox.HSplitTop(15.0f, &Button, &ListBox);
ListBox.HSplitTop(2.0f, 0, &ListBox);
Button.VSplitLeft(5.0f, 0, &Button);
if(DoButton_MenuItem(&m_Map.m_lSettings[i], m_Map.m_lSettings[i].m_aCommand, s_CommandSelectedIndex == i, &Button, 0, 0))
s_CommandSelectedIndex = i;
}
ListCur += 17.0f;
}
UI()->ClipDisable();
}
int CEditor::PopupMenuFile(CEditor *pEditor, CUIRect View)
{
static int s_NewMapButton = 0;
@ -4874,8 +5008,8 @@ void CEditor::Render()
// render checker
RenderBackground(View, ms_CheckerTexture, 32.0f, 1.0f);
CUIRect MenuBar, CModeBar, ToolBar, StatusBar, EnvelopeEditor, UndoList, ToolBox;
m_ShowPicker = Input()->KeyPressed(KEY_SPACE) != 0 && m_Dialog == DIALOG_NONE && m_EditBoxActive == 0;
CUIRect MenuBar, CModeBar, ToolBar, StatusBar, ExtraEditor, UndoList, ToolBox;
m_ShowPicker = Input()->KeyPressed(KEY_SPACE) != 0 && m_Dialog == DIALOG_NONE && m_EditBoxActive == 0 && UI()->LastActiveItem() != &m_CommandBox;
if(m_GuiActive)
{
@ -4892,12 +5026,15 @@ void CEditor::Render()
size *= 2.0f;
else if(m_ShowEnvelopeEditor == 3)
size *= 3.0f;
View.HSplitBottom(size, &View, &EnvelopeEditor);
View.HSplitBottom(size, &View, &ExtraEditor);
}
if (m_ShowUndo && !m_ShowPicker)
{
View.HSplitBottom(250.0f, &View, &UndoList);
}
if(m_ShowServerSettingsEditor && !m_ShowPicker)
View.HSplitBottom(250.0f, &View, &ExtraEditor);
}
// a little hack for now
@ -4963,10 +5100,10 @@ void CEditor::Render()
if(m_GuiActive)
{
if(m_ShowEnvelopeEditor)
if(m_ShowEnvelopeEditor || m_ShowServerSettingsEditor)
{
RenderBackground(EnvelopeEditor, ms_BackgroundTexture, 128.0f, Brightness);
EnvelopeEditor.Margin(2.0f, &EnvelopeEditor);
RenderBackground(ExtraEditor, ms_BackgroundTexture, 128.0f, Brightness);
ExtraEditor.Margin(2.0f, &ExtraEditor);
}
if(m_ShowUndo)
{
@ -4991,9 +5128,11 @@ void CEditor::Render()
RenderModebar(CModeBar);
if(m_ShowEnvelopeEditor && !m_ShowPicker)
RenderEnvelopeEditor(EnvelopeEditor);
RenderEnvelopeEditor(ExtraEditor);
if(m_ShowUndo)
RenderUndoList(UndoList);
if(m_ShowServerSettingsEditor)
RenderServerSettingsEditor(ExtraEditor);
}
if(m_Dialog == DIALOG_FILE)
@ -5215,6 +5354,8 @@ void CEditorMap::Clean()
m_MapInfo.Reset();
m_lSettings.clear();
m_pGameLayer = 0x0;
m_pGameGroup = 0x0;

View file

@ -376,6 +376,12 @@ public:
};
CMapInfo m_MapInfo;
struct CSetting
{
char m_aCommand[64];
};
array<CSetting> m_lSettings;
class CLayerGame *m_pGameLayer;
CLayerGroup *m_pGameGroup;
@ -678,11 +684,15 @@ public:
m_ShowEnvelopeEditor = 0;
m_ShowUndo = 0;
m_UndoScrollValue = 0.0f;
m_ShowServerSettingsEditor = false;
m_ShowEnvelopePreview = 0;
m_SelectedQuadEnvelope = -1;
m_SelectedEnvelopePoint = -1;
m_CommandBox = 0.0f;
m_aSettingsCommand[0] = 0;
ms_CheckerTexture = 0;
ms_BackgroundTexture = 0;
ms_CursorTexture = 0;
@ -842,6 +852,7 @@ public:
int m_ShowEnvelopeEditor;
int m_ShowEnvelopePreview; //Values: 0-Off|1-Selected Envelope|2-All
bool m_ShowServerSettingsEditor;
bool m_ShowPicker;
int m_SelectedLayer;
@ -871,6 +882,9 @@ public:
static void EnvelopeEval(float TimeOffset, int Env, float *pChannels, void *pUser);
float m_CommandBox;
char m_aSettingsCommand[64];
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);
@ -959,6 +973,7 @@ public:
void RenderStatusbar(CUIRect View);
void RenderEnvelopeEditor(CUIRect View);
void RenderUndoList(CUIRect View);
void RenderServerSettingsEditor(CUIRect View);
void RenderMenubar(CUIRect Menubar);
void RenderFileDialog();

View file

@ -238,7 +238,7 @@ int CEditorMap::Save(class IStorage *pStorage, const char *pFileName)
// save map info
{
CMapItemInfo Item;
CMapItemInfoSettings Item;
Item.m_Version = 1;
if(m_MapInfo.m_aAuthor[0])
@ -258,6 +258,27 @@ int CEditorMap::Save(class IStorage *pStorage, const char *pFileName)
else
Item.m_License = -1;
Item.m_Settings = -1;
if(m_lSettings.size())
{
int Size = 0;
for(int i = 0; i < m_lSettings.size(); i++)
{
Size += str_length(m_lSettings[i].m_aCommand) + 1;
}
char *pSettings = (char *)mem_alloc(Size, 1);
char *pNext = pSettings;
for(int i = 0; i < m_lSettings.size(); i++)
{
int Length = str_length(m_lSettings[i].m_aCommand) + 1;
mem_copy(pNext, m_lSettings[i].m_aCommand, Length);
pNext += Length;
}
Item.m_Settings = df.AddData(Size, pSettings);
mem_free(pSettings);
}
df.AddItem(MAPITEMTYPE_INFO, 0, sizeof(Item), &Item);
}
@ -589,9 +610,16 @@ int CEditorMap::Load(class IStorage *pStorage, const char *pFileName, int Storag
// load map info
{
CMapItemInfo *pItem = (CMapItemInfo *)DataFile.FindItem(MAPITEMTYPE_INFO, 0);
if(pItem && pItem->m_Version == 1)
int Start, Num;
DataFile.GetType(MAPITEMTYPE_INFO, &Start, &Num);
for(int i = Start; i < Start + Num; i++)
{
int ItemSize = DataFile.GetItemSize(Start) - 8;
int ItemID;
CMapItemInfoSettings *pItem = (CMapItemInfoSettings *)DataFile.GetItem(i, 0, &ItemID);
if(!pItem || ItemID != 0)
continue;
if(pItem->m_Author > -1)
str_copy(m_MapInfo.m_aAuthor, (char *)DataFile.GetData(pItem->m_Author), sizeof(m_MapInfo.m_aAuthor));
if(pItem->m_MapVersion > -1)
@ -600,6 +628,24 @@ int CEditorMap::Load(class IStorage *pStorage, const char *pFileName, int Storag
str_copy(m_MapInfo.m_aCredits, (char *)DataFile.GetData(pItem->m_Credits), sizeof(m_MapInfo.m_aCredits));
if(pItem->m_License > -1)
str_copy(m_MapInfo.m_aLicense, (char *)DataFile.GetData(pItem->m_License), sizeof(m_MapInfo.m_aLicense));
if(pItem->m_Version != 1 || ItemSize < (int)sizeof(CMapItemInfoSettings))
break;
if(!(pItem->m_Settings > -1))
break;
int Size = DataFile.GetUncompressedDataSize(pItem->m_Settings);
char *pSettings = (char *)DataFile.GetData(pItem->m_Settings);
char *pNext = pSettings;
while(pNext < pSettings + Size)
{
int StrSize = str_length(pNext) + 1;
CSetting Setting;
str_copy(Setting.m_aCommand, pNext, sizeof(Setting.m_aCommand));
m_lSettings.add(Setting);
pNext += StrSize;
}
}
}

View file

@ -221,6 +221,11 @@ struct CMapItemInfo
int m_License;
} ;
struct CMapItemInfoSettings : CMapItemInfo
{
int m_Settings;
} ;
struct CMapItemImage
{
int m_Version;

View file

@ -7,6 +7,9 @@
#include <engine/shared/config.h>
#include <engine/map.h>
#include <engine/console.h>
#include <engine/shared/datafile.h>
#include <engine/shared/linereader.h>
#include <engine/storage.h>
#include "gamecontext.h"
#include <game/version.h>
#include <game/collision.h>
@ -56,6 +59,7 @@ void CGameContext::Construct(int Resetting)
m_NumMutes = 0;
}
m_ChatResponseTargetID = -1;
m_aDeleteTempfile[0] = 0;
}
CGameContext::CGameContext(int Resetting)
@ -2242,15 +2246,15 @@ void CGameContext::OnConsoleInit()
m_ChatPrintCBIndex = Console()->RegisterPrintCallback(0, SendChatResponse, this);
Console()->Register("tune", "si", CFGFLAG_SERVER, ConTuneParam, this, "Tune variable to value");
Console()->Register("tune", "si", CFGFLAG_SERVER|CFGFLAG_GAME, 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("tune_zone", "isi", CFGFLAG_SERVER, ConTuneZone, this, "Tune in zone a variable to value");
Console()->Register("tune_zone", "isi", CFGFLAG_SERVER|CFGFLAG_GAME, ConTuneZone, this, "Tune in zone a variable to value");
Console()->Register("tune_zone_dump", "i", CFGFLAG_SERVER, ConTuneDumpZone, this, "Dump zone tuning in zone x");
Console()->Register("tune_zone_reset", "?i", CFGFLAG_SERVER, ConTuneResetZone, this, "reset zone tuning in zone x or in all zones");
Console()->Register("tune_zone_enter", "is", CFGFLAG_SERVER, ConTuneSetZoneMsgEnter, this, "which message to display on zone enter; use 0 for normal area");
Console()->Register("tune_zone_leave", "is", CFGFLAG_SERVER, ConTuneSetZoneMsgLeave, this, "which message to display on zone leave; use 0 for normal area");
Console()->Register("switch_open", "i", CFGFLAG_SERVER, ConSwitchOpen, this, "Whether a switch is open by default (otherwise closed)");
Console()->Register("tune_zone_enter", "is", CFGFLAG_SERVER|CFGFLAG_GAME, ConTuneSetZoneMsgEnter, this, "which message to display on zone enter; use 0 for normal area");
Console()->Register("tune_zone_leave", "is", CFGFLAG_SERVER|CFGFLAG_GAME, ConTuneSetZoneMsgLeave, this, "which message to display on zone leave; use 0 for normal area");
Console()->Register("switch_open", "i", CFGFLAG_SERVER|CFGFLAG_GAME, ConSwitchOpen, this, "Whether a switch is open by default (otherwise closed)");
Console()->Register("pause_game", "", CFGFLAG_SERVER, ConPause, this, "Pause/unpause game");
Console()->Register("change_map", "?r", CFGFLAG_SERVER|CFGFLAG_STORE, ConChangeMap, this, "Change map");
Console()->Register("random_map", "?i", CFGFLAG_SERVER, ConRandomMap, this, "Random map");
@ -2285,6 +2289,8 @@ void CGameContext::OnInit(/*class IKernel *pKernel*/)
m_World.SetGameServer(this);
m_Events.SetGameServer(this);
DeleteTempfile();
//if(!data) // only load once
//data = load_data_from_memory(internal_data);
@ -2347,11 +2353,8 @@ void CGameContext::OnInit(/*class IKernel *pKernel*/)
Console()->ExecuteFile(g_Config.m_SvResetFile);
char buf[512];
str_format(buf, sizeof(buf), "maps/%s.cfg", g_Config.m_SvMap);
Console()->ExecuteFile(buf);
str_format(buf, sizeof(buf), "maps/%s.map.cfg", g_Config.m_SvMap);
Console()->ExecuteFile(buf);
LoadMapSettings();
/* // select gametype
if(str_comp(g_Config.m_SvGametype, "mod") == 0)
m_pController = new CGameControllerMOD(this);
@ -2514,8 +2517,132 @@ void CGameContext::OnInit(/*class IKernel *pKernel*/)
#endif
}
void CGameContext::DeleteTempfile()
{
if(m_aDeleteTempfile[0] != 0)
{
IStorage *pStorage = Kernel()->RequestInterface<IStorage>();
pStorage->RemoveFile(m_aDeleteTempfile, IStorage::TYPE_SAVE);
m_aDeleteTempfile[0] = 0;
}
}
void CGameContext::OnMapChange(char *pNewMapName, int MapNameSize)
{
IStorage *pStorage = Kernel()->RequestInterface<IStorage>();
char aConfig[128];
char aTemp[128];
str_format(aConfig, sizeof(aConfig), "maps/%s.cfg", g_Config.m_SvMap);
str_format(aTemp, sizeof(aTemp), "%s.temp.%d", pNewMapName, pid());
IOHANDLE File = pStorage->OpenFile(aConfig, IOFLAG_READ, IStorage::TYPE_ALL);
if(!File)
{
// No map-specific config, just return.
return;
}
CLineReader LineReader;
LineReader.Init(File);
array<char *> aLines;
char *pLine;
int TotalLength = 0;
while((pLine = LineReader.Get()))
{
int Length = str_length(pLine) + 1;
char *pCopy = (char *)mem_alloc(Length, 1);
mem_copy(pCopy, pLine, Length);
aLines.add(pCopy);
TotalLength += Length;
}
char *pSettings = (char *)mem_alloc(TotalLength, 1);
int Offset = 0;
for(int i = 0; i < aLines.size(); i++)
{
int Length = str_length(aLines[i]) + 1;
mem_copy(pSettings + Offset, aLines[i], Length);
Offset += Length;
mem_free(aLines[i]);
}
CDataFileReader Reader;
Reader.Open(pStorage, pNewMapName, IStorage::TYPE_ALL);
CDataFileWriter Writer;
Writer.Open(pStorage, aTemp);
int SettingsIndex = Reader.NumData();
for(int i = 0; i < Reader.NumItems(); i++)
{
int TypeID;
int ItemID;
int *pData = (int *)Reader.GetItem(i, &TypeID, &ItemID);
// GetItemSize returns item size including header, remove that.
int Size = Reader.GetItemSize(i) - sizeof(int) * 2;
CMapItemInfoSettings MapInfo;
if(TypeID == MAPITEMTYPE_INFO && ItemID == 0)
{
CMapItemInfoSettings *pInfo = (CMapItemInfoSettings *)pData;
if(Size >= (int)sizeof(CMapItemInfoSettings))
{
if(pInfo->m_Settings > -1)
{
SettingsIndex = pInfo->m_Settings;
char *pMapSettings = (char *)Reader.GetData(SettingsIndex);
int DataSize = Reader.GetUncompressedDataSize(SettingsIndex);
if(DataSize == TotalLength && mem_comp(pSettings, pMapSettings, Size) == 0)
{
// Configs coincide, no need to update map.
return;
}
Reader.UnloadData(pInfo->m_Settings);
}
else
{
MapInfo = *pInfo;
MapInfo.m_Settings = SettingsIndex;
pData = (int *)&MapInfo;
Size = sizeof(MapInfo);
}
}
else
{
*(CMapItemInfo *)&MapInfo = *(CMapItemInfo *)pInfo;
MapInfo.m_Settings = SettingsIndex;
pData = (int *)&MapInfo;
Size = sizeof(MapInfo);
}
}
Writer.AddItem(TypeID, ItemID, Size, pData);
}
for(int i = 0; i < Reader.NumData() || i == SettingsIndex; i++)
{
if(i == SettingsIndex)
{
Writer.AddData(TotalLength, pSettings);
continue;
}
unsigned char *pData = (unsigned char *)Reader.GetData(i);
int Size = Reader.GetUncompressedDataSize(i);
Writer.AddData(Size, pData);
Reader.UnloadData(i);
}
dbg_msg("mapchange", "imported settings");
Reader.Close();
Writer.Finish();
str_copy(pNewMapName, aTemp, MapNameSize);
str_copy(m_aDeleteTempfile, aTemp, sizeof(m_aDeleteTempfile));
}
void CGameContext::OnShutdown()
{
DeleteTempfile();
Console()->ResetServerGameSettings();
Layers()->Dest();
Collision()->Dest();
delete m_pController;
@ -2523,6 +2650,42 @@ void CGameContext::OnShutdown()
Clear();
}
void CGameContext::LoadMapSettings()
{
IMap *pMap = Kernel()->RequestInterface<IMap>();
int Start, Num;
pMap->GetType(MAPITEMTYPE_INFO, &Start, &Num);
for(int i = Start; i < Start + Num; i++)
{
int ItemID;
CMapItemInfoSettings *pItem = (CMapItemInfoSettings *)pMap->GetItem(i, 0, &ItemID);
int ItemSize = pMap->GetItemSize(i) - 8;
if(!pItem || ItemID != 0)
continue;
if(ItemSize < (int)sizeof(CMapItemInfoSettings))
break;
if(!(pItem->m_Settings > -1))
break;
int Size = pMap->GetUncompressedDataSize(pItem->m_Settings);
char *pSettings = (char *)pMap->GetData(pItem->m_Settings);
char *pNext = pSettings;
while(pNext < pSettings + Size)
{
int StrSize = str_length(pNext) + 1;
Console()->ExecuteLine(pNext, IConsole::CLIENT_ID_GAME);
pNext += StrSize;
}
pMap->UnloadData(pItem->m_Settings);
break;
}
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "maps/%s.map.cfg", g_Config.m_SvMap);
Console()->ExecuteFile(aBuf, IConsole::CLIENT_ID_NO_GAME);
}
void CGameContext::OnSnap(int ClientID)
{
// add tuning to demo

View file

@ -137,6 +137,9 @@ public:
char m_ZoneEnterMsg[NUM_TUNINGZONES][256]; // 0 is used for switching from or to area without tunings
char m_ZoneLeaveMsg[NUM_TUNINGZONES][256];
char m_aDeleteTempfile[128];
void DeleteTempfile();
enum
{
VOTE_ENFORCE_UNKNOWN=0,
@ -188,9 +191,12 @@ public:
//
//void SwapTeams();
void LoadMapSettings();
// engine events
virtual void OnInit();
virtual void OnConsoleInit();
virtual void OnMapChange(char *pNewMapName, int MapNameSize);
virtual void OnShutdown();
virtual void OnTick();

View file

@ -145,10 +145,10 @@ MACRO_CONFIG_INT(SvVoteSpectateRejoindelay, sv_vote_spectate_rejoindelay, 3, 0,
MACRO_CONFIG_INT(SvVoteKick, sv_vote_kick, 1, 0, 1, CFGFLAG_SERVER, "Allow voting to kick players")
MACRO_CONFIG_INT(SvVoteKickMin, sv_vote_kick_min, 0, 0, MAX_CLIENTS, CFGFLAG_SERVER, "Minimum number of players required to start a kick vote")
MACRO_CONFIG_INT(SvVoteKickBantime, sv_vote_kick_bantime, 5, 0, 1440, CFGFLAG_SERVER, "The time to ban a player if kicked by vote. 0 makes it just use kick")
MACRO_CONFIG_INT(SvOldTeleportWeapons, sv_old_teleport_weapons, 0, 0, 1, CFGFLAG_SERVER, "Teleporting of all weapons (deprecated, use special entities instead)");
MACRO_CONFIG_INT(SvOldTeleportHook, sv_old_teleport_hook, 0, 0, 1, CFGFLAG_SERVER, "Hook through teleporter (deprecated, use special entities instead)");
MACRO_CONFIG_INT(SvTeleportHoldHook, sv_teleport_hold_hook, 0, 0, 1, CFGFLAG_SERVER, "Hold hook when teleported");
MACRO_CONFIG_INT(SvTeleportLoseWeapons, sv_teleport_lose_weapons, 0, 0, 1, CFGFLAG_SERVER, "Lose weapons when teleported (useful for some race maps)");
MACRO_CONFIG_INT(SvOldTeleportWeapons, sv_old_teleport_weapons, 0, 0, 1, CFGFLAG_SERVER|CFGFLAG_GAME, "Teleporting of all weapons (deprecated, use special entities instead)");
MACRO_CONFIG_INT(SvOldTeleportHook, sv_old_teleport_hook, 0, 0, 1, CFGFLAG_SERVER|CFGFLAG_GAME, "Hook through teleporter (deprecated, use special entities instead)");
MACRO_CONFIG_INT(SvTeleportHoldHook, sv_teleport_hold_hook, 0, 0, 1, CFGFLAG_SERVER|CFGFLAG_GAME, "Hold hook when teleported");
MACRO_CONFIG_INT(SvTeleportLoseWeapons, sv_teleport_lose_weapons, 0, 0, 1, CFGFLAG_SERVER|CFGFLAG_GAME, "Lose weapons when teleported (useful for some race maps)");
MACRO_CONFIG_INT(SvMapUpdateRate, sv_mapupdaterate, 5, 1, 100, CFGFLAG_SERVER, "64 player id <-> vanilla id players map update rate")

37
src/tools/config_common.h Normal file
View file

@ -0,0 +1,37 @@
#include <base/system.h>
#include <engine/storage.h>
int main(int argc, const char **argv)
{
dbg_logger_stdout();
IStorage *pStorage = CreateLocalStorage();
if(argc == 1)
{
dbg_msg("Usage", "%s FILE1 [ FILE2... ]", argv[0]);
return -1;
}
for(int i = 1; i < argc; i++)
{
char aConfig[2048];
size_t Len = str_length(argv[i]) + 1; // including '\0'
if(Len > sizeof(aConfig))
{
dbg_msg("config_common", "can't process overlong filename '%s'", argv[i]);
continue;
}
if(Len < sizeof(".map") || str_comp(argv[i] + Len - sizeof(".map"), ".map") != 0)
{
dbg_msg("config_common", "can't process non-map file '%s'", argv[i]);
continue;
}
str_copy(aConfig, argv[i], sizeof(aConfig));
aConfig[Len - sizeof(".map")] = 0;
str_append(aConfig, ".cfg", sizeof(aConfig));
dbg_msg("config_common", "processing '%s'", argv[i]);
Process(pStorage, argv[i], aConfig);
}
return 0;
}

View file

@ -0,0 +1,58 @@
#include <base/system.h>
#include <engine/shared/datafile.h>
#include <engine/storage.h>
#include <game/mapitems.h>
void Process(IStorage *pStorage, const char *pMapName, const char *pConfigName)
{
CDataFileReader Map;
if(!Map.Open(pStorage, pMapName, IStorage::TYPE_ALL))
{
dbg_msg("config_retrieve", "error opening map '%s'", pMapName);
return;
}
bool ConfigFound = false;
int Start, Num;
Map.GetType(MAPITEMTYPE_INFO, &Start, &Num);
for(int i = Start; i < Start + Num; i++)
{
int ItemID;
CMapItemInfoSettings *pItem = (CMapItemInfoSettings *)Map.GetItem(i, 0, &ItemID);
int ItemSize = Map.GetItemSize(i) - 8;
if(!pItem || ItemID != 0)
continue;
if(ItemSize < (int)sizeof(CMapItemInfoSettings))
break;
if(!(pItem->m_Settings > -1))
break;
ConfigFound = true;
IOHANDLE Config = pStorage->OpenFile(pConfigName, IOFLAG_WRITE, IStorage::TYPE_ALL);
if(!Config)
{
dbg_msg("config_retrieve", "error opening config for writing '%s'", pConfigName);
return;
}
int Size = Map.GetUncompressedDataSize(pItem->m_Settings);
char *pSettings = (char *)Map.GetData(pItem->m_Settings);
char *pNext = pSettings;
while(pNext < pSettings + Size)
{
int StrSize = str_length(pNext) + 1;
io_write(Config, pNext, StrSize - 1);
io_write_newline(Config);
pNext += StrSize;
}
Map.UnloadData(pItem->m_Settings);
io_close(Config);
break;
}
Map.Close();
if(!ConfigFound)
{
fs_remove(pConfigName);
}
}
#include "config_common.h"

119
src/tools/config_store.cpp Normal file
View file

@ -0,0 +1,119 @@
#include <base/system.h>
#include <base/tl/array.h>
#include <engine/shared/datafile.h>
#include <engine/shared/linereader.h>
#include <engine/storage.h>
#include <game/mapitems.h>
void Process(IStorage *pStorage, const char *pMapName, const char *pConfigName)
{
IOHANDLE File = pStorage->OpenFile(pConfigName, IOFLAG_READ, IStorage::TYPE_ALL);
array<char *> aLines;
char *pSettings = NULL;
if(!File)
{
dbg_msg("config_store", "config '%s' not found", pConfigName);
return;
}
CLineReader LineReader;
LineReader.Init(File);
char *pLine;
int TotalLength = 0;
while((pLine = LineReader.Get()))
{
int Length = str_length(pLine) + 1;
char *pCopy = (char *)mem_alloc(Length, 1);
mem_copy(pCopy, pLine, Length);
aLines.add(pCopy);
TotalLength += Length;
}
pSettings = (char *)mem_alloc(TotalLength, 1);
int Offset = 0;
for(int i = 0; i < aLines.size(); i++)
{
int Length = str_length(aLines[i]) + 1;
mem_copy(pSettings + Offset, aLines[i], Length);
Offset += Length;
mem_free(aLines[i]);
}
CDataFileReader Reader;
Reader.Open(pStorage, pMapName, IStorage::TYPE_ALL);
CDataFileWriter Writer;
Writer.Init();
int SettingsIndex = Reader.NumData();
for(int i = 0; i < Reader.NumItems(); i++)
{
int TypeID;
int ItemID;
int *pData = (int *)Reader.GetItem(i, &TypeID, &ItemID);
// GetItemSize returns item size including header, remove that.
int Size = Reader.GetItemSize(i) - sizeof(int) * 2;
CMapItemInfoSettings MapInfo;
if(TypeID == MAPITEMTYPE_INFO && ItemID == 0)
{
CMapItemInfoSettings *pInfo = (CMapItemInfoSettings *)pData;
if(Size >= (int)sizeof(CMapItemInfoSettings))
{
MapInfo = *pInfo;
pData = (int *)&MapInfo;
Size = sizeof(MapInfo);
if(pInfo->m_Settings > -1)
{
SettingsIndex = pInfo->m_Settings;
char *pMapSettings = (char *)Reader.GetData(SettingsIndex);
int DataSize = Reader.GetUncompressedDataSize(SettingsIndex);
if(DataSize == TotalLength && mem_comp(pSettings, pMapSettings, Size) == 0)
{
dbg_msg("config_store", "configs coincide, not updating map");
return;
}
Reader.UnloadData(pInfo->m_Settings);
}
else
{
MapInfo = *pInfo;
MapInfo.m_Settings = SettingsIndex;
pData = (int *)&MapInfo;
Size = sizeof(MapInfo);
}
}
else
{
*(CMapItemInfo *)&MapInfo = *(CMapItemInfo *)pInfo;
MapInfo.m_Settings = SettingsIndex;
pData = (int *)&MapInfo;
Size = sizeof(MapInfo);
}
}
Writer.AddItem(TypeID, ItemID, Size, pData);
}
for(int i = 0; i < Reader.NumData() || i == SettingsIndex; i++)
{
if(i == SettingsIndex)
{
Writer.AddData(TotalLength, pSettings);
continue;
}
unsigned char *pData = (unsigned char *)Reader.GetData(i);
int Size = Reader.GetUncompressedDataSize(i);
Writer.AddData(Size, pData);
Reader.UnloadData(i);
}
Reader.Close();
if(!Writer.OpenFile(pStorage, pMapName))
{
dbg_msg("config_store", "couldn't open map file '%s' for writing", pMapName);
return;
}
Writer.Finish();
dbg_msg("config_store", "imported settings");
}
#include "config_common.h"