]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Added new cl_hooks, menu_cmd isdemo and fixed demoseeking.cfg
authorDr. Jaska <drjaska83@gmail.com>
Mon, 27 Jan 2025 16:28:52 +0000 (16:28 +0000)
committerDr. Jaska <drjaska83@gmail.com>
Mon, 27 Jan 2025 16:28:52 +0000 (16:28 +0000)
commands.cfg
demoseeking.cfg
gamemodes-client.cfg
qcsrc/client/main.qc
qcsrc/client/main.qh
qcsrc/client/view.qc
qcsrc/menu/command/menu_cmd.qc

index 8ff4e78b838aeecf71bdd36690509c7065e118cc..daf64570b1f4a8e84e16f38efba1c1b371d6beff 100644 (file)
@@ -130,6 +130,7 @@ alias menu_showsandboxtools "menu_cmd directmenu SandboxTools"
 alias menu_showquitdialog "menu_cmd directmenu Quit"
 alias menu_showgamemenudialog "menu_cmd directmenu GameMenu"
 alias menu_showmonstertools "menu_cmd directmenu MonsterTools"
+alias menu_isdemo "menu_cmd isdemo ${* ?}"
 
 // command executed before loading a map by the menu
 // makes sure maxplayers is at least minplayers or minplayers_per_team * 4 or bot_number + 1
index 5dbaf86b3a783e886327afe150edbc6b148b0c90..ff4a20a97d158f4ab9af34858866e8529b3d9638 100644 (file)
@@ -3,12 +3,11 @@
 //
 // Setup:
 //
-// Add "exec input-demoseeking.cfg" and the following cl_hook_gamestart_all
-// hook to autoexec.cfg. If you already have a cl_hook_gamestart_all hook, add
-// the quoted command to your hook, separated with a semicolon:
+// Add either of the following to your autoexec.cfg:
+//
+//     exec input-demoseeking.cfg
 //
 //     exec demoseeking.cfg
-//     alias cl_hook_gamestart_all "demoseeking_game_started"
 //
 // Usage:
 //     1. start a demo (ply/playdemo command or menu), and
 //
 // Variables:
 //
-// _demo_is_playing
-//     Indicates whether a demo is currently playing. Set to 1 when playdemo
-//     starts a demo.
-//     Note: the setup above is needed to reset this reliably.
 // _current_demo_name
 //     The name of the latest played demo. Same as the argument passed to the
 //     last playdemo command. If playdemo fails to start the demo (e.g. when
@@ -58,7 +53,8 @@
 //
 // Extras:
 //
-// - The alias playdemo_hook is run when demo playback is started.
+// - The alias playdemo_hook is run when playdemo command is called.
+//   Regardless of its success to load a demo with that name.
 // - The alias seekdemo_hook_seek_end is run after a seek completed successfully.
 // - The alias seekdemo_getseektime can be used by scripts to get the current
 //   playback time or seek target time. See its usage below.
@@ -71,13 +67,14 @@ set _demoseeking_fast_speed 80
 set _demoseeking_speed_factor 10
 
 // state initialization
-alias _demoseeking_init_vars "set _demoseeking_vars_loaded 1; set _demo_is_playing 0; set _current_demo_name \"\"; set _demoseeking_is_seeking 0; set _seekdemo_state idle; set _seekdemo_target 0; alias playdemo_hook \"\"; alias seekdemo_hook_seek_end"
+alias _demoseeking_init_vars "set _demoseeking_vars_loaded 1; set _seekdemo_demo_is_playing 0; set _current_demo_name \"\"; set _demoseeking_is_seeking 0; set _seekdemo_state idle; set _seekdemo_target 0; alias playdemo_hook \"\"; alias seekdemo_hook_seek_end"
 alias _demoseeking_init_vars1 ""
 _demoseeking_init_vars${_demoseeking_vars_loaded ?}
 
