This commit is contained in:
Boondorl 2025-05-04 03:30:35 -04:00 committed by GitHub
commit d9cfe48cd8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 194 additions and 2 deletions

View file

@ -158,6 +158,7 @@ void I_ShutdownInput();
void SetConsoleNotifyBuffer();
void I_UpdateDiscordPresence(bool SendPresence, const char* curstatus, const char* appid, const char* steamappid);
bool M_SetSpecialMenu(FName& menu, int param); // game specific checks
void SetHandledACSFunctions();
const FIWADInfo *D_FindIWAD(TArray<FString> &wadfiles, const char *iwad, const char *basewad);
void InitWidgetResources(const char* basewad);
@ -3064,6 +3065,7 @@ static int FileSystemPrintf(FSMessageLevel level, const char* fmt, ...)
static int D_InitGame(const FIWADInfo* iwad_info, std::vector<std::string>& allwads, std::vector<std::string>& pwads)
{
NetworkEntityManager::InitializeNetworkEntities();
SetHandledACSFunctions();
if (!restart)
{

View file

@ -975,6 +975,18 @@ void EventManager::NetCommand(FNetworkCommand& cmd)
handler->NetCommandProcess(cmd);
}
int EventManager::ProcessACSFunction(int func, const TArray<int>* args)
{
int res = 0;
if (ShouldCallStatic(false))
res = staticEventManager.ProcessACSFunction(func, args);
for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next)
handler->ACSFunctionProcess(func, args, res);
return res;
}
void EventManager::Console(int player, FString name, int arg1, int arg2, int arg3, bool manual, bool ui)
{
if (ShouldCallStatic(false)) staticEventManager.Console(player, name, arg1, arg2, arg3, manual, ui);
@ -2274,6 +2286,23 @@ void DStaticEventHandler::NetCommandProcess(FNetworkCommand& cmd)
}
}
void DStaticEventHandler::ACSFunctionProcess(int code, const TArray<int>* args, int& res)
{
IFVIRTUAL(DStaticEventHandler, ACSFunctionProcess)
{
if (isEmpty(func))
return;
TArray<int> funcArgs = {};
if (args != nullptr)
funcArgs = *args;
VMValue params[] = { this, code, &funcArgs };
VMReturn returns[] = { &res };
VMCall(func, params, 3, returns, 1);
}
}
void DStaticEventHandler::ConsoleProcess(int player, FString name, int arg1, int arg2, int arg3, bool manual, bool ui)
{
if (player < 0)

View file

@ -345,6 +345,7 @@ public:
//
void ConsoleProcess(int player, FString name, int arg1, int arg2, int arg3, bool manual, bool ui);
void NetCommandProcess(FNetworkCommand& cmd);
void ACSFunctionProcess(int func, const TArray<int>* args, int& res);
//
void CheckReplacement(PClassActor* replacee, PClassActor** replacement, bool* final);
@ -539,6 +540,8 @@ struct EventManager
void Console(int player, FString name, int arg1, int arg2, int arg3, bool manual, bool ui);
// This reads from ZScript network commands.
void NetCommand(FNetworkCommand& cmd);
// Custom handling for known but unsupported ACS events.
int ProcessACSFunction(int func, const TArray<int>* args);
// called when looking up the replacement for an actor class
bool CheckReplacement(PClassActor* replacee, PClassActor** replacement);

View file

@ -78,6 +78,7 @@
#include "s_music.h"
#include "v_video.h"
#include "texturemanager.h"
#include "events.h"
// P-codes for ACS scripts
enum
@ -4854,6 +4855,77 @@ enum EACSFunctions
ACSF_SetTeamScore, // (int team, int value
};
// Op code -> minimum arg count
static TMap<int, int> HandledACSFunctions = {};
void SetHandledACSFunctions()
{
// Zandronum
HandledACSFunctions[100] = 0; // ResetMap
HandledACSFunctions[101] = 1; // PlayerIsSpectator
// ConsolePlayerNumber will be intentionally left out until proper client-side
// ACS scripts are implemented. Right now it'd just leave the game prone to desyncs.
HandledACSFunctions[103] = 2; // GetTeamProperty
HandledACSFunctions[104] = 1; // GetPlayersLivesLeft
HandledACSFunctions[105] = 2; // SetPlayerLivesLeft
HandledACSFunctions[106] = 2; // KickFromGame
HandledACSFunctions[107] = 0; // GetGamemodeState
HandledACSFunctions[108] = 3; // SetDBEntry
HandledACSFunctions[109] = 2; // GetDBEntry
HandledACSFunctions[110] = 3; // SetDBEntryString
HandledACSFunctions[111] = 2; // GetDBEntryString
HandledACSFunctions[112] = 3; // IncrementDBEntry
HandledACSFunctions[113] = 1; // PlayerIsLoggedIn
HandledACSFunctions[114] = 1; // GetPlayerAccountName
HandledACSFunctions[115] = 4; // SortDBEntries
HandledACSFunctions[116] = 1; // CountDBResults
HandledACSFunctions[117] = 1; // FreeDBResults
HandledACSFunctions[118] = 2; // GetDBResultKeyString
HandledACSFunctions[119] = 2; // GetDBResultValueString
HandledACSFunctions[120] = 2; // GetDBResultValue
HandledACSFunctions[121] = 3; // GetDBEntryRank
HandledACSFunctions[122] = 4; // RequestScriptPuke
HandledACSFunctions[123] = 0; // BeginDBTransaction
HandledACSFunctions[124] = 0; // EndDBTransaction
HandledACSFunctions[125] = 1; // GetDBEntries
HandledACSFunctions[126] = 1; // NamedRequestScriptPuke
// System time functions are intentionally left out since they're prone to causing desyncs. Can be added
// in if client/server ever becomes a thing.
HandledACSFunctions[130] = 2; // SetDeadSpectator
HandledACSFunctions[131] = 1; // SetActivatorToPlayer
HandledACSFunctions[132] = 1; // SetCurrentGamemode
HandledACSFunctions[133] = 0; // GetCurrentGamemode
HandledACSFunctions[134] = 2; // SetGamemodeLimit
// Player class handling isn't implemented yet.
HandledACSFunctions[136] = 2; // SetPlayerChasecam
HandledACSFunctions[137] = 1; // GetPlayerChasecam
HandledACSFunctions[138] = 3; // SetPlayerScore
HandledACSFunctions[139] = 2; // GetPlayerScore
HandledACSFunctions[140] = 0; // InDemoMode
// Client-side scripts aren't implemented yet for ClientScript functions.
HandledACSFunctions[146] = 2; // SendNetworkString
HandledACSFunctions[147] = 2; // NamedSendNetworkString
HandledACSFunctions[148] = 2; // GetChatMessage
HandledACSFunctions[149] = 0; // GetMapRotationSize
HandledACSFunctions[150] = 2; // GetMapRotationInfo
HandledACSFunctions[151] = 0; // GetCurrentMapPosition
HandledACSFunctions[152] = 0; // GetEventResult
HandledACSFunctions[153] = 2; // GetActorSectorLocation
HandledACSFunctions[154] = 3; // ChangeTeamScore
HandledACSFunctions[155] = 2; // SetGameplaySettings
HandledACSFunctions[156] = 3; // SetCustomPlayerValue
HandledACSFunctions[157] = 2; // GetCustomPlayerValue
HandledACSFunctions[158] = 2; // ResetCustomDataToDefault
HandledACSFunctions[159] = 1; // LumpOpen
HandledACSFunctions[160] = 2; // LumpRead
HandledACSFunctions[161] = 2; // LumpReadString
HandledACSFunctions[166] = 2; // LumpGetInfo
HandledACSFunctions[167] = 1; // LumpClose
// Eternity
HandledACSFunctions[302] = 1; // SetAirFriction
}
int DLevelScript::SideFromID(int id, int side)
{
if (side != 0 && side != 1) return -1;
@ -7280,8 +7352,28 @@ int DLevelScript::RunScript()
int argCount = NEXTBYTE;
int funcIndex = NEXTSHORT;
int retval, minCount = 0;
retval = CallFunction(argCount, funcIndex, &STACK(argCount), minCount);
int retval = 0, minCount = 0;
auto undefined = HandledACSFunctions.CheckKey(funcIndex);
if (undefined != nullptr)
{
if (argCount >= *undefined || (Level->i_compatflags2 & COMPATF2_NOACSARGCHECK))
{
TArray<int> args = {};
auto argStart = &STACK(argCount);
for (size_t p = 0u; p < argCount; ++p)
args.Push(argStart[p]);
retval = primaryLevel->localEventManager->ProcessACSFunction(funcIndex, &args);
}
else
{
minCount = *undefined;
}
}
else
{
retval = CallFunction(argCount, funcIndex, &STACK(argCount), minCount);
}
if (minCount != 0)
{
Printf("Called ACS function index %d with too few args: %d (need %d)\n", funcIndex, argCount, minCount);

View file

@ -144,6 +144,71 @@ struct ReplacedEvent native version("3.7")
native bool IsFinal;
}
enum EACSFunction
{
ACSF_ResetMap = 100,
ACSF_PlayerIsSpectator,
ACSF_GetTeamProperty = 103,
ACSF_GetPlayerLivesLeft,
ACSF_SetPlayerLivesLeft,
ACSF_KickFromGame,
ACSF_GetGamemodeState,
ACSF_SetDBEntry,
ACSF_GetDBEntry,
ACSF_SetDBEntryString,
ACSF_GetDBEntryString,
ACSF_IncrementDBEntry,
ACSF_PlayerIsLoggedIn,
ACSF_GetPlayerAccountName,
ACSF_SortDBEntries,
ACSF_CountDBResults,
ACSF_FreeDBResults,
ACSF_GetDBResultKeyString,
ACSF_GetDBResultValueString,
ACSF_GetDBResultValue,
ACSF_GetDBEntryRank,
ACSF_RequestScriptPuke,
ACSF_BeginDBTransaction,
ACSF_EndDBTransaction,
ACSF_GetDBEntries,
ACSF_NamedRequestScriptPuke,
ACSF_SetDeadSpectator = 130,
ACSF_SetActivatorToPlayer,
ACSF_SetCurrentGamemode,
ACSF_GetCurrentGamemode,
ACSF_SetGamemodeLimit,
ACSF_SetPlayerChasecam = 136,
ACSF_GetPlayerChasecam,
ACSF_SetPlayerScore,
ACSF_GetPlayerScore,
ACSF_InDemoMode,
ACSF_SendNetworkString = 146,
ACSF_NamedSendNetworkString,
ACSF_GetChatMessage,
ACSF_GetMapRotationSize,
ACSF_GetMapRotationInfo,
ACSF_GetCurrentMapPosition,
ACSF_GetEventResult,
ACSF_GetActorSectorLocation,
ACSF_ChangeTeamScore,
ACSF_SetGameplaySettings,
ACSF_SetCustomPlayerValue,
ACSF_GetCustomPlayerValue,
ACSF_ResetCustomDataToDefault,
ACSF_LumpOpen,
ACSF_LumpRead,
ACSF_LumpReadString,
ACSF_LumpGetInfo = 166,
ACSF_LumpClose,
ACSF_SetAirFriction = 302,
}
class StaticEventHandler : Object native play version("2.4")
{
// static event handlers CAN register other static event handlers.
@ -200,6 +265,7 @@ class StaticEventHandler : Object native play version("2.4")
virtual ui void InterfaceProcess(ConsoleEvent e) {}
virtual void NetworkProcess(ConsoleEvent e) {}
version("4.12") virtual void NetworkCommandProcess(NetworkCommand cmd) {}
version("4.15") virtual int ACSFunctionProcess(EACSFunction func, Array<int> args) { return 0; }
//
virtual void CheckReplacement(ReplaceEvent e) {}