]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Finish savestate implementation for now, hooked up savestate saving for each checkpoi...
authordrjaska <drjaska83@gmail.com>
Sat, 7 May 2022 12:21:20 +0000 (15:21 +0300)
committerdrjaska <drjaska83@gmail.com>
Sat, 7 May 2022 12:21:20 +0000 (15:21 +0300)
13 files changed:
qcsrc/common/gamemodes/gamemode/ctscup/TODO.txt
qcsrc/common/gamemodes/gamemode/ctscup/_mod.inc
qcsrc/common/gamemodes/gamemode/ctscup/_mod.qh
qcsrc/common/gamemodes/gamemode/ctscup/savestate.qc [deleted file]
qcsrc/common/gamemodes/gamemode/ctscup/savestate.qh [deleted file]
qcsrc/common/gamemodes/gamemode/ctscup/sv_ctscup.qc
qcsrc/common/gamemodes/gamemode/ctscup/sv_ctscup.qh
qcsrc/server/_mod.inc
qcsrc/server/_mod.qh
qcsrc/server/mutators/events.qh
qcsrc/server/race.qc
qcsrc/server/savestate.qc [new file with mode: 0644]
qcsrc/server/savestate.qh [new file with mode: 0644]

index 581582f8c917d51194ff77f3bdfbe967b39384b2..898d1db1a55d480d494c0ba3ddca87e88aebbce8 100644 (file)
@@ -6,15 +6,14 @@ Round handler:
 - Clear times upon round reset
 
 Savestates:
-- Finish implementating savestates
-- Hook up savestate saving to touching a checkpoint
-- Delete savestates upon round reset
+- Softlock prevention
+- FIXME?: Splat damage is dealt AFTER health restoring of savestate loading if the player were to smash into something and die from another source during I think the same frame
 - I hope that loading a savestate from Damage_Calculate hook when player is about to die and setting incoming
 damage to 0 can still save them and dying (for example by suicide bind) isn't a hardcoded death :)
 
 HUD:
 - Display current round's players
-- Display splits
+- Display checkpoint splits
 - Display how many players are about to lose this round and show that on splits
 - Maybe show eliminated players on leaderboard, there should be a difference between 2nd place and Nth place for bragging rights
 - Medals for placements?
index d57a6255ec95c682479ab6e2892f6fb743392695..89d6a2c7a48ba0a69b2c2e0df4cc25bb5b1fd72f 100644 (file)
@@ -6,4 +6,3 @@
 #ifdef SVQC
     #include <common/gamemodes/gamemode/ctscup/sv_ctscup.qc>
 #endif
-#include <common/gamemodes/gamemode/ctscup/savestate.qc>
index 6c08b79f42c6bdb1d428f56d61669a32e694bcf9..e9459a01769fddc2fdaeb0472810819d9ccd4815 100644 (file)
@@ -6,4 +6,3 @@
 #ifdef SVQC
     #include <common/gamemodes/gamemode/ctscup/sv_ctscup.qh>
 #endif
