mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2025-10-30 08:01:01 +00:00
to address the grand star late join model bug that can happen with mods like omm. the bug happened when players have different dynos packs, and during a late join, the model ids are relied on to be the same. dynos packs can offset the available model ids, therefore desyncing the model used on late join.
216 lines
7.1 KiB
C++
216 lines
7.1 KiB
C++
#include <map>
|
|
#include <algorithm>
|
|
#include "dynos.cpp.h"
|
|
|
|
extern "C" {
|
|
#include "object_fields.h"
|
|
#include "game/level_update.h"
|
|
#include "game/object_list_processor.h"
|
|
#include "pc/configfile.h"
|
|
#include "pc/lua/smlua_hooks.h"
|
|
}
|
|
|
|
// Static maps/arrays
|
|
static std::map<const void*, ActorGfx>& DynosValidActors() {
|
|
static std::map<const void*, ActorGfx> sDynosValidActors;
|
|
return sDynosValidActors;
|
|
}
|
|
|
|
static Array<Pair<const char*, void *>>& DynosCustomActors() {
|
|
static Array<Pair<const char*, void *>> sDynosCustomActors;
|
|
return sDynosCustomActors;
|
|
}
|
|
|
|
// TODO: the cleanup/refactor didn't really go as planned.
|
|
// clean up the actor management code more
|
|
|
|
void DynOS_Actor_AddCustom(const SysPath &aFilename, const char *aActorName) {
|
|
const void* georef = DynOS_Builtin_Actor_GetFromName(aActorName);
|
|
|
|
u16 actorLen = strlen(aActorName);
|
|
char* actorName = (char*)calloc(1, sizeof(char) * (actorLen + 1));
|
|
strcpy(actorName, aActorName);
|
|
|
|
GfxData *_GfxData = DynOS_Actor_LoadFromBinary(aFilename, actorName, aFilename, false);
|
|
if (!_GfxData) {
|
|
PrintError(" ERROR: Couldn't load Actor Binary \"%s\" from \"%s\"", actorName, aFilename.c_str());
|
|
free(actorName);
|
|
return;
|
|
}
|
|
|
|
void* geoLayout = (*(_GfxData->mGeoLayouts.end() - 1))->mData;
|
|
if (!geoLayout) {
|
|
PrintError(" ERROR: Couldn't load geo layout for \"%s\"", actorName);
|
|
free(actorName);
|
|
return;
|
|
}
|
|
|
|
// Alloc and init the actors gfx list
|
|
u32 id = 0;
|
|
ActorGfx actorGfx = { };
|
|
actorGfx.mGfxData = _GfxData;
|
|
actorGfx.mPackIndex = MOD_PACK_INDEX;
|
|
actorGfx.mGraphNode = (GraphNode *) DynOS_Model_LoadGeo(&id, MODEL_POOL_SESSION, geoLayout, true);
|
|
if (!actorGfx.mGraphNode) {
|
|
PrintError(" ERROR: Couldn't load graph node for \"%s\"", actorName);
|
|
free(actorName);
|
|
return;
|
|
}
|
|
actorGfx.mGraphNode->georef = georef;
|
|
|
|
// Add to custom actors
|
|
if (georef == NULL) {
|
|
DynosCustomActors().Add({ strdup(actorName), geoLayout });
|
|
georef = geoLayout;
|
|
}
|
|
|
|
// Add to list
|
|
DynOS_Actor_Valid(georef, actorGfx);
|
|
free(actorName);
|
|
}
|
|
|
|
const void *DynOS_Actor_GetLayoutFromName(const char *aActorName) {
|
|
if (aActorName == NULL) { return NULL; }
|
|
|
|
// check levels
|
|
auto& levelsArray = DynOS_Lvl_GetArray();
|
|
for (auto& lvl : levelsArray) {
|
|
for (auto& geo : lvl.second->mGeoLayouts) {
|
|
if (geo->mName == aActorName) {
|
|
return geo->mData;
|
|
}
|
|
}
|
|
}
|
|
|
|
// check custom actors
|
|
for (auto& pair : DynosCustomActors()) {
|
|
if (!strcmp(aActorName, pair.first)) {
|
|
return pair.second;
|
|
}
|
|
}
|
|
|
|
// check loaded actors
|
|
for (auto& pair : DynosValidActors()) {
|
|
for (auto& geo : pair.second.mGfxData->mGeoLayouts) {
|
|
if (!strcmp(aActorName, geo->mName.begin())) {
|
|
return geo->mData;
|
|
}
|
|
}
|
|
}
|
|
|
|
// check built in actors
|
|
for (s32 i = 0; i < DynOS_Builtin_Actor_GetCount(); ++i) {
|
|
auto name = DynOS_Builtin_Actor_GetNameFromIndex(i);
|
|
if (!strcmp(aActorName, name)) {
|
|
return DynOS_Builtin_Actor_GetFromIndex(i);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
ActorGfx* DynOS_Actor_GetActorGfx(const GraphNode* aGraphNode) {
|
|
if (aGraphNode == NULL) { return NULL; }
|
|
auto& _ValidActors = DynosValidActors();
|
|
|
|
// If georef is not NULL, check georef
|
|
if (aGraphNode->georef != NULL) {
|
|
if (_ValidActors.count(aGraphNode->georef) != 0) {
|
|
return &_ValidActors[aGraphNode->georef];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// Check graph node
|
|
for (const auto& _Actor : _ValidActors) {
|
|
if (_Actor.second.mGraphNode == aGraphNode) {
|
|
return (ActorGfx*)&_Actor.second;
|
|
}
|
|
}
|
|
|
|
// No actor found
|
|
return NULL;
|
|
}
|
|
|
|
void DynOS_Actor_Valid(const void* aGeoref, ActorGfx& aActorGfx) {
|
|
if (aGeoref == NULL) { return; }
|
|
auto& _ValidActors = DynosValidActors();
|
|
_ValidActors[aGeoref] = aActorGfx;
|
|
DynOS_Tex_Valid(aActorGfx.mGfxData);
|
|
}
|
|
|
|
void DynOS_Actor_Invalid(const void* aGeoref, s32 aPackIndex) {
|
|
if (aGeoref == NULL) { return; }
|
|
auto& _ValidActors = DynosValidActors();
|
|
if (_ValidActors.count(aGeoref) == 0) { return; }
|
|
if (_ValidActors[aGeoref].mPackIndex != aPackIndex) { return; }
|
|
|
|
DynOS_Tex_Invalid(_ValidActors[aGeoref].mGfxData);
|
|
_ValidActors.erase(aGeoref);
|
|
}
|
|
|
|
void DynOS_Actor_Override(struct Object* obj, void** aSharedChild) {
|
|
if ((aSharedChild == NULL) || (*aSharedChild == NULL)) { return; }
|
|
|
|
const void* georef = (*(GraphNode**)aSharedChild)->georef;
|
|
if (georef == NULL) { return; }
|
|
|
|
auto& _ValidActors = DynosValidActors();
|
|
if (_ValidActors.count(georef) == 0) { return; }
|
|
|
|
// Check if the behavior uses a character specific model
|
|
if (obj && (obj->behavior == smlua_override_behavior(bhvMario) ||
|
|
obj->behavior == smlua_override_behavior(bhvNormalCap) ||
|
|
obj->behavior == smlua_override_behavior(bhvWingCap) ||
|
|
obj->behavior == smlua_override_behavior(bhvMetalCap) ||
|
|
obj->behavior == smlua_override_behavior(bhvVanishCap))) {
|
|
struct NetworkPlayer* np = network_player_from_global_index(obj->globalPlayerIndex);
|
|
if (np && np->localIndex > 0 && configDynosLocalPlayerModelOnly) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
*aSharedChild = (void*)_ValidActors[georef].mGraphNode;
|
|
}
|
|
|
|
void DynOS_Actor_Override_All(void) {
|
|
if (!gObjectLists) { return; }
|
|
// Loop through all object lists
|
|
for (s32 list : { OBJ_LIST_PLAYER, OBJ_LIST_DESTRUCTIVE, OBJ_LIST_GENACTOR, OBJ_LIST_PUSHABLE, OBJ_LIST_LEVEL, OBJ_LIST_DEFAULT, OBJ_LIST_SURFACE, OBJ_LIST_POLELIKE, OBJ_LIST_UNIMPORTANT }) {
|
|
struct Object *_Head = (struct Object *) &gObjectLists[list];
|
|
for (struct Object *_Object = (struct Object *) _Head->header.next; _Object != _Head; _Object = (struct Object *) _Object->header.next) {
|
|
if (_Object->activeFlags && _Object->header.gfx.sharedChild != NULL) {
|
|
if (_Object->header.gfx.sharedChild->georef != NULL) {
|
|
GraphNode* georef = (GraphNode*)_Object->header.gfx.sharedChild->georef;
|
|
u32 id = 0;
|
|
_Object->header.gfx.sharedChild = DynOS_Model_LoadGeo(&id, MODEL_POOL_PERMANENT, georef, true);
|
|
}
|
|
DynOS_Actor_Override(_Object, (void**)&_Object->header.gfx.sharedChild);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void DynOS_Actor_ModShutdown() {
|
|
auto& _DynosCustomActors = DynosCustomActors();
|
|
while (_DynosCustomActors.Count() > 0) {
|
|
auto& pair = _DynosCustomActors[0];
|
|
DynOS_Actor_Invalid(pair.second, MOD_PACK_INDEX);
|
|
free((void*)pair.first);
|
|
_DynosCustomActors.Remove(0);
|
|
}
|
|
|
|
auto& _ValidActors = DynosValidActors();
|
|
for (auto it = _ValidActors.cbegin(); it != _ValidActors.cend();) {
|
|
auto& actorGfx = it->second;
|
|
if (actorGfx.mPackIndex == MOD_PACK_INDEX) {
|
|
DynOS_Gfx_Free(actorGfx.mGfxData);
|
|
_ValidActors.erase(it++);
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
|
|
DynOS_Actor_Override_All();
|
|
}
|