Synchronized respawners and entities created after level load

This commit is contained in:
MysterD 2021-06-08 21:21:52 -07:00
parent 5db1a9e827
commit 33fbed94e4
8 changed files with 125 additions and 36 deletions

View file

@ -220,6 +220,7 @@ struct Object
/*0x218*/ void *collisionData; /*0x218*/ void *collisionData;
/*0x21C*/ Mat4 transform; /*0x21C*/ Mat4 transform;
/*0x25C*/ void *respawnInfo; /*0x25C*/ void *respawnInfo;
/*?????*/ u8 createdThroughNetwork;
}; };
struct ObjectHitbox struct ObjectHitbox

View file

@ -778,10 +778,11 @@ static s32 bhv_cmd_load_collision_data(void) {
// Command 0x2D: Sets the home position of the object to its current position. // Command 0x2D: Sets the home position of the object to its current position.
// Usage: SET_HOME() // Usage: SET_HOME()
static s32 bhv_cmd_set_home(void) { static s32 bhv_cmd_set_home(void) {
if (!gCurrentObject->createdThroughNetwork) {
gCurrentObject->oHomeX = gCurrentObject->oPosX; gCurrentObject->oHomeX = gCurrentObject->oPosX;
gCurrentObject->oHomeY = gCurrentObject->oPosY; gCurrentObject->oHomeY = gCurrentObject->oPosY;
gCurrentObject->oHomeZ = gCurrentObject->oPosZ; gCurrentObject->oHomeZ = gCurrentObject->oPosZ;
}
gCurBhvCommand++; gCurBhvCommand++;
return BHV_PROC_CONTINUE; return BHV_PROC_CONTINUE;
} }

View file

@ -57,4 +57,8 @@ void create_respawner(s32 model, const BehaviorScript *behToSpawn, s32 minSpawnD
respawner->oRespawnerMinSpawnDist = minSpawnDist; respawner->oRespawnerMinSpawnDist = minSpawnDist;
respawner->oRespawnerBehaviorToRespawn = behToSpawn; respawner->oRespawnerBehaviorToRespawn = behToSpawn;
respawner->oSyncID = syncID; respawner->oSyncID = syncID;
network_forget_sync_object(&gSyncObjects[syncID]);
network_init_object(respawner, SYNC_DISTANCE_ONLY_EVENTS);
o->oSyncID = 0;
} }

View file

@ -354,6 +354,8 @@ struct Object *create_object(const BehaviorScript *bhvScript) {
break; break;
} }
obj->createdThroughNetwork = false;
return obj; return obj;
} }

View file

@ -101,6 +101,7 @@ void network_update_objects(void);
// packet_spawn_object.c // packet_spawn_object.c
void network_send_spawn_objects(struct Object* objects[], u32 models[], u8 objectCount); void network_send_spawn_objects(struct Object* objects[], u32 models[], u8 objectCount);
void network_send_spawn_objects_to(u8 sendToLocalIndex, struct Object* objects[], u32 models[], u8 objectCount);
void network_receive_spawn_objects(struct Packet* p); void network_receive_spawn_objects(struct Packet* p);
// packet_spawn_star.c // packet_spawn_star.c

View file