-// Hook into game start to reset seekdemo state. This prevents reloading the
-// last demo when seekdemo is accidentally called during an actual game.
-alias demoseeking_game_started "set _demo_is_playing 0; set _current_demo_name \"\""
+// Hook into "playdemo" command. This alias runs immediately after the actual
+// "playdemo" command runs. Needed for seekdemo to restart the demo when
+// seeking backwards.
+alias playdemo "set _current_demo_name \"$1\"; playdemo_hook \"$1\""
 
 // usage: seekdemo_getseektime <varname>
 // Populates <varname> with the current seek target time, if seeking. If not
@@ -88,19 +85,6 @@ set _seekdemo_getseektime_rpn_idle time
 set _seekdemo_getseektime_rpn_starting _seekdemo_target
 set _seekdemo_getseektime_rpn_seeking _seekdemo_target
 
-// Hook into "playdemo" command. This alias runs immediately after the actual
-// "playdemo" command runs. Needed for seekdemo to restart the demo when
-// seeking backwards. Runs the playdemo_hook alias when a demo file is being
-// loaded.
-// ---
-// "cl_cmd rpn" fails while a map is loading, leaving the value of
-// _demoseeking_playdemo_success untouched, which means the playdemo command
-// succeeded.
-alias playdemo "set _demoseeking_playdemo_success 1; cl_cmd rpn /_demoseeking_playdemo_success 0 def; _demoseeking_playdemo_check \"$1\""
-alias _demoseeking_playdemo_check "_demoseeking_playdemo_check_$_demoseeking_playdemo_success \"$1\""
-alias _demoseeking_playdemo_check_0 "echo \"playdemo failed\""
-alias _demoseeking_playdemo_check_1 "set _demo_is_playing 1; set _current_demo_name \"$1\"; playdemo_hook"
-
 // Hook into the "defer" command to restore state when "defer clear" is run
 // while seeking. "defer clear" seems to be run by some csprogs.
 // ---
@@ -128,13 +112,13 @@ alias _demoseeking_restore_seeking "_seekdemo_check_time"
 // check if seek should start or if target time should be adjusted instead
 alias seekdemo "_seekdemo_checkstate_$_seekdemo_state ${* q}"
 // before starting seek, verify demo is playing first
-alias _seekdemo_checkstate_idle "set _seekdemo_demo_is_playing 0; cl_cmd rpn /_seekdemo_demo_is_playing _demo_is_playing 0 != def; _seekdemo_checkstart ${* q}"
+alias _seekdemo_checkstate_idle "menu_cmd isdemo _seekdemo_demo_is_playing; _seekdemo_checkstart ${* q}"
 // when already seeking, only update the variable holding the target time
 alias _seekdemo_checkstate_starting "_seekdemo_checkstate_seeking ${* q}"
 alias _seekdemo_checkstate_seeking "rpn /_seekdemo_target _seekdemo_target \"$1\" add def"
 
 alias _seekdemo_checkstart "_seekdemo_checkstart_$_seekdemo_demo_is_playing ${* q}"
-alias _seekdemo_checkstart_0 "echo \"no demo currently playing\""
+alias _seekdemo_checkstart_0 "set _current_demo_name \"\";echo \"no demo currently playing\""
 // start new seek
 alias _seekdemo_checkstart_1 "cl_cmd rpn /_seekdemo_target time \"$1\" add def; set _demoseeking_is_seeking 1; set _seekdemo_state starting; _seekdemo_save_options; _seekdemo_start_seek"
 
index 1648daca5b0fb83440b780b57b17dc1f332979c5..02aea9cf97c3cfb9b5f1b522aa085f969a6a432c 100644 (file)
@@ -14,34 +14,38 @@ alias asay_drop "say_team (%l) dropped %w ; impulse 17"
 seta cl_matchcount 0 // incremented by cl_hook_gameend and used by playerstats to know when to
 alias _cl_hook_gamestart "set _cl_hook_gametype $1; _cl_hook_gamestart_stage2"
 alias _cl_hook_gamestart_stage2 "cl_hook_gamestart_all; cl_hook_gamestart_${_cl_hook_gametype}"
