sm64coopdx/data/dynos_bin_lvl.cpp
MysterD b2bdf8859c Cleanup ; recursive descent fixes ; fixed behavior override comparisons
Moved dynos parsing for bhvs and models to a common file
Fixed recursive descent to correctly parse the entire expression
Adjusted bhv generation to use recursive descent
Switched all known behavior comparisons to the overridden versions
Fixed issue with Chain Chomp in star road
2022-06-02 19:07:43 -07:00

1195 lines
46 KiB
C++

#include "dynos.cpp.h"
extern "C" {
#include "include/level_commands.h"
#include "include/model_ids.h"
#include "include/behavior_data.h"
#include "include/surface_terrains.h"
#include "include/seq_ids.h"
#include "level_commands.h"
#include "src/game/level_update.h"
#include "include/dialog_ids.h"
#include "levels/scripts.h"
#include "src/game/area.h"
}
// Free data pointers, but keep nodes and tokens intact
// Delete nodes generated from GfxDynCmds
template <typename T>
static void ClearLvlDataNodes(DataNodes<T> &aDataNodes) {
for (s32 i = aDataNodes.Count(); i != 0; --i) {
Delete(aDataNodes[i - 1]->mData);
}
}
/////////////
// Parsing //
/////////////
#define LEVEL_SCRIPT_SIZE_PER_TOKEN 4
#define lvl_constant(x) if (_Arg == #x) { return (LevelScript) (x); }
#define lvl_legacy_constant(x, y) if (_Arg == #x) { return (LevelScript) (y); }
s64 DynOS_Lvl_ParseLevelScriptConstants(const String& _Arg, bool* found) {
*found = true;
// Behavior constants
s64 cBhvConstant = DynOS_Common_ParseBhvConstants(_Arg, found);
if (*found) { return cBhvConstant; }
*found = true; // reset found value
// Level constants
lvl_constant(LEVEL_UNKNOWN_1);
lvl_constant(LEVEL_UNKNOWN_2);
lvl_constant(LEVEL_UNKNOWN_3);
lvl_constant(LEVEL_BBH);
lvl_constant(LEVEL_CCM);
lvl_constant(LEVEL_CASTLE);
lvl_constant(LEVEL_HMC);
lvl_constant(LEVEL_SSL);
lvl_constant(LEVEL_BOB);
lvl_constant(LEVEL_SL);
lvl_constant(LEVEL_WDW);
lvl_constant(LEVEL_JRB);
lvl_constant(LEVEL_THI);
lvl_constant(LEVEL_TTC);
lvl_constant(LEVEL_RR);
lvl_constant(LEVEL_CASTLE_GROUNDS);
lvl_constant(LEVEL_BITDW);
lvl_constant(LEVEL_VCUTM);
lvl_constant(LEVEL_BITFS);
lvl_constant(LEVEL_SA);
lvl_constant(LEVEL_BITS);
lvl_constant(LEVEL_LLL);
lvl_constant(LEVEL_DDD);
lvl_constant(LEVEL_WF);
lvl_constant(LEVEL_ENDING);
lvl_constant(LEVEL_CASTLE_COURTYARD);
lvl_constant(LEVEL_PSS);
lvl_constant(LEVEL_COTMC);
lvl_constant(LEVEL_TOTWC);
lvl_constant(LEVEL_BOWSER_1);
lvl_constant(LEVEL_WMOTR);
lvl_constant(LEVEL_UNKNOWN_32);
lvl_constant(LEVEL_BOWSER_2);
lvl_constant(LEVEL_BOWSER_3);
lvl_constant(LEVEL_UNKNOWN_35);
lvl_constant(LEVEL_TTM);
lvl_constant(LEVEL_UNKNOWN_37);
lvl_constant(LEVEL_UNKNOWN_38);
// Surface constants
lvl_constant(TERRAIN_GRASS);
lvl_constant(TERRAIN_STONE);
lvl_constant(TERRAIN_SNOW);
lvl_constant(TERRAIN_SAND);
lvl_constant(TERRAIN_SPOOKY);
lvl_constant(TERRAIN_WATER);
lvl_constant(TERRAIN_SLIDE);
lvl_constant(TERRAIN_MASK);
// Seq ids constants
lvl_constant(SEQ_BASE_ID);
lvl_constant(SEQ_VARIATION);
lvl_constant(SEQ_SOUND_PLAYER);
lvl_constant(SEQ_EVENT_CUTSCENE_COLLECT_STAR);
lvl_constant(SEQ_MENU_TITLE_SCREEN);
lvl_constant(SEQ_LEVEL_GRASS);
lvl_constant(SEQ_LEVEL_INSIDE_CASTLE);
lvl_constant(SEQ_LEVEL_WATER);
lvl_constant(SEQ_LEVEL_HOT);
lvl_constant(SEQ_LEVEL_BOSS_KOOPA);
lvl_constant(SEQ_LEVEL_SNOW);
lvl_constant(SEQ_LEVEL_SLIDE);
lvl_constant(SEQ_LEVEL_SPOOKY);
lvl_constant(SEQ_EVENT_PIRANHA_PLANT);
lvl_constant(SEQ_LEVEL_UNDERGROUND);
lvl_constant(SEQ_MENU_STAR_SELECT);
lvl_constant(SEQ_EVENT_POWERUP);
lvl_constant(SEQ_EVENT_METAL_CAP);
lvl_constant(SEQ_EVENT_KOOPA_MESSAGE);
lvl_constant(SEQ_LEVEL_KOOPA_ROAD);
lvl_constant(SEQ_EVENT_HIGH_SCORE);
lvl_constant(SEQ_EVENT_MERRY_GO_ROUND);
lvl_constant(SEQ_EVENT_RACE);
lvl_constant(SEQ_EVENT_CUTSCENE_STAR_SPAWN);
lvl_constant(SEQ_EVENT_BOSS);
lvl_constant(SEQ_EVENT_CUTSCENE_COLLECT_KEY);
lvl_constant(SEQ_EVENT_ENDLESS_STAIRS);
lvl_constant(SEQ_LEVEL_BOSS_KOOPA_FINAL);
lvl_constant(SEQ_EVENT_CUTSCENE_CREDITS);
lvl_constant(SEQ_EVENT_SOLVE_PUZZLE);
lvl_constant(SEQ_EVENT_TOAD_MESSAGE);
lvl_constant(SEQ_EVENT_PEACH_MESSAGE);
lvl_constant(SEQ_EVENT_CUTSCENE_INTRO);
lvl_constant(SEQ_EVENT_CUTSCENE_VICTORY);
lvl_constant(SEQ_EVENT_CUTSCENE_ENDING);
lvl_constant(SEQ_MENU_FILE_SELECT);
lvl_constant(SEQ_EVENT_CUTSCENE_LAKITU);
lvl_constant(SEQ_COUNT);
// Model constants
s64 cModelConstant = DynOS_Common_ParseModelConstants(_Arg, found);
if (*found) { return cModelConstant; }
*found = true; // reset found value
// dialog constants
lvl_constant(DIALOG_000);
lvl_constant(DIALOG_001);
lvl_constant(DIALOG_002);
lvl_constant(DIALOG_003);
lvl_constant(DIALOG_004);
lvl_constant(DIALOG_005);
lvl_constant(DIALOG_006);
lvl_constant(DIALOG_007);
lvl_constant(DIALOG_008);
lvl_constant(DIALOG_009);
lvl_constant(DIALOG_010);
lvl_constant(DIALOG_011);
lvl_constant(DIALOG_012);
lvl_constant(DIALOG_013);
lvl_constant(DIALOG_014);
lvl_constant(DIALOG_015);
lvl_constant(DIALOG_016);
lvl_constant(DIALOG_017);
lvl_constant(DIALOG_018);
lvl_constant(DIALOG_019);
lvl_constant(DIALOG_020);
lvl_constant(DIALOG_021);
lvl_constant(DIALOG_022);
lvl_constant(DIALOG_023);
lvl_constant(DIALOG_024);
lvl_constant(DIALOG_025);
lvl_constant(DIALOG_026);
lvl_constant(DIALOG_027);
lvl_constant(DIALOG_028);
lvl_constant(DIALOG_029);
lvl_constant(DIALOG_030);
lvl_constant(DIALOG_031);
lvl_constant(DIALOG_032);
lvl_constant(DIALOG_033);
lvl_constant(DIALOG_034);
lvl_constant(DIALOG_035);
lvl_constant(DIALOG_036);
lvl_constant(DIALOG_037);
lvl_constant(DIALOG_038);
lvl_constant(DIALOG_039);
lvl_constant(DIALOG_040);
lvl_constant(DIALOG_041);
lvl_constant(DIALOG_042);
lvl_constant(DIALOG_043);
lvl_constant(DIALOG_044);
lvl_constant(DIALOG_045);
lvl_constant(DIALOG_046);
lvl_constant(DIALOG_047);
lvl_constant(DIALOG_048);
lvl_constant(DIALOG_049);
lvl_constant(DIALOG_050);
lvl_constant(DIALOG_051);
lvl_constant(DIALOG_052);
lvl_constant(DIALOG_053);
lvl_constant(DIALOG_054);
lvl_constant(DIALOG_055);
lvl_constant(DIALOG_056);
lvl_constant(DIALOG_057);
lvl_constant(DIALOG_058);
lvl_constant(DIALOG_059);
lvl_constant(DIALOG_060);
lvl_constant(DIALOG_061);
lvl_constant(DIALOG_062);
lvl_constant(DIALOG_063);
lvl_constant(DIALOG_064);
lvl_constant(DIALOG_065);
lvl_constant(DIALOG_066);
lvl_constant(DIALOG_067);
lvl_constant(DIALOG_068);
lvl_constant(DIALOG_069);
lvl_constant(DIALOG_070);
lvl_constant(DIALOG_071);
lvl_constant(DIALOG_072);
lvl_constant(DIALOG_073);
lvl_constant(DIALOG_074);
lvl_constant(DIALOG_075);
lvl_constant(DIALOG_076);
lvl_constant(DIALOG_077);
lvl_constant(DIALOG_078);
lvl_constant(DIALOG_079);
lvl_constant(DIALOG_080);
lvl_constant(DIALOG_081);
lvl_constant(DIALOG_082);
lvl_constant(DIALOG_083);
lvl_constant(DIALOG_084);
lvl_constant(DIALOG_085);
lvl_constant(DIALOG_086);
lvl_constant(DIALOG_087);
lvl_constant(DIALOG_088);
lvl_constant(DIALOG_089);
lvl_constant(DIALOG_090);
lvl_constant(DIALOG_091);
lvl_constant(DIALOG_092);
lvl_constant(DIALOG_093);
lvl_constant(DIALOG_094);
lvl_constant(DIALOG_095);
lvl_constant(DIALOG_096);
lvl_constant(DIALOG_097);
lvl_constant(DIALOG_098);
lvl_constant(DIALOG_099);
lvl_constant(DIALOG_100);
lvl_constant(DIALOG_101);
lvl_constant(DIALOG_102);
lvl_constant(DIALOG_103);
lvl_constant(DIALOG_104);
lvl_constant(DIALOG_105);
lvl_constant(DIALOG_106);
lvl_constant(DIALOG_107);
lvl_constant(DIALOG_108);
lvl_constant(DIALOG_109);
lvl_constant(DIALOG_110);
lvl_constant(DIALOG_111);
lvl_constant(DIALOG_112);
lvl_constant(DIALOG_113);
lvl_constant(DIALOG_114);
lvl_constant(DIALOG_115);
lvl_constant(DIALOG_116);
lvl_constant(DIALOG_117);
lvl_constant(DIALOG_118);
lvl_constant(DIALOG_119);
lvl_constant(DIALOG_120);
lvl_constant(DIALOG_121);
lvl_constant(DIALOG_122);
lvl_constant(DIALOG_123);
lvl_constant(DIALOG_124);
lvl_constant(DIALOG_125);
lvl_constant(DIALOG_126);
lvl_constant(DIALOG_127);
lvl_constant(DIALOG_128);
lvl_constant(DIALOG_129);
lvl_constant(DIALOG_130);
lvl_constant(DIALOG_131);
lvl_constant(DIALOG_132);
lvl_constant(DIALOG_133);
lvl_constant(DIALOG_134);
lvl_constant(DIALOG_135);
lvl_constant(DIALOG_136);
lvl_constant(DIALOG_137);
lvl_constant(DIALOG_138);
lvl_constant(DIALOG_139);
lvl_constant(DIALOG_140);
lvl_constant(DIALOG_141);
lvl_constant(DIALOG_142);
lvl_constant(DIALOG_143);
lvl_constant(DIALOG_144);
lvl_constant(DIALOG_145);
lvl_constant(DIALOG_146);
lvl_constant(DIALOG_147);
lvl_constant(DIALOG_148);
lvl_constant(DIALOG_149);
lvl_constant(DIALOG_150);
lvl_constant(DIALOG_151);
lvl_constant(DIALOG_152);
lvl_constant(DIALOG_153);
lvl_constant(DIALOG_154);
lvl_constant(DIALOG_155);
lvl_constant(DIALOG_156);
lvl_constant(DIALOG_157);
lvl_constant(DIALOG_158);
lvl_constant(DIALOG_159);
lvl_constant(DIALOG_160);
lvl_constant(DIALOG_161);
lvl_constant(DIALOG_162);
lvl_constant(DIALOG_163);
lvl_constant(DIALOG_164);
lvl_constant(DIALOG_165);
lvl_constant(DIALOG_166);
lvl_constant(DIALOG_167);
lvl_constant(DIALOG_168);
lvl_constant(DIALOG_169);
lvl_constant(DIALOG_COUNT);
// global scripts
lvl_constant(level_main_scripts_entry);
lvl_constant(script_func_global_1);
lvl_constant(script_func_global_2);
lvl_constant(script_func_global_3);
lvl_constant(script_func_global_4);
lvl_constant(script_func_global_5);
lvl_constant(script_func_global_6);
lvl_constant(script_func_global_7);
lvl_constant(script_func_global_8);
lvl_constant(script_func_global_9);
lvl_constant(script_func_global_10);
lvl_constant(script_func_global_11);
lvl_constant(script_func_global_12);
lvl_constant(script_func_global_13);
lvl_constant(script_func_global_14);
lvl_constant(script_func_global_15);
lvl_constant(script_func_global_16);
lvl_constant(script_func_global_17);
lvl_constant(script_func_global_18);
// level command constants
lvl_constant(OP_AND);
lvl_constant(OP_NAND);
lvl_constant(OP_EQ);
lvl_constant(OP_NEQ);
lvl_constant(OP_LT);
lvl_constant(OP_LEQ);
lvl_constant(OP_GT);
lvl_constant(OP_GEQ);
lvl_constant(OP_SET);
lvl_constant(OP_GET);
lvl_constant(VAR_CURR_SAVE_FILE_NUM);
lvl_constant(VAR_CURR_COURSE_NUM);
lvl_constant(VAR_CURR_ACT_NUM);
lvl_constant(VAR_CURR_LEVEL_NUM);
lvl_constant(VAR_CURR_AREA_INDEX);
lvl_constant(WARP_CHECKPOINT);
lvl_constant(WARP_NO_CHECKPOINT);
lvl_constant(WHIRLPOOL_COND_ALWAYS);
lvl_constant(WHIRLPOOL_COND_BOWSER2_BEATEN);
lvl_constant(WHIRLPOOL_COND_AT_LEAST_SECOND_STAR);
lvl_constant(REGULAR_FACE);
lvl_constant(DIZZY_FACE);
// warp transitions
lvl_constant(WARP_TRANSITION_FADE_FROM_COLOR);
lvl_constant(WARP_TRANSITION_FADE_INTO_COLOR);
lvl_constant(WARP_TRANSITION_FADE_FROM_STAR);
lvl_constant(WARP_TRANSITION_FADE_INTO_STAR);
lvl_constant(WARP_TRANSITION_FADE_FROM_CIRCLE);
lvl_constant(WARP_TRANSITION_FADE_INTO_CIRCLE);
lvl_constant(WARP_TRANSITION_FADE_FROM_MARIO);
lvl_constant(WARP_TRANSITION_FADE_INTO_MARIO);
lvl_constant(WARP_TRANSITION_FADE_FROM_BOWSER);
lvl_constant(WARP_TRANSITION_FADE_INTO_BOWSER);
// Other constants
lvl_constant(NULL);
lvl_constant(FALSE);
*found = false;
return 0;
}
template <typename T>
DataNode<T>* FindDataNode(DataNodes<T>& aDataNodes, String& aName, u32 aModelIdentifier) {
DataNode<T>* best = NULL;
for (auto& node : aDataNodes) {
if (aName == node->mName) {
if (aModelIdentifier == node->mModelIdentifier) {
return node;
}
best = node;
}
}
return best;
}
static LevelScript ParseLevelScriptSymbolArgInternal(GfxData* aGfxData, DataNode<LevelScript>* aNode, u64& aTokenIndex, bool* found) {
String _Arg = aNode->mTokens[aTokenIndex++];
u64 _ModelIdentifier = aNode->mModelIdentifier;
*found = true;
// Integers
bool integerFound = false;
s64 integerValue = DynOS_Misc_ParseInteger(_Arg, &integerFound);
if (integerFound) {
return integerValue;
}
// Offset
s32 _Offset = 0;
s32 _Plus = _Arg.Find('+');
if (_Plus != -1) {
_Offset = _Arg.SubString(_Plus + 1).ParseInt();
_Arg = _Arg.SubString(0, _Plus);
}
// Built-in functions
const void *_FunctionPtr = DynOS_Builtin_Func_GetFromName(_Arg.begin());
if (_FunctionPtr != NULL) {
return (s64) _FunctionPtr;
}
bool constantFound = false;
s64 constantValue = DynOS_Lvl_ParseLevelScriptConstants(_Arg, &constantFound);
if (constantFound) {
return (LevelScript) constantValue;
}
// Level Scripts
{
auto _Node = FindDataNode<LevelScript>(aGfxData->mLevelScripts, _Arg, aGfxData->mModelIdentifier);
if (_Node != NULL) {
auto base = DynOS_Lvl_Parse(aGfxData, _Node, false)->mData;
auto data = (u8*)base + _Offset;
if (_Offset != 0) {
aGfxData->mPointerOffsetList.Add({ data, base });
}
return (LevelScript) data;
}
}
// Geo layouts
{
auto _Node = FindDataNode<GeoLayout>(aGfxData->mGeoLayouts, _Arg, aGfxData->mModelIdentifier);
if (_Node != NULL) {
return (LevelScript) DynOS_Geo_Parse(aGfxData, _Node, false)->mData;
}
}
// Collisions
{
auto _Node = FindDataNode<Collision>(aGfxData->mCollisions, _Arg, aGfxData->mModelIdentifier);
if (_Node != NULL) {
return (LevelScript) DynOS_Col_Parse(aGfxData, _Node, false)->mData;
}
}
// MacroObjects
{
auto _Node = FindDataNode<MacroObject>(aGfxData->mMacroObjects, _Arg, aGfxData->mModelIdentifier);
if (_Node != NULL) {
return (LevelScript) DynOS_MacroObject_Parse(aGfxData, _Node, false)->mData;
}
}
// Trajectories
{
auto _Node = FindDataNode<Trajectory>(aGfxData->mTrajectories, _Arg, aGfxData->mModelIdentifier);
if (_Node != NULL) {
return (LevelScript) DynOS_Trajectory_Parse(aGfxData, _Node, false)->mData;
}
}
// Movtexs
{
auto _Node = FindDataNode<Movtex>(aGfxData->mMovtexs, _Arg, aGfxData->mModelIdentifier);
if (_Node != NULL) {
return (LevelScript) DynOS_Movtex_Parse(aGfxData, _Node, false)->mData;
}
}
// MovtexQCs
{
auto _Node = FindDataNode<MovtexQC>(aGfxData->mMovtexQCs, _Arg, aGfxData->mModelIdentifier);
if (_Node != NULL) {
return (LevelScript) DynOS_MovtexQC_Parse(aGfxData, _Node)->mData;
}
}
// Rooms
{
auto _Node = FindDataNode<u8>(aGfxData->mRooms, _Arg, aGfxData->mModelIdentifier);
if (_Node != NULL) {
return (LevelScript) DynOS_Rooms_Parse(aGfxData, _Node)->mData;
}
}
// Built-in actors
auto builtinActor = DynOS_Builtin_Actor_GetFromName(_Arg.begin());
if (builtinActor != NULL) {
return (LevelScript)builtinActor;
}
// Built-in Lvl Geos
auto builtinGeo = DynOS_Builtin_LvlGeo_GetFromName(_Arg.begin());
if (builtinGeo != NULL) {
return (LevelScript)builtinGeo;
}
// Built-in Cols
auto builtinCol = DynOS_Builtin_Col_GetFromName(_Arg.begin());
if (builtinCol != NULL) {
return (LevelScript)builtinCol;
}
// Recursive descent parsing
bool rdSuccess = false;
s64 rdValue = DynOS_RecursiveDescent_Parse(_Arg.begin(), &rdSuccess, DynOS_Lvl_ParseLevelScriptConstants);
if (rdSuccess) {
return (LevelScript)rdValue;
}
*found = false;
return 0;
}
static LevelScript ParseLevelScriptSymbolArg(GfxData* aGfxData, DataNode<LevelScript>* aNode, u64& aTokenIndex) {
bool found = true;
LevelScript value = ParseLevelScriptSymbolArgInternal(aGfxData, aNode, aTokenIndex, &found);
if (!found) {
const String& _Arg = aNode->mTokens[aTokenIndex - 1];
PrintError(" ERROR: Unknown lvl arg: %s", _Arg.begin());
}
return value;
}
#define lvl_symbol_0(symb) \
if (_Symbol == #symb) { \
LevelScript _Ls[] = { symb() }; \
memcpy(aHead, _Ls, sizeof(_Ls)); \
aHead += (sizeof(_Ls) / sizeof(_Ls[0])); \
return; \
}
#define lvl_symbol_1(symb, n) \
if (_Symbol == #symb) { \
LevelScript _Arg0 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \
if (n != 0) { aGfxData->mPointerList.Add(aHead + n); } \
LevelScript _Ls[] = { symb(_Arg0) }; \
memcpy(aHead, _Ls, sizeof(_Ls)); \
aHead += (sizeof(_Ls) / sizeof(_Ls[0])); \
return; \
}
#define lvl_symbol_2(symb, n1, n2) \
if (_Symbol == #symb) { \
LevelScript _Arg0 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \
LevelScript _Arg1 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \
if (n1 != 0) { aGfxData->mPointerList.Add(aHead + n1); } \
if (n2 != 0) { aGfxData->mPointerList.Add(aHead + n2); } \
LevelScript _Ls[] = { symb(_Arg0, _Arg1) }; \
memcpy(aHead, _Ls, sizeof(_Ls)); \
aHead += (sizeof(_Ls) / sizeof(_Ls[0])); \
return; \
}
#define lvl_symbol_3(symb, n1, n2, n3) \
if (_Symbol == #symb) { \
LevelScript _Arg0 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \
LevelScript _Arg1 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \
LevelScript _Arg2 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \
if (n1 != 0) { aGfxData->mPointerList.Add(aHead + n1); } \
if (n2 != 0) { aGfxData->mPointerList.Add(aHead + n2); } \
if (n3 != 0) { aGfxData->mPointerList.Add(aHead + n3); } \
LevelScript _Ls[] = { symb(_Arg0, _Arg1, _Arg2) }; \
memcpy(aHead, _Ls, sizeof(_Ls)); \
aHead += (sizeof(_Ls) / sizeof(_Ls[0])); \
return; \
}
#define lvl_symbol_4(symb, n1, n2, n3) \
if (_Symbol == #symb) { \
LevelScript _Arg0 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \
LevelScript _Arg1 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \
LevelScript _Arg2 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \
LevelScript _Arg3 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \
if (n1 != 0) { aGfxData->mPointerList.Add(aHead + n1); } \
if (n2 != 0) { aGfxData->mPointerList.Add(aHead + n2); } \
if (n3 != 0) { aGfxData->mPointerList.Add(aHead + n3); } \
LevelScript _Ls[] = { symb(_Arg0, _Arg1, _Arg2, _Arg3) }; \
memcpy(aHead, _Ls, sizeof(_Ls)); \
aHead += (sizeof(_Ls) / sizeof(_Ls[0])); \
return; \
}
#define lvl_symbol_5(symb, n1, n2, n3) \
if (_Symbol == #symb) { \
LevelScript _Arg0 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \
LevelScript _Arg1 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \
LevelScript _Arg2 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \
LevelScript _Arg3 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \
LevelScript _Arg4 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \
if (n1 != 0) { aGfxData->mPointerList.Add(aHead + n1); } \
if (n2 != 0) { aGfxData->mPointerList.Add(aHead + n2); } \
if (n3 != 0) { aGfxData->mPointerList.Add(aHead + n3); } \
LevelScript _Ls[] = { symb(_Arg0, _Arg1, _Arg2, _Arg3, _Arg4) }; \
memcpy(aHead, _Ls, sizeof(_Ls)); \
aHead += (sizeof(_Ls) / sizeof(_Ls[0])); \
return; \
}
#define lvl_symbol_6(symb, n1, n2, n3) \
if (_Symbol == #symb) { \
LevelScript _Arg0 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \
LevelScript _Arg1 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \
LevelScript _Arg2 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \
LevelScript _Arg3 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \
LevelScript _Arg4 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \
LevelScript _Arg5 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \
if (n1 != 0) { aGfxData->mPointerList.Add(aHead + n1); } \
if (n2 != 0) { aGfxData->mPointerList.Add(aHead + n2); } \
if (n3 != 0) { aGfxData->mPointerList.Add(aHead + n3); } \
LevelScript _Ls[] = { symb(_Arg0, _Arg1, _Arg2, _Arg3, _Arg4, _Arg5) }; \
memcpy(aHead, _Ls, sizeof(_Ls)); \
aHead += (sizeof(_Ls) / sizeof(_Ls[0])); \
return; \
}
#define lvl_symbol_noop_3(symb) \
if (_Symbol == #symb) { \
aTokenIndex += 3; \
LevelScript _Ls[] = { symb(0, 0, 0) }; \
memcpy(aHead, _Ls, sizeof(_Ls)); \
aHead += (sizeof(_Ls) / sizeof(_Ls[0])); \
return; \
}
static void ParseLevelScriptSymbol(GfxData* aGfxData, DataNode<LevelScript>* aNode, LevelScript*& aHead, u64& aTokenIndex, Array<u64>& aSwitchNodes) {
const String& _Symbol = aNode->mTokens[aTokenIndex++];
// execution
lvl_symbol_4(EXECUTE, 1, 2, 3);
lvl_symbol_4(EXIT_AND_EXECUTE, 1, 2, 3);
lvl_symbol_0(EXIT);
// sleep
lvl_symbol_1(SLEEP, 0);
lvl_symbol_1(SLEEP_BEFORE_EXIT, 0);
// jumps
lvl_symbol_1(JUMP, 1);
lvl_symbol_1(JUMP_LINK, 1);
lvl_symbol_0(RETURN);
lvl_symbol_1(JUMP_LINK_PUSH_ARG, 0);
lvl_symbol_0(JUMP_N_TIMES);
lvl_symbol_0(LOOP_BEGIN);
lvl_symbol_2(LOOP_UNTIL, 0, 0);
lvl_symbol_3(JUMP_IF, 2, 0, 0);
lvl_symbol_2(SKIP_IF, 0, 0);
lvl_symbol_0(SKIP);
lvl_symbol_0(SKIP_NOP);
lvl_symbol_3(JUMP_AREA_EXT, 2, 0, 0);
// calls
lvl_symbol_2(CALL, 1, 0);
lvl_symbol_2(CALL_LOOP, 1, 0);
// misc memory
lvl_symbol_1(SET_REG, 0);
lvl_symbol_0(PUSH_POOL);
lvl_symbol_0(POP_POOL);
lvl_symbol_3(FIXED_LOAD, 1, 2, 3);
lvl_symbol_noop_3(LOAD_RAW);
lvl_symbol_noop_3(LOAD_MIO0);
lvl_symbol_1(LOAD_MARIO_HEAD, 0);
lvl_symbol_noop_3(LOAD_MIO0_TEXTURE);
// levels
lvl_symbol_0(INIT_LEVEL);
lvl_symbol_0(CLEAR_LEVEL);
lvl_symbol_0(ALLOC_LEVEL_POOL);
lvl_symbol_0(FREE_LEVEL_POOL);
// areas
lvl_symbol_2(AREA, 1, 0);
lvl_symbol_0(END_AREA);
// models
lvl_symbol_3(LOAD_MODEL_FROM_DL, 1, 0, 0);
lvl_symbol_3(CMD23, 1, 0, 0);
// objects
lvl_symbol_3(MARIO, 2, 0, 0);
// warps
lvl_symbol_5(WARP_NODE, 0, 0, 0);
lvl_symbol_5(PAINTING_WARP_NODE, 0, 0, 0);
lvl_symbol_5(INSTANT_WARP, 0, 0, 0);
// misc
lvl_symbol_1(LOAD_AREA, 0);
lvl_symbol_1(CMD2A, 0);
lvl_symbol_5(MARIO_POS, 0, 0, 0);
lvl_symbol_0(CMD2C);
lvl_symbol_0(CMD2D);
lvl_symbol_1(TERRAIN, 1);
lvl_symbol_1(ROOMS, 1);
lvl_symbol_2(SHOW_DIALOG, 0, 0);
lvl_symbol_1(TERRAIN_TYPE, 0);
lvl_symbol_0(NOP);
// transitions
lvl_symbol_5(TRANSITION, 0, 0, 0);
lvl_symbol_1(BLACKOUT, 0);
lvl_symbol_1(GAMMA, 0);
// music
lvl_symbol_2(SET_BACKGROUND_MUSIC, 0, 0);
lvl_symbol_1(SET_MENU_MUSIC, 0);
lvl_symbol_1(STOP_MUSIC, 0);
// misc
lvl_symbol_1(MACRO_OBJECTS, 1);
lvl_symbol_5(CMD3A, 0, 0, 0);
lvl_symbol_6(WHIRLPOOL, 0, 0, 0);
lvl_symbol_2(GET_OR_SET, 0, 0);
lvl_symbol_0(ADV_DEMO);
lvl_symbol_0(CLEAR_DEMO_PTR);
// object
if (_Symbol == "OBJECT") {
u64 topTokenIndex = aTokenIndex;
bool foundModel = true;
bool foundBeh = true;
LevelScript model = ParseLevelScriptSymbolArgInternal(aGfxData, aNode, aTokenIndex, &foundModel);
LevelScript posX = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex);
LevelScript posY = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex);
LevelScript posZ = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex);
LevelScript angleX = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex);
LevelScript angleY = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex);
LevelScript angleZ = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex);
LevelScript behParam = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex);
LevelScript beh = ParseLevelScriptSymbolArgInternal(aGfxData, aNode, aTokenIndex, &foundBeh);
if (foundModel && foundBeh) {
aGfxData->mPointerList.Add(aHead + 5);
LevelScript _Ls[] = { OBJECT(model, posX, posY, posZ, angleX, angleY, angleZ, behParam, beh) };
memcpy(aHead, _Ls, sizeof(_Ls));
aHead += (sizeof(_Ls) / sizeof(_Ls[0]));
} else if (foundModel) {
u32 behIndex = DynOS_Lua_RememberVariable(aGfxData, aHead + 5, aNode->mTokens[topTokenIndex + 8]);
LevelScript _Ls[] = { OBJECT_EXT(model, posX, posY, posZ, angleX, angleY, angleZ, behParam, behIndex) };
memcpy(aHead, _Ls, sizeof(_Ls));
aHead += (sizeof(_Ls) / sizeof(_Ls[0]));
} else {
u32 modelIndex = DynOS_Lua_RememberVariable(aGfxData, aHead + 5, aNode->mTokens[topTokenIndex + 0]);
u32 behIndex = DynOS_Lua_RememberVariable(aGfxData, aHead + 6, aNode->mTokens[topTokenIndex + 8]);
LevelScript _Ls[] = { OBJECT_EXT2(modelIndex, posX, posY, posZ, angleX, angleY, angleZ, behParam, behIndex) };
memcpy(aHead, _Ls, sizeof(_Ls));
aHead += (sizeof(_Ls) / sizeof(_Ls[0]));
}
return;
}
// object with acts
if (_Symbol == "OBJECT_WITH_ACTS") {
u64 topTokenIndex = aTokenIndex;
bool foundModel = true;
bool foundBeh = true;
LevelScript model = ParseLevelScriptSymbolArgInternal(aGfxData, aNode, aTokenIndex, &foundModel);
LevelScript posX = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex);
LevelScript posY = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex);
LevelScript posZ = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex);
LevelScript angleX = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex);
LevelScript angleY = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex);
LevelScript angleZ = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex);
LevelScript behParam = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex);
LevelScript beh = ParseLevelScriptSymbolArgInternal(aGfxData, aNode, aTokenIndex, &foundBeh);
LevelScript acts = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex);
if (foundModel && foundBeh) {
aGfxData->mPointerList.Add(aHead + 5);
LevelScript _Ls[] = { OBJECT_WITH_ACTS(model, posX, posY, posZ, angleX, angleY, angleZ, behParam, beh, acts) };
memcpy(aHead, _Ls, sizeof(_Ls));
aHead += (sizeof(_Ls) / sizeof(_Ls[0]));
} else if (foundModel) {
u32 behIndex = DynOS_Lua_RememberVariable(aGfxData, aHead + 5, aNode->mTokens[topTokenIndex + 8]);
LevelScript _Ls[] = { OBJECT_WITH_ACTS_EXT(model, posX, posY, posZ, angleX, angleY, angleZ, behParam, behIndex, acts) };
memcpy(aHead, _Ls, sizeof(_Ls));
aHead += (sizeof(_Ls) / sizeof(_Ls[0]));
} else {
u32 modelIndex = DynOS_Lua_RememberVariable(aGfxData, aHead + 5, aNode->mTokens[topTokenIndex + 0]);
u32 behIndex = DynOS_Lua_RememberVariable(aGfxData, aHead + 6, aNode->mTokens[topTokenIndex + 8]);
LevelScript _Ls[] = { OBJECT_WITH_ACTS_EXT2(modelIndex, posX, posY, posZ, angleX, angleY, angleZ, behParam, behIndex, acts) };
memcpy(aHead, _Ls, sizeof(_Ls));
aHead += (sizeof(_Ls) / sizeof(_Ls[0]));
}
return;
}
// LOAD_MODEL_FROM_GEO
if (_Symbol == "LOAD_MODEL_FROM_GEO") {
u64 topTokenIndex = aTokenIndex;
bool foundGeo = false;
LevelScript model = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex);
LevelScript geo = ParseLevelScriptSymbolArgInternal(aGfxData, aNode, aTokenIndex, &foundGeo);
if (foundGeo) {
aGfxData->mPointerList.Add(aHead + 1);
LevelScript _Ls[] = { LOAD_MODEL_FROM_GEO(model, geo) };
memcpy(aHead, _Ls, sizeof(_Ls));
aHead += (sizeof(_Ls) / sizeof(_Ls[0]));
} else {
u32 geoIndex = DynOS_Lua_RememberVariable(aGfxData, aHead + 1, aNode->mTokens[topTokenIndex + 1]);
LevelScript _Ls[] = { LOAD_MODEL_FROM_GEO_EXT(model, geoIndex) };
memcpy(aHead, _Ls, sizeof(_Ls));
aHead += (sizeof(_Ls) / sizeof(_Ls[0]));
}
return;
}
// JUMP_AREA
if (_Symbol == "JUMP_AREA") {
LevelScript _Arg0 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex);
LevelScript _Arg1 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex);
LevelScript _Arg2 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex);
aGfxData->mPointerList.Add(aHead + 2);
LevelScript _Ls[] = { JUMP_AREA_EXT(_Arg0, _Arg1, _Arg2) };
memcpy(aHead, _Ls, sizeof(_Ls));
aHead += (sizeof(_Ls) / sizeof(_Ls[0]));
return;
}
// Unknown
PrintError(" ERROR: Unknown lvl symbol: %s", _Symbol.begin());
}
DataNode<LevelScript>* DynOS_Lvl_Parse(GfxData* aGfxData, DataNode<LevelScript>* aNode, bool aDisplayPercent) {
if (aNode->mData) return aNode;
// Level script data
aNode->mData = New<LevelScript>(aNode->mTokens.Count() * LEVEL_SCRIPT_SIZE_PER_TOKEN);
LevelScript* _Head = aNode->mData;
Array<u64> _SwitchNodes;
for (u64 _TokenIndex = 0; _TokenIndex < aNode->mTokens.Count();) { // Don't increment _TokenIndex here!
ParseLevelScriptSymbol(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++;
return aNode;
}
static DataNode<LevelScript> *GetLevelScript(GfxData *aGfxData, const String& aGeoRoot) {
for (DataNode<LevelScript> *_Node : aGfxData->mLevelScripts) {
if (_Node->mName == aGeoRoot) {
return _Node;
}
}
return NULL;
}
/////////////
// Writing //
/////////////
static void DynOS_Lvl_Write(FILE* aFile, GfxData* aGfxData, DataNode<LevelScript> *aNode) {
if (!aNode->mData) return;
// Name
WriteBytes<u8>(aFile, DATA_TYPE_LEVEL_SCRIPT);
aNode->mName.Write(aFile);
// Data
WriteBytes<u32>(aFile, aNode->mSize);
for (u32 i = 0; i != aNode->mSize; ++i) {
LevelScript *_Head = &aNode->mData[i];
if (aGfxData->mPointerList.Find((void *) _Head) != -1) {
DynOS_Pointer_Write(aFile, (const void *) (*_Head), aGfxData);
} else if (aGfxData->mLuaPointerList.Find((void *) _Head) != -1) {
DynOS_Pointer_Lua_Write(aFile, *(u32 *)_Head, aGfxData);
} else {
WriteBytes<u32>(aFile, *((u32 *) _Head));
}
}
}
static bool DynOS_Lvl_WriteBinary(const SysPath &aOutputFilename, GfxData *aGfxData) {
FILE *_File = fopen(aOutputFilename.c_str(), "wb");
if (!_File) {
PrintError(" ERROR: Unable to create file \"%s\"", aOutputFilename.c_str());
return false;
}
for (u64 i = 0; i != aGfxData->mLoadIndex; ++i) {
for (auto &_Node : aGfxData->mLights) {
if (_Node->mLoadIndex == i) {
DynOS_Lights_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mLightTs) {
if (_Node->mLoadIndex == i) {
DynOS_LightT_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mAmbientTs) {
if (_Node->mLoadIndex == i) {
DynOS_AmbientT_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mTextures) {
if (_Node->mLoadIndex == i) {
DynOS_Tex_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mTextureLists) {
if (_Node->mLoadIndex == i) {
DynOS_TexList_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mVertices) {
if (_Node->mLoadIndex == i) {
DynOS_Vtx_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mDisplayLists) {
if (_Node->mLoadIndex == i) {
DynOS_Gfx_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mGeoLayouts) {
if (_Node->mLoadIndex == i) {
DynOS_Geo_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mCollisions) {
if (_Node->mLoadIndex == i) {
DynOS_Col_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mLevelScripts) {
if (_Node->mLoadIndex == i) {
DynOS_Lvl_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mMacroObjects) {
if (_Node->mLoadIndex == i) {
DynOS_MacroObject_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mTrajectories) {
if (_Node->mLoadIndex == i) {
DynOS_Trajectory_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mMovtexs) {
if (_Node->mLoadIndex == i) {
DynOS_Movtex_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mMovtexQCs) {
if (_Node->mLoadIndex == i) {
DynOS_MovtexQC_Write(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mRooms) {
if (_Node->mLoadIndex == i) {
DynOS_Rooms_Write(_File, aGfxData, _Node);
}
}
}
fclose(_File);
return true;
}
/////////////
// Reading //
/////////////
static DataNode<LevelScript>* DynOS_Lvl_Load(FILE *aFile, GfxData *aGfxData) {
DataNode<LevelScript> *_Node = New<DataNode<LevelScript>>();
// Name
_Node->mName.Read(aFile);
// Data
_Node->mSize = ReadBytes<u32>(aFile);
_Node->mData = New<LevelScript>(_Node->mSize);
// Add it
if (aGfxData != NULL) {
aGfxData->mLevelScripts.Add(_Node);
}
// Read it
for (u32 i = 0; i != _Node->mSize; ++i) {
u32 _Value = ReadBytes<u32>(aFile);
void *_Ptr = DynOS_Pointer_Load(aFile, aGfxData, _Value, &_Node->mFlags);
if (_Ptr) {
_Node->mData[i] = (uintptr_t) _Ptr;
} else {
_Node->mData[i] = (uintptr_t) _Value;
}
}
return _Node;
}
GfxData *DynOS_Lvl_LoadFromBinary(const SysPath &aFilename, const char *aLevelName) {
struct DynosGfxDataCache { SysPath mPackFolder; Array<Pair<const char *, GfxData *>> mGfxData; };
static Array<DynosGfxDataCache *> sDynosGfxDataCache;
// Load data from binary file
GfxData *_GfxData = NULL;
FILE *_File = fopen(aFilename.c_str(), "rb");
if (_File) {
_GfxData = New<GfxData>();
for (bool _Done = false; !_Done;) {
switch (ReadBytes<u8>(_File)) {
case DATA_TYPE_LIGHT: DynOS_Lights_Load (_File, _GfxData); break;
case DATA_TYPE_LIGHT_T: DynOS_LightT_Load (_File, _GfxData); break;
case DATA_TYPE_AMBIENT_T: DynOS_AmbientT_Load (_File, _GfxData); break;
case DATA_TYPE_TEXTURE: DynOS_Tex_Load (_File, _GfxData); break;
case DATA_TYPE_TEXTURE_LIST: DynOS_TexList_Load (_File, _GfxData); break;
case DATA_TYPE_VERTEX: DynOS_Vtx_Load (_File, _GfxData); break;
case DATA_TYPE_DISPLAY_LIST: DynOS_Gfx_Load (_File, _GfxData); break;
case DATA_TYPE_GEO_LAYOUT: DynOS_Geo_Load (_File, _GfxData); break;
case DATA_TYPE_ANIMATION: DynOS_Anim_Load (_File, _GfxData); break;
case DATA_TYPE_ANIMATION_TABLE: DynOS_Anim_Table_Load (_File, _GfxData); break;
case DATA_TYPE_GFXDYNCMD: DynOS_GfxDynCmd_Load (_File, _GfxData); break;
case DATA_TYPE_COLLISION: DynOS_Col_Load (_File, _GfxData); break;
case DATA_TYPE_LEVEL_SCRIPT: DynOS_Lvl_Load (_File, _GfxData); break;
case DATA_TYPE_MACRO_OBJECT: DynOS_MacroObject_Load(_File, _GfxData); break;
case DATA_TYPE_TRAJECTORY: DynOS_Trajectory_Load (_File, _GfxData); break;
case DATA_TYPE_MOVTEX: DynOS_Movtex_Load (_File, _GfxData); break;
case DATA_TYPE_MOVTEXQC: DynOS_MovtexQC_Load (_File, _GfxData); break;
case DATA_TYPE_ROOMS: DynOS_Rooms_Load (_File, _GfxData); break;
default: _Done = true; break;
}
}
fclose(_File);
}
return _GfxData;
}
//////////////
// Generate //
//////////////
static bool DynOS_Lvl_GeneratePack_Internal(const SysPath &aPackFolder, Array<Pair<u64, String>> _ActorsFolders, GfxData *_GfxData) {
bool generated = false;
for (auto &_LvlNode : _GfxData->mLevelScripts) {
String _LvlRootName = _LvlNode->mName;
DataNode<LevelScript> *_LvlRoot = GetLevelScript(_GfxData, _LvlRootName);
if (_LvlRoot == NULL) { continue; }
if (_LvlRootName.Find("_entry") == -1) { continue; }
// If there is an existing binary file for this level, skip and go to the next level
SysPath _LvlFilename = fstring("%s/%s.lvl", aPackFolder.c_str(), _LvlRootName.begin());
if (fs_sys_file_exists(_LvlFilename.c_str())) {
continue;
}
// Init
_GfxData->mLoadIndex = 0;
_GfxData->mErrorCount = 0;
_GfxData->mModelIdentifier = _LvlRoot->mModelIdentifier;
_GfxData->mPackFolder = aPackFolder;
_GfxData->mPointerList = { NULL }; // The NULL pointer is needed, so we add it here
_GfxData->mPointerOffsetList = { };
_GfxData->mLuaPointerList = { };
_GfxData->mLuaTokenList = { };
_GfxData->mGfxContext.mCurrentTexture = NULL;
_GfxData->mGfxContext.mCurrentPalette = NULL;
_GfxData->mGeoNodeStack.Clear();
// Parse data
PrintNoNewLine("%s.lvl: Model identifier: %X - Processing... ", _LvlRootName.begin(), _GfxData->mModelIdentifier);
DynOS_Lvl_Parse(_GfxData, _LvlRoot, true);
// Force all of the movtexs, collisions, and trajectories into the compiled lvl
for (auto &_Node : _GfxData->mMovtexs) {
if (_Node->mModelIdentifier != _GfxData->mModelIdentifier) { continue; }
DynOS_Movtex_Parse(_GfxData, _Node, false);
}
for (auto &_Node : _GfxData->mMovtexQCs) {
if (_Node->mModelIdentifier != _GfxData->mModelIdentifier) { continue; }
DynOS_MovtexQC_Parse(_GfxData, _Node);
}
for (auto &_Node : _GfxData->mCollisions) {
if (_Node->mModelIdentifier != _GfxData->mModelIdentifier) { continue; }
DynOS_Col_Parse(_GfxData, _Node, false);
}
for (auto &_Node : _GfxData->mTrajectories) {
if (_Node->mModelIdentifier != _GfxData->mModelIdentifier) { continue; }
DynOS_Trajectory_Parse(_GfxData, _Node, false);
}
// Write if no error
if (_GfxData->mErrorCount == 0) {
DynOS_Lvl_WriteBinary(_LvlFilename, _GfxData);
} else {
Print(" %u error(s): Unable to parse data", _GfxData->mErrorCount);
}
// Clear data pointers
ClearLvlDataNodes(_GfxData->mLights);
ClearLvlDataNodes(_GfxData->mLightTs);
ClearLvlDataNodes(_GfxData->mAmbientTs);
ClearLvlDataNodes(_GfxData->mTextures);
ClearLvlDataNodes(_GfxData->mTextureLists);
ClearLvlDataNodes(_GfxData->mVertices);
ClearLvlDataNodes(_GfxData->mDisplayLists);
ClearLvlDataNodes(_GfxData->mGeoLayouts);
ClearLvlDataNodes(_GfxData->mCollisions);
ClearLvlDataNodes(_GfxData->mLevelScripts);
ClearLvlDataNodes(_GfxData->mMacroObjects);
ClearLvlDataNodes(_GfxData->mTrajectories);
ClearLvlDataNodes(_GfxData->mMovtexs);
ClearLvlDataNodes(_GfxData->mMovtexQCs);
ClearLvlDataNodes(_GfxData->mRooms);
_GfxData->mPointerList.Clear();
_GfxData->mPointerOffsetList.Clear();
_GfxData->mLuaPointerList.Clear();
_GfxData->mLuaTokenList.Clear();
generated = true;
}
_GfxData->mChildGeoLayouts.Clear();
return generated;
}
static void DynOS_Lvl_GeneratePack_Recursive(const SysPath &directory, GfxData *_GfxData) {
DIR *aPackDir = opendir(directory.c_str());
if (aPackDir) {
struct dirent *_PackEnt = NULL;
while ((_PackEnt = readdir(aPackDir)) != NULL) {
// Skip . and ..
if (SysPath(_PackEnt->d_name) == ".") continue;
if (SysPath(_PackEnt->d_name) == "..") continue;
SysPath path = fstring("%s/%s", directory.c_str(), _PackEnt->d_name);
// Recurse through subfolders
if (fs_sys_dir_exists(path.c_str())) {
DynOS_Lvl_GeneratePack_Recursive(path, _GfxData);
continue;
}
// skip files that don't end in '.c'
size_t nameLen = strlen(_PackEnt->d_name);
if (_PackEnt->d_name[nameLen - 2] != '.' || _PackEnt->d_name[nameLen - 1] != 'c') {
continue;
}
// read the file
DynOS_Read_Source(_GfxData, path.c_str());
}
closedir(aPackDir);
}
}
void DynOS_Lvl_GeneratePack(const SysPath &aPackFolder) {
Print("---------- Level pack folder: \"%s\" ----------", aPackFolder.c_str());
Array<Pair<u64, String>> _ActorsFolders;
GfxData *_GfxData = New<GfxData>();
_GfxData->mModelIdentifier = 0;
DIR *aPackDir = opendir(aPackFolder.c_str());
if (aPackDir) {
struct dirent *_PackEnt = NULL;
while ((_PackEnt = readdir(aPackDir)) != NULL) {
// Skip . and ..
if (SysPath(_PackEnt->d_name) == ".") continue;
if (SysPath(_PackEnt->d_name) == "..") continue;
// For each subfolder, read tokens from script.c
SysPath _Folder = fstring("%s/%s", aPackFolder.c_str(), _PackEnt->d_name);
if (!fs_sys_dir_exists(_Folder.c_str())) continue;
// Prevent generating from folders that likely already generated
SysPath _LvlFile = fstring("%s/level_%s_entry.lvl", aPackFolder.c_str(), _PackEnt->d_name);
if (fs_sys_file_exists(_LvlFile.c_str())) continue;
// Only parse folders with a 'script.c'
if (!fs_sys_file_exists(fstring("%s/script.c", _Folder.c_str()).c_str()) && !fs_sys_file_exists(fstring("%s/custom.script.c", _Folder.c_str()).c_str())) continue;
_GfxData->mModelIdentifier++;
DynOS_Lvl_GeneratePack_Recursive(_Folder, _GfxData);
}
closedir(aPackDir);
}
// Generate a binary file for each level found in the GfxData
DynOS_Lvl_GeneratePack_Internal(aPackFolder, _ActorsFolders, _GfxData);
DynOS_Gfx_Free(_GfxData);
}