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/>.
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"
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"
27 #include "dedicated_v.h"
30 # include <sys/time.h> /* gettimeofday */
31 # include <sys/types.h>
34 # define STDIN 0 /* file descriptor for standard input */
37 static void DedicatedSignalHandler(int sig
)
39 if (_game_mode
== GM_NORMAL
&& _settings_client
.gui
.autosave_on_exit
) DoExitSave();
41 signal(sig
, DedicatedSignalHandler
);
46 # include <windows.h> /* GetTickCount */
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");
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()
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");
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 const char *VideoDriver_Dedicated::Start(const StringList
&)
108 this->UpdateAutoResolution();
110 int bpp
= BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
111 _dedicated_video_mem
= (bpp
== 0) ? nullptr : MallocT
<byte
>(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
;
117 BlitterFactory::GetCurrentBlitter()->PostResize();
120 /* For win32 we need to allocate a console (debug mode does the same) */
122 CreateWindowsConsoleThread();
123 SetConsoleTitle(L
"OpenTTD Dedicated Server");
127 /* Disable the MSVC assertion message box. */
128 _set_error_mode(_OUT_TO_STDERR
);
131 Debug(driver
, 1, "Loading dedicated server");
135 void VideoDriver_Dedicated::Stop()
138 CloseWindowsConsoleThread();
140 free(_dedicated_video_mem
);
143 void VideoDriver_Dedicated::MakeDirty(int, int, int, int) {}
144 bool VideoDriver_Dedicated::ChangeResolution(int, int) { return false; }
145 bool VideoDriver_Dedicated::ToggleFullscreen(bool) { return false; }
148 static bool InputWaiting()
157 FD_SET(STDIN
, &readfds
);
159 /* don't care about writefds and exceptfds: */
160 return select(STDIN
+ 1, &readfds
, nullptr, nullptr, &tv
) > 0;
165 static bool InputWaiting()
167 return WaitForSingleObject(_hInputReady
, 1) == WAIT_OBJECT_0
;
172 static void DedicatedHandleKeyInput()
174 if (!InputWaiting()) return;
176 if (_exit_game
) return;
178 std::string input_line
;
180 if (!std::getline(std::cin
, input_line
)) return;
182 /* Handle console input, and signal console thread, it can accept input again */
183 std::swap(input_line
, _win_console_thread_buffer
);
184 SetEvent(_hWaitForInputHandling
);
187 /* Remove any trailing \r or \n, and ensure the string is valid. */
188 auto p
= input_line
.find_last_not_of("\r\n");
189 if (p
!= std::string::npos
) p
++;
190 IConsoleCmdExec(StrMakeValid(input_line
.substr(0, p
)));
193 void VideoDriver_Dedicated::MainLoop()
195 /* Signal handlers */
197 signal(SIGTERM
, DedicatedSignalHandler
);
198 signal(SIGINT
, DedicatedSignalHandler
);
199 signal(SIGQUIT
, DedicatedSignalHandler
);
202 /* Load the dedicated server stuff */
203 _is_network_server
= true;
204 _network_dedicated
= true;
205 _current_company
= _local_company
= COMPANY_SPECTATOR
;
207 /* If SwitchMode is SM_LOAD_GAME / SM_START_HEIGHTMAP, it means that the user used the '-g' options */
208 if (_switch_mode
!= SM_LOAD_GAME
&& _switch_mode
!= SM_START_HEIGHTMAP
) {
209 StartNewGameWithoutGUI(GENERATE_NEW_SEED
);
212 this->is_game_threaded
= false;
214 /* Done loading, start game! */
216 while (!_exit_game
) {
217 if (!_dedicated_forks
) DedicatedHandleKeyInput();
218 this->DrainCommandQueue();
220 ChangeGameSpeed(_ddc_fastforward
);
222 this->SleepTillNextTick();