-#include <common/gamemodes/gamemode/ctscup/savestate.qh>
diff --git a/qcsrc/common/gamemodes/gamemode/ctscup/savestate.qc b/qcsrc/common/gamemodes/gamemode/ctscup/savestate.qc
deleted file mode 100644 (file)
index e07c55e..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-//these files can be moved but while CTS Cup is WIP I'll keep them in CTS Cup's gamemode folder
-//files to update if moving: sv_ctscup.qh, ctscup folder's _mod files
-
-#include "savestate.qh"
-
-void SaveSaveState(entity player)
-{
-       if (player.savestate)
-       {
-               player.savestate.origin = player.origin;
-               player.savestate.v_angle = player.v_angle;
-               player.savestate.angles = player.angles;
-               player.savestate.velocity = player.velocity;
-               //SetResource(player.savestate, RES_ROCKETS, GetResource(player, RES_ROCKETS));
-               //SetResource(player.savestate, RES_BULLETS, GetResource(player, RES_BULLETS));
-               //SetResource(player.savestate, RES_CELLS, GetResource(player, RES_CELLS));
-               //SetResource(player.savestate, RES_PLASMA, GetResource(player, RES_PLASMA));
-               //SetResource(player.savestate, RES_SHELLS, GetResource(player, RES_SHELLS));
-               //SetResource(player.savestate, RES_FUEL, GetResource(player, RES_FUEL));
-               //SetResource(player.savestate, RES_HEALTH, max(1, GetResource(player, RES_HEALTH)));
-               //SetResource(player.savestate, RES_ARMOR, GetResource(player, RES_ARMOR));
-               //STAT(WEAPONS, player.savestate) = STAT(WEAPONS, player);
-               //StatusEffects_copy(player.statuseffects, player.savestate, 0);
-               player.savestate.items = player.items;
-               player.savestate.pauserotarmor_finished = player.pauserotarmor_finished;
-               player.savestate.pauserothealth_finished = player.pauserothealth_finished;
-               player.savestate.pauserotfuel_finished = player.pauserotfuel_finished;
-               player.savestate.pauseregen_finished = player.pauseregen_finished;
-               player.savestate.teleport_time = time;
-       }
-}
-
-bool LoadSaveState(entity player)
-{
-       if (player.savestate)
-       {
-               player.origin = player.savestate.origin;
-               player.v_angle = player.savestate.v_angle;
-               player.angles = player.savestate.angles;
-               player.fixangle = true;
-               player.velocity = player.savestate.velocity;
-               //SetResource(player, RES_ROCKETS, GetResource(player.savestate, RES_ROCKETS));
-               //SetResource(player, RES_BULLETS, GetResource(player.savestate, RES_BULLETS));
-               //SetResource(player, RES_CELLS, GetResource(player.savestate, RES_CELLS));
-               //SetResource(player, RES_PLASMA, GetResource(player.savestate, RES_PLASMA));
-               //SetResource(player, RES_SHELLS, GetResource(player.savestate, RES_SHELLS));
-               //SetResource(player, RES_FUEL, GetResource(player.savestate, RES_FUEL));
-               //SetResource(player, RES_HEALTH, GetResource(player.savestate, RES_HEALTH));
-               //SetResource(player, RES_ARMOR, GetResource(player.savestate, RES_ARMOR));
-               //STAT(WEAPONS, player) = STAT(WEAPONS, player.savestate);
-               //StatusEffects_copy(player.savestate, player.statuseffects, player.savestate.teleport_time);
-               //StatusEffects_update(player);
-               player.items = player.savestate.items;
-               player.pauserotarmor_finished = time + player.savestate.pauserotarmor_finished - player.savestate.teleport_time;
-               player.pauserothealth_finished = time + player.savestate.pauserothealth_finished - player.savestate.teleport_time;
-               player.pauserotfuel_finished = time + player.savestate.pauserotfuel_finished - player.savestate.teleport_time;
-               player.pauseregen_finished = time + player.savestate.pauseregen_finished - player.savestate.teleport_time;
-
-               return true;
-       }
-       return false;
-}
-
-void DeleteSaveState(entity player)
-{
-       if (player.savestate)
-               delete(player.savestate);
-}
-
diff --git a/qcsrc/common/gamemodes/gamemode/ctscup/savestate.qh b/qcsrc/common/gamemodes/gamemode/ctscup/savestate.qh
deleted file mode 100644 (file)
index eac6517..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-//#include <common/resources/cl_resources.qh>
-//#include <common/mutators/mutator/status_effects/status_effects.qh>
-//#include <lib/stats.qh>
-
-.entity savestate;
-
-void SaveSaveState(entity player);
-bool LoadSaveState(entity player);
-void DeleteSaveState(entity player);
-
-.vector origin;
-.vector v_angle;
-.vector angles;
-.bool fixangle;
-.vector velocity;
-.float items;
-.float pauserotarmor_finished;
-.float pauserothealth_finished;
-.float pauserotfuel_finished;
-.float pauseregen_finished;
-.float teleport_time;
index f801ebb4c623303f39da8a8863ec11ac3d46b885..80808ea56b39cd32dfc1bf3426fadbb3e6bf7612 100644 (file)
@@ -287,8 +287,15 @@ MUTATOR_HOOKFUNCTION(ctscup, PlayerSpawn)
                SaveSaveState(player);
        }
 
-       // upon spawning for a new round within 1s of the round starting, save a savestate
-       if ((time - 1) < (round_handler_GetEndTime() - autocvar_g_ctscup_maxroundlength))
+       //debug print
+       //print(sprintf("%f", time), " time \n");
+       //print(sprintf("%f", round_handler_GetEndTime()), " round_handler_GetEndTime() \n");
+       //print(sprintf("%f", (roundFirstFinisherTime + autocvar_g_ctscup_finishwait)), " (roundFirstFinisherTime + autocvar_g_ctscup_finishwait) \n\n");
+
+       // upon spawning for a new round, save a savestate instead of loading an old one
+       // for whatever reason on the frame players are reset and spawned for a new round to start
+       // round_handler_GetEndTime() still gives the end time for last round and time should be bigger than that
+       if ((time > round_handler_GetEndTime()) || (roundFirstFinisherTime && (time > (roundFirstFinisherTime + autocvar_g_ctscup_finishwait))))
        {
                SaveSaveState(player);
        }
