From 3d7e8bf7af864cf35ed19129984d629a7a10ad76 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Sat, 21 Jan 2023 12:05:50 -0600 Subject: [PATCH] Merged https://github.com/ZDoom/gzdoom/pull/1927 (Host/Join CCMDs) --- src/common/platform/win32/base_sysfb.h | 4 +- src/common/platform/win32/i_main.cpp | 12 ++ src/common/platform/win32/i_mainwindow.cpp | 57 +++++- src/common/platform/win32/i_mainwindow.h | 2 +- .../rendering/vulkan/shaders/vk_shader.cpp | 2 +- .../rendering/vulkan/textures/vk_texture.cpp | 2 +- src/d_main.cpp | 173 +++++++++++++++++- src/d_net.cpp | 118 ++++++++++++ src/d_net.h | 17 ++ src/r_data/gldefs.cpp | 7 +- 10 files changed, 372 insertions(+), 22 deletions(-) diff --git a/src/common/platform/win32/base_sysfb.h b/src/common/platform/win32/base_sysfb.h index 9db8f8420..4b1e0c4f5 100644 --- a/src/common/platform/win32/base_sysfb.h +++ b/src/common/platform/win32/base_sysfb.h @@ -23,13 +23,13 @@ public: void ToggleFullscreen(bool yes) override; void SetWindowSize(int client_w, int client_h); + void PositionWindow(bool fullscreen, bool initialcall = false); // RicardoLuis0: this needs to be public for proper fullscreen handling in netgame restarts + protected: void GetCenteredPos(int in_w, int in_h, int &winx, int &winy, int &winw, int &winh, int &scrwidth, int &scrheight); void KeepWindowOnScreen(int &winx, int &winy, int winw, int winh, int scrwidth, int scrheight); - void PositionWindow(bool fullscreen, bool initialcall = false); - float m_Gamma, m_Brightness, m_Contrast; uint16_t m_origGamma[768]; bool m_Fullscreen = false; diff --git a/src/common/platform/win32/i_main.cpp b/src/common/platform/win32/i_main.cpp index c28a3ff4b..99c1c495f 100644 --- a/src/common/platform/win32/i_main.cpp +++ b/src/common/platform/win32/i_main.cpp @@ -79,6 +79,7 @@ #include "printf.h" #include "i_mainwindow.h" +#include "base_sysfb.h" // MACROS ------------------------------------------------------------------ @@ -314,6 +315,17 @@ void I_ShowFatalError(const char *msg) } } +void I_NetRestartShowConsole() +{ + if(vid_fullscreen) + { + static_cast(screen)->PositionWindow(false, true); + screen->Update(); + vid_fullscreen = true; // vid_fullscreen is forced to false by PositionWindow + } + mainwindow.RestoreConView(true); +} + // Here is how the error logging system works. // // To catch exceptions that occur in secondary threads, CatchAllExceptions is diff --git a/src/common/platform/win32/i_mainwindow.cpp b/src/common/platform/win32/i_mainwindow.cpp index 5b246e457..afaf66d78 100644 --- a/src/common/platform/win32/i_mainwindow.cpp +++ b/src/common/platform/win32/i_mainwindow.cpp @@ -95,20 +95,22 @@ int MainWindow::GetGameTitleWindowHeight() // Sets the main WndProc, hides all the child windows, and starts up in-game input. void MainWindow::ShowGameView() { - if (GetWindowLongPtr(Window, GWLP_USERDATA) == 0) + if (GetWindowLongPtr(Window, GWLP_USERDATA) != 1) { - SetWindowLongPtr(Window, GWLP_USERDATA, 1); SetWindowLongPtr(Window, GWLP_WNDPROC, (LONG_PTR)WndProc); ShowWindow(ConWindow, SW_HIDE); ShowWindow(ProgressBar, SW_HIDE); ConWindowHidden = true; ShowWindow(GameTitleWindow, SW_HIDE); - I_InitInput(Window); + + if (GetWindowLongPtr(Window, GWLP_USERDATA) != 2) I_InitInput(Window); + + SetWindowLongPtr(Window, GWLP_USERDATA, 1); } } // Returns the main window to its startup state. -void MainWindow::RestoreConView() +void MainWindow::RestoreConView(bool netgame_restart) { HDC screenDC = GetDC(0); int dpi = GetDeviceCaps(screenDC, LOGPIXELSX); @@ -118,25 +120,62 @@ void MainWindow::RestoreConView() // Make sure the window has a frame in case it was fullscreened. SetWindowLongPtr(Window, GWL_STYLE, WS_VISIBLE | WS_OVERLAPPEDWINDOW); - if (GetWindowLong(Window, GWL_EXSTYLE) & WS_EX_TOPMOST) + if(netgame_restart) { - SetWindowPos(Window, HWND_BOTTOM, 0, 0, width, height, SWP_DRAWFRAME | SWP_NOCOPYBITS | SWP_NOMOVE); - SetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE); + DEVMODE displaysettings; + // Many Windows structures that specify their size do so with the first + // element. DEVMODE is not one of those structures. + memset (&displaysettings, 0, sizeof(displaysettings)); + displaysettings.dmSize = sizeof(displaysettings); + EnumDisplaySettings (NULL, ENUM_CURRENT_SETTINGS, &displaysettings); + int x = (displaysettings.dmPelsWidth - width) / 2; + int y = (displaysettings.dmPelsHeight - height) / 2; + + // Make sure the window has a frame in case it was fullscreened. + SetWindowLongPtr(Window, GWL_STYLE, WS_VISIBLE | WS_OVERLAPPEDWINDOW); + if (GetWindowLong(Window, GWL_EXSTYLE) & WS_EX_TOPMOST) + { + SetWindowPos(Window, HWND_BOTTOM, x, y, width, height, SWP_DRAWFRAME | SWP_NOCOPYBITS); + SetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE); + } + else + { + SetWindowPos(Window, NULL, x, y, width, height, SWP_DRAWFRAME | SWP_NOCOPYBITS | SWP_NOZORDER); + } } else { - SetWindowPos(Window, NULL, 0, 0, width, height, SWP_DRAWFRAME | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOZORDER); + if (GetWindowLong(Window, GWL_EXSTYLE) & WS_EX_TOPMOST) + { + SetWindowPos(Window, HWND_BOTTOM, 0, 0, width, height, SWP_DRAWFRAME | SWP_NOCOPYBITS | SWP_NOMOVE); + SetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE); + } + else + { + SetWindowPos(Window, NULL, 0, 0, width, height, SWP_DRAWFRAME | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOZORDER); + } } SetWindowLongPtr(Window, GWLP_WNDPROC, (LONG_PTR)LConProc); ShowWindow(ConWindow, SW_SHOW); ConWindowHidden = false; ShowWindow(GameTitleWindow, SW_SHOW); - I_ShutdownInput(); // Make sure the mouse pointer is available. + + if(netgame_restart) + { // Make sure the input system isn't reset + I_CheckNativeMouse(true, false); + } + else + { // Make sure the mouse pointer is available. + I_ShutdownInput(); + } // Make sure the progress bar isn't visible. DeleteStartupScreen(); FlushBufferedConsoleStuff(); + + // Make sure the input system isn't reset + SetWindowLongPtr(Window, GWLP_USERDATA, 2); } // Shows an error message, preferably in the main window, but it can use a normal message box too. diff --git a/src/common/platform/win32/i_mainwindow.h b/src/common/platform/win32/i_mainwindow.h index 2adea7bfa..913d8d9d9 100644 --- a/src/common/platform/win32/i_mainwindow.h +++ b/src/common/platform/win32/i_mainwindow.h @@ -17,7 +17,7 @@ public: void Create(const FString& title, int x, int y, int width, int height); void ShowGameView(); - void RestoreConView(); + void RestoreConView(bool netgame_restart = false); void ShowErrorPane(const char* text); void CheckForRestart(); diff --git a/src/common/rendering/vulkan/shaders/vk_shader.cpp b/src/common/rendering/vulkan/shaders/vk_shader.cpp index 25b585531..961ad7e9f 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.cpp +++ b/src/common/rendering/vulkan/shaders/vk_shader.cpp @@ -479,7 +479,7 @@ FString VkShaderManager::LoadPrivateShaderLump(const char *lumpname) VkPPShader* VkShaderManager::GetVkShader(PPShader* shader) { - if (!shader->Backend) + if (!shader->Backend || !static_cast(shader->Backend.get())->VertexShader) shader->Backend = std::make_unique(fb, shader); return static_cast(shader->Backend.get()); } diff --git a/src/common/rendering/vulkan/textures/vk_texture.cpp b/src/common/rendering/vulkan/textures/vk_texture.cpp index b7d88a08a..046d783eb 100644 --- a/src/common/rendering/vulkan/textures/vk_texture.cpp +++ b/src/common/rendering/vulkan/textures/vk_texture.cpp @@ -136,7 +136,7 @@ VkFormat VkTextureManager::GetTextureFormat(PPTexture* texture) VkPPTexture* VkTextureManager::GetVkTexture(PPTexture* texture) { - if (!texture->Backend) + if (!texture->Backend || !static_cast(texture->Backend.get())->TexImage.View) texture->Backend = std::make_unique(fb, texture); return static_cast(texture->Backend.get()); } diff --git a/src/d_main.cpp b/src/d_main.cpp index ce49a75cb..2ef6570e5 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -142,6 +142,14 @@ void Local_Job_Init(); // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- extern void I_SetWindowTitle(const char* caption); + +#ifdef _WIN32 + extern void I_NetRestartShowConsole(); + //RicardoLuis0: TODO fix host/join CCMD startup window on non-windows platforms +#else + #define I_NetRestartShowConsole() +#endif + extern void ReadStatistics(); extern void M_SetDefaultMode (); extern void G_NewInit (); @@ -166,6 +174,7 @@ void G_BuildTiccmd (ticcmd_t* cmd); void D_DoAdvanceDemo (); void D_LoadWadSettings (); void ParseGLDefs(); +void ClearGLDefs(); void DrawFullscreenSubtitle(FFont* font, const char *text); void D_Cleanup(); void FreeSBarInfoScript(); @@ -332,6 +341,7 @@ const char *Subtitle; bool nospriterename; FString lastIWAD; int restart = 0; +bool restart_multiplayer = false; extern bool AppActive; bool playedtitlemusic; @@ -3049,6 +3059,9 @@ static int D_InitGame(const FIWADInfo* iwad_info, TArray& allwads, TArr gameinfo.nokeyboardcheats = iwad_info->nokeyboardcheats; gameinfo.ConfigName = iwad_info->Configname; + // make sure shaders/etc aren't loaded twice when restarting the engine + ClearGLDefs(); + const char *v = Args->CheckValue("-rngseed"); if (v) { @@ -3173,7 +3186,7 @@ static int D_InitGame(const FIWADInfo* iwad_info, TArray& allwads, TArr CT_Init (); - if (!restart) + if (!restart || restart_multiplayer) { if (!batchrun) Printf ("I_Init: Setting up machine state.\n"); CheckCPUID(&CPU); @@ -3215,7 +3228,7 @@ static int D_InitGame(const FIWADInfo* iwad_info, TArray& allwads, TArr } if (!batchrun) Printf ("ST_Init: Init startup screen.\n"); - if (!restart) + if (!restart || restart_multiplayer) { StartWindow = FStartupScreen::CreateInstance (TexMan.GuesstimateNumTextures() + 5, StartScreen == nullptr); } @@ -3382,7 +3395,7 @@ static int D_InitGame(const FIWADInfo* iwad_info, TArray& allwads, TArr } } - if (!restart) + if (!restart || restart_multiplayer) { if (!batchrun) Printf ("D_CheckNetGame: Checking network game status.\n"); if (StartScreen) StartScreen->LoadingStatus ("Checking network game status.", 0x3f); @@ -3409,7 +3422,7 @@ static int D_InitGame(const FIWADInfo* iwad_info, TArray& allwads, TArr if (cl_customizeinvulmap) R_UpdateInvulnerabilityColormap(); - if (!restart) + if (!restart || restart_multiplayer) { // start the apropriate game based on parms auto v = Args->CheckValue ("-record"); @@ -3462,7 +3475,7 @@ static int D_InitGame(const FIWADInfo* iwad_info, TArray& allwads, TArr } v = Args->CheckValue("-playdemo"); - if (v != NULL) + if (v && !restart_multiplayer) { singledemo = true; // quit after one demo G_DeferedPlayDemo (v); @@ -3470,7 +3483,7 @@ static int D_InitGame(const FIWADInfo* iwad_info, TArray& allwads, TArr else { v = Args->CheckValue("-timedemo"); - if (v) + if (v && !restart_multiplayer) { G_TimeDemo(v); } @@ -3524,7 +3537,7 @@ static int D_InitGame(const FIWADInfo* iwad_info, TArray& allwads, TArr D_StartTitle (); // start up intro loop setmodeneeded = false; // This may be set to true here, but isn't needed for a restart } - + restart_multiplayer = false; staticEventManager.OnEngineInitialize(); return 0; } @@ -3646,6 +3659,10 @@ static int D_DoomMain_Internal (void) if (restart) { C_InitConsole(SCREENWIDTH, SCREENHEIGHT, false); + if(restart_multiplayer) + { + I_NetRestartShowConsole(); + } } nospriterename = false; @@ -3858,6 +3875,148 @@ UNSAFE_CCMD(restart) wantToRestart = true; } +UNSAFE_CCMD(host) +{ + if(netgame || multiplayer) + { + Printf ("You must not be in a net game when hosting\n"); + return; + } + int numplayers = 0; + FString map = ""; + int ticdup = -1; + int port = -1; + int skill = -1; + FString loadsave = ""; + int flags = 0; + + const auto n = argv.argc(); + + if(n <= 1) + { + Printf ("Not enough arguments for host\n"); + return; + } + + numplayers = atoi(argv[1]); + + for(int i = 2; i < n; i++) + { + FString arg(argv[i]); + + auto sep = arg.IndexOf('='); + if(sep == -1) + { + if(arg.CompareNoCase("EXTRATIC") == 0) + { + flags |= MP_EXTRATIC; + } + else if(arg.CompareNoCase("PACKET_SERVER") == 0) + { + flags |= MP_PACKET_SERVER; + } + else if(arg.CompareNoCase("DEATHMATCH") == 0) + { + flags |= MP_DEATHMATCH; + } + else if(arg.CompareNoCase("ALTDEATH") == 0) + { + flags |= MP_ALTDEATH; + } + else if(arg.CompareNoCase("NOMONSTERS") == 0) + { + flags |= MP_NOMONSTERS; + } + else + { + Printf ("Invalid argument for host: %s\n",arg.GetChars()); + return; + } + } + else + { + if(strnicmp(arg.GetChars(),"MAP",sep) == 0) + { + map = FString(arg.GetChars() + sep + 1); + } + else if(strnicmp(arg.GetChars(),"LOADSAVE",sep) == 0) + { + loadsave = FString(arg.GetChars() + sep + 1); + } + else if(strnicmp(arg.GetChars(),"PORT",sep) == 0) + { + port = atoi(arg.GetChars() + sep + 1); + } + else if(strnicmp(arg.GetChars(),"SKILL",sep) == 0) + { + skill = atoi(arg.GetChars() + sep + 1); + } + else if(strnicmp(arg.GetChars(),"TICDUP",sep) == 0) + { + ticdup = atoi(arg.GetChars() + sep + 1); + } + else + { + Printf ("Invalid argument for host: %s\n",arg.GetChars()); + return; + } + } + } + D_RestartHostMultiplayer(numplayers,map,ticdup,port,skill,loadsave,flags); + +} + +UNSAFE_CCMD(join) +{ + if(netgame || multiplayer) + { + Printf ("You must not be in a net game when joining\n"); + return; + } + FString addr = ""; + int port = -1; + FString loadsave = ""; + + const auto n = argv.argc(); + + if(n <= 1) + { + Printf ("Not enough arguments for host\n"); + return; + } + + addr = FString(argv[1]); + + for(int i = 2; i < n; i++) + { + FString arg(argv[i]); + + auto sep = arg.IndexOf('='); + if(sep == -1) + { + Printf ("Invalid argument for host: %s\n",arg.GetChars()); + return; + } + else + { + if(strnicmp(arg.GetChars(),"LOADSAVE",sep) == 0) + { + loadsave = FString(arg.GetChars() + sep + 1); + } + else if(strnicmp(arg.GetChars(),"PORT",sep) == 0) + { + port = atoi(arg.GetChars() + sep + 1); + } + else + { + Printf ("Invalid argument for host: %s\n",arg.GetChars()); + return; + } + } + } + D_RestartJoinMultiplayer(addr,port,loadsave); +} + DEFINE_FIELD_X(InputEventData, event_t, type) DEFINE_FIELD_X(InputEventData, event_t, subtype) DEFINE_FIELD_X(InputEventData, event_t, data1) diff --git a/src/d_net.cpp b/src/d_net.cpp index e83b06939..ea86c489c 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -1802,6 +1802,124 @@ void D_QuitNetGame (void) fclose (debugfile); } + + +extern bool wantToRestart; +extern bool restart_multiplayer; + +void D_RestartHostMultiplayer(int numplayers, FString map, int ticdup, int port, int skill, FString loadsave, int flags) +{ + if(netgame || multiplayer) + { + I_FatalError ("You must not be in a net game before starting one"); + } + + Args->RemoveArgs("-join"); + Args->RemoveArgs("-host"); + Args->RemoveArgs("-net"); + Args->RemoveArgs("-netmode"); + Args->RemoveArgs("-port"); + Args->RemoveArgs("-dup"); + Args->RemoveArgs("-extratic"); + Args->RemoveArgs("-deathmatch"); + Args->RemoveArgs("-nomonsters"); + Args->RemoveArgs("+map"); + + FString tmp; + + tmp.Format("%d",numplayers); + Args->AppendArg("-host"); + Args->AppendArg(tmp); + + if(!map.IsEmpty()) { + Args->AppendArg("+map"); + Args->AppendArg(map); + } + if(ticdup > 0) + { + tmp.Format("%d",ticdup); + Args->AppendArg("-dup"); + Args->AppendArg(tmp); + } + if(port >= 0) + { + tmp.Format("%d",port); + Args->AppendArg("-port"); + Args->AppendArg(tmp); + } + if(skill >= 0) + { + tmp.Format("%d",skill); + Args->AppendArg("-skill"); + Args->AppendArg(tmp); + } + if(!loadsave.IsEmpty()) + { + Args->AppendArg("+loadsave"); + Args->AppendArg(loadsave); + } + if(flags & MP_EXTRATIC) + { + Args->AppendArg("-extratic"); + } + if(flags & MP_PACKET_SERVER) + { + Args->AppendArg("-netmode"); + Args->AppendArg("1"); + } + if(flags & MP_DEATHMATCH) + { + Args->AppendArg("-deathmatch"); + if(flags & MP_ALTDEATH) + { + Args->AppendArg("-altdeath"); + } + } + if(flags & MP_NOMONSTERS) + { + Args->AppendArg("-nomonsters"); + } + wantToRestart = true; + restart_multiplayer = true; +} + +void D_RestartJoinMultiplayer(const char * host_addr, int port, FString loadsave) +{ + if(netgame || multiplayer) + { + I_FatalError ("You must not be in a net game before starting one"); + } + + Args->RemoveArgs("-join"); + Args->RemoveArgs("-host"); + Args->RemoveArgs("-net"); + Args->RemoveArgs("-netmode"); + Args->RemoveArgs("-port"); + Args->RemoveArgs("-dup"); + Args->RemoveArgs("-extratic"); + Args->RemoveArgs("-deathmatch"); + Args->RemoveArgs("-nomonsters"); + Args->RemoveArgs("+map"); + + Args->AppendArg("-join"); + Args->AppendArg(host_addr); + if(port >= 0) + { + FString tmp; + tmp.Format("%d",port); + Args->AppendArg("-port"); + Args->AppendArg(tmp); + } + if(!loadsave.IsEmpty()) + { + Args->AppendArg("+loadsave"); + Args->AppendArg(loadsave); + } + wantToRestart = true; + restart_multiplayer = true; +} + + // Forces playsim processing time to be consistent across frames. // This improves interpolation for frames in between tics. // diff --git a/src/d_net.h b/src/d_net.h index 309ea4d34..668db5edd 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -56,6 +56,23 @@ void NetUpdate (void); // to notify of game exit void D_QuitNetGame (void); + +enum EMultiplayerHostFlags +{ + MP_EXTRATIC = 1, + MP_PACKET_SERVER = 2, + MP_DEATHMATCH = 4, + MP_ALTDEATH = 8, + MP_NOMONSTERS = 16, +}; + + +void D_RestartHostMultiplayer(int numplayers, FString map= "", int ticdup = -1, int port = -1, int skill = -1, FString loadsave = "", int flags = 0); + +void D_RestartJoinMultiplayer(const char * host_addr, int port = -1, FString loadsave = ""); + + + //? how many ticks to run? void TryRunTics (void); diff --git a/src/r_data/gldefs.cpp b/src/r_data/gldefs.cpp index 9718c77ec..6fe663694 100644 --- a/src/r_data/gldefs.cpp +++ b/src/r_data/gldefs.cpp @@ -2016,7 +2016,6 @@ void LoadGLDefs(const char *defsLump) InitializeActorLights(LightAssociations); } - //========================================================================== // // @@ -2053,3 +2052,9 @@ void ParseGLDefs() ParseVavoomSkybox(); LoadGLDefs(defsLump); } + +void ClearGLDefs() +{ + PostProcessShaders.Clear(); + usershaders.Clear(); +} \ No newline at end of file