diff options
| author | Franklin Wei <git@fwei.tk> | 2018-02-11 15:34:30 -0500 |
|---|---|---|
| committer | Franklin Wei <git@fwei.tk> | 2018-02-11 15:34:30 -0500 |
| commit | 33bfba86222efb6cc5b271b3e12b6cf3f38836c5 (patch) | |
| tree | 8a7f11e101af6a094b4b86d3c0b9d72793005ed3 /apps/plugins/sdl/progs/quake/host.c | |
| parent | 8dd00a02d49a99997165a4c38a967738e90ba72f (diff) | |
| download | rockbox-duke3d.zip rockbox-duke3d.tar.gz rockbox-duke3d.tar.bz2 rockbox-duke3d.tar.xz | |
Quake: attempt 2duke3d
Change-Id: I4285036e967d7f0722802d43cf2096c808ca5799
Diffstat (limited to 'apps/plugins/sdl/progs/quake/host.c')
| -rw-r--r-- | apps/plugins/sdl/progs/quake/host.c | 972 |
1 files changed, 972 insertions, 0 deletions
diff --git a/apps/plugins/sdl/progs/quake/host.c b/apps/plugins/sdl/progs/quake/host.c new file mode 100644 index 0000000..b9b16e4 --- /dev/null +++ b/apps/plugins/sdl/progs/quake/host.c @@ -0,0 +1,972 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program 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; either version 2 +of the License, or (at your option) any later version. + +This program 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. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// host.c -- coordinates spawning and killing of local servers + +#include "quakedef.h" +#include "r_local.h" + +/* + +A server can allways be started, even if the system started out as a client +to a remote system. + +A client can NOT be started if the system started as a dedicated server. + +Memory is cleared / released when a server or client begins, not when they end. + +*/ + +quakeparms_t host_parms; + +qboolean host_initialized; // true if into command execution + +double host_frametime; +double host_time; +double realtime; // without any filtering or bounding +double oldrealtime; // last frame run +int host_framecount; + +int host_hunklevel; + +int minimum_memory; + +client_t *host_client; // current client + +jmp_buf host_abortserver; + +byte *host_basepal; +byte *host_colormap; + +cvar_t host_framerate = {"host_framerate","0"}; // set for slow motion +cvar_t host_speeds = {"host_speeds","0"}; // set for running times + +cvar_t sys_ticrate = {"sys_ticrate","0.05"}; +cvar_t serverprofile = {"serverprofile","0"}; + +cvar_t fraglimit = {"fraglimit","0",false,true}; +cvar_t timelimit = {"timelimit","0",false,true}; +cvar_t teamplay = {"teamplay","0",false,true}; + +cvar_t samelevel = {"samelevel","0"}; +cvar_t noexit = {"noexit","0",false,true}; + +#ifdef QUAKE2 +cvar_t developer = {"developer","1"}; // should be 0 for release! +#else +cvar_t developer = {"developer","0"}; +#endif + +cvar_t skill = {"skill","1"}; // 0 - 3 +cvar_t deathmatch = {"deathmatch","0"}; // 0, 1, or 2 +cvar_t coop = {"coop","0"}; // 0 or 1 + +cvar_t pausable = {"pausable","1"}; + +cvar_t temp1 = {"temp1","0"}; + + +/* +================ +Host_EndGame +================ +*/ +void Host_EndGame (char *message, ...) +{ + va_list argptr; + char string[1024]; + + va_start (argptr,message); + vsprintf (string,message,argptr); + va_end (argptr); + Con_DPrintf ("Host_EndGame: %s\n",string); + + if (sv.active) + Host_ShutdownServer (false); + + if (cls.state == ca_dedicated) + Sys_Error ("Host_EndGame: %s\n",string); // dedicated servers exit + + if (cls.demonum != -1) + CL_NextDemo (); + else + CL_Disconnect (); + + longjmp (host_abortserver, 1); +} + +/* +================ +Host_Error + +This shuts down both the client and server +================ +*/ +void Host_Error (char *error, ...) +{ + va_list argptr; + char string[1024]; + static qboolean inerror = false; + + if (inerror) + Sys_Error ("Host_Error: recursively entered"); + inerror = true; + + SCR_EndLoadingPlaque (); // reenable screen updates + + va_start (argptr,error); + vsprintf (string,error,argptr); + va_end (argptr); + Con_Printf ("Host_Error: %s\n",string); + + if (sv.active) + Host_ShutdownServer (false); + + if (cls.state == ca_dedicated) + Sys_Error ("Host_Error: %s\n",string); // dedicated servers exit + + CL_Disconnect (); + cls.demonum = -1; + + inerror = false; + + longjmp (host_abortserver, 1); +} + +/* +================ +Host_FindMaxClients +================ +*/ +void Host_FindMaxClients (void) +{ + int i; + + svs.maxclients = 1; + + i = COM_CheckParm ("-dedicated"); + if (i) + { + cls.state = ca_dedicated; + if (i != (com_argc - 1)) + { + svs.maxclients = Q_atoi (com_argv[i+1]); + } + else + svs.maxclients = 8; + } + else + cls.state = ca_disconnected; + + i = COM_CheckParm ("-listen"); + if (i) + { + if (cls.state == ca_dedicated) + Sys_Error ("Only one of -dedicated or -listen can be specified"); + if (i != (com_argc - 1)) + svs.maxclients = Q_atoi (com_argv[i+1]); + else + svs.maxclients = 8; + } + if (svs.maxclients < 1) + svs.maxclients = 8; + else if (svs.maxclients > MAX_SCOREBOARD) + svs.maxclients = MAX_SCOREBOARD; + + svs.maxclientslimit = svs.maxclients; + if (svs.maxclientslimit < 4) + svs.maxclientslimit = 4; + svs.clients = Hunk_AllocName (svs.maxclientslimit*sizeof(client_t), "clients"); + + if (svs.maxclients > 1) + Cvar_SetValue ("deathmatch", 1.0); + else + Cvar_SetValue ("deathmatch", 0.0); +} + + +/* +======================= +Host_InitLocal +====================== +*/ +void Host_InitLocal (void) +{ + Host_InitCommands (); + + Cvar_RegisterVariable (&host_framerate); + Cvar_RegisterVariable (&host_speeds); + + Cvar_RegisterVariable (&sys_ticrate); + Cvar_RegisterVariable (&serverprofile); + + Cvar_RegisterVariable (&fraglimit); + Cvar_RegisterVariable (&timelimit); + Cvar_RegisterVariable (&teamplay); + Cvar_RegisterVariable (&samelevel); + Cvar_RegisterVariable (&noexit); + Cvar_RegisterVariable (&skill); + Cvar_RegisterVariable (&developer); + Cvar_RegisterVariable (&deathmatch); + Cvar_RegisterVariable (&coop); + + Cvar_RegisterVariable (&pausable); + + Cvar_RegisterVariable (&temp1); + + Host_FindMaxClients (); + + host_time = 1.0; // so a think at time 0 won't get called +} + + +/* +=============== +Host_WriteConfiguration + +Writes key bindings and archived cvars to config.cfg +=============== +*/ +void Host_WriteConfiguration (void) +{ + FILE *f; + +// dedicated servers initialize the host but don't parse and set the +// config.cfg cvars + if (host_initialized & !isDedicated) + { + f = fopen (va("%s/config.cfg",com_gamedir), "w"); + if (!f) + { + Con_Printf ("Couldn't write config.cfg.\n"); + return; + } + + Key_WriteBindings (f); + Cvar_WriteVariables (f); + + fclose (f); + } +} + + +/* +================= +SV_ClientPrintf + +Sends text across to be displayed +FIXME: make this just a stuffed echo? +================= +*/ +void SV_ClientPrintf (char *fmt, ...) +{ + va_list argptr; + char string[1024]; + + va_start (argptr,fmt); + vsprintf (string, fmt,argptr); + va_end (argptr); + + MSG_WriteByte (&host_client->message, svc_print); + MSG_WriteString (&host_client->message, string); +} + +/* +================= +SV_BroadcastPrintf + +Sends text to all active clients +================= +*/ +void SV_BroadcastPrintf (char *fmt, ...) +{ + va_list argptr; + char string[1024]; + int i; + + va_start (argptr,fmt); + vsprintf (string, fmt,argptr); + va_end (argptr); + + for (i=0 ; i<svs.maxclients ; i++) + if (svs.clients[i].active && svs.clients[i].spawned) + { + MSG_WriteByte (&svs.clients[i].message, svc_print); + MSG_WriteString (&svs.clients[i].message, string); + } +} + +/* +================= +Host_ClientCommands + +Send text over to the client to be executed +================= +*/ +void Host_ClientCommands (char *fmt, ...) +{ + va_list argptr; + char string[1024]; + + va_start (argptr,fmt); + vsprintf (string, fmt,argptr); + va_end (argptr); + + MSG_WriteByte (&host_client->message, svc_stufftext); + MSG_WriteString (&host_client->message, string); +} + +/* +===================== +SV_DropClient + +Called when the player is getting totally kicked off the host +if (crash = true), don't bother sending signofs +===================== +*/ +void SV_DropClient (qboolean crash) +{ + int saveSelf; + int i; + client_t *client; + + if (!crash) + { + // send any final messages (don't check for errors) + if (NET_CanSendMessage (host_client->netconnection)) + { + MSG_WriteByte (&host_client->message, svc_disconnect); + NET_SendMessage (host_client->netconnection, &host_client->message); + } + + if (host_client->edict && host_client->spawned) + { + // call the prog function for removing a client + // this will set the body to a dead frame, among other things + saveSelf = pr_global_struct->self; + pr_global_struct->self = EDICT_TO_PROG(host_client->edict); + PR_ExecuteProgram (pr_global_struct->ClientDisconnect); + pr_global_struct->self = saveSelf; + } + + Sys_Printf ("Client %s removed\n",host_client->name); + } + +// break the net connection + NET_Close (host_client->netconnection); + host_client->netconnection = NULL; + +// free the client (the body stays around) + host_client->active = false; + host_client->name[0] = 0; + host_client->old_frags = -999999; + net_activeconnections--; + +// send notification to all clients + for (i=0, client = svs.clients ; i<svs.maxclients ; i++, client++) + { + if (!client->active) + continue; + MSG_WriteByte (&client->message, svc_updatename); + MSG_WriteByte (&client->message, host_client - svs.clients); + MSG_WriteString (&client->message, ""); + MSG_WriteByte (&client->message, svc_updatefrags); + MSG_WriteByte (&client->message, host_client - svs.clients); + MSG_WriteShort (&client->message, 0); + MSG_WriteByte (&client->message, svc_updatecolors); + MSG_WriteByte (&client->message, host_client - svs.clients); + MSG_WriteByte (&client->message, 0); + } +} + +/* +================== +Host_ShutdownServer + +This only happens at the end of a game, not between levels +================== +*/ +void Host_ShutdownServer(qboolean crash) +{ + int i; + int count; + sizebuf_t buf; + char message[4]; + double start; + + if (!sv.active) + return; + + sv.active = false; + +// stop all client sounds immediately + if (cls.state == ca_connected) + CL_Disconnect (); + +// flush any pending messages - like the score!!! + start = Sys_FloatTime(); + do + { + count = 0; + for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++) + { + if (host_client->active && host_client->message.cursize) + { + if (NET_CanSendMessage (host_client->netconnection)) + { + NET_SendMessage(host_client->netconnection, &host_client->message); + SZ_Clear (&host_client->message); + } + else + { + NET_GetMessage(host_client->netconnection); + count++; + } + } + } + if ((Sys_FloatTime() - start) > 3.0) + break; + } + while (count); + +// make sure all the clients know we're disconnecting + buf.data = message; + buf.maxsize = 4; + buf.cursize = 0; + MSG_WriteByte(&buf, svc_disconnect); + count = NET_SendToAll(&buf, 5); + if (count) + Con_Printf("Host_ShutdownServer: NET_SendToAll failed for %u clients\n", count); + + for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++) + if (host_client->active) + SV_DropClient(crash); + +// +// clear structures +// + memset (&sv, 0, sizeof(sv)); + memset (svs.clients, 0, svs.maxclientslimit*sizeof(client_t)); +} + + +/* +================ +Host_ClearMemory + +This clears all the memory used by both the client and server, but does +not reinitialize anything. +================ +*/ +void Host_ClearMemory (void) +{ + Con_DPrintf ("Clearing memory\n"); + D_FlushCaches (); + Mod_ClearAll (); + if (host_hunklevel) + Hunk_FreeToLowMark (host_hunklevel); + + cls.signon = 0; + memset (&sv, 0, sizeof(sv)); + memset (&cl, 0, sizeof(cl)); +} + + +//============================================================================ + + +/* +=================== +Host_FilterTime + +Returns false if the time is too short to run a frame +=================== +*/ +qboolean Host_FilterTime (float time) +{ + realtime += time; + + if (!cls.timedemo && realtime - oldrealtime < 1.0/72.0) + return false; // framerate is too high + + host_frametime = realtime - oldrealtime; + oldrealtime = realtime; + + if (host_framerate.value > 0) + host_frametime = host_framerate.value; + else + { // don't allow really long or short frames + if (host_frametime > 0.1) + host_frametime = 0.1; + if (host_frametime < 0.001) + host_frametime = 0.001; + } + + return true; +} + + +/* +=================== +Host_GetConsoleCommands + +Add them exactly as if they had been typed at the console +=================== +*/ +void Host_GetConsoleCommands (void) +{ + char *cmd; + + while (1) + { + cmd = Sys_ConsoleInput (); + if (!cmd) + break; + Cbuf_AddText (cmd); + } +} + + +/* +================== +Host_ServerFrame + +================== +*/ +#ifdef FPS_20 + +void _Host_ServerFrame (void) +{ +// run the world state + pr_global_struct->frametime = host_frametime; + +// read client messages + SV_RunClients (); + +// move things around and think +// always pause in single player if in console or menus + if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) ) + SV_Physics (); +} + +void Host_ServerFrame (void) +{ + float save_host_frametime; + float temp_host_frametime; + +// run the world state + pr_global_struct->frametime = host_frametime; + +// set the time and clear the general datagram + SV_ClearDatagram (); + +// check for new clients + SV_CheckForNewClients (); + + temp_host_frametime = save_host_frametime = host_frametime; + while(temp_host_frametime > (1.0/72.0)) + { + if (temp_host_frametime > 0.05) + host_frametime = 0.05; + else + host_frametime = temp_host_frametime; + temp_host_frametime -= host_frametime; + _Host_ServerFrame (); + } + host_frametime = save_host_frametime; + +// send all messages to the clients + SV_SendClientMessages (); +} + +#else + +void Host_ServerFrame (void) +{ +// run the world state + pr_global_struct->frametime = host_frametime; + +// set the time and clear the general datagram + SV_ClearDatagram (); + +// check for new clients + SV_CheckForNewClients (); + +// read client messages + SV_RunClients (); + +// move things around and think +// always pause in single player if in console or menus + if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) ) + SV_Physics (); + +// send all messages to the clients + SV_SendClientMessages (); +} + +#endif + + +/* +================== +Host_Frame + +Runs all active servers +================== +*/ +void _Host_Frame (float time) +{ + static double time1 = 0; + static double time2 = 0; + static double time3 = 0; + int pass1, pass2, pass3; + + if (setjmp (host_abortserver) ) + return; // something bad happened, or the server disconnected + +// keep the random time dependent + rand (); + +// decide the simulation time + if (!Host_FilterTime (time)) + return; // don't run too fast, or packets will flood out + +// get new key events + Sys_SendKeyEvents (); + +// allow mice or other external controllers to add commands + IN_Commands (); + +// process console commands + Cbuf_Execute (); + + NET_Poll(); + +// if running the server locally, make intentions now + if (sv.active) + CL_SendCmd (); + +//------------------- +// +// server operations +// +//------------------- + +// check for commands typed to the host + Host_GetConsoleCommands (); + + if (sv.active) + Host_ServerFrame (); + +//------------------- +// +// client operations +// +//------------------- + +// if running the server remotely, send intentions now after +// the incoming messages have been read + if (!sv.active) + CL_SendCmd (); + + host_time += host_frametime; + +// fetch results from server + if (cls.state == ca_connected) + { + CL_ReadFromServer (); + } + +// update video + if (host_speeds.value) + time1 = Sys_FloatTime (); + + SCR_UpdateScreen (); + + if (host_speeds.value) + time2 = Sys_FloatTime (); + +// update audio + if (cls.signon == SIGNONS) + { + S_Update (r_origin, vpn, vright, vup); + CL_DecayLights (); + } + else + S_Update (vec3_origin, vec3_origin, vec3_origin, vec3_origin); + + CDAudio_Update(); + + if (host_speeds.value) + { + pass1 = (time1 - time3)*1000; + time3 = Sys_FloatTime (); + pass2 = (time2 - time1)*1000; + pass3 = (time3 - time2)*1000; + Con_Printf ("%3i tot %3i server %3i gfx %3i snd\n", + pass1+pass2+pass3, pass1, pass2, pass3); + } + + host_framecount++; +} + +void Host_Frame (float time) +{ + double time1, time2; + static double timetotal; + static int timecount; + int i, c, m; + + if (!serverprofile.value) + { + _Host_Frame (time); + return; + } + + time1 = Sys_FloatTime (); + _Host_Frame (time); + time2 = Sys_FloatTime (); + + timetotal += time2 - time1; + timecount++; + + if (timecount < 1000) + return; + + m = timetotal*1000/timecount; + timecount = 0; + timetotal = 0; + c = 0; + for (i=0 ; i<svs.maxclients ; i++) + { + if (svs.clients[i].active) + c++; + } + + Con_Printf ("serverprofile: %2i clients %2i msec\n", c, m); +} + +//============================================================================ + + +extern int vcrFile; +#define VCR_SIGNATURE 0x56435231 +// "VCR1" + +void Host_InitVCR (quakeparms_t *parms) +{ + int i, len, n; + char *p; + + if (COM_CheckParm("-playback")) + { + if (com_argc != 2) + Sys_Error("No other parameters allowed with -playback\n"); + + Sys_FileOpenRead("quake.vcr", &vcrFile); + if (vcrFile == -1) + Sys_Error("playback file not found\n"); + + Sys_FileRead (vcrFile, &i, sizeof(int)); + if (i != VCR_SIGNATURE) + Sys_Error("Invalid signature in vcr file\n"); + + Sys_FileRead (vcrFile, &com_argc, sizeof(int)); + com_argv = malloc(com_argc * sizeof(char *)); + com_argv[0] = parms->argv[0]; + for (i = 0; i < com_argc; i++) + { + Sys_FileRead (vcrFile, &len, sizeof(int)); + p = malloc(len); + Sys_FileRead (vcrFile, p, len); + com_argv[i+1] = p; + } + com_argc++; /* add one for arg[0] */ + parms->argc = com_argc; + parms->argv = com_argv; + } + + if ( (n = COM_CheckParm("-record")) != 0) + { + vcrFile = Sys_FileOpenWrite("quake.vcr"); + + i = VCR_SIGNATURE; + Sys_FileWrite(vcrFile, &i, sizeof(int)); + i = com_argc - 1; + Sys_FileWrite(vcrFile, &i, sizeof(int)); + for (i = 1; i < com_argc; i++) + { + if (i == n) + { + len = 10; + Sys_FileWrite(vcrFile, &len, sizeof(int)); + Sys_FileWrite(vcrFile, "-playback", len); + continue; + } + len = Q_strlen(com_argv[i]) + 1; + Sys_FileWrite(vcrFile, &len, sizeof(int)); + Sys_FileWrite(vcrFile, com_argv[i], len); + } + } + +} + +/* +==================== +Host_Init +==================== +*/ +void Host_Init (quakeparms_t *parms) +{ + + if (standard_quake) + minimum_memory = MINIMUM_MEMORY; + else + minimum_memory = MINIMUM_MEMORY_LEVELPAK; + + if (COM_CheckParm ("-minmemory")) + parms->memsize = minimum_memory; + + host_parms = *parms; + + if (parms->memsize < minimum_memory) + Sys_Error ("Only %4.1f megs of memory available, can't execute game", parms->memsize / (float)0x100000); + + com_argc = parms->argc; + com_argv = parms->argv; + + printf("init 1"); + + Memory_Init (parms->membase, parms->memsize); + printf("init 2"); + Cbuf_Init (); + printf("init 3"); + Cmd_Init (); + printf("init 4"); + V_Init (); + printf("init 5"); + Chase_Init (); + printf("init 6"); + Host_InitVCR (parms); + printf("init 7"); + COM_Init (parms->basedir); + printf("init 8"); + Host_InitLocal (); + printf("init 9"); + W_LoadWadFile ("gfx.wad"); + printf("init 10"); + Key_Init (); + Con_Init (); + M_Init (); + PR_Init (); + Mod_Init (); + NET_Init (); + printf("init 11"); + SV_Init (); + printf("init 12"); + + Con_Printf ("Exe: "__TIME__" "__DATE__"\n"); + Con_Printf ("%4.1f megabyte heap\n",parms->memsize/ (1024*1024.0)); + + R_InitTextures (); // needed even for dedicated servers + + printf("init 13"); + if (cls.state != ca_dedicated) + { + host_basepal = (byte *)COM_LoadHunkFile ("gfx/palette.lmp"); + if (!host_basepal) + Sys_Error ("Couldn't load gfx/palette.lmp"); + host_colormap = (byte *)COM_LoadHunkFile ("gfx/colormap.lmp"); + if (!host_colormap) + Sys_Error ("Couldn't load gfx/colormap.lmp"); + +#ifndef _WIN32 // on non win32, mouse comes before video for security reasons + IN_Init (); +#endif + VID_Init (host_basepal); + + Draw_Init (); + SCR_Init (); + R_Init (); +#ifndef _WIN32 + // on Win32, sound initialization has to come before video initialization, so we + // can put up a popup if the sound hardware is in use + S_Init (); +#else + +#ifdef GLQUAKE + // FIXME: doesn't use the new one-window approach yet + S_Init (); +#endif + +#endif // _WIN32 + CDAudio_Init (); + Sbar_Init (); + CL_Init (); +#ifdef _WIN32 // on non win32, mouse comes before video for security reasons + IN_Init (); +#endif + } + + Cbuf_InsertText ("exec quake.rc\n"); + + Hunk_AllocName (0, "-HOST_HUNKLEVEL-"); + host_hunklevel = Hunk_LowMark (); + + host_initialized = true; + + Sys_Printf ("========Quake Initialized=========\n"); +} + + +/* +=============== +Host_Shutdown + +FIXME: this is a callback from Sys_Quit and Sys_Error. It would be better +to run quit through here before the final handoff to the sys code. +=============== +*/ +void Host_Shutdown(void) +{ + static qboolean isdown = false; + + if (isdown) + { + printf ("recursive shutdown\n"); + return; + } + isdown = true; + +// keep Con_Printf from trying to update the screen + scr_disabled_for_loading = true; + + Host_WriteConfiguration (); + + CDAudio_Shutdown (); + NET_Shutdown (); + S_Shutdown(); + IN_Shutdown (); + + if (cls.state != ca_dedicated) + { + VID_Shutdown(); + } +} + |