@@ -377,6 +384,8 @@ bool CTSCUP_CanRoundStart()
 
 void CTSCUP_RoundStart()
 {
+       roundFirstFinisherTime = 0;
+
        CTSCUP_AliveParticipants();
 }
 
@@ -425,7 +434,7 @@ void CTSCUP_TournamentStart()
 
 MUTATOR_HOOKFUNCTION(ctscup, reset_map_players)
 {
-       roundFirstFinisherTime = 0;
+       // roundFirstFinisherTime = 0;
 
        if (tournamentStarted) roundCounter++;
        else CTSCUP_TournamentStart();
@@ -465,6 +474,13 @@ MUTATOR_HOOKFUNCTION(ctscup, ForbidSpawn)
        return canSpawn;
 }
 
+MUTATOR_HOOKFUNCTION(ctscup, Race_Checkpoint)
+{
+       entity player = M_ARGV(0, entity);
+
+       SaveSaveState(player);
+}
+
 MUTATOR_HOOKFUNCTION(ctscup, ClientCommand_Spectate)
 {
        entity player = M_ARGV(0, entity);
index 943db58d9d84ce19b96fa93ce61e6250ef4f2bdc..4378c20dd77df00f55c06eeb5fc5528b626dabe5 100644 (file)
@@ -1,9 +1,8 @@
 #pragma once
 
-#include "savestate.qh"
-
 #include <common/mutators/base.qh>
 #include <server/race.qh>
+#include <server/savestate.qh>
 #include <common/gamemodes/gamemode/cts/sv_cts.qh>
 
 void ctscup_Initialize();
index c82e892f721815fdeff9c6b46d0260eee26fe86d..eb02899b1949594d7e32d9b9da360e44bed183eb 100644 (file)
@@ -21,6 +21,7 @@
 #include <server/portals.qc>
 #include <server/race.qc>
 #include <server/round_handler.qc>
+#include <server/savestate.qc>
 #include <server/scores.qc>
 #include <server/scores_rules.qc>
 #include <server/spawnpoints.qc>
index 52574efecc1ac689a2d9a341cc9a10a7d40c6943..716594c24ca930433d0a066e95782a14ace05284 100644 (file)
@@ -21,6 +21,7 @@
 #include <server/portals.qh>
 #include <server/race.qh>
 #include <server/round_handler.qh>
+#include <server/savestate.qh>
 #include <server/scores.qh>
 #include <server/scores_rules.qh>
 #include <server/spawnpoints.qh>
index 6feb8113233dd0280b964a3b7f7e0687a324b89a..5f4010e78f469c63e217ff0f65754e3b30fb74d9 100644 (file)
@@ -905,6 +905,11 @@ MUTATOR_HOOKABLE(DecodeLevelParms, EV_NO_ARGS);
     /**/
 MUTATOR_HOOKABLE(GetRecords, EV_GetRecords);
 
+#define EV_Race_Checkpoint(i, o) \
+    /** player */ i(entity, MUTATOR_ARGV_0_entity) \
+    /**/
+MUTATOR_HOOKABLE(Race_Checkpoint, EV_Race_Checkpoint);
+
 #define EV_Race_FinalCheckpoint(i, o) \
     /** player */ i(entity, MUTATOR_ARGV_0_entity) \
     /**/
index 24a25f87fb9ab314853e69c975deedc04dc68fdc..f3af86b48588cde3e3344a270aea4fdeb6332741 100644 (file)
@@ -790,6 +790,8 @@ void checkpoint_passed(entity this, entity player)
                        }
                        fclose(fh);
                }
