2005-07-24 16:12:37 +02:00
/* $Id$ */
2005-07-25 09:16:10 +02:00
# include "../stdafx.h"
2005-07-23 19:22:39 +02:00
# ifdef ENABLE_NETWORK
2005-07-25 18:33:58 +02:00
# include "../openttd.h"
2005-07-25 09:16:10 +02:00
# include "../debug.h"
# include "../functions.h"
# include "../gfx.h"
2007-01-02 18:34:03 +01:00
# include "../network/network.h"
2005-07-25 09:16:10 +02:00
# include "../window.h"
# include "../console.h"
# include "../variables.h"
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
# include "../genworld.h"
2007-06-12 22:24:12 +02:00
# include "../blitter/blitter.hpp"
2005-07-25 18:33:58 +02:00
# include "dedicated_v.h"
2005-07-23 19:22:39 +02:00
2005-10-06 20:28:27 +02:00
# ifdef BEOS_NET_SERVER
# include <net/socket.h>
# endif
2005-07-23 19:22:39 +02:00
# ifdef __OS2__
# include <sys / time.h> /* gettimeofday */
# include <sys / types.h>
# include <unistd.h>
# include <conio.h>
2005-07-23 21:00:56 +02:00
# define INCL_DOS
# include <os2.h>
2005-07-23 19:22:39 +02:00
# define STDIN 0 /* file descriptor for standard input */
2005-08-01 18:31:19 +02:00
/**
2005-07-23 20:46:17 +02:00
* Switches OpenTTD to a console app at run - time , instead of a PM app
* Necessary to see stdout , etc . */
2007-03-07 12:47:46 +01:00
static void OS2_SwitchToConsoleMode ( )
2005-07-23 20:46:17 +02:00
{
PPIB pib ;
PTIB tib ;
DosGetInfoBlocks ( & tib , & pib ) ;
// Change flag from PM to VIO
pib - > pib_ultype = 3 ;
}
2005-07-23 19:22:39 +02:00
# endif
2007-02-16 10:39:32 +01:00
# if defined(UNIX) || defined(PSP)
2005-07-23 19:22:39 +02:00
# include <sys / time.h> /* gettimeofday */
# include <sys / types.h>
# include <unistd.h>
# include <signal.h>
# define STDIN 0 /* file descriptor for standard input */
2007-02-16 10:39:32 +01:00
# if defined(PSP)
# include <sys / fd_set.h>
# include <sys / select.h>
# endif /* PSP */
2005-07-23 19:22:39 +02:00
/* Signal handlers */
static void DedicatedSignalHandler ( int sig )
{
_exit_game = true ;
signal ( sig , DedicatedSignalHandler ) ;
}
# endif
# ifdef WIN32
2005-07-23 20:46:17 +02:00
# include <windows.h> /* GetTickCount */
# include <conio.h>
2005-07-23 19:22:39 +02:00
# include <time.h>
2006-11-28 20:58:13 +01:00
# include <tchar.h>
2006-09-14 22:40:59 +02:00
static HANDLE _hInputReady , _hWaitForInputHandling ;
static HANDLE _hThread ; // Thread to close
2005-07-23 19:22:39 +02:00
static char _win_console_thread_buffer [ 200 ] ;
/* Windows Console thread. Just loop and signal when input has been received */
2007-03-07 12:47:46 +01:00
static void WINAPI CheckForConsoleInput ( )
2005-07-23 19:22:39 +02:00
{
2007-03-09 01:15:43 +01:00
DWORD nb ;
HANDLE hStdin = GetStdHandle ( STD_INPUT_HANDLE ) ;
2005-07-23 19:22:39 +02:00
while ( true ) {
2007-03-09 01:15:43 +01:00
ReadFile ( hStdin , _win_console_thread_buffer , lengthof ( _win_console_thread_buffer ) , & nb , NULL ) ;
2006-09-14 22:40:59 +02:00
/* Signal input waiting that input is read and wait for it being handled
* SignalObjectAndWait ( ) should be used here , but it ' s unsupported in Win98 < */
SetEvent ( _hInputReady ) ;
WaitForSingleObject ( _hWaitForInputHandling , INFINITE ) ;
2005-07-23 19:22:39 +02:00
}
}
2007-03-07 12:47:46 +01:00
static void CreateWindowsConsoleThread ( )
2005-07-23 19:22:39 +02:00
{
DWORD dwThreadId ;
/* Create event to signal when console input is ready */
2006-09-14 22:40:59 +02:00
_hInputReady = CreateEvent ( NULL , false , false , NULL ) ;
_hWaitForInputHandling = CreateEvent ( NULL , false , false , NULL ) ;
if ( _hInputReady = = NULL | | _hWaitForInputHandling = = NULL ) error ( " Cannot create console event! " ) ;
2005-07-23 19:22:39 +02:00
2006-09-14 22:40:59 +02:00
_hThread = CreateThread ( NULL , 0 , ( LPTHREAD_START_ROUTINE ) CheckForConsoleInput , NULL , 0 , & dwThreadId ) ;
if ( _hThread = = NULL ) error ( " Cannot create console thread! " ) ;
2005-07-23 19:22:39 +02:00
2006-12-26 18:36:18 +01:00
DEBUG ( driver , 2 , " Windows console thread started " ) ;
2005-07-23 19:22:39 +02:00
}
2007-03-07 12:47:46 +01:00
static void CloseWindowsConsoleThread ( )
2005-07-23 19:22:39 +02:00
{
2006-09-14 22:40:59 +02:00
CloseHandle ( _hThread ) ;
CloseHandle ( _hInputReady ) ;
CloseHandle ( _hWaitForInputHandling ) ;
2006-12-26 18:36:18 +01:00
DEBUG ( driver , 2 , " Windows console thread shut down " ) ;
2005-07-23 19:22:39 +02:00
}
# endif
2005-07-23 20:46:17 +02:00
2007-06-12 22:24:12 +02:00
static void * _dedicated_video_mem ;
2005-07-23 20:46:17 +02:00
extern bool SafeSaveOrLoad ( const char * filename , int mode , int newgm ) ;
extern void SwitchMode ( int new_mode ) ;
2005-07-23 19:22:39 +02:00
static const char * DedicatedVideoStart ( const char * const * parm )
{
2007-06-12 22:24:12 +02:00
int bpp = BlitterFactoryBase : : GetCurrentBlitter ( ) - > GetScreenDepth ( ) ;
if ( bpp = = 0 ) _dedicated_video_mem = NULL ;
else _dedicated_video_mem = malloc ( _cur_resolution [ 0 ] * _cur_resolution [ 1 ] * ( bpp / 8 ) ) ;
2005-07-23 19:22:39 +02:00
_screen . width = _screen . pitch = _cur_resolution [ 0 ] ;
_screen . height = _cur_resolution [ 1 ] ;
2007-06-12 22:24:12 +02:00
_screen . renderer = RendererFactoryBase : : SelectRenderer ( BlitterFactoryBase : : GetCurrentBlitter ( ) - > GetRenderer ( ) ) ;
if ( _screen . renderer = = NULL ) error ( " Couldn't load the renderer '%s' the selected blitter depends on " , BlitterFactoryBase : : GetCurrentBlitter ( ) - > GetRenderer ( ) ) ;
2005-07-23 19:22:39 +02:00
2006-12-28 20:38:09 +01:00
SetDebugString ( " net=6 " ) ;
2005-07-23 19:22:39 +02:00
# ifdef WIN32
2006-11-28 20:58:13 +01:00
// For win32 we need to allocate a console (debug mode does the same)
2005-07-23 19:22:39 +02:00
CreateConsole ( ) ;
CreateWindowsConsoleThread ( ) ;
2006-11-28 20:58:13 +01:00
SetConsoleTitle ( _T ( " OpenTTD Dedicated Server " ) ) ;
2005-07-23 19:22:39 +02:00
# endif
# ifdef __OS2__
// For OS/2 we also need to switch to console mode instead of PM mode
OS2_SwitchToConsoleMode ( ) ;
# endif
2006-12-26 18:36:18 +01:00
DEBUG ( driver , 1 , " Loading dedicated server " ) ;
2005-07-23 19:22:39 +02:00
return NULL ;
}
2007-03-07 12:47:46 +01:00
static void DedicatedVideoStop ( )
2005-07-23 19:22:39 +02:00
{
# ifdef WIN32
CloseWindowsConsoleThread ( ) ;
# endif
free ( _dedicated_video_mem ) ;
}
static void DedicatedVideoMakeDirty ( int left , int top , int width , int height ) { }
static bool DedicatedVideoChangeRes ( int w , int h ) { return false ; }
static void DedicatedVideoFullScreen ( bool fs ) { }
2007-02-16 10:39:32 +01:00
# if defined(UNIX) || defined(__OS2__) || defined(PSP)
2007-03-07 12:47:46 +01:00
static bool InputWaiting ( )
2005-07-23 19:22:39 +02:00
{
struct timeval tv ;
fd_set readfds ;
tv . tv_sec = 0 ;
tv . tv_usec = 1 ;
FD_ZERO ( & readfds ) ;
FD_SET ( STDIN , & readfds ) ;
/* don't care about writefds and exceptfds: */
2005-07-23 20:46:17 +02:00
return select ( STDIN + 1 , & readfds , NULL , NULL , & tv ) > 0 ;
}
2005-07-23 19:22:39 +02:00
2007-03-07 12:47:46 +01:00
static uint32 GetTime ( )
2005-07-23 20:46:17 +02:00
{
struct timeval tim ;
2005-07-23 19:22:39 +02:00
2005-07-23 20:46:17 +02:00
gettimeofday ( & tim , NULL ) ;
return tim . tv_usec / 1000 + tim . tv_sec * 1000 ;
2005-07-23 19:22:39 +02:00
}
2005-07-23 20:46:17 +02:00
2005-07-23 19:22:39 +02:00
# else
2005-07-23 20:46:17 +02:00
2007-03-07 12:47:46 +01:00
static bool InputWaiting ( )
2005-07-23 19:22:39 +02:00
{
2006-09-14 22:40:59 +02:00
return WaitForSingleObject ( _hInputReady , 1 ) = = WAIT_OBJECT_0 ;
2005-07-23 20:46:17 +02:00
}
2005-07-23 19:22:39 +02:00
2007-03-07 12:47:46 +01:00
static uint32 GetTime ( )
2005-07-23 20:46:17 +02:00
{
return GetTickCount ( ) ;
2005-07-23 19:22:39 +02:00
}
2005-07-23 20:46:17 +02:00
2005-07-23 19:22:39 +02:00
# endif
2007-03-07 12:47:46 +01:00
static void DedicatedHandleKeyInput ( )
2005-07-23 19:22:39 +02:00
{
static char input_line [ 200 ] = " " ;
2006-09-14 22:40:59 +02:00
if ( ! InputWaiting ( ) ) return ;
2005-07-23 19:22:39 +02:00
2006-09-14 22:40:59 +02:00
if ( _exit_game ) return ;
2005-07-23 19:22:39 +02:00
2007-02-16 10:39:32 +01:00
# if defined(UNIX) || defined(__OS2__) || defined(PSP)
2006-10-19 11:39:29 +02:00
if ( fgets ( input_line , lengthof ( input_line ) , stdin ) = = NULL ) return ;
2005-07-23 19:22:39 +02:00
# else
2006-09-14 22:40:59 +02:00
/* Handle console input, and singal console thread, it can accept input again */
strncpy ( input_line , _win_console_thread_buffer , lengthof ( input_line ) ) ;
SetEvent ( _hWaitForInputHandling ) ;
2005-07-23 19:22:39 +02:00
# endif
/* XXX - strtok() does not 'forget' \n\r if it is the first character! */
strtok ( input_line , " \r \n " ) ; // Forget about the final \n (or \r)
{ /* Remove any special control characters */
uint i ;
for ( i = 0 ; i < lengthof ( input_line ) ; i + + ) {
if ( input_line [ i ] = = ' \n ' | | input_line [ i ] = = ' \r ' ) // cut missed beginning '\0'
input_line [ i ] = ' \0 ' ;
if ( input_line [ i ] = = ' \0 ' )
break ;
if ( ! IS_INT_INSIDE ( input_line [ i ] , ' ' , 256 ) )
input_line [ i ] = ' ' ;
}
}
IConsoleCmdExec ( input_line ) ; // execute command
}
2007-03-07 12:47:46 +01:00
static void DedicatedVideoMainLoop ( )
2005-07-23 19:22:39 +02:00
{
2007-01-10 16:00:20 +01:00
uint32 cur_ticks = GetTime ( ) ;
uint32 next_tick = cur_ticks + 30 ;
2005-07-23 19:22:39 +02:00
/* Signal handlers */
2007-02-16 10:39:32 +01:00
# if defined(UNIX) || defined(PSP)
2005-07-23 19:22:39 +02:00
signal ( SIGTERM , DedicatedSignalHandler ) ;
signal ( SIGINT , DedicatedSignalHandler ) ;
signal ( SIGQUIT , DedicatedSignalHandler ) ;
# endif
// Load the dedicated server stuff
_is_network_server = true ;
_network_dedicated = true ;
2006-10-14 17:49:43 +02:00
_network_playas = PLAYER_SPECTATOR ;
_local_player = PLAYER_SPECTATOR ;
2005-07-23 19:22:39 +02:00
/* If SwitchMode is SM_LOAD, it means that the user used the '-g' options */
if ( _switch_mode ! = SM_LOAD ) {
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
StartNewGameWithoutGUI ( GENERATE_NEW_SEED ) ;
SwitchMode ( _switch_mode ) ;
2005-07-23 19:22:39 +02:00
_switch_mode = SM_NONE ;
} else {
_switch_mode = SM_NONE ;
/* First we need to test if the savegame can be loaded, else we will end up playing the
* intro game . . . */
if ( ! SafeSaveOrLoad ( _file_to_saveload . name , _file_to_saveload . mode , GM_NORMAL ) ) {
/* Loading failed, pop out.. */
2006-12-26 18:36:18 +01:00
DEBUG ( net , 0 , " Loading requested map failed, aborting " ) ;
2005-07-23 19:22:39 +02:00
_networking = false ;
} else {
/* We can load this game, so go ahead */
SwitchMode ( SM_LOAD ) ;
}
}
// Done loading, start game!
if ( ! _networking ) {
2006-12-26 18:36:18 +01:00
DEBUG ( net , 0 , " Dedicated server could not be started, aborting " ) ;
2005-07-29 18:40:29 +02:00
return ;
2005-07-23 19:22:39 +02:00
}
2005-07-29 18:40:29 +02:00
while ( ! _exit_game ) {
2007-01-10 16:00:20 +01:00
uint32 prev_cur_ticks = cur_ticks ; // to check for wrapping
2005-07-23 19:22:39 +02:00
InteractiveRandom ( ) ; // randomness
if ( ! _dedicated_forks )
DedicatedHandleKeyInput ( ) ;
2005-07-23 20:46:17 +02:00
cur_ticks = GetTime ( ) ;
2007-01-10 16:00:20 +01:00
if ( cur_ticks > = next_tick | | cur_ticks < prev_cur_ticks ) {
next_tick = cur_ticks + 30 ;
2005-07-23 19:22:39 +02:00
GameLoop ( ) ;
2007-05-14 17:20:50 +02:00
_screen . dst_ptr = _dedicated_video_mem ;
2005-07-23 19:22:39 +02:00
UpdateWindows ( ) ;
}
CSleep ( 1 ) ;
}
}
const HalVideoDriver _dedicated_video_driver = {
DedicatedVideoStart ,
DedicatedVideoStop ,
DedicatedVideoMakeDirty ,
DedicatedVideoMainLoop ,
DedicatedVideoChangeRes ,
DedicatedVideoFullScreen ,
} ;
2005-07-25 18:33:58 +02:00
# endif /* ENABLE_NETWORK */