diff --git a/src/engine/map.h b/src/engine/map.h index e9bac7906..a831cd202 100644 --- a/src/engine/map.h +++ b/src/engine/map.h @@ -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; diff --git a/src/engine/shared/map.cpp b/src/engine/shared/map.cpp index 7bda44643..923dc8308 100644 --- a/src/engine/shared/map.cpp +++ b/src/engine/shared/map.cpp @@ -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(); } diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index a03126ac5..e3a718065 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -4096,7 +4096,20 @@ void CEditor::RenderStatusbar(CUIRect View) if(MouseButton == 2) m_ShowEnvelopeEditor = (m_ShowEnvelopeEditor+3)%4; 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) { @@ -4707,6 +4720,110 @@ 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.")) + { + 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.")) + 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); + } + + 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 +4991,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 +5009,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 +5083,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 +5111,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 +5337,8 @@ void CEditorMap::Clean() m_MapInfo.Reset(); + m_lSettings.clear(); + m_pGameLayer = 0x0; m_pGameGroup = 0x0; diff --git a/src/game/editor/editor.h b/src/game/editor/editor.h index 6c0843763..f0162d210 100644 --- a/src/game/editor/editor.h +++ b/src/game/editor/editor.h @@ -376,6 +376,12 @@ public: }; CMapInfo m_MapInfo; + struct CSetting + { + char m_aCommand[64]; + }; + array 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(); diff --git a/src/game/editor/io.cpp b/src/game/editor/io.cpp index 93fad4b7f..d75041d3e 100644 --- a/src/game/editor/io.cpp +++ b/src/game/editor/io.cpp @@ -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,26 @@ 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); + } + Item.m_Settings = df.AddData(Size, pSettings); + mem_free(pSettings); + } + df.AddItem(MAPITEMTYPE_INFO, 0, sizeof(Item), &Item); } @@ -589,9 +609,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 +627,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; + } } } diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index 9f1bbfe75..4acbea0ac 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -2300,6 +2300,8 @@ void CGameContext::OnInit(/*class IKernel *pKernel*/) m_Layers.Init(Kernel()); m_Collision.Init(&m_Layers); + LoadMapSettings(); + // reset everything here //world = new GAMEWORLD; //players = new CPlayer[MAX_CLIENTS]; @@ -2641,6 +2643,37 @@ void CGameContext::OnShutdown() Clear(); } +void CGameContext::LoadMapSettings() +{ + IMap *pMap = Kernel()->RequestInterface(); + 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); + pNext += StrSize; + } + pMap->UnloadData(pItem->m_Settings); + } +} + void CGameContext::OnSnap(int ClientID) { // add tuning to demo diff --git a/src/game/server/gamecontext.h b/src/game/server/gamecontext.h index 7d7e4c146..a306fafdd 100644 --- a/src/game/server/gamecontext.h +++ b/src/game/server/gamecontext.h @@ -191,6 +191,8 @@ public: // //void SwapTeams(); + void LoadMapSettings(); + // engine events virtual void OnInit(); virtual void OnConsoleInit();