-alias cl_hook_gamestart_all
-alias cl_hook_gamestart_nop  //is only called when CSQC unloads before knowing the gametype, very unlikely
-alias cl_hook_gamestart_dm
-alias cl_hook_gamestart_tdm
-alias cl_hook_gamestart_dom
-alias cl_hook_gamestart_ctf
-alias cl_hook_gamestart_lms
-alias cl_hook_gamestart_ca
-alias cl_hook_gamestart_kh
-alias cl_hook_gamestart_ons
-alias cl_hook_gamestart_as
-alias cl_hook_gamestart_rc
-alias cl_hook_gamestart_nb
-alias cl_hook_gamestart_cts
-alias cl_hook_gamestart_ka
-alias cl_hook_gamestart_ft
-alias cl_hook_gamestart_inv
-alias cl_hook_gamestart_duel
-alias cl_hook_gamestart_mayhem
-alias cl_hook_gamestart_tmayhem
-alias cl_hook_gamestart_tka
-alias cl_hook_gamestart_surv
-alias cl_hook_gameend
-alias cl_hook_shutdown
-alias cl_hook_activeweapon
-// called on client personal best set
-// $1 new pb time,
-// $2 old pb time,
-// $3 how much time the pb improved by
-// $4 new rank# on the leaderboard
-alias cl_hook_race_pb
+alias cl_hook_gamestart_all "" "// this alias is called after loading into a match"
+alias cl_hook_gamestart_nop "" "// this alias is only called when CSQC unloads before knowing the gametype, very unlikely"
+alias cl_hook_gamestart_dm "" "// this alias is called after loading into deathmatch"
+alias cl_hook_gamestart_tdm "" "// this alias is called after loading into team deathmatch"
+alias cl_hook_gamestart_dom "" "// this alias is called after loading into domination"
+alias cl_hook_gamestart_ctf "" "// this alias is called after loading into capture the flag"
+alias cl_hook_gamestart_lms "" "// this alias is called after loading into last man standing"
+alias cl_hook_gamestart_ca "" "// this alias is called after loading into clan arena"
+alias cl_hook_gamestart_kh "" "// this alias is called after loading into keyhunt"
+alias cl_hook_gamestart_ons "" "// this alias is called after loading into onslaught"
+alias cl_hook_gamestart_as "" "// this alias is called after loading into assault"
+alias cl_hook_gamestart_rc "" "// this alias is called after loading into race"
+alias cl_hook_gamestart_nb "" "// this alias is called after loading into nexball"
+alias cl_hook_gamestart_cts "" "// this alias is called after loading into complete the stage"
+alias cl_hook_gamestart_ka "" "// this alias is called after loading into keepaway"
+alias cl_hook_gamestart_ft "" "// this alias is called after loading into freezetag"
+alias cl_hook_gamestart_inv "" "// this alias is called after loading into invasion"
+alias cl_hook_gamestart_duel "" "// this alias is called after loading into duel"
+alias cl_hook_gamestart_mayhem "" "// this alias is called after loading into mayhem"
+alias cl_hook_gamestart_tmayhem "" "// this alias is called after loading into team mayhem"
+alias cl_hook_gamestart_tka "" "// this alias is called after loading into team keepaway"
+alias cl_hook_gamestart_surv "" "// this alias is called after loading into survival"
+
+alias cl_hook_gameintermission "" "// this alias is called when intermission starts in a match"
+alias cl_hook_gameend "" "// this alias is called when intermission starts in a match or client quits from a match before intermission"
+
+alias cl_hook_shutdown "" "// this alias is called when the CSQC unloads"
+
+alias cl_hook_demostart "" "// this alias is called when a demo replay starts"
+alias cl_hook_demointermission "" "// this alias is called when intermission starts in a demo replay"
+alias cl_hook_demoend "" "// this alias is called when a demo replay ends"
+
+alias cl_hook_activeweapon "" "// this alias is called when switching weapons, with the new weapon's name as the first argument ( $1 )"
+
+alias cl_hook_race_pb "" "// called on client personal best set, $1 new pb time, $2 old pb time, $3 how much time the pb improved by, $4 new rank# on the leaderboard"
index 9cf0185ed268b7d01e4bdbe35b4221ab3d4b72f2..8bf013b1af7b5d04735d24942041c470a92304a2 100644 (file)
@@ -179,19 +179,29 @@ void Shutdown()
 
        cvar_set("slowmo", cvar_defstring("slowmo")); // reset it back to 'default'
 
