Fix: Don't allow right-click to close world generation progress window. (#13084)
[openttd-github.git] / src / video / dedicated_v.cpp
blobc620f441102650f35bc95976c7b47a0c8b21629a
1 /*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
8 /** @file dedicated_v.cpp Dedicated server video 'driver'. */
10 #include "../stdafx.h"
12 #include "../gfx_func.h"
13 #include "../error_func.h"
14 #include "../network/network.h"
15 #include "../network/network_internal.h"
16 #include "../console_func.h"
17 #include "../genworld.h"
18 #include "../fileio_type.h"
19 #include "../fios.h"
20 #include "../blitter/factory.hpp"
21 #include "../company_func.h"
22 #include "../core/random_func.hpp"
23 #include "../saveload/saveload.h"
24 #include "../thread.h"
25 #include "../window_func.h"
26 #include <iostream>
27 #include "dedicated_v.h"
29 #if defined(UNIX)
30 # include <sys/time.h> /* gettimeofday */
31 # include <sys/types.h>
32 # include <unistd.h>
33 # include <signal.h>
34 # define STDIN 0 /* file descriptor for standard input */
36 /* Signal handlers */
37 static void DedicatedSignalHandler(int sig)
39 if (_game_mode == GM_NORMAL && _settings_client.gui.autosave_on_exit) DoExitSave();
40 _exit_game = true;
41 signal(sig, DedicatedSignalHandler);
43 #endif
45 #if defined(_WIN32)
46 # include <windows.h> /* GetTickCount */
47 # include <conio.h>
48 # include <time.h>
49 # include <tchar.h>
50 # include "../os/windows/win32.h"
52 static HANDLE _hInputReady, _hWaitForInputHandling;
53 static HANDLE _hThread; // Thread to close
54 static std::string _win_console_thread_buffer;
56 /* Windows Console thread. Just loop and signal when input has been received */
57 static void WINAPI CheckForConsoleInput()
59 SetCurrentThreadName("ottd:win-console");
61 for (;;) {
62 std::getline(std::cin, _win_console_thread_buffer);
64 /* Signal input waiting that input is read and wait for it being handled. */
65 SignalObjectAndWait(_hInputReady, _hWaitForInputHandling, INFINITE, FALSE);
69 static void CreateWindowsConsoleThread()
71 DWORD dwThreadId;
72 /* Create event to signal when console input is ready */
73 _hInputReady = CreateEvent(nullptr, false, false, nullptr);
74 _hWaitForInputHandling = CreateEvent(nullptr, false, false, nullptr);
75 if (_hInputReady == nullptr || _hWaitForInputHandling == nullptr) UserError("Cannot create console event!");
77 _hThread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)CheckForConsoleInput, nullptr, 0, &dwThreadId);
78 if (_hThread == nullptr) UserError("Cannot create console thread!");
80 Debug(driver, 2, "Windows console thread started");
83 static void CloseWindowsConsoleThread()
85 CloseHandle(_hThread);
86 CloseHandle(_hInputReady);
87 CloseHandle(_hWaitForInputHandling);
88 Debug(driver, 2, "Windows console thread shut down");
91 #endif
93 #include "../safeguards.h"
96 static void *_dedicated_video_mem;
98 /* Whether a fork has been done. */
99 bool _dedicated_forks;
101 extern bool SafeLoad(const std::string &filename, SaveLoadOperation fop, DetailedFileType dft, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = nullptr);
103 static FVideoDriver_Dedicated iFVideoDriver_Dedicated;
106 std::optional<std::string_view> VideoDriver_Dedicated::Start(const StringList &)
108 this->UpdateAutoResolution();
110 int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
111 _dedicated_video_mem = (bpp == 0) ? nullptr : MallocT<uint8_t>(static_cast<size_t>(_cur_resolution.width) * _cur_resolution.height * (bpp / 8));
113 _screen.width = _screen.pitch = _cur_resolution.width;
114 _screen.height = _cur_resolution.height;
115 _screen.dst_ptr = _dedicated_video_mem;
116 ScreenSizeChanged();
117 BlitterFactory::GetCurrentBlitter()->PostResize();
119 #if defined(_WIN32)
120 /* For win32 we need to allocate a console (debug mode does the same) */
121 CreateConsole();
122 CreateWindowsConsoleThread();
123 SetConsoleTitle(L"OpenTTD Dedicated Server");
124 #endif
126 #ifdef _MSC_VER
127 /* Disable the MSVC assertion message box. */
128 _set_error_mode(_OUT_TO_STDERR);
129 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
130 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
131 #endif
133 Debug(driver, 1, "Loading dedicated server");
134 return std::nullopt;
137 void VideoDriver_Dedicated::Stop()
139 #ifdef _WIN32
140 CloseWindowsConsoleThread();
141 #endif
142 free(_dedicated_video_mem);
145 void VideoDriver_Dedicated::MakeDirty(int, int, int, int) {}
146 bool VideoDriver_Dedicated::ChangeResolution(int, int) { return false; }
147 bool VideoDriver_Dedicated::ToggleFullscreen(bool) { return false; }
149 #if defined(UNIX)
150 static bool InputWaiting()
152 struct timeval tv;
153 fd_set readfds;
155 tv.tv_sec = 0;
156 tv.tv_usec = 1;
158 FD_ZERO(&readfds);
159 FD_SET(STDIN, &readfds);
161 /* don't care about writefds and exceptfds: */
162 return select(STDIN + 1, &readfds, nullptr, nullptr, &tv) > 0;
165 #else
167 static bool InputWaiting()
169 return WaitForSingleObject(_hInputReady, 1) == WAIT_OBJECT_0;
172 #endif
174 static void DedicatedHandleKeyInput()
176 if (!InputWaiting()) return;
178 if (_exit_game) return;
180 std::string input_line;
181 #if defined(UNIX)
182 if (!std::getline(std::cin, input_line)) return;
183 #else
184 /* Handle console input, and signal console thread, it can accept input again */
185 std::swap(input_line, _win_console_thread_buffer);
186 SetEvent(_hWaitForInputHandling);
187 #endif
189 /* Remove any trailing \r or \n, and ensure the string is valid. */
190 auto p = input_line.find_last_not_of("\r\n");
191 if (p != std::string::npos) p++;
192 IConsoleCmdExec(StrMakeValid(input_line.substr(0, p)));
195 void VideoDriver_Dedicated::MainLoop()
197 /* Signal handlers */
198 #if defined(UNIX)
199 signal(SIGTERM, DedicatedSignalHandler);
200 signal(SIGINT, DedicatedSignalHandler);
201 signal(SIGQUIT, DedicatedSignalHandler);
202 #endif
204 /* Load the dedicated server stuff */
205 _is_network_server = true;
206 _network_dedicated = true;
207 _current_company = _local_company = COMPANY_SPECTATOR;
209 /* If SwitchMode is SM_LOAD_GAME / SM_START_HEIGHTMAP, it means that the user used the '-g' options */
210 if (_switch_mode != SM_LOAD_GAME && _switch_mode != SM_START_HEIGHTMAP) {
211 StartNewGameWithoutGUI(GENERATE_NEW_SEED);
214 this->is_game_threaded = false;
216 /* Done loading, start game! */
218 while (!_exit_game) {
219 if (!_dedicated_forks) DedicatedHandleKeyInput();
220 this->DrainCommandQueue();
222 this->Tick();
223 this->SleepTillNextTick();