Validate DynOS behaviors (#1115)
Some checks are pending
Build coop / build-linux (push) Waiting to run
Build coop / build-steamos (push) Waiting to run
Build coop / build-windows-opengl (push) Waiting to run
Build coop / build-windows-directx (push) Waiting to run
Build coop / build-macos-arm (push) Waiting to run
Build coop / build-macos-intel (push) Waiting to run

This commit is contained in:
PeachyPeach 2026-02-12 00:41:28 +01:00 committed by GitHub
parent 6f4b1b3b7c
commit dceffd3d0d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 54 additions and 2 deletions

View file

@ -2449,6 +2449,48 @@ static void ParseBehaviorScriptSymbol(GfxData *aGfxData, DataNode<BehaviorScript
PrintDataError(" ERROR: Unknown behavior symbol: %s", _Symbol.begin());
}
static bool DynOS_Bhv_CheckCommands(const BehaviorScript *aBhv, const Array<BehaviorScript> &aCommands) {
u8 bhvCommand = (*aBhv >> 24) & 0xFF;
for (const auto &commandToCheck : aCommands) {
if (bhvCommand == ((commandToCheck >> 24) & 0xFF)) {
return true;
}
}
return false;
}
static bool DynOS_Bhv_Validate(GfxData *aGfxData, const DataNode<BehaviorScript> *aNode) {
// 1st command must be BEGIN
if (!DynOS_Bhv_CheckCommands(aNode->mData + 0, { BEGIN(0) })) {
PrintDataError(" ERROR: Validation failed for behavior %s: First command of the script must be BEGIN.", aNode->mName.begin());
return false;
}
// 2nd command must be ID
if (!DynOS_Bhv_CheckCommands(aNode->mData + 1, { ID(0) })) {
PrintDataError(" ERROR: Validation failed for behavior %s: Second command of the script must be ID.", aNode->mName.begin());
return false;
}
// Last command must be a terminating command
if (!DynOS_Bhv_CheckCommands(aNode->mData + aNode->mSize - 1, {
CALL(0),
RETURN(),
GOTO(0),
END_LOOP(),
BREAK(),
DEACTIVATE(),
CALL_EXT(0),
GOTO_EXT(0),
})) {
PrintDataError(" ERROR: Validation failed for behavior %s: Last command of the script must be one of:\n CALL, RETURN, GOTO, END_LOOP, BREAK, DEACTIVATE", aNode->mName.begin());
return false;
}
return true;
}
DataNode<BehaviorScript> *DynOS_Bhv_Parse(GfxData *aGfxData, DataNode<BehaviorScript> *aNode, bool aDisplayPercent) {
if (aNode->mData) return aNode;
@ -2460,9 +2502,13 @@ DataNode<BehaviorScript> *DynOS_Bhv_Parse(GfxData *aGfxData, DataNode<BehaviorSc
ParseBehaviorScriptSymbol(aGfxData, aNode, _Head, _TokenIndex, _SwitchNodes);
if (aDisplayPercent && aGfxData->mErrorCount == 0) { PrintNoNewLine("%3d%%\b\b\b\b", (s32) (_TokenIndex * 100) / aNode->mTokens.Count()); }
}
if (aDisplayPercent && aGfxData->mErrorCount == 0) { Print("100%%"); }
aNode->mSize = (u32)(_Head - aNode->mData);
aNode->mLoadIndex = aGfxData->mLoadIndex++;
// Validate behavior script
DynOS_Bhv_Validate(aGfxData, aNode);
if (aDisplayPercent && aGfxData->mErrorCount == 0) { Print("100%%"); }
return aNode;
}
@ -2592,6 +2638,12 @@ static DataNode<BehaviorScript> *DynOS_Bhv_Load(BinFile *aFile, GfxData *aGfxDat
}
}
// Validate it
if (!DynOS_Bhv_Validate(aGfxData, _Node)) {
Delete(_Node);
return NULL;
}
// Add it
if (aGfxData != NULL) {
aGfxData->mBehaviorScripts.Add(_Node);

View file

@ -988,7 +988,7 @@ static s32 bhv_cmd_call_native_ext(void) {
const char *funcStr = dynos_behavior_get_token(behavior, BHV_CMD_GET_U32(1));
if (!funcStr) {
LOG_LUA("Could not retrieve function name from behavior command. Do you have an unclosed behavior script?");
LOG_LUA("Could not retrieve function name from behavior command.");
gCurBhvCommand += 2;
return BHV_PROC_CONTINUE;
}