-       if (!isdemo())
+       // if _cl_hook_gamestart wasn't called with an actual gamemode
+       // before CSQC VM shutdown then call it with nop fallback here
+       if (!(calledhooks & HOOK_START) && !isdemo())
+               localcmd("\n_cl_hook_gamestart nop\n");
+
+       // fire game or demo end hooks when CSQC VM shuts down
+       if (!(calledhooks & HOOK_END))
        {
-               if (!(calledhooks & HOOK_START))
-                       localcmd("\n_cl_hook_gamestart nop\n");
-               if (!(calledhooks & HOOK_END))
+               // call gameend hook if it hasn't somehow yet fired by intermission starting
+               if (!isdemo())
                {
-                       int gamecount = cvar("cl_matchcount");
                        localcmd("\ncl_hook_gameend\n");
+
                        // NOTE: using localcmd here to ensure it's executed AFTER cl_hook_gameend
                        // earlier versions of the game abuse the hook to set this cvar
+                       int gamecount = cvar("cl_matchcount");
                        localcmd(strcat("cl_matchcount ", itos(gamecount + 1), "\n"));
                        //cvar_set("cl_matchcount", itos(gamecount + 1));
                }
+               else
+                       localcmd("\ncl_hook_demoend\n");
+
+               calledhooks |= HOOK_END; // mark the hook as having fired
        }
 
        localcmd("\ncl_hook_shutdown\n");
@@ -1019,19 +1029,25 @@ void CSQC_Ent_Remove(entity this)
 
 void Gamemode_Init()
 {
-       if (!isdemo())
+       // fire game or demo start hooks here
+       if (!(calledhooks & HOOK_START))
        {
-               if(!(calledhooks & HOOK_START))
+               if (!isdemo())
                        localcmd("\n_cl_hook_gamestart ", MapInfo_Type_ToString(gametype), "\n");
-               calledhooks |= HOOK_START;
+               else
+                       localcmd("\ncl_hook_demostart\n");
+
+               calledhooks |= HOOK_START; // mark start hook as fired
        }
 }
+
 // CSQC_Parse_StuffCmd : Provides the stuffcmd string in the first parameter that the server provided.  To execute standard behavior, simply execute localcmd with the string.
 void CSQC_Parse_StuffCmd(string strMessage)
 {
        if (autocvar_developer_csqcentities) LOG_INFOF("CSQC_Parse_StuffCmd(\"%s\")", strMessage);
        localcmd(strMessage);
 }
