From 417b6e88bb5107a03fe5db468147ef19b68be343 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Mon, 10 Oct 2016 21:36:03 +0300 Subject: [PATCH] 'Start Server' menu Windows implementation was never tested or compiled, but what possibly could go wrong? --- src/base/tl/string.h | 2 +- src/base/vmath.h | 2 +- src/game/client/components/menus.cpp | 12 +- src/game/client/components/menus.h | 5 + src/game/client/components/menus_server.cpp | 238 ++++++++++++++++++++ 5 files changed, 256 insertions(+), 3 deletions(-) create mode 100644 src/game/client/components/menus_server.cpp diff --git a/src/base/tl/string.h b/src/base/tl/string.h index ced25452..dad73fa3 100644 --- a/src/base/tl/string.h +++ b/src/base/tl/string.h @@ -40,7 +40,7 @@ class string_base : private ALLOCATOR public: string_base() { reset(); } string_base(const char *other_str) { copy(other_str, str_length(other_str)); } - string_base(const char *other_str, int length) { copy(other_str, length); } + string_base(const char *other_str, int length) { copy(other_str, length); str[length] = 0; } string_base(const string_base &other) { reset(); copy(other); } ~string_base() { free(); } diff --git a/src/base/vmath.h b/src/base/vmath.h index 0d7a54ad..cbdf1644 100644 --- a/src/base/vmath.h +++ b/src/base/vmath.h @@ -16,7 +16,7 @@ class vector2_base union { T y,v; }; vector2_base() {} - vector2_base(float nx, float ny) + vector2_base(T nx, T ny) { x = nx; y = ny; diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp index 65b6abb1..c76c516f 100644 --- a/src/game/client/components/menus.cpp +++ b/src/game/client/components/menus.cpp @@ -564,7 +564,15 @@ int CMenus::RenderMenubar(CUIRect r) NewPage = PAGE_FAVORITES; } - Box.VSplitLeft(4.0f*5, 0, &Box); + Box.VSplitLeft(10.0f, 0, &Box); + Box.VSplitLeft(100.0f, &Button, &Box); + static int s_ServerButton=0; + if(DoButton_MenuTab(&s_ServerButton, Localize("Server"), m_ActivePage==PAGE_SERVER, &Button, CUI::CORNER_T)) + { + NewPage = PAGE_SERVER; + } + + Box.VSplitLeft(10.0f, 0, &Box); Box.VSplitLeft(100.0f, &Button, &Box); static int s_DemosButton=0; if(DoButton_MenuTab(&s_DemosButton, Localize("Demos"), m_ActivePage==PAGE_DEMOS, &Button, CUI::CORNER_T)) @@ -840,6 +848,8 @@ int CMenus::Render() RenderServerbrowser(MainView); else if(g_Config.m_UiPage == PAGE_LAN) RenderServerbrowser(MainView); + else if(g_Config.m_UiPage == PAGE_SERVER) + ServerCreatorProcess(MainView); else if(g_Config.m_UiPage == PAGE_DEMOS) RenderDemoList(MainView); else if(g_Config.m_UiPage == PAGE_FAVORITES) diff --git a/src/game/client/components/menus.h b/src/game/client/components/menus.h index 8e4b1b83..f53af242 100644 --- a/src/game/client/components/menus.h +++ b/src/game/client/components/menus.h @@ -120,6 +120,7 @@ class CMenus : public CComponent PAGE_INTERNET, PAGE_LAN, PAGE_FAVORITES, + PAGE_SERVER, PAGE_DEMOS, PAGE_SETTINGS, PAGE_SYSTEM, @@ -244,6 +245,10 @@ class CMenus : public CComponent void RenderDemoPlayer(CUIRect MainView); void RenderDemoList(CUIRect MainView); + // found in menus_server.cpp + void ServerCreatorInit(); + void ServerCreatorProcess(CUIRect MainView); + // found in menus_ingame.cpp void RenderGame(CUIRect MainView); void RenderPlayers(CUIRect MainView); diff --git a/src/game/client/components/menus_server.cpp b/src/game/client/components/menus_server.cpp new file mode 100644 index 00000000..cbad30a3 --- /dev/null +++ b/src/game/client/components/menus_server.cpp @@ -0,0 +1,238 @@ + + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include "menus.h" + +#if defined(WIN32) +#include +#include +#include +#include + +static HANDLE serverProcess = -1; +#else +#include +#include +#include +#include +#endif + +static sorted_array s_maplist; +static bool atexitRegistered = false; + +static int MapScan(const char *pName, int IsDir, int DirType, void *pUser) +{ + sorted_array *maplist = (sorted_array *)pUser; + int l = str_length(pName); + if(l < 4 || IsDir || str_comp(pName+l-4, ".map") != 0) + return 0; + maplist->add(string(pName, l - 4)); + return 0; +} + +void CMenus::ServerCreatorInit() +{ + if( s_maplist.size() == 0 ) + { + Storage()->ListDirectory(IStorage::TYPE_ALL, "maps", MapScan, &s_maplist); + } +} + +static void StopServer() +{ +#if defined(WIN32) + if( serverProcess != -1 ) + TerminateProcess(serverProcess, 0); + serverProcess = -1; +#elif defined(__ANDROID__) + system("$SECURE_STORAGE_DIR/busybox killall ninslash_srv"); +#else + system("killall ninslash_srv ninslash_srv_d"); +#endif +} + +static void StartServer(const char *type, const char *map, int bots) +{ + char aBuf[4096]; + str_format(aBuf, sizeof(aBuf), + "sv_port 8303\n" + "sv_name \"%s\"\n" + "sv_gametype %s\n" + "sv_map %s\n" + "sv_maprotation %s\n" + "sv_preferredteamsize %d\n" + "sv_scorelimit 0\n" + "sv_randomweapons 1\n" + "sv_vanillapickups 1\n" + "sv_weapondrops 1\n", + type, type, map, map, bots); + + FILE *ff = fopen("server.cfg", "wb"); + if( !ff ) + return; + fwrite(aBuf, str_length(aBuf), 1, ff); + fclose(ff); + +#if defined(WIN32) + serverProcess = (HANDLE) _spawnl(_P_NOWAIT, "ninslash_srv.exe", "ninslash_srv.exe", "-f", "server.cfg", NULL); +#elif defined(__ANDROID__) + system("$SECURE_STORAGE_DIR/ninslash_srv -f server.cfg >/dev/null 2>&1 &"); +#else + system("./ninslash_srv_d -f server.cfg || ./ninslash_srv -f server.cfg &"); +#endif + + if( !atexitRegistered ) + atexit(&StopServer); + atexitRegistered = true; +} + +static bool ServerStatus() +{ +#if defined(WIN32) + return serverProcess != -1; +#elif defined(__ANDROID__) + int status = system("$SECURE_STORAGE_DIR/busybox sh -c 'ps | grep ninslash_srv'"); + return WEXITSTATUS(status) == 0; +#else + int status = system("ps | grep ninslash_srv"); + return WEXITSTATUS(status) == 0; +#endif +} + +void CMenus::ServerCreatorProcess(CUIRect MainView) +{ + static int s_map = 0; + static int s_bots = 5; + + static int64 LastUpdateTime = 0; + static bool ServerRunning = false; + static bool ServerStarting = false; + + bool ServerStarted = false; + + ServerCreatorInit(); + + // background + RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActive, CUI::CORNER_ALL, 20.0f); + MainView.Margin(20.0f, &MainView); + + MainView.HSplitTop(10, 0, &MainView); + CUIRect MsgBox = MainView; + UI()->DoLabelScaled(&MsgBox, Localize("Local server"), 20.0f, 0); + + if (time_get() / time_freq() > LastUpdateTime + 2) + { + LastUpdateTime = time_get() / time_freq(); + ServerRunning = ServerStatus(); + if (ServerRunning && ServerStarting) + ServerStarted = true; + ServerStarting = false; + } + + MainView.HSplitTop(30, 0, &MainView); + MsgBox = MainView; + UI()->DoLabelScaled(&MsgBox, ServerStarting ? Localize("Server is starting") : + ServerRunning ? Localize("Server is running") : + Localize("Server stopped"), 20.0f, 0); + + MainView.HSplitTop(50, 0, &MainView); + + CUIRect Button; + + MainView.VSplitLeft(50, 0, &Button); + Button.h = 30; + Button.w = 200; + static int s_StopServerButton = 0; + if( ServerRunning && DoButton_Menu(&s_StopServerButton, Localize("Stop server"), 0, &Button)) + { + StopServer(); + LastUpdateTime = time_get() / time_freq() - 2; + } + + static int s_StartDmServerButton = 0; + if( !ServerRunning && !ServerStarting && DoButton_Menu(&s_StartDmServerButton, Localize("Start DM server"), 0, &Button)) + { + StartServer("dm", s_maplist[s_map].cstr(), s_bots); + LastUpdateTime = time_get() / time_freq(); // We do not actually ping the server, just wait 3 seconds + ServerStarting = true; + } + + MainView.VSplitLeft(300, 0, &Button); + Button.h = 30; + Button.w = 200; + static int s_StartInfServerButton = 0; + if( !ServerRunning && !ServerStarting && DoButton_Menu(&s_StartInfServerButton, Localize("Start INF server"), 0, &Button) ) + { + StartServer("inf", s_maplist[s_map].cstr(), s_bots); + LastUpdateTime = time_get() / time_freq(); // We do not actually ping the server, just wait 3 seconds + ServerStarting = true; + } + + MainView.VSplitLeft(550, 0, &Button); + Button.h = 30; + Button.w = 200; + static int s_StartCtfServerButton = 0; + if( !ServerRunning && !ServerStarting && DoButton_Menu(&s_StartCtfServerButton, Localize("Start CTF server"), 0, &Button) ) + { + StartServer("ctf", s_maplist[s_map].cstr(), s_bots); + LastUpdateTime = time_get() / time_freq(); // We do not actually ping the server, just wait 3 seconds + ServerStarting = true; + } + + static int s_JoinServerButton = 0; + if(ServerStarted || (ServerRunning && DoButton_Menu(&s_JoinServerButton, Localize("Join server"), 0, &Button))) + { + strcpy(g_Config.m_UiServerAddress, "127.0.0.1"); + Client()->Connect(g_Config.m_UiServerAddress); + } + + MainView.HSplitTop(60, 0, &MainView); + + MainView.VSplitLeft(50, 0, &MsgBox); + MsgBox.w = 100; + + char aBuf[64]; + str_format(aBuf, sizeof(aBuf), "%s: %i", Localize("Bots"), s_bots); + UI()->DoLabelScaled(&MsgBox, aBuf, 20.0f, -1); + + MainView.VSplitLeft(150, 0, &Button); + Button.h = 30; + Button.w = 500; + + s_bots = (int)(DoScrollbarH(&s_bots, &Button, s_bots/15.0f)*15.0f+0.1f); + + MainView.HSplitTop(60, 0, &MainView); + + static float s_ScrollValue = 0.0f; + UiDoListboxStart(&s_ScrollValue, &MainView, 50.0f, Localize("Map"), "", s_maplist.size(), 1, s_map, s_ScrollValue); + + for(int i = 0; i < s_maplist.size(); ++i) + { + CListboxItem Item = UiDoListboxNextItem(&s_maplist[i], s_map == i); + if(Item.m_Visible) + { + CUIRect Label; + //Item.m_Rect.Margin(5.0f, &Item.m_Rect); + Item.m_Rect.HSplitTop(10.0f, &Item.m_Rect, &Label); + UI()->DoLabelScaled(&Label, s_maplist[i].cstr(), 20.0f, 0); + } + } + + s_map = UiDoListboxEnd(&s_ScrollValue, 0); +}