truelight@543: #include "stdafx.h" truelight@543: #include "ttd.h" tron@1299: #include "debug.h" truelight@543: #include "network.h" truelight@543: #include "hal.h" truelight@543: truelight@543: #ifdef ENABLE_NETWORK truelight@543: truelight@543: #include "gfx.h" truelight@543: #include "window.h" truelight@543: #include "command.h" truelight@543: #include "console.h" truelight@543: #ifdef WIN32 truelight@543: # include /* GetTickCount */ truelight@543: # include truelight@543: #endif truelight@781: truelight@781: #ifdef __OS2__ truelight@781: # include /* gettimeofday */ truelight@781: # include truelight@781: # include truelight@781: # include truelight@781: # define STDIN 0 /* file descriptor for standard input */ truelight@810: truelight@810: extern void OS2_SwitchToConsoleMode(); truelight@781: #endif truelight@781: truelight@543: #ifdef UNIX truelight@543: # include /* gettimeofday */ truelight@543: # include truelight@543: # include truelight@702: # include truelight@543: # define STDIN 0 /* file descriptor for standard input */ truelight@543: #endif bjarni@770: #ifdef __MORPHOS__ tron@1290: /* Voids the fork, option will be disabled for MorphOS build anyway, because tron@1290: * MorphOS doesn't support forking (could only implemented with lots of code tron@1290: * changes here). */ tron@1290: int fork(void) { return -1; } tron@1290: int dup2(int oldd, int newd) { return -1; } bjarni@770: #endif truelight@543: truelight@543: // This file handles all dedicated-server in- and outputs truelight@543: truelight@543: static void *_dedicated_video_mem; truelight@543: truelight@1414: extern bool SafeSaveOrLoad(const char *filename, int mode, int newgm); truelight@1414: extern void SwitchMode(int new_mode); truelight@1414: truelight@702: #ifdef UNIX truelight@704: /* We want to fork our dedicated server */ darkvater@774: void DedicatedFork(void) truelight@704: { truelight@704: /* Fork the program */ tron@1406: pid_t pid = fork(); tron@1406: switch (pid) { truelight@704: case -1: truelight@704: perror("Unable to fork"); truelight@704: exit(1); truelight@704: case 0: truelight@704: // We're the child truelight@704: truelight@704: /* Open the log-file to log all stuff too */ truelight@704: _log_file_fd = fopen(_log_file, "a"); truelight@704: if (!_log_file_fd) { truelight@704: perror("Unable to open logfile"); truelight@704: exit(1); truelight@704: } truelight@704: /* Redirect stdout and stderr to log-file */ truelight@704: if (dup2(fileno(_log_file_fd), fileno(stdout)) == -1) { pasky@1626: perror("Rerouting stdout"); truelight@704: exit(1); truelight@704: } truelight@704: if (dup2(fileno(_log_file_fd), fileno(stderr)) == -1) { pasky@1626: perror("Rerouting stderr"); truelight@704: exit(1); truelight@704: } truelight@704: break; truelight@704: default: truelight@704: // We're the parent truelight@704: printf("Loading dedicated server...\n"); tron@1406: printf(" - Forked to background with pid %d\n", pid); truelight@704: exit(0); truelight@704: } truelight@704: } truelight@704: truelight@702: /* Signal handlers */ truelight@704: static void DedicatedSignalHandler(int sig) truelight@702: { truelight@736: _exit_game = true; truelight@736: signal(sig, DedicatedSignalHandler); truelight@702: } truelight@702: #endif truelight@702: darkvater@1046: #ifdef WIN32 darkvater@1114: #include darkvater@1046: HANDLE hEvent; darkvater@1046: static HANDLE hThread; // Thread to close darkvater@1046: static char _win_console_thread_buffer[200]; darkvater@1046: darkvater@1046: /* Windows Console thread. Just loop and signal when input has been received */ darkvater@1046: void WINAPI CheckForConsoleInput(void) darkvater@1046: { darkvater@1046: while (true) { darkvater@1046: fgets(_win_console_thread_buffer, lengthof(_win_console_thread_buffer), stdin); darkvater@1046: SetEvent(hEvent); // signal input waiting that the line is ready darkvater@1046: } darkvater@1046: } darkvater@1046: darkvater@1046: void CreateWindowsConsoleThread(void) darkvater@1046: { darkvater@1114: static char tbuffer[9]; Darkvater@1762: DWORD dwThreadId; darkvater@1046: /* Create event to signal when console input is ready */ darkvater@1114: hEvent = CreateEvent(NULL, false, false, _strtime(tbuffer)); darkvater@1114: if (hEvent == NULL) darkvater@1114: error("Cannot create console event!"); darkvater@1046: Darkvater@1762: hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CheckForConsoleInput, NULL, 0, &dwThreadId); darkvater@1046: if (hThread == NULL) darkvater@1046: error("Cannot create console thread!"); darkvater@1046: darkvater@1046: DEBUG(misc, 0) ("Windows console thread started..."); darkvater@1046: } darkvater@1046: darkvater@1046: void CloseWindowsConsoleThread(void) darkvater@1046: { darkvater@1046: CloseHandle(hThread); darkvater@1114: CloseHandle(hEvent); darkvater@1046: DEBUG(misc, 0) ("Windows console thread shut down..."); darkvater@1046: } darkvater@1046: darkvater@1046: #endif darkvater@1046: tron@1301: static const char *DedicatedVideoStart(const char * const *parm) tron@1301: { truelight@543: _screen.width = _screen.pitch = _cur_resolution[0]; truelight@543: _screen.height = _cur_resolution[1]; truelight@543: _dedicated_video_mem = malloc(_cur_resolution[0]*_cur_resolution[1]); truelight@543: truelight@543: _debug_net_level = 6; truelight@543: _debug_misc_level = 0; truelight@543: truelight@626: #ifdef WIN32 truelight@626: // For win32 we need to allocate an console (debug mode does the same) truelight@626: CreateConsole(); darkvater@1046: CreateWindowsConsoleThread(); truelight@626: SetConsoleTitle("OpenTTD Dedicated Server"); truelight@626: #endif truelight@626: truelight@810: #ifdef __OS2__ truelight@810: // For OS/2 we also need to switch to console mode instead of PM mode truelight@810: OS2_SwitchToConsoleMode(); truelight@810: #endif truelight@810: truelight@543: DEBUG(misc,0)("Loading dedicated server..."); truelight@543: return NULL; truelight@543: } darkvater@1046: darkvater@1046: static void DedicatedVideoStop(void) darkvater@1046: { darkvater@1046: #ifdef WIN32 darkvater@1046: CloseWindowsConsoleThread(); darkvater@1046: #endif tron@1109: free(_dedicated_video_mem); darkvater@1046: } darkvater@1046: truelight@543: static void DedicatedVideoMakeDirty(int left, int top, int width, int height) {} truelight@543: static bool DedicatedVideoChangeRes(int w, int h) { return false; } truelight@543: tron@1090: #if defined(UNIX) || defined(__OS2__) darkvater@1046: static bool InputWaiting(void) truelight@543: { truelight@543: struct timeval tv; truelight@543: fd_set readfds; truelight@736: byte ret; truelight@543: truelight@543: tv.tv_sec = 0; truelight@543: tv.tv_usec = 1; truelight@543: truelight@543: FD_ZERO(&readfds); truelight@543: FD_SET(STDIN, &readfds); truelight@543: truelight@543: /* don't care about writefds and exceptfds: */ truelight@736: ret = select(STDIN + 1, &readfds, NULL, NULL, &tv); truelight@543: truelight@736: if (ret > 0) truelight@543: return true; darkvater@1046: darkvater@1046: return false; truelight@543: } truelight@543: #else darkvater@1046: static bool InputWaiting(void) truelight@543: { darkvater@1046: if (WaitForSingleObject(hEvent, 1) == WAIT_OBJECT_0) darkvater@1046: return true; tron@1109: darkvater@1046: return false; truelight@543: } truelight@543: #endif truelight@543: darkvater@1046: static void DedicatedHandleKeyInput(void) truelight@704: { truelight@721: static char input_line[200] = ""; truelight@704: darkvater@1046: if (!InputWaiting()) darkvater@1046: return; darkvater@1046: darkvater@1046: if (_exit_game) darkvater@1046: return; darkvater@1046: truelight@781: #if defined(UNIX) || defined(__OS2__) darkvater@1046: fgets(input_line, lengthof(input_line), stdin); darkvater@1046: #else darkvater@1046: strncpy(input_line, _win_console_thread_buffer, lengthof(input_line)); darkvater@1046: #endif truelight@736: darkvater@1046: /* XXX - strtok() does not 'forget' \n\r if it is the first character! */ darkvater@1046: strtok(input_line, "\r\n"); // Forget about the final \n (or \r) darkvater@1046: { /* Remove any special control characters */ darkvater@1046: uint i; darkvater@1046: for (i = 0; i < lengthof(input_line); i++) { darkvater@1046: if (input_line[i] == '\n' || input_line[i] == '\r') // cut missed beginning '\0' darkvater@1046: input_line[i] = '\0'; darkvater@1046: darkvater@1046: if (input_line[i] == '\0') darkvater@1046: break; darkvater@1046: darkvater@1046: if (!IS_INT_INSIDE(input_line[i], ' ', 256)) darkvater@1046: input_line[i] = ' '; truelight@704: } truelight@704: } darkvater@1046: darkvater@1046: IConsoleCmdExec(input_line); // execute command truelight@704: } truelight@704: darkvater@1046: static int DedicatedVideoMainLoop(void) truelight@704: { truelight@543: #ifndef WIN32 truelight@543: struct timeval tim; truelight@543: #endif truelight@543: uint32 next_tick; truelight@543: uint32 cur_ticks; truelight@543: truelight@543: #ifdef WIN32 truelight@543: next_tick = GetTickCount() + 30; truelight@543: #else truelight@543: gettimeofday(&tim, NULL); truelight@543: next_tick = (tim.tv_usec / 1000) + 30 + (tim.tv_sec * 1000); truelight@543: #endif truelight@543: bjarni@770: /* Signal handlers */ truelight@702: #ifdef UNIX truelight@702: signal(SIGTERM, DedicatedSignalHandler); truelight@702: signal(SIGINT, DedicatedSignalHandler); truelight@736: signal(SIGQUIT, DedicatedSignalHandler); truelight@702: #endif truelight@702: truelight@543: // Load the dedicated server stuff truelight@543: _is_network_server = true; truelight@543: _network_dedicated = true; truelight@543: _network_playas = OWNER_SPECTATOR; truelight@543: _local_player = OWNER_SPECTATOR; truelight@1414: truelight@1414: /* If SwitchMode is SM_LOAD, it means that the user used the '-g' options */ truelight@1414: if (_switch_mode != SM_LOAD) { truelight@1414: _switch_mode = SM_NONE; truelight@1414: DoCommandP(0, Random(), InteractiveRandom(), NULL, CMD_GEN_RANDOM_NEW_GAME); truelight@1414: } else { truelight@1414: _switch_mode = SM_NONE; truelight@1414: /* First we need to test if the savegame can be loaded, else we will end up playing the truelight@1414: * intro game... */ truelight@1414: if (!SafeSaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_NORMAL)) { truelight@1414: /* Loading failed, pop out.. */ pasky@1626: DEBUG(net, 0)("Loading requested map failed. Aborting."); truelight@1414: _networking = false; truelight@1414: } else { truelight@1414: /* We can load this game, so go ahead */ truelight@1414: SwitchMode(SM_LOAD); truelight@1414: } truelight@1414: } truelight@1414: truelight@543: // Done loading, start game! truelight@543: truelight@543: if (!_networking) { pasky@1626: DEBUG(net, 1)("Dedicated server could not be launched. Aborting."); truelight@543: return ML_QUIT; truelight@543: } truelight@543: truelight@543: while (true) { truelight@543: InteractiveRandom(); // randomness truelight@543: truelight@702: if (_exit_game) return ML_QUIT; truelight@702: truelight@704: if (!_dedicated_forks) truelight@704: DedicatedHandleKeyInput(); truelight@543: truelight@543: #ifdef WIN32 truelight@543: cur_ticks = GetTickCount(); truelight@543: #else truelight@543: gettimeofday(&tim, NULL); truelight@543: cur_ticks = (tim.tv_usec / 1000) + (tim.tv_sec * 1000); truelight@543: #endif truelight@543: truelight@543: if (cur_ticks >= next_tick) { truelight@1543: next_tick += 30; truelight@543: truelight@543: GameLoop(); truelight@543: _screen.dst_ptr = _dedicated_video_mem; truelight@543: UpdateWindows(); truelight@543: } truelight@543: CSleep(1); truelight@543: } truelight@543: truelight@543: return ML_QUIT; truelight@543: } truelight@543: truelight@543: truelight@543: const HalVideoDriver _dedicated_video_driver = { truelight@543: DedicatedVideoStart, truelight@543: DedicatedVideoStop, truelight@543: DedicatedVideoMakeDirty, truelight@543: DedicatedVideoMainLoop, truelight@543: DedicatedVideoChangeRes, truelight@543: }; truelight@543: truelight@543: #else truelight@543: truelight@543: static void *_dedicated_video_mem; truelight@543: Darkvater@1614: static const char *DedicatedVideoStart(const char * const *parm) tron@1301: { pasky@1626: DEBUG(misc, 0) ("OpenTTD compiled without network support, exiting."); truelight@543: truelight@543: return NULL; truelight@543: } truelight@543: darkvater@774: void DedicatedFork(void) {} darkvater@1046: static void DedicatedVideoStop(void) { free(_dedicated_video_mem); } truelight@543: static void DedicatedVideoMakeDirty(int left, int top, int width, int height) {} truelight@543: static bool DedicatedVideoChangeRes(int w, int h) { return false; } darkvater@1046: static int DedicatedVideoMainLoop(void) { return ML_QUIT; } truelight@543: truelight@543: const HalVideoDriver _dedicated_video_driver = { truelight@543: DedicatedVideoStart, truelight@543: DedicatedVideoStop, truelight@543: DedicatedVideoMakeDirty, truelight@543: DedicatedVideoMainLoop, truelight@543: DedicatedVideoChangeRes, truelight@543: }; truelight@543: truelight@543: #endif /* ENABLE_NETWORK */