1 //**************************************************************************
2 //**
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
9 //**
10 //** $Id: sv_main.cpp 4297 2010-06-03 22:49:00Z firebrand_kh $
11 //**
12 //** Copyright (C) 1999-2006 Jānis Legzdiņš
13 //**
14 //** This program is free software; you can redistribute it and/or
15 //** modify it under the terms of the GNU General Public License
16 //** as published by the Free Software Foundation; either version 2
17 //** of the License, or (at your option) any later version.
18 //**
19 //** This program is distributed in the hope that it will be useful,
20 //** but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 //** GNU General Public License for more details.
23 //**
24 //**************************************************************************
25
26 // HEADER FILES ------------------------------------------------------------
27
28 #include "gamedefs.h"
29 #include "network.h"
30 #include "sv_local.h"
31 #include "cl_local.h"
32
33 // MACROS ------------------------------------------------------------------
34
35 // TYPES -------------------------------------------------------------------
36
37 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
38
39 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
40
41 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
42
43 static void G_DoReborn(int playernum);
44 static void G_DoCompleted();
45
46 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
47
48 // PUBLIC DATA DEFINITIONS -------------------------------------------------
49
50 VCvarI real_time("real_time", "1");
51
52 server_t sv;
53 server_static_t svs;
54
55 // increment every time a check is made
56 int validcount = 1;
57
58 bool sv_loading = false;
59 bool sv_map_travel = false;
60 int sv_load_num_players;
61 bool run_open_scripts;
62
63 VBasePlayer* GPlayersBase[MAXPLAYERS];
64
65 vuint8 deathmatch = false; // only if started as net death
66
67 int TimerGame;
68
69 VLevelInfo* GLevelInfo;
70
71 int LeavePosition;
72
73 bool completed;
74
75 VNetContext* GDemoRecordingContext;
76
77 // PRIVATE DATA DEFINITIONS ------------------------------------------------
78
79 static int RebornPosition; // Position indicator for cooperative net-play reborn
80
81 static bool mapteleport_issued;
82
83 static VCvarI TimeLimit("TimeLimit", "0");
84 static VCvarI DeathMatch("DeathMatch", "0", CVAR_ServerInfo);
85 static VCvarI NoMonsters("NoMonsters", "0");
86 static VCvarI Skill("Skill", "2");
87 static VCvarI sv_cheats("sv_cheats", "0", CVAR_ServerInfo | CVAR_Latch);
88 static VCvarI split_frame("split_frame", "1", CVAR_Archive);
89 static VCvarI sv_maxmove("sv_maxmove", "400", CVAR_Archive);
90 static VCvarF master_heartbeat_time("master_heartbeat_time", "300", CVAR_Archive);
91
92 static VServerNetContext* ServerNetContext;
93
94 static double LastMasterUpdate;
95
96 // CODE --------------------------------------------------------------------
97
98 //==========================================================================
99 //
100 // SV_Init
101 //
102 //==========================================================================
103
SV_Init()104 void SV_Init()
105 {
106 guard(SV_Init);
107 int i;
108
109 svs.max_clients = 1;
110
111 VMemberBase::StaticLoadPackage(NAME_game, TLocation());
112
113 GGameInfo = (VGameInfo*)VObject::StaticSpawnObject(
114 VClass::FindClass("MainGameInfo"));
115 GGameInfo->eventInit();
116
117 ProcessDecorateScripts();
118
119 ProcessDehackedFiles();
120
121 for (int i = 0; i < VClass::GSpriteNames.Num(); i++)
122 {
123 R_InstallSprite(*VClass::GSpriteNames[i], i);
124 }
125
126 ServerNetContext = new VServerNetContext();
127
128 VClass* PlayerClass = VClass::FindClass("Player");
129 for (i = 0; i < MAXPLAYERS; i++)
130 {
131 GPlayersBase[i] = (VBasePlayer*)VObject::StaticSpawnObject(
132 PlayerClass);
133 }
134
135 GGameInfo->validcount = &validcount;
136 GGameInfo->skyflatnum = skyflatnum;
137 VEntity::InitFuncIndexes();
138
139 P_InitSwitchList();
140 P_InitTerrainTypes();
141 InitLockDefs();
142 unguard;
143 }
144
145 //==========================================================================
146 //
147 // P_InitThinkers
148 //
149 //==========================================================================
150
P_InitThinkers()151 void P_InitThinkers()
152 {
153 VThinker::FIndex_Tick = VThinker::StaticClass()->GetMethodIndex(NAME_Tick);
154 }
155
156 //==========================================================================
157 //
158 // SV_Shutdown
159 //
160 //==========================================================================
161
SV_Shutdown()162 void SV_Shutdown()
163 {
164 guard(SV_Shutdown);
165 if (GGameInfo)
166 {
167 SV_ShutdownGame();
168 GGameInfo->ConditionalDestroy();
169 }
170 for (int i = 0; i < MAXPLAYERS; i++)
171 {
172 if (GPlayersBase[i])
173 {
174 delete GPlayersBase[i]->Net;
175 GPlayersBase[i]->Net = NULL;
176 GPlayersBase[i]->ConditionalDestroy();
177 }
178 }
179
180 P_FreeTerrainTypes();
181 ShutdownLockDefs();
182 svs.serverinfo.Clean();
183
184 delete ServerNetContext;
185 ServerNetContext = NULL;
186 unguard;
187 }
188
189 //==========================================================================
190 //
191 // SV_Clear
192 //
193 //==========================================================================
194
SV_Clear()195 void SV_Clear()
196 {
197 guard(SV_Clear);
198 if (GLevel)
199 {
200 GLevel->ConditionalDestroy();
201 GLevel = NULL;
202 VObject::CollectGarbage();
203 }
204 memset(&sv, 0, sizeof(sv));
205 #ifdef CLIENT
206 // Make sure all sounds are stopped.
207 GAudio->StopAllSound();
208 #endif
209 unguard;
210 }
211
212 //==========================================================================
213 //
214 // SV_SendClientMessages
215 //
216 //==========================================================================
217
SV_SendClientMessages()218 void SV_SendClientMessages()
219 {
220 guard(SV_SendClientMessages);
221 // Update player replication infos.
222 for (int i = 0; i < svs.max_clients; i++)
223 {
224 if (!GGameInfo->Players[i])
225 {
226 continue;
227 }
228
229 VBasePlayer* Player = GGameInfo->Players[i];
230
231 VPlayerReplicationInfo* RepInfo = Player->PlayerReplicationInfo;
232 RepInfo->PlayerName = Player->PlayerName;
233 RepInfo->UserInfo = Player->UserInfo;
234 RepInfo->TranslStart = Player->TranslStart;
235 RepInfo->TranslEnd = Player->TranslEnd;
236 RepInfo->Colour = Player->Colour;
237 RepInfo->Frags = Player->Frags;
238 RepInfo->Deaths = Player->Deaths;
239 RepInfo->KillCount = Player->KillCount;
240 RepInfo->ItemCount = Player->ItemCount;
241 RepInfo->SecretCount = Player->SecretCount;
242
243 // Update view angle if needed.
244 if (Player->PlayerFlags & VBasePlayer::PF_Spawned)
245 {
246 Player->WriteViewData();
247 }
248 }
249
250 ServerNetContext->Tick();
251
252 if (GDemoRecordingContext)
253 {
254 for (int i = 0; i < GDemoRecordingContext->ClientConnections.Num(); i++)
255 {
256 GDemoRecordingContext->ClientConnections[i]->NeedsUpdate = true;
257 }
258 GDemoRecordingContext->Tick();
259 }
260 unguard;
261 }
262
263 //========================================================================
264 //
265 // CheckForSkip
266 //
267 // Check to see if any player hit a key
268 //
269 //========================================================================
270
CheckForSkip()271 static void CheckForSkip()
272 {
273 int i;
274 VBasePlayer *player;
275 static bool triedToSkip;
276 bool skip = false;
277
278 for (i = 0; i < MAXPLAYERS; i++)
279 {
280 player = GGameInfo->Players[i];
281 if (player)
282 {
283 if (player->Buttons & BT_ATTACK)
284 {
285 if (!(player->PlayerFlags & VBasePlayer::PF_AttackDown))
286 {
287 skip = true;
288 }
289 player->PlayerFlags |= VBasePlayer::PF_AttackDown;
290 }
291 else
292 {
293 player->PlayerFlags &= ~VBasePlayer::PF_AttackDown;
294 }
295 if (player->Buttons & BT_USE)
296 {
297 if (!(player->PlayerFlags & VBasePlayer::PF_UseDown))
298 {
299 skip = true;
300 }
301 player->PlayerFlags |= VBasePlayer::PF_UseDown;
302 }
303 else
304 {
305 player->PlayerFlags &= ~VBasePlayer::PF_UseDown;
306 }
307 }
308 }
309
310 if (deathmatch && sv.intertime < 140)
311 {
312 // wait for 4 seconds before allowing a skip
313 if (skip)
314 {
315 triedToSkip = true;
316 skip = false;
317 }
318 }
319 else
320 {
321 if (triedToSkip)
322 {
323 skip = true;
324 triedToSkip = false;
325 }
326 }
327 if (skip)
328 {
329 for (int i = 0; i < svs.max_clients; i++)
330 if (GGameInfo->Players[i])
331 GGameInfo->Players[i]->eventClientSkipIntermission();
332 }
333 }
334
335 //==========================================================================
336 //
337 // SV_RunClients
338 //
339 //==========================================================================
340
SV_RunClients()341 void SV_RunClients()
342 {
343 guard(SV_RunClients);
344 // get commands
345 for (int i = 0; i < MAXPLAYERS; i++)
346 {
347 VBasePlayer* Player = GGameInfo->Players[i];
348 if (!Player)
349 {
350 continue;
351 }
352
353 if ((Player->PlayerFlags & VBasePlayer::PF_IsBot) &&
354 !(Player->PlayerFlags & VBasePlayer::PF_Spawned))
355 {
356 Player->SpawnClient();
357 }
358
359 // do player reborns if needed
360 if (Player->PlayerState == PST_REBORN)
361 {
362 G_DoReborn(i);
363 }
364
365 if (Player->Net)
366 {
367 Player->Net->NeedsUpdate = false;
368 Player->Net->GetMessages();
369 }
370
371 // pause if in menu or console and at least one tic has been run
372 if (Player->PlayerFlags & VBasePlayer::PF_Spawned &&
373 !sv.intermission && !GGameInfo->IsPaused())
374 {
375 Player->ForwardMove = Player->ClientForwardMove;
376 Player->SideMove = Player->ClientSideMove;
377 // Don't move faster than maxmove
378 if (Player->ForwardMove > sv_maxmove)
379 {
380 Player->ForwardMove = sv_maxmove;
381 }
382 else if (Player->ForwardMove < -sv_maxmove)
383 {
384 Player->ForwardMove = -sv_maxmove;
385 }
386 if (Player->SideMove > sv_maxmove)
387 {
388 Player->SideMove = sv_maxmove;
389 }
390 else if (Player->SideMove < -sv_maxmove)
391 {
392 Player->SideMove = -sv_maxmove;
393 }
394 // Check for disabled freelook and jumping
395 if (GLevelInfo->LevelInfoFlags & VLevelInfo::LIF_NoFreelook)
396 {
397 Player->ViewAngles.pitch = 0;
398 }
399 if (GLevelInfo->LevelInfoFlags & VLevelInfo::LIF_NoJump)
400 {
401 Player->Buttons &= ~BT_JUMP;
402 }
403 Player->OldViewAngles = Player->ViewAngles;
404 Player->eventPlayerTick(host_frametime);
405 Player->OldButtons = Player->Buttons;
406 }
407 }
408
409 if (sv.intermission)
410 {
411 CheckForSkip();
412 sv.intertime++;
413 }
414 unguard;
415 }
416
417 //==========================================================================
418 //
419 // SV_Ticker
420 //
421 //==========================================================================
422
SV_Ticker()423 void SV_Ticker()
424 {
425 guard(SV_Ticker);
426 float saved_frametime;
427 int exec_times;
428
429 if (GGameInfo->NetMode >= NM_DedicatedServer && (!LastMasterUpdate ||
430 host_time - LastMasterUpdate > master_heartbeat_time))
431 {
432 GNet->UpdateMaster();
433 LastMasterUpdate = host_time;
434 }
435
436 saved_frametime = host_frametime;
437 exec_times = 1;
438 if (!real_time)
439 {
440 // Rounded a little bit up to prevent "slow motion"
441 host_frametime = 0.028572f;//1.0 / 35.0;
442 }
443 else if (split_frame)
444 {
445 while (host_frametime / exec_times > 0.028572f/*1.0 / 35.0*/)
446 exec_times++;
447 }
448
449 GGameInfo->frametime = host_frametime;
450 SV_RunClients();
451
452 if (sv_loading)
453 return;
454
455 // do main actions
456 if (!sv.intermission)
457 {
458 host_frametime /= exec_times;
459 GGameInfo->frametime = host_frametime;
460 for (int i = 0; i < exec_times && !completed; i++)
461 {
462 if (!GGameInfo->IsPaused())
463 {
464 // LEVEL TIMER
465 if (TimerGame)
466 {
467 if (!--TimerGame)
468 {
469 LeavePosition = 0;
470 completed = true;
471 }
472 }
473 if (i)
474 {
475 VObject::CollectGarbage();
476 }
477 GLevel->TickWorld(host_frametime);
478 }
479 }
480 }
481
482 if (completed)
483 {
484 G_DoCompleted();
485 }
486
487 host_frametime = saved_frametime;
488 unguard;
489 }
490
491 //==========================================================================
492 //
493 // CheckRedirects
494 //
495 //==========================================================================
496
CheckRedirects(VName Map)497 static VName CheckRedirects(VName Map)
498 {
499 guard(CheckRedirects);
500 const mapInfo_t& Info = P_GetMapInfo(Map);
501 if (Info.RedirectType == NAME_None || Info.RedirectMap == NAME_None)
502 {
503 // No redirect for this map.
504 return Map;
505 }
506
507 // Check all players.
508 for (int i = 0; i < MAXPLAYERS; i++)
509 {
510 VBasePlayer* P = GGameInfo->Players[i];
511 if (!P || !(P->PlayerFlags & VBasePlayer::PF_Spawned))
512 {
513 continue;
514 }
515 if (P->MO->eventCheckInventory(Info.RedirectType) > 0)
516 {
517 return CheckRedirects(Info.RedirectMap);
518 }
519 }
520
521 // None of the players have required item, no redirect.
522 return Map;
523 unguard;
524 }
525
526 //==========================================================================
527 //
528 // G_DoCompleted
529 //
530 //==========================================================================
531
G_DoCompleted()532 static void G_DoCompleted()
533 {
534 int i;
535
536 completed = false;
537 if (sv.intermission)
538 {
539 return;
540 }
541 if ((GGameInfo->NetMode < NM_DedicatedServer) && (!GGameInfo->Players[0] ||
542 !(GGameInfo->Players[0]->PlayerFlags & VBasePlayer::PF_Spawned)))
543 {
544 //FIXME Some ACS left from previous visit of the level
545 return;
546 }
547 sv.intermission = 1;
548 sv.intertime = 0;
549 GLevelInfo->CompletitionTime = GLevel->Time;
550
551 GLevel->Acs->StartTypedACScripts(SCRIPT_Unloading, 0, 0, 0, NULL, false,
552 true);
553
554 GLevelInfo->NextMap = CheckRedirects(GLevelInfo->NextMap);
555
556 const mapInfo_t& old_info = P_GetMapInfo(GLevel->MapName);
557 const mapInfo_t& new_info = P_GetMapInfo(GLevelInfo->NextMap);
558 const VClusterDef* ClusterD = P_GetClusterDef(old_info.Cluster);
559 bool HubChange = !old_info.Cluster || !(ClusterD->Flags & CLUSTERF_Hub) ||
560 old_info.Cluster != new_info.Cluster;
561
562 for (i = 0; i < MAXPLAYERS; i++)
563 {
564 if (GGameInfo->Players[i])
565 {
566 GGameInfo->Players[i]->eventPlayerExitMap(HubChange);
567 if (deathmatch || HubChange)
568 {
569 GGameInfo->Players[i]->eventClientIntermission(
570 GLevelInfo->NextMap);
571 }
572 }
573 }
574
575 if (!deathmatch && !HubChange)
576 {
577 GCmdBuf << "TeleportNewMap\n";
578 }
579 }
580
581 //==========================================================================
582 //
583 // COMMAND TeleportNewMap
584 //
585 //==========================================================================
586
COMMAND(TeleportNewMap)587 COMMAND(TeleportNewMap)
588 {
589 guard(COMMAND TeleportNewMap);
590 if (Source == SRC_Command)
591 {
592 ForwardToServer();
593 return;
594 }
595
596 if (GGameInfo->NetMode == NM_None ||
597 GGameInfo->NetMode == NM_Client)
598 {
599 return;
600 }
601
602 if (Args.Num() == 3)
603 {
604 GLevelInfo->NextMap = VName(*Args[1], VName::AddLower8);
605 LeavePosition = atoi(*Args[2]);
606 }
607 else if (sv.intermission != 1)
608 {
609 return;
610 }
611
612 if (!deathmatch)
613 {
614 if (VStr(GLevelInfo->NextMap).StartsWith("EndGame"))
615 {
616 for (int i = 0; i < svs.max_clients; i++)
617 if (GGameInfo->Players[i])
618 GGameInfo->Players[i]->eventClientFinale(*GLevelInfo->NextMap);
619 sv.intermission = 2;
620 return;
621 }
622 }
623
624 #ifdef CLIENT
625 Draw_TeleportIcon();
626 #endif
627 RebornPosition = LeavePosition;
628 GGameInfo->RebornPosition = RebornPosition;
629 mapteleport_issued = true;
630 unguard;
631 }
632
633 //==========================================================================
634 //
635 // G_DoReborn
636 //
637 //==========================================================================
638
G_DoReborn(int playernum)639 static void G_DoReborn(int playernum)
640 {
641 if (!GGameInfo->Players[playernum] ||
642 !(GGameInfo->Players[playernum]->PlayerFlags & VBasePlayer::PF_Spawned))
643 {
644 return;
645 }
646 if (GGameInfo->NetMode == NM_Standalone)
647 {
648 GCmdBuf << "Restart\n";
649 GGameInfo->Players[playernum]->PlayerState = PST_LIVE;
650 }
651 else
652 {
653 GGameInfo->Players[playernum]->eventNetGameReborn();
654 }
655 }
656
657 //==========================================================================
658 //
659 // NET_SendToAll
660 //
661 //==========================================================================
662
NET_SendToAll(int blocktime)663 int NET_SendToAll(int blocktime)
664 {
665 guard(NET_SendToAll);
666 double start;
667 int i;
668 int count = 0;
669 bool state1[MAXPLAYERS];
670 bool state2[MAXPLAYERS];
671
672 for (i = 0; i < svs.max_clients; i++)
673 {
674 VBasePlayer* Player = GGameInfo->Players[i];
675 if (Player && Player->Net)
676 {
677 if (Player->Net->IsLocalConnection())
678 {
679 state1[i] = false;
680 state2[i] = true;
681 continue;
682 }
683 count++;
684 state1[i] = false;
685 state2[i] = false;
686 }
687 else
688 {
689 state1[i] = true;
690 state2[i] = true;
691 }
692 }
693
694 start = Sys_Time();
695 while (count)
696 {
697 count = 0;
698 for (i = 0; i < svs.max_clients; i++)
699 {
700 VBasePlayer* Player = GGameInfo->Players[i];
701 if (!state1[i])
702 {
703 state1[i] = true;
704 Player->Net->Channels[0]->Close();
705 count++;
706 continue;
707 }
708
709 if (!state2[i])
710 {
711 if (Player->Net->State == NETCON_Closed)
712 {
713 state2[i] = true;
714 }
715 else
716 {
717 Player->Net->GetMessages();
718 Player->Net->Tick();
719 }
720 count++;
721 continue;
722 }
723 }
724 if ((Sys_Time() - start) > blocktime)
725 break;
726 }
727 return count;
728 unguard;
729 }
730
731 //==========================================================================
732 //
733 // SV_SendServerInfoToClients
734 //
735 //==========================================================================
736
SV_SendServerInfoToClients()737 void SV_SendServerInfoToClients()
738 {
739 guard(SV_SendServerInfoToClients);
740 for (int i = 0; i < svs.max_clients; i++)
741 {
742 VBasePlayer* Player = GGameInfo->Players[i];
743 if (!Player)
744 {
745 continue;
746 }
747 Player->Level = GLevelInfo;
748 if (Player->Net)
749 {
750 Player->Net->SendServerInfo();
751 }
752 }
753 unguard;
754 }
755
756 //==========================================================================
757 //
758 // SV_SpawnServer
759 //
760 //==========================================================================
761
SV_SpawnServer(const char * mapname,bool spawn_thinkers,bool titlemap)762 void SV_SpawnServer(const char *mapname, bool spawn_thinkers, bool titlemap)
763 {
764 guard(SV_SpawnServer);
765 int i;
766
767 GCon->Logf(NAME_Dev, "Spawning server %s", mapname);
768 GGameInfo->Flags &= ~VGameInfo::GIF_Paused;
769 mapteleport_issued = false;
770 run_open_scripts = spawn_thinkers;
771
772 if (GGameInfo->NetMode != NM_None)
773 {
774 // Level change
775 for (i = 0; i < MAXPLAYERS; i++)
776 {
777 if (!GGameInfo->Players[i])
778 continue;
779
780 GGameInfo->Players[i]->KillCount = 0;
781 GGameInfo->Players[i]->SecretCount = 0;
782 GGameInfo->Players[i]->ItemCount = 0;
783
784 GGameInfo->Players[i]->PlayerFlags &= ~VBasePlayer::PF_Spawned;
785 GGameInfo->Players[i]->MO = NULL;
786 GGameInfo->Players[i]->Frags = 0;
787 GGameInfo->Players[i]->Deaths = 0;
788 if (GGameInfo->Players[i]->PlayerState == PST_DEAD)
789 GGameInfo->Players[i]->PlayerState = PST_REBORN;
790 }
791 }
792 else
793 {
794 // New game
795 deathmatch = DeathMatch;
796 GGameInfo->deathmatch = deathmatch;
797
798 P_InitThinkers();
799
800 #ifdef CLIENT
801 GGameInfo->NetMode = titlemap ? NM_TitleMap :
802 svs.max_clients == 1 ? NM_Standalone : NM_ListenServer;
803 #else
804 GGameInfo->NetMode = NM_DedicatedServer;
805 #endif
806
807 GGameInfo->WorldInfo = GGameInfo->eventCreateWorldInfo();
808
809 GGameInfo->WorldInfo->SetSkill(Skill);
810 GGameInfo->eventInitNewGame(GGameInfo->WorldInfo->GameSkill);
811 }
812
813 SV_Clear();
814 VCvar::Unlatch();
815
816 // Load it
817 SV_LoadLevel(VName(mapname, VName::AddLower8));
818 GLevel->NetContext = ServerNetContext;
819 GLevel->WorldInfo = GGameInfo->WorldInfo;
820
821 const mapInfo_t& info = P_GetMapInfo(GLevel->MapName);
822
823 if (spawn_thinkers)
824 {
825 // Create level info.
826 GLevelInfo = (VLevelInfo*)GLevel->SpawnThinker(
827 GGameInfo->LevelInfoClass);
828 GLevelInfo->Level = GLevelInfo;
829 GLevelInfo->Game = GGameInfo;
830 GLevelInfo->World = GGameInfo->WorldInfo;
831 GLevel->LevelInfo = GLevelInfo;
832 GLevelInfo->SetMapInfo(info);
833
834 // Spawn things.
835 for (i = 0; i < GLevel->NumThings; i++)
836 {
837 GLevelInfo->eventSpawnMapThing(&GLevel->Things[i]);
838 }
839 if (deathmatch && GLevelInfo->DeathmatchStarts.Num() < 4)
840 {
841 Host_Error("Level needs more deathmatch start spots");
842 }
843 }
844
845 if (deathmatch)
846 {
847 TimerGame = TimeLimit * 35 * 60;
848 }
849 else
850 {
851 TimerGame = 0;
852 }
853
854 // set up world state
855
856 //
857 // P_SpawnSpecials
858 // After the map has been loaded, scan for specials that spawn thinkers
859 //
860 if (spawn_thinkers)
861 {
862 GLevelInfo->eventSpawnSpecials();
863 }
864
865 if (!spawn_thinkers)
866 {
867 // if (level.thinkerHead)
868 // {
869 // Sys_Error("Spawned a thinker when it's not allowed");
870 // }
871 return;
872 }
873
874 SV_SendServerInfoToClients();
875
876 // Call BeginPlay events.
877 for (TThinkerIterator<VEntity> Ent(GLevel); Ent; ++Ent)
878 {
879 Ent->eventBeginPlay();
880 }
881 GLevelInfo->LevelInfoFlags2 |= VLevelInfo::LIF2_BegunPlay;
882
883 if (GGameInfo->NetMode != NM_TitleMap &&
884 GGameInfo->NetMode != NM_Standalone)
885 {
886 GLevel->TickWorld(host_frametime);
887 GLevel->TickWorld(host_frametime);
888
889 // Start open scripts.
890 GLevel->Acs->StartTypedACScripts(SCRIPT_Open, 0, 0, 0, NULL, false,
891 false);
892 }
893
894 GCon->Log(NAME_Dev, "Server spawned");
895 unguard;
896 }
897
898 //==========================================================================
899 //
900 // COMMAND PreSpawn
901 //
902 //==========================================================================
903
COMMAND(PreSpawn)904 COMMAND(PreSpawn)
905 {
906 guard(COMMAND PreSpawn);
907 if (Source == SRC_Command)
908 {
909 GCon->Log("PreSpawn is not valid from console");
910 return;
911 }
912
913 // Make sure level info is spawned on client side, since there
914 // could be some RPCs that depend on it.
915 VThinkerChannel* Chan = Player->Net->ThinkerChannels.FindPtr(GLevelInfo);
916 if (!Chan)
917 {
918 Chan = (VThinkerChannel*)Player->Net->CreateChannel(CHANNEL_Thinker,
919 -1);
920 if (Chan)
921 {
922 Chan->SetThinker(GLevelInfo);
923 Chan->Update();
924 }
925 }
926 unguard;
927 }
928
929 //==========================================================================
930 //
931 // COMMAND Spawn
932 //
933 //==========================================================================
934
COMMAND(Spawn)935 COMMAND(Spawn)
936 {
937 guard(COMMAND Spawn);
938 if (Source == SRC_Command)
939 {
940 GCon->Log("Spawn is not valid from console");
941 return;
942 }
943
944 Player->SpawnClient();
945 unguard;
946 }
947
948 //==========================================================================
949 //
950 // SV_DropClient
951 //
952 //==========================================================================
953
SV_DropClient(VBasePlayer * Player,bool)954 void SV_DropClient(VBasePlayer* Player, bool)
955 {
956 guard(SV_DropClient);
957 if (GLevel && GLevel->Acs)
958 {
959 GLevel->Acs->StartTypedACScripts(SCRIPT_Disconnect,
960 SV_GetPlayerNum(Player), 0, 0, NULL, true, false);
961 }
962 if (Player->PlayerFlags & VBasePlayer::PF_Spawned)
963 {
964 Player->eventDisconnectClient();
965 }
966 Player->PlayerFlags &= ~VBasePlayer::PF_Active;
967 GGameInfo->Players[SV_GetPlayerNum(Player)] = NULL;
968 Player->PlayerFlags &= ~VBasePlayer::PF_Spawned;
969
970 Player->PlayerReplicationInfo->DestroyThinker();
971
972 delete Player->Net;
973 Player->Net = NULL;
974
975 svs.num_connected--;
976 Player->UserInfo = VStr();
977 unguard;
978 }
979
980 //==========================================================================
981 //
982 // SV_ShutdownGame
983 //
984 // This only happens at the end of a game, not between levels
985 // This is also called on Host_Error, so it shouldn't cause any errors
986 //
987 //==========================================================================
988
SV_ShutdownGame()989 void SV_ShutdownGame()
990 {
991 guard(SV_ShutdownGame);
992 if (GGameInfo->NetMode == NM_None)
993 {
994 return;
995 }
996
997 #ifdef CLIENT
998 if (GGameInfo->Flags & VGameInfo::GIF_Paused)
999 {
1000 GGameInfo->Flags &= ~VGameInfo::GIF_Paused;
1001 GAudio->ResumeSound();
1002 }
1003
1004 // stop sounds (especially looping!)
1005 GAudio->StopAllSound();
1006
1007 if (cls.demorecording)
1008 {
1009 CL_StopRecording();
1010 }
1011 #endif
1012
1013 if (GGameInfo->NetMode == NM_Client)
1014 {
1015 #ifdef CLIENT
1016 if (cls.demoplayback)
1017 {
1018 GClGame->eventDemoPlaybackStopped();
1019 }
1020
1021 // Sends a disconnect message to the server
1022 if (!cls.demoplayback)
1023 {
1024 GCon->Log(NAME_Dev, "Sending clc_disconnect");
1025 cl->Net->Channels[0]->Close();
1026 cl->Net->Flush();
1027 }
1028
1029 delete cl->Net;
1030 cl->Net = NULL;
1031 cl->ConditionalDestroy();
1032
1033 if (GClLevel)
1034 {
1035 delete GClLevel;
1036 GClLevel = NULL;
1037 }
1038 #endif
1039 }
1040 else
1041 {
1042 sv_loading = false;
1043 sv_map_travel = false;
1044
1045 // make sure all the clients know we're disconnecting
1046 int count = NET_SendToAll(5);
1047 if (count)
1048 {
1049 GCon->Logf("Shutdown server failed for %d clients", count);
1050 }
1051
1052 for (int i = 0; i < svs.max_clients; i++)
1053 {
1054 if (GGameInfo->Players[i])
1055 {
1056 SV_DropClient(GGameInfo->Players[i], false);
1057 }
1058 }
1059
1060 //
1061 // clear structures
1062 //
1063 if (GLevel)
1064 {
1065 delete GLevel;
1066 GLevel = NULL;
1067 }
1068 if (GGameInfo->WorldInfo)
1069 {
1070 delete GGameInfo->WorldInfo;
1071 GGameInfo->WorldInfo = NULL;
1072 }
1073 for (int i = 0; i < MAXPLAYERS; i++)
1074 {
1075 // Save net pointer
1076 VNetConnection* OldNet = GPlayersBase[i]->Net;
1077 GPlayersBase[i]->GetClass()->DestructObject(GPlayersBase[i]);
1078 memset((vuint8*)GPlayersBase[i] + sizeof(VObject), 0,
1079 GPlayersBase[i]->GetClass()->ClassSize - sizeof(VObject));
1080 // Restore pointer
1081 GPlayersBase[i]->Net = OldNet;
1082 }
1083 memset(GGameInfo->Players, 0, sizeof(GGameInfo->Players));
1084 memset(&sv, 0, sizeof(sv));
1085
1086 // Tell master server that this server is gone.
1087 if (GGameInfo->NetMode >= NM_DedicatedServer)
1088 {
1089 GNet->QuitMaster();
1090 LastMasterUpdate = 0;
1091 }
1092 }
1093
1094 #ifdef CLIENT
1095 GClLevel = NULL;
1096 cl = NULL;
1097 cls.demoplayback = false;
1098 cls.signon = 0;
1099
1100 if (GGameInfo->NetMode != NM_DedicatedServer)
1101 {
1102 GClGame->eventDisconnected();
1103 }
1104 #endif
1105
1106 SV_InitBaseSlot();
1107
1108 GGameInfo->NetMode = NM_None;
1109 unguard;
1110 }
1111
1112 #ifdef CLIENT
1113
1114 //==========================================================================
1115 //
1116 // G_DoSingleReborn
1117 //
1118 // Called by G_Ticker based on gameaction. Loads a game from the reborn
1119 // save slot.
1120 //
1121 //==========================================================================
1122
COMMAND(Restart)1123 COMMAND(Restart)
1124 {
1125 guard(COMMAND Restart);
1126 if (GGameInfo->NetMode != NM_Standalone)
1127 {
1128 return;
1129 }
1130
1131 if (SV_RebornSlotAvailable())
1132 {
1133 // Use the reborn code if the slot is available
1134 SV_LoadGame(SV_GetRebornSlot());
1135 }
1136 else
1137 {
1138 // reload the level from scratch
1139 SV_SpawnServer(*GLevel->MapName, true, false);
1140 }
1141 unguard;
1142 }
1143
1144 #endif
1145
1146 //==========================================================================
1147 //
1148 // COMMAND Pause
1149 //
1150 //==========================================================================
1151
COMMAND(Pause)1152 COMMAND(Pause)
1153 {
1154 guard(COMMAND Pause);
1155 if (Source == SRC_Command)
1156 {
1157 ForwardToServer();
1158 return;
1159 }
1160
1161 GGameInfo->Flags ^= VGameInfo::GIF_Paused;
1162 for (int i = 0; i < svs.max_clients; i++)
1163 {
1164 if (GGameInfo->Players[i])
1165 {
1166 GGameInfo->Players[i]->eventClientPause(
1167 !!(GGameInfo->Flags & VGameInfo::GIF_Paused));
1168 }
1169 }
1170 unguard;
1171 }
1172
1173 //==========================================================================
1174 //
1175 // Stats_f
1176 //
1177 //==========================================================================
1178
COMMAND(Stats)1179 COMMAND(Stats)
1180 {
1181 guard(COMMAND Stats);
1182 if (Source == SRC_Command)
1183 {
1184 ForwardToServer();
1185 return;
1186 }
1187
1188 Player->Printf("Kills: %d of %d", Player->KillCount, GLevelInfo->TotalKills);
1189 Player->Printf("Items: %d of %d", Player->ItemCount, GLevelInfo->TotalItems);
1190 Player->Printf("Secrets: %d of %d", Player->SecretCount, GLevelInfo->TotalSecret);
1191 unguard;
1192 }
1193
1194 //==========================================================================
1195 //
1196 // SV_ConnectClient
1197 //
1198 // Initialises a client_t for a new net connection. This will only be
1199 // called once for a player each game, not once for each level change.
1200 //
1201 //==========================================================================
1202
SV_ConnectClient(VBasePlayer * player)1203 void SV_ConnectClient(VBasePlayer *player)
1204 {
1205 guard(SV_ConnectClient);
1206 if (player->Net)
1207 {
1208 GCon->Logf(NAME_Dev, "Client %s connected", *player->Net->GetAddress());
1209
1210 ServerNetContext->ClientConnections.Append(player->Net);
1211 player->Net->NeedsUpdate = false;
1212 }
1213
1214 GGameInfo->Players[SV_GetPlayerNum(player)] = player;
1215 player->ClientNum = SV_GetPlayerNum(player);
1216 player->PlayerFlags |= VBasePlayer::PF_Active;
1217
1218 player->PlayerFlags &= ~VBasePlayer::PF_Spawned;
1219 player->Level = GLevelInfo;
1220 if (!sv_loading)
1221 {
1222 player->MO = NULL;
1223 player->PlayerState = PST_REBORN;
1224 player->eventPutClientIntoServer();
1225 }
1226 player->Frags = 0;
1227 player->Deaths = 0;
1228
1229 player->PlayerReplicationInfo =
1230 (VPlayerReplicationInfo*)GLevel->SpawnThinker(GGameInfo->PlayerReplicationInfoClass);
1231 player->PlayerReplicationInfo->Player = player;
1232 player->PlayerReplicationInfo->PlayerNum = SV_GetPlayerNum(player);
1233 unguard;
1234 }
1235
1236 //==========================================================================
1237 //
1238 // SV_CheckForNewClients
1239 //
1240 //==========================================================================
1241
SV_CheckForNewClients()1242 void SV_CheckForNewClients()
1243 {
1244 guard(SV_CheckForNewClients);
1245 VSocketPublic* sock;
1246 int i;
1247
1248 //
1249 // check for new connections
1250 //
1251 while (1)
1252 {
1253 sock = GNet->CheckNewConnections();
1254 if (!sock)
1255 {
1256 break;
1257 }
1258
1259 //
1260 // init a new client structure
1261 //
1262 for (i = 0; i < svs.max_clients; i++)
1263 {
1264 if (!GGameInfo->Players[i])
1265 {
1266 break;
1267 }
1268 }
1269 if (i == svs.max_clients)
1270 {
1271 Sys_Error("Host_CheckForNewClients: no free clients");
1272 }
1273
1274 VBasePlayer* Player = GPlayersBase[i];
1275 Player->Net = new VNetConnection(sock, ServerNetContext, Player);
1276 Player->Net->ObjMap->SetUpClassLookup();
1277 ((VPlayerChannel*)Player->Net->Channels[CHANIDX_Player])->SetPlayer(Player);
1278 Player->Net->CreateChannel(CHANNEL_ObjectMap, -1);
1279 SV_ConnectClient(Player);
1280 svs.num_connected++;
1281 }
1282 unguard;
1283 }
1284
1285 //==========================================================================
1286 //
1287 // SV_ConnectBot
1288 //
1289 //==========================================================================
1290
SV_ConnectBot(const char * name)1291 void SV_ConnectBot(const char *name)
1292 {
1293 guard(SV_ConnectBot);
1294 int i;
1295
1296 if (GGameInfo->NetMode == NM_None || GGameInfo->NetMode == NM_Client)
1297 {
1298 GCon->Log("Game is not running");
1299 return;
1300 }
1301
1302 if (svs.num_connected >= svs.max_clients)
1303 {
1304 GCon->Log("Server is full");
1305 return;
1306 }
1307
1308 //
1309 // init a new client structure
1310 //
1311 for (i = 0; i < svs.max_clients; i++)
1312 if (!GGameInfo->Players[i])
1313 break;
1314 if (i == svs.max_clients)
1315 Sys_Error("SV_ConnectBot: no free clients");
1316
1317 VBasePlayer* Player = GPlayersBase[i];
1318 Player->PlayerFlags |= VBasePlayer::PF_IsBot;
1319 Player->PlayerName = name;
1320 SV_ConnectClient(Player);
1321 svs.num_connected++;
1322 Player->SetUserInfo(Player->UserInfo);
1323 Player->SpawnClient();
1324 unguard;
1325 }
1326
1327 //==========================================================================
1328 //
1329 // COMMAND AddBot
1330 //
1331 //==========================================================================
1332
COMMAND(AddBot)1333 COMMAND(AddBot)
1334 {
1335 SV_ConnectBot(Args.Num() > 1 ? *Args[1] : "");
1336 }
1337
1338 //==========================================================================
1339 //
1340 // Map
1341 //
1342 //==========================================================================
1343
COMMAND(Map)1344 COMMAND(Map)
1345 {
1346 guard(COMMAND Map);
1347 VStr mapname;
1348
1349 if (Args.Num() != 2)
1350 {
1351 GCon->Log("map <mapname> : change level");
1352 return;
1353 }
1354 mapname = Args[1];
1355
1356 SV_ShutdownGame();
1357
1358 // Default the player start spot group to 0
1359 RebornPosition = 0;
1360 GGameInfo->RebornPosition = RebornPosition;
1361
1362 if ((int)Skill < 0)
1363 {
1364 Skill = 0;
1365 }
1366 else if ((int)Skill >= P_GetNumSkills())
1367 {
1368 Skill = P_GetNumSkills() - 1;
1369 }
1370
1371 SV_SpawnServer(*mapname, true, false);
1372 #ifdef CLIENT
1373 if (GGameInfo->NetMode != NM_DedicatedServer)
1374 {
1375 CL_SetUpLocalPlayer();
1376 }
1377 #endif
1378 unguard;
1379 }
1380
1381 //==========================================================================
1382 //
1383 // Host_StartTitleMap
1384 //
1385 //==========================================================================
1386
Host_StartTitleMap()1387 bool Host_StartTitleMap()
1388 {
1389 guard(Host_StartTitleMap);
1390 if (!FL_FileExists("maps/titlemap.wad") &&
1391 W_CheckNumForName(NAME_titlemap) < 0)
1392 {
1393 return false;
1394 }
1395
1396 // Default the player start spot group to 0
1397 RebornPosition = 0;
1398 GGameInfo->RebornPosition = RebornPosition;
1399
1400 SV_SpawnServer("titlemap", true, true);
1401 #ifdef CLIENT
1402 CL_SetUpLocalPlayer();
1403 #endif
1404 return true;
1405 unguard;
1406 }
1407
1408 //==========================================================================
1409 //
1410 // COMMAND MaxPlayers
1411 //
1412 //==========================================================================
1413
COMMAND(MaxPlayers)1414 COMMAND(MaxPlayers)
1415 {
1416 guard(COMMAND MaxPlayers);
1417 int n;
1418
1419 if (Args.Num() != 2)
1420 {
1421 GCon->Logf("maxplayers is %d", svs.max_clients);
1422 return;
1423 }
1424
1425 if (GGameInfo->NetMode != NM_None && GGameInfo->NetMode != NM_Client)
1426 {
1427 GCon->Log("maxplayers can not be changed while a server is running.");
1428 return;
1429 }
1430
1431 n = atoi(*Args[1]);
1432 if (n < 1)
1433 n = 1;
1434 if (n > MAXPLAYERS)
1435 {
1436 n = MAXPLAYERS;
1437 GCon->Logf("maxplayers set to %d", n);
1438 }
1439 svs.max_clients = n;
1440
1441 if (n == 1)
1442 {
1443 #ifdef CLIENT
1444 GCmdBuf << "listen 0\n";
1445 #endif
1446 DeathMatch = 0;
1447 NoMonsters = 0;
1448 }
1449 else
1450 {
1451 #ifdef CLIENT
1452 GCmdBuf << "listen 1\n";
1453 #endif
1454 DeathMatch = 2;
1455 NoMonsters = 1;
1456 }
1457 unguard;
1458 }
1459
1460 //==========================================================================
1461 //
1462 // ServerFrame
1463 //
1464 //==========================================================================
1465
ServerFrame(int realtics)1466 void ServerFrame(int realtics)
1467 {
1468 guard(ServerFrame);
1469 SV_CheckForNewClients();
1470
1471 if (real_time)
1472 {
1473 SV_Ticker();
1474 }
1475 else
1476 {
1477 // run the count dics
1478 while (realtics--)
1479 {
1480 SV_Ticker();
1481 }
1482 }
1483
1484 if (mapteleport_issued)
1485 {
1486 SV_MapTeleport(GLevelInfo->NextMap);
1487 }
1488
1489 SV_SendClientMessages();
1490 unguard;
1491 }
1492
1493 //==========================================================================
1494 //
1495 // SV_FindClassFromEditorId
1496 //
1497 //==========================================================================
1498
SV_FindClassFromEditorId(int Id,int GameFilter)1499 VClass* SV_FindClassFromEditorId(int Id, int GameFilter)
1500 {
1501 guard(SV_FindClassFromEditorId);
1502 for (int i = VClass::GMobjInfos.Num() - 1; i >= 0; i--)
1503 {
1504 if ((!VClass::GMobjInfos[i].GameFilter ||
1505 (VClass::GMobjInfos[i].GameFilter & GameFilter)) &&
1506 Id == VClass::GMobjInfos[i].DoomEdNum)
1507 {
1508 return VClass::GMobjInfos[i].Class;
1509 }
1510 }
1511 return NULL;
1512 unguard;
1513 }
1514
1515 //==========================================================================
1516 //
1517 // SV_FindClassFromScriptId
1518 //
1519 //==========================================================================
1520
SV_FindClassFromScriptId(int Id,int GameFilter)1521 VClass* SV_FindClassFromScriptId(int Id, int GameFilter)
1522 {
1523 guard(SV_FindClassFromScriptId);
1524 for (int i = VClass::GScriptIds.Num() - 1; i >= 0; i--)
1525 {
1526 if ((!VClass::GScriptIds[i].GameFilter ||
1527 (VClass::GScriptIds[i].GameFilter & GameFilter)) &&
1528 Id == VClass::GScriptIds[i].DoomEdNum)
1529 {
1530 return VClass::GScriptIds[i].Class;
1531 }
1532 }
1533 return NULL;
1534 unguard;
1535 }
1536
1537 //==========================================================================
1538 //
1539 // COMMAND Say
1540 //
1541 //==========================================================================
1542
COMMAND(Say)1543 COMMAND(Say)
1544 {
1545 guard(COMMAND Say);
1546 if (Source == SRC_Command)
1547 {
1548 ForwardToServer();
1549 return;
1550 }
1551 if (Args.Num() < 2)
1552 return;
1553
1554 VStr Text = Player->PlayerName;
1555 Text += ":";
1556 for (int i = 1; i < Args.Num(); i++)
1557 {
1558 Text += " ";
1559 Text += Args[i];
1560 }
1561 GLevelInfo->BroadcastPrint(*Text);
1562 GLevelInfo->StartSound(TVec(0, 0, 0), 0,
1563 GSoundManager->GetSoundID("misc/chat"), 0, 1.0, 0, false);
1564 unguard;
1565 }
1566
1567 //==========================================================================
1568 //
1569 // VServerNetContext::GetLevel
1570 //
1571 //==========================================================================
1572
GetLevel()1573 VLevel* VServerNetContext::GetLevel()
1574 {
1575 return GLevel;
1576 }
1577
1578 //**************************************************************************
1579 //
1580 // Dedicated server console streams
1581 //
1582 //**************************************************************************
1583
1584 #ifndef CLIENT
1585
1586 class FConsoleDevice : public FOutputDevice
1587 {
1588 public:
Serialise(const char * V,EName)1589 void Serialise(const char* V, EName)
1590 {
1591 printf("%s\n", V);
1592 }
1593 };
1594
1595 FConsoleDevice Console;
1596
1597 FOutputDevice *GCon = &Console;
1598
1599 #endif
1600