@ -5,6 +5,9 @@
#include "game/object_list_processor.h" #include "game/object_list_processor.h"
#include "object_constants.h" #include "object_constants.h"
#include "object_fields.h" #include "object_fields.h"
#include "game/object_helpers.h"
#include "behavior_table.h"
#include "model_ids.h"
//#define DISABLE_MODULE_LOG 1 //#define DISABLE_MODULE_LOG 1
#include "pc/debuglog.h" #include "pc/debuglog.h"
@ -57,10 +60,8 @@ void network_send_location_request(void) {
struct NetworkPlayer* np = get_network_player_from_valid_location(gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex); struct NetworkPlayer* np = get_network_player_from_valid_location(gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex);
if (np == NULL) { if (np == NULL) {
gNetworkPlayerLocal->currAreaSyncValid = true; gNetworkPlayerLocal->currAreaSyncValid = true;
//LOG_INFO("set currAreaSyncValid to true (1)");
return; return;
} }
//LOG_INFO("network_send_location_request()");
network_send_client_location_request(gNetworkPlayerLocal->globalIndex, np->globalIndex); network_send_client_location_request(gNetworkPlayerLocal->globalIndex, np->globalIndex);
return; return;
} }
@ -72,7 +73,6 @@ void network_send_location_request(void) {
packet_write(&p, &gCurrLevelNum, sizeof(s16)); packet_write(&p, &gCurrLevelNum, sizeof(s16));
packet_write(&p, &gCurrAreaIndex, sizeof(s16)); packet_write(&p, &gCurrAreaIndex, sizeof(s16));
network_send_to(0, &p); network_send_to(0, &p);
//LOG_INFO("network_send_location_request() { %d, %d, %d, %d }", gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex);
} }
void network_receive_location_request(struct Packet* p) { void network_receive_location_request(struct Packet* p) {
@ -98,9 +98,6 @@ void network_receive_location_request(struct Packet* p) {
np->currLevelNum = levelNum; np->currLevelNum = levelNum;
np->currAreaIndex = areaIndex; np->currAreaIndex = areaIndex;
np->currAreaSyncValid = false; np->currAreaSyncValid = false;
//LOG_INFO("set global %d's currAreaSyncValid to false", np->globalIndex);
//LOG_INFO("network_receive_location_request() { %d, %d, %d, %d }", courseNum, actNum, levelNum, areaIndex);
struct NetworkPlayer* np2 = get_network_player_from_valid_location(courseNum, actNum, levelNum, areaIndex); struct NetworkPlayer* np2 = get_network_player_from_valid_location(courseNum, actNum, levelNum, areaIndex);
if (np2 == NULL) { if (np2 == NULL) {
@ -134,8 +131,6 @@ void network_send_client_location_request(u8 destGlobalIndex, u8 srcGlobalIndex)
packet_write(&p, &destNp->currLevelNum, sizeof(s16)); packet_write(&p, &destNp->currLevelNum, sizeof(s16));
packet_write(&p, &destNp->currAreaIndex, sizeof(s16)); packet_write(&p, &destNp->currAreaIndex, sizeof(s16));
//LOG_INFO("network_send_client_location_request() { %d, %d, %d, %d, %d }", destGlobalIndex, destNp->currCourseNum, destNp->currActNum, destNp->currLevelNum, destNp->currAreaIndex);
struct NetworkPlayer* srcNp = network_player_from_global_index(srcGlobalIndex); struct NetworkPlayer* srcNp = network_player_from_global_index(srcGlobalIndex);
if (srcNp == NULL || !srcNp->connected || !srcNp->currAreaSyncValid) { if (srcNp == NULL || !srcNp->connected || !srcNp->currAreaSyncValid) {
LOG_ERROR("network_send_client_location_request: source np is invalid (global %d)", srcGlobalIndex); LOG_ERROR("network_send_client_location_request: source np is invalid (global %d)", srcGlobalIndex);
@ -159,8 +154,6 @@ void network_receive_client_location_request(struct Packet* p) {
packet_read(p, &levelNum, sizeof(s16)); packet_read(p, &levelNum, sizeof(s16));
packet_read(p, &areaIndex, sizeof(s16)); packet_read(p, &areaIndex, sizeof(s16));
//LOG_INFO("network_receive_client_location_request() { %d, %d, %d, %d, %d }", destGlobalIndex, courseNum, actNum, levelNum, areaIndex);
if (courseNum != gCurrCourseNum || actNum != gCurrActNum || levelNum != gCurrLevelNum || areaIndex != gCurrAreaIndex) { if (courseNum != gCurrCourseNum || actNum != gCurrActNum || levelNum != gCurrLevelNum || areaIndex != gCurrAreaIndex) {
LOG_ERROR("Receiving 'client location request' with the wrong location!"); LOG_ERROR("Receiving 'client location request' with the wrong location!");
return; return;
@ -192,20 +185,66 @@ void network_send_location_response(u8 destGlobalIndex) {
packet_write(&p, &gMarioStates[0].numCoins, sizeof(s16)); packet_write(&p, &gMarioStates[0].numCoins, sizeof(s16));
// static spawn removal
packet_write(&p, &sStaticSpawnRemovalIndex, sizeof(u8)); packet_write(&p, &sStaticSpawnRemovalIndex, sizeof(u8));
for (int i = 0; i < sStaticSpawnRemovalIndex; i++) { for (int i = 0; i < sStaticSpawnRemovalIndex; i++) {
packet_write(&p, &sStaticSpawnRemoval[i], sizeof(u8)); packet_write(&p, &sStaticSpawnRemoval[i], sizeof(u8));
} }
// coin collection
packet_write(&p, &sCoinCollectionIndex, sizeof(u8)); packet_write(&p, &sCoinCollectionIndex, sizeof(u8));
for (int i = 0; i < sCoinCollectionIndex; i++) { for (int i = 0; i < sCoinCollectionIndex; i++) {
packet_write(&p, &sCoinCollection[i], sizeof(u8)); packet_write(&p, &sCoinCollection[i], sizeof(u8));
} }
//LOG_INFO("network_send_location_response() { %d, %d, %d, %d, %d } to: %d", destGlobalIndex, gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex, (gNetworkType == NT_SERVER) ? destNp->localIndex : 0); // respawners
u8 respawnerCount = 0;
for (int i = 0; i < MAX_SYNC_OBJECTS; i++) {
struct SyncObject* so = &gSyncObjects[i];
if (so == NULL || so->o == NULL || so->behavior != bhvRespawner) { continue; }
respawnerCount++;
}
packet_write(&p, &respawnerCount, sizeof(u8));
for (int i = 0; i < MAX_SYNC_OBJECTS; i++) {
struct SyncObject* so = &gSyncObjects[i];
if (so == NULL || so->o == NULL || so->behavior != bhvRespawner) { continue; }
u32 behaviorToRespawn = get_id_from_behavior(so->o->oRespawnerBehaviorToRespawn);
packet_write(&p, &so->o->oPosX, sizeof(f32));
packet_write(&p, &so->o->oPosY, sizeof(f32));
packet_write(&p, &so->o->oPosZ, sizeof(f32));
packet_write(&p, &so->o->oBehParams, sizeof(s32));
packet_write(&p, &so->o->oRespawnerModelToRespawn, sizeof(s32));
packet_write(&p, &so->o->oRespawnerMinSpawnDist, sizeof(f32));
packet_write(&p, &behaviorToRespawn, sizeof(s32));
packet_write(&p, &so->o->oSyncID, sizeof(u32));
}
network_send_to(destNp->localIndex, &p); network_send_to(destNp->localIndex, &p);
// send non-static objects
for (int i = 0; i < MAX_SYNC_OBJECTS; i++) {
struct SyncObject* so = &gSyncObjects[i];
if (so == NULL || so->o == NULL || so->o->oSyncID != i) { continue; }
if (so->staticLevelSpawn) { continue; }
if (so->o->behavior == bhvRespawner) { continue; }
struct Object* spawn_objects[] = { so->o };
// TODO: move find model to a utility file/function
// find model
u32 model = 0;
for (int j = 0; j < 256; j++) {
if (so->o->header.gfx.sharedChild == gLoadedGraphNodes[j]) {
model = j;
break;
}
}
u32 models[] = { model };
network_send_spawn_objects_to(destNp->localIndex, spawn_objects, models, 1);
}
// send last reliable ent packet
for (int i = 0; i < MAX_SYNC_OBJECTS; i++) { for (int i = 0; i < MAX_SYNC_OBJECTS; i++) {
struct SyncObject* so = &gSyncObjects[i]; struct SyncObject* so = &gSyncObjects[i];
if (so == NULL || so->o == NULL) { continue; } if (so == NULL || so->o == NULL) { continue; }
@ -224,18 +263,11 @@ void network_receive_location_response(struct Packet* p) {
packet_read(p, &levelNum, sizeof(s16)); packet_read(p, &levelNum, sizeof(s16));
packet_read(p, &areaIndex, sizeof(s16)); packet_read(p, &areaIndex, sizeof(s16));
//LOG_INFO("network_receive_location_response() { %d, %d, %d, %d, %d }", destGlobalIndex, courseNum, actNum, levelNum, areaIndex);
if (courseNum != gCurrCourseNum || actNum != gCurrActNum || levelNum != gCurrLevelNum || areaIndex != gCurrAreaIndex) { if (courseNum != gCurrCourseNum || actNum != gCurrActNum || levelNum != gCurrLevelNum || areaIndex != gCurrAreaIndex) {
LOG_ERROR("Receiving 'location response' with the wrong location!"); LOG_ERROR("Receiving 'location response' with the wrong location!");
return; return;
} }
/*if (gNetworkType == NT_SERVER) {
struct NetworkPlayer* srcNp = &gNetworkPlayers[p->localIndex];
LOG_INFO("sending location response from global %d to global %d", srcNp->globalIndex, gNetworkPlayerLocal->globalIndex);
}*/
if (gNetworkPlayerLocal->currAreaSyncValid) { if (gNetworkPlayerLocal->currAreaSyncValid) {
LOG_ERROR("Receiving 'location response' when our location is already valid!"); LOG_ERROR("Receiving 'location response' when our location is already valid!");
return; return;
@ -279,12 +311,43 @@ void network_receive_location_response(struct Packet* p) {
} }
} }
// read respawners
u8 respawnerCount = 0;
packet_read(p, &respawnerCount, sizeof(u8));
for (int i = 0; i < respawnerCount; i++) {
f32 posX, posY, posZ;
packet_read(p, &posX, sizeof(f32));
packet_read(p, &posY, sizeof(f32));
packet_read(p, &posZ, sizeof(f32));
s32 behParams, respawnerModelToRespawn;
packet_read(p, &behParams, sizeof(s32));
packet_read(p, &respawnerModelToRespawn, sizeof(s32));
f32 respawnerMinSpawnDist;
packet_read(p, &respawnerMinSpawnDist, sizeof(f32));
u32 behaviorToRespawn, syncId;
packet_read(p, &behaviorToRespawn, sizeof(u32));
packet_read(p, &syncId, sizeof(u32));
struct Object* respawner = spawn_object_abs_with_rot(gMarioStates[0].marioObj, 0, MODEL_NONE, bhvRespawner, posX, posY, posZ, 0, 0, 0);
respawner->parentObj = respawner;
respawner->oBehParams = behParams;
respawner->oRespawnerModelToRespawn = respawnerModelToRespawn;
respawner->oRespawnerMinSpawnDist = respawnerMinSpawnDist;
respawner->oRespawnerBehaviorToRespawn = get_behavior_from_id(behaviorToRespawn);
respawner->oSyncID = syncId;
network_forget_sync_object(&gSyncObjects[syncId]);
network_init_object(respawner, SYNC_DISTANCE_ONLY_EVENTS);
}
gMarioStates[0].numCoins = numCoins; gMarioStates[0].numCoins = numCoins;
gNetworkPlayerLocal->currAreaSyncValid = true; gNetworkPlayerLocal->currAreaSyncValid = true;
//LOG_INFO("set currAreaSyncValid to true (2)");
if (gNetworkType != NT_SERVER) { if (gNetworkType != NT_SERVER) {
network_send_level_area_valid(0); network_send_level_area_valid(0);
} }
//LOG_INFO("network_receive_location_response() ==> valid");
} }

View file

@ -155,6 +155,10 @@ void network_set_sync_id(struct Object* o) {
o->oSyncID = nextSyncID; o->oSyncID = nextSyncID;
nextSyncID = (nextSyncID + 1) % MAX_SYNC_OBJECTS; nextSyncID = (nextSyncID + 1) % MAX_SYNC_OBJECTS;
if (gNetworkLevelLoaded) {
LOG_INFO("set sync id for object w/behavior %d", get_id_from_behavior(o->behavior));
}
assert(o->oSyncID < MAX_SYNC_OBJECTS); assert(o->oSyncID < MAX_SYNC_OBJECTS);
} }
@ -241,7 +245,6 @@ static struct SyncObject* packet_read_object_header(struct Packet* p, u8* fromLo
return NULL; return NULL;
} if (o->behavior != behavior && !allowable_behavior_change(so, behavior)) { } if (o->behavior != behavior && !allowable_behavior_change(so, behavior)) {
LOG_ERROR("behavior mismatch for %d: %04X vs %04X", syncId, get_id_from_behavior(o->behavior), get_id_from_behavior(behavior)); LOG_ERROR("behavior mismatch for %d: %04X vs %04X", syncId, get_id_from_behavior(o->behavior), get_id_from_behavior(behavior));
network_forget_sync_object(so);
return NULL; return NULL;
} }
@ -373,7 +376,6 @@ void network_send_object(struct Object* o) {
if (so == NULL) { return; } if (so == NULL) { return; }
if (o != so->o) { if (o != so->o) {
LOG_ERROR("object mismatch for %d", o->oSyncID); LOG_ERROR("object mismatch for %d", o->oSyncID);
network_forget_sync_object(so);
return; return;
} }
if (o->behavior != so->behavior && !allowable_behavior_change(so, so->behavior)) { if (o->behavior != so->behavior && !allowable_behavior_change(so, so->behavior)) {
@ -393,7 +395,6 @@ void network_send_object_reliability(struct Object* o, bool reliable) {
if (so == NULL) { return; } if (so == NULL) { return; }
if (o != so->o) { if (o != so->o) {
LOG_ERROR("object mismatch for %d", o->oSyncID); LOG_ERROR("object mismatch for %d", o->oSyncID);
network_forget_sync_object(so);
return; return;
} }
if (o->behavior != so->behavior && !allowable_behavior_change(so, so->behavior)) { if (o->behavior != so->behavior && !allowable_behavior_change(so, so->behavior)) {
@ -515,7 +516,7 @@ void network_update_objects(void) {
// check for stale sync object // check for stale sync object
if (so->o->oSyncID != i) { if (so->o->oSyncID != i) {
LOG_ERROR("sync id mismatch: %d vs %d", so->o->oSyncID, i); LOG_ERROR("sync id mismatch: %d vs %d (behavior %d)", so->o->oSyncID, i, get_id_from_behavior(so->o->behavior));
network_forget_sync_object(so); network_forget_sync_object(so);
continue; continue;
} }

View file

@ -5,6 +5,8 @@
#include "src/game/object_helpers.h" #include "src/game/object_helpers.h"
#include "behavior_data.h" #include "behavior_data.h"
#include "behavior_table.h" #include "behavior_table.h"
//#define DISABLE_MODULE_LOG 1
#include "pc/debuglog.h"
#define MAX_SPAWN_OBJECTS_PER_PACKET 8 #define MAX_SPAWN_OBJECTS_PER_PACKET 8
@ -17,13 +19,16 @@ struct SpawnObjectData {
s32 rawData[80]; s32 rawData[80];
}; };
static u8 generate_parent_id(struct Object* objects[], u8 onIndex) { static u8 generate_parent_id(struct Object* objects[], u8 onIndex, bool sanitize) {
struct Object* o = objects[onIndex]; struct Object* o = objects[onIndex];
// special case if the parent is itself // special case if the parent is itself
if (o->parentObj == o) { return (u8)-1; } if (o->parentObj == o) { return (u8)-1; }
if (onIndex == 0) { if (onIndex == 0) {
if (sanitize && o->parentObj->oSyncID == 0) {
return (u8)-1;
}
assert(o->parentObj->oSyncID != 0); assert(o->parentObj->oSyncID != 0);
return (u8)o->parentObj->oSyncID; return (u8)o->parentObj->oSyncID;
} }
@ -36,6 +41,10 @@ static u8 generate_parent_id(struct Object* objects[], u8 onIndex) {
} }
void network_send_spawn_objects(struct Object* objects[], u32 models[], u8 objectCount) { void network_send_spawn_objects(struct Object* objects[], u32 models[], u8 objectCount) {
network_send_spawn_objects_to(PACKET_DESTINATION_BROADCAST, objects, models, objectCount);
}
void network_send_spawn_objects_to(u8 sendToLocalIndex, struct Object* objects[], u32 models[], u8 objectCount) {
assert(objectCount < MAX_SPAWN_OBJECTS_PER_PACKET); assert(objectCount < MAX_SPAWN_OBJECTS_PER_PACKET);
struct Packet p; struct Packet p;
@ -45,7 +54,7 @@ void network_send_spawn_objects(struct Object* objects[], u32 models[], u8 objec
for (u8 i = 0; i < objectCount; i++) { for (u8 i = 0; i < objectCount; i++) {
struct Object* o = objects[i]; struct Object* o = objects[i];
u32 model = models[i]; u32 model = models[i];
u8 parentId = generate_parent_id(objects, i); u8 parentId = generate_parent_id(objects, i, true);
u16 behaviorId = get_id_from_behavior(o->behavior); u16 behaviorId = get_id_from_behavior(o->behavior);
packet_write(&p, &parentId, sizeof(u8)); packet_write(&p, &parentId, sizeof(u8));
packet_write(&p, &model, sizeof(u32)); packet_write(&p, &model, sizeof(u32));
@ -57,7 +66,11 @@ void network_send_spawn_objects(struct Object* objects[], u32 models[], u8 objec
packet_write(&p, &o->header.gfx.scale[2], sizeof(f32)); packet_write(&p, &o->header.gfx.scale[2], sizeof(f32));
} }
if (sendToLocalIndex == PACKET_DESTINATION_BROADCAST) {
network_send(&p); network_send(&p);
} else {
network_send_to(sendToLocalIndex, &p);
}
} }
void network_receive_spawn_objects(struct Packet* p) { void network_receive_spawn_objects(struct Packet* p) {
@ -106,6 +119,7 @@ void network_receive_spawn_objects(struct Packet* p) {
void* behavior = (void*)get_behavior_from_id(data.behaviorId); void* behavior = (void*)get_behavior_from_id(data.behaviorId);
struct Object* o = spawn_object(parentObj, data.model, behavior); struct Object* o = spawn_object(parentObj, data.model, behavior);
o->createdThroughNetwork = true;
memcpy(o->rawData.asU32, data.rawData, sizeof(u32) * 80); memcpy(o->rawData.asU32, data.rawData, sizeof(u32) * 80);
o->header.gfx.scale[0] = scale[0]; o->header.gfx.scale[0] = scale[0];
@ -115,11 +129,13 @@ void network_receive_spawn_objects(struct Packet* p) {
// correct the temporary parent with the object itself // correct the temporary parent with the object itself
if (data.parentId == (u8)-1) { o->parentObj = o; } if (data.parentId == (u8)-1) { o->parentObj = o; }
// they've allocated one of their reserved sync objects if (o->oSyncID != 0) {
if (o->oSyncID != 0 && gSyncObjects[o->oSyncID].reserved == reserveId) { // check if they've allocated one of their reserved sync objects
receivedReservedSyncObject = (o->oSyncID != 0 && gSyncObjects[o->oSyncID].reserved == reserveId);
if (receivedReservedSyncObject || gNetworkLevelSyncing) {
gSyncObjects[o->oSyncID].o = o; gSyncObjects[o->oSyncID].o = o;
gSyncObjects[o->oSyncID].reserved = 0; gSyncObjects[o->oSyncID].reserved = 0;
receivedReservedSyncObject = true; }
} }
spawned[i] = o; spawned[i] = o;