# HG changeset patch # User Adam Kaminski # Date 1609004170 18000 # Sat Dec 26 12:36:10 2020 -0500 # Node ID a20c5397be072a3fde7d31c30a5ae9005b8fbe05 # Parent 32e97212fdfe8569f641f4c352fe8b3a22eec115 Added ACS functions: ExecuteClientScript and NamedExecuteClientScript which let the server execute clientside scripts for only one client as opposed to everyone. This allows net traffic to be greatly optimized, such that the server only sends out commands to the client(s) that matter. diff -r 32e97212fdfe -r a20c5397be07 docs/zandronum-history.txt --- a/docs/zandronum-history.txt Fri Dec 25 13:22:00 2020 -0500 +++ b/docs/zandronum-history.txt Sat Dec 26 12:36:10 2020 -0500 @@ -29,6 +29,7 @@ + - Added ACS functions: SetPlayerScore(int player, int type, int value) and GetPlayerScore(int player, int type) to get or set the player's score. The type can be either frags, points, wins, deaths, kills, or the item and secret counts. [Kaminsky] + - Added an ACS special to check whether the game is in demo or not [DoomJoshuaBoy/geNia] + - Added new SBARINFO commands: IfSpectator [not] [dead] and IfSpying [not] that execute a sub block if the local player is (not) a (dead) spectator, or (not) spying on another player respectively. [Kaminsky] ++ - Added ACS functions: ExecuteClientScript and NamedExecuteClientScript which let the server execute clientside scripts for only one client as opposed to everyone. This allows net traffic to be greatly optimized, such that the server only sends out commands to the client(s) that matter. [Kaminsky] - - Fixed: Bots tries to jump to reach item when sv_nojump is true. [sleep] - - Fixed: ACS function SetSkyScrollSpeed didn't work online. [Edward-san] - - Fixed: color codes in callvote reasons weren't terminated properly. [Dusk] diff -r 32e97212fdfe -r a20c5397be07 src/p_acs.cpp --- a/src/p_acs.cpp Fri Dec 25 13:22:00 2020 -0500 +++ b/src/p_acs.cpp Sat Dec 26 12:36:10 2020 -0500 @@ -1729,6 +1729,66 @@ return 1; } +// ================================================================================================ +// +// [AK] ExecuteClientScript +// +// Executes a clientside script for only one client if called from the server. +// +// ================================================================================================ + +static int ExecuteClientScript ( AActor* activator, int script, int client, int* args, int argCount ) +{ + FString rep = FBehavior::RepresentScript( script ); + + // [AK] Don't execute during demo playback. + if ( CLIENTDEMO_IsPlaying() ) + return 1; + + // [AK] If we're in singleplayer, execute the script like normal. + if (( NETWORK_GetState() == NETSTATE_SINGLE ) || ( NETWORK_GetState() == NETSTATE_SINGLE_MULTIPLAYER )) + { + P_StartScript( activator, NULL, script, NULL, args, argCount, ACS_ALWAYS ); + return 1; + } + + // [AK] Don't let the client do anything here. + if ( NETWORK_GetState() == NETSTATE_CLIENT ) + { + Printf( "ExecuteClientScript can only be invoked from serversided scripts " + "(attempted to call script %s).\n", rep.GetChars() ); + return 0; + } + + // [AK] If we're the server, execute the script but only for the specified client. + if (( NETWORK_GetState() == NETSTATE_SERVER ) && ( PLAYER_IsValidPlayer( client ) )) + { + // [AK] Don't send a command to the client if the script doesn't exist. + if ( ACS_ExistsScript( script ) == false ) + { + Printf( "ExecuteClientScript: Script %s doesn't exist.\n", rep.GetChars() ); + return 0; + } + + // [AK] Don't execute the script if it isn't clientside. + if ( ACS_IsScriptClientSide( script ) == false ) + { + Printf( "ExecuteClientScript: Script %s must be CLIENTSIDE but isn't.\n", rep.GetChars() ); + return 0; + } + + int scriptArgs[4] = { 0, 0, 0, 0 }; + + for ( int i = 0; i < MIN( argCount, 4 ); i++ ) + scriptArgs[i] = args[i]; + + SERVERCOMMANDS_ACSScriptExecute( script, activator, NULL, NULL, NULL, scriptArgs, 4, true, client, SVCF_ONLYTHISCLIENT ); + return 1; + } + + return 0; +} + //---- Plane watchers ----// class DPlaneWatcher : public DThinker @@ -5209,6 +5269,8 @@ ACSF_SetPlayerScore, ACSF_GetPlayerScore, ACSF_InDemoMode, + ACSF_ExecuteClientScript, + ACSF_NamedExecuteClientScript, // ZDaemon ACSF_GetTeamScore = 19620, // (int team) @@ -7448,6 +7510,17 @@ return 0; } + case ACSF_ExecuteClientScript: + { + return ExecuteClientScript( activator, args[0], args[1], &args[2], argCount - 2 ); + } + + case ACSF_NamedExecuteClientScript: + { + FName scriptName = FBehavior::StaticLookupString( args[0] ); + return ExecuteClientScript( activator, -scriptName, args[1], &args[2], argCount - 2 ); + } + case ACSF_GetActorFloorTexture: { auto a = SingleActorFromTID(args[0], activator);