+
 // CSQC_Parse_Print : Provides the print string in the first parameter that the server provided.  To execute standard behavior, simply execute print with the string.
 void CSQC_Parse_Print(string strMessage)
 {
index 8b96b0833e2a9229931b05ca8519d4513c57ec98..14e6239dd5b59a57081c76f288ea14a37e8a6387 100644 (file)
@@ -157,8 +157,9 @@ float damagepush_speedfactor;
 
 //hooks
 int calledhooks;
-const int HOOK_START =    1;
-const int HOOK_END =      2;
+const int HOOK_START        = 1; // VM init
+const int HOOK_END          = 2; // VM shutdown
+const int HOOK_INTERMISSION = 4; // intermission start
 
 .float ping, ping_packetloss, ping_movementloss;
 
index 19f3c0a2cf19c960b9d814d758b95db414435c9d..070adf13a9887f402512809b4a13658fe75dc59c 100644 (file)
@@ -1683,9 +1683,15 @@ void CSQC_UpdateView(entity this, float w, float h, bool notmenu)
        else if(game_stopped_time && !STAT(GAME_STOPPED))
                game_stopped_time = 0;
 
-       if(intermission && !isdemo() && !(calledhooks & HOOK_END))
-       {
-               if(calledhooks & HOOK_START)
+       // fire intermission hooks and gameend hook here
+       // gameend hook is executed on CSQC VM shutdown if
+       // the shutdown happens before intermission start
+       if (intermission
+       && (calledhooks & HOOK_START) // ensure that we have initiated a gamemode
+       && !(calledhooks & HOOK_END) // fire only once
+       && !(calledhooks & HOOK_INTERMISSION))
+       {
+               if(!isdemo())
                {
                        int gamecount = cvar("cl_matchcount");
                        localcmd("\ncl_hook_gameend\n");
@@ -1694,6 +1700,14 @@ void CSQC_UpdateView(entity this, float w, float h, bool notmenu)
                        localcmd(strcat("cl_matchcount ", itos(gamecount + 1), "\n"));
                        //cvar_set("cl_matchcount", itos(gamecount + 1));
                        calledhooks |= HOOK_END;
+
+                       localcmd("\ncl_hook_gameintermission\n");
+                       calledhooks |= HOOK_INTERMISSION;
+               }
+               else
+               {
+                       localcmd("\ncl_hook_demointermission\n");
+                       calledhooks |= HOOK_INTERMISSION;
                }
        }
 
index 97deef1d47210678c81f470a22514cd7b7639bfd..9c1b9d0c6f7280a0e2deed526302f3bb204d8902 100644 (file)
@@ -54,6 +54,8 @@ void GameCommand(string theCommand)
                LOG_HELP("  'closemenu' closes the menu window named <item> (or the menu window containing an item named <item>)");
                LOG_HELP("   if <item> is not specified it shows the list of available items in the console");
                LOG_HELP("  'dumptree' dumps the state of the menu as a tree to the console");
+               LOG_HELP("  'isdemo' checks if engine is currently running a demo. If given an <item> then 1 / 0 is placed");
+               LOG_HELP("   in the cvar with that name. Otherwise without an argument the result is printed to console.");
 
                LOG_HELP("\nGeneric commands shared by all programs:");
                GenericCommand_macro_help();
@@ -75,21 +77,21 @@ void GameCommand(string theCommand)
                return;
        }
 
-       string cmd = argv(0);
+       string argcmd = argv(0);
        string filter = string_null;
        bool close_mode = false;
-       if (cmd == "closemenu")
+       if (argcmd == "closemenu")
        {
                close_mode = true;
-               cmd = "directmenu";
+               argcmd = "directmenu";
        }
-       else if (cmd == "directpanelhudmenu")
+       else if (argcmd == "directpanelhudmenu")
        {
                filter = "HUD";
-               cmd = "directmenu";
+               argcmd = "directmenu";
        }
 
-       if (cmd == "directmenu")
+       if (argcmd == "directmenu")
        {
                if (argc == 1)
                {
@@ -201,6 +203,22 @@ void GameCommand(string theCommand)
                return;
        }
 
+       if (argv(0) == "isdemo")
+       {
+               int value = isdemo();
+
+               if (argv(1) != "")
+               {
+                       cvar_set(argv(1), ftos(value));
+               }
+               else
+               {
+                       print(sprintf("%d\n", value));
+               }
+
+               return;
+       }
+
        if(MUTATOR_CALLHOOK(Menu_ConsoleCommand, ss, argc, theCommand)) // handled by a mutator
                return;