+
+               MUTATOR_CALLHOOK(Race_Checkpoint, player);
        }
        else if(player.race_checkpoint == race_NextCheckpoint(this.race_checkpoint))
        {
diff --git a/qcsrc/server/savestate.qc b/qcsrc/server/savestate.qc
new file mode 100644 (file)
index 0000000..ef08083
--- /dev/null
@@ -0,0 +1,66 @@
+#include "savestate.qh"
+
+void SaveSaveState(entity player)
+{
+       if (player.savestate)
+       {
+               player.savestate.origin = player.origin;
+               player.savestate.v_angle = player.v_angle;
+               player.savestate.angles = player.angles;
+               player.savestate.velocity = player.velocity;
+               SetResource(player.savestate, RES_ROCKETS, GetResource(player, RES_ROCKETS));
+               SetResource(player.savestate, RES_BULLETS, GetResource(player, RES_BULLETS));
+               SetResource(player.savestate, RES_CELLS, GetResource(player, RES_CELLS));
+               SetResource(player.savestate, RES_PLASMA, GetResource(player, RES_PLASMA));
+               SetResource(player.savestate, RES_SHELLS, GetResource(player, RES_SHELLS));
+               SetResource(player.savestate, RES_FUEL, GetResource(player, RES_FUEL));
+               SetResource(player.savestate, RES_HEALTH, max(1, GetResource(player, RES_HEALTH)));
+               SetResource(player.savestate, RES_ARMOR, GetResource(player, RES_ARMOR));
+               STAT(WEAPONS, player.savestate) = STAT(WEAPONS, player);
+               StatusEffects_copy(player.statuseffects, player.savestate, 0);
+               player.savestate.items = player.items;
+               player.savestate.pauserotarmor_finished = player.pauserotarmor_finished;
+               player.savestate.pauserothealth_finished = player.pauserothealth_finished;
+               player.savestate.pauserotfuel_finished = player.pauserotfuel_finished;
+               player.savestate.pauseregen_finished = player.pauseregen_finished;
+               player.savestate.teleport_time = time;
+       }
+}
+
+bool LoadSaveState(entity player)
+{
+       if (player.savestate)
+       {
+               player.origin = player.savestate.origin;
+               player.v_angle = player.savestate.v_angle;
+               player.angles = player.savestate.angles;
+               player.fixangle = true;
+               player.velocity = player.savestate.velocity;
+               SetResource(player, RES_ROCKETS, GetResource(player.savestate, RES_ROCKETS));
+               SetResource(player, RES_BULLETS, GetResource(player.savestate, RES_BULLETS));
+               SetResource(player, RES_CELLS, GetResource(player.savestate, RES_CELLS));
+               SetResource(player, RES_PLASMA, GetResource(player.savestate, RES_PLASMA));
+               SetResource(player, RES_SHELLS, GetResource(player.savestate, RES_SHELLS));
+               SetResource(player, RES_FUEL, GetResource(player.savestate, RES_FUEL));
+               SetResource(player, RES_HEALTH, GetResource(player.savestate, RES_HEALTH));
+               SetResource(player, RES_ARMOR, GetResource(player.savestate, RES_ARMOR));
+               STAT(WEAPONS, player) = STAT(WEAPONS, player.savestate);
+               StatusEffects_copy(player.savestate, player.statuseffects, player.savestate.teleport_time);
+               StatusEffects_update(player);
+               player.items = player.savestate.items;
+               player.pauserotarmor_finished = time + player.savestate.pauserotarmor_finished - player.savestate.teleport_time;
+               player.pauserothealth_finished = time + player.savestate.pauserothealth_finished - player.savestate.teleport_time;
+               player.pauserotfuel_finished = time + player.savestate.pauserotfuel_finished - player.savestate.teleport_time;
+               player.pauseregen_finished = time + player.savestate.pauseregen_finished - player.savestate.teleport_time;
+
+               return true;
+       }
+       return false;
+}
+
+void DeleteSaveState(entity player)
+{
+       if (player.savestate)
+               delete(player.savestate);
+}
+
diff --git a/qcsrc/server/savestate.qh b/qcsrc/server/savestate.qh
new file mode 100644 (file)
index 0000000..720ce4e
--- /dev/null
@@ -0,0 +1,21 @@
+#include <common/resources/cl_resources.qh>
+#include <common/mutators/mutator/status_effects/status_effects.qh>
+#include <lib/stats.qh>
+
+.entity savestate;
+
+void SaveSaveState(entity player);
+bool LoadSaveState(entity player);
+void DeleteSaveState(entity player);
+
+.vector origin;
+.vector v_angle;
+.vector angles;
+.bool fixangle;
+.vector velocity;
+.float items;
+.float pauserotarmor_finished;
+.float pauserothealth_finished;
+.float pauserotfuel_finished;
+.float pauseregen_finished;
+.float teleport_time;