From 33fbed94e4aa48677a76f84e667aa7317fcf22e8 Mon Sep 17 00:00:00 2001 From: MysterD Date: Tue, 8 Jun 2021 21:21:52 -0700 Subject: [PATCH] Synchronized respawners and entities created after level load --- include/types.h | 1 + src/engine/behavior_script.c | 9 +- src/game/behaviors/corkbox.inc.c | 4 + src/game/spawn_object.c | 2 + src/pc/network/packets/packet.h | 1 + .../network/packets/packet_location_request.c | 103 ++++++++++++++---- src/pc/network/packets/packet_object.c | 9 +- src/pc/network/packets/packet_spawn_objects.c | 32 ++++-- 8 files changed, 125 insertions(+), 36 deletions(-) diff --git a/include/types.h b/include/types.h index 17750c93..6ed9cf9c 100644 --- a/include/types.h +++ b/include/types.h @@ -220,6 +220,7 @@ struct Object /*0x218*/ void *collisionData; /*0x21C*/ Mat4 transform; /*0x25C*/ void *respawnInfo; + /*?????*/ u8 createdThroughNetwork; }; struct ObjectHitbox diff --git a/src/engine/behavior_script.c b/src/engine/behavior_script.c index 929bc798..6f52f6bd 100644 --- a/src/engine/behavior_script.c +++ b/src/engine/behavior_script.c @@ -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. // Usage: SET_HOME() static s32 bhv_cmd_set_home(void) { - gCurrentObject->oHomeX = gCurrentObject->oPosX; - gCurrentObject->oHomeY = gCurrentObject->oPosY; - gCurrentObject->oHomeZ = gCurrentObject->oPosZ; - + if (!gCurrentObject->createdThroughNetwork) { + gCurrentObject->oHomeX = gCurrentObject->oPosX; + gCurrentObject->oHomeY = gCurrentObject->oPosY; + gCurrentObject->oHomeZ = gCurrentObject->oPosZ; + } gCurBhvCommand++; return BHV_PROC_CONTINUE; } diff --git a/src/game/behaviors/corkbox.inc.c b/src/game/behaviors/corkbox.inc.c index c1b9ad32..e19ba4f3 100644 --- a/src/game/behaviors/corkbox.inc.c +++ b/src/game/behaviors/corkbox.inc.c @@ -57,4 +57,8 @@ void create_respawner(s32 model, const BehaviorScript *behToSpawn, s32 minSpawnD respawner->oRespawnerMinSpawnDist = minSpawnDist; respawner->oRespawnerBehaviorToRespawn = behToSpawn; respawner->oSyncID = syncID; + + network_forget_sync_object(&gSyncObjects[syncID]); + network_init_object(respawner, SYNC_DISTANCE_ONLY_EVENTS); + o->oSyncID = 0; } diff --git a/src/game/spawn_object.c b/src/game/spawn_object.c index 0ea54884..9f4788a9 100644 --- a/src/game/spawn_object.c +++ b/src/game/spawn_object.c @@ -354,6 +354,8 @@ struct Object *create_object(const BehaviorScript *bhvScript) { break; } + obj->createdThroughNetwork = false; + return obj; } diff --git a/src/pc/network/packets/packet.h b/src/pc/network/packets/packet.h index 75d6727e..53f427d9 100644 --- a/src/pc/network/packets/packet.h +++ b/src/pc/network/packets/packet.h @@ -101,6 +101,7 @@ void network_update_objects(void); // packet_spawn_object.c 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); // packet_spawn_star.c diff --git a/src/pc/network/packets/packet_location_request.c b/src/pc/network/packets/packet_location_request.c index 80408f19..1feb972c 100644 --- a/src/pc/network/packets/packet_location_request.c +++ b/src/pc/network/packets/packet_location_request.c @@ -5,6 +5,9 @@ #include "game/object_list_processor.h" #include "object_constants.h" #include "object_fields.h" +#include "game/object_helpers.h" +#include "behavior_table.h" +#include "model_ids.h" //#define DISABLE_MODULE_LOG 1 #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); if (np == NULL) { gNetworkPlayerLocal->currAreaSyncValid = true; - //LOG_INFO("set currAreaSyncValid to true (1)"); return; } - //LOG_INFO("network_send_location_request()"); network_send_client_location_request(gNetworkPlayerLocal->globalIndex, np->globalIndex); return; } @@ -72,7 +73,6 @@ void network_send_location_request(void) { packet_write(&p, &gCurrLevelNum, sizeof(s16)); packet_write(&p, &gCurrAreaIndex, sizeof(s16)); 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) { @@ -98,9 +98,6 @@ void network_receive_location_request(struct Packet* p) { np->currLevelNum = levelNum; np->currAreaIndex = areaIndex; 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); 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->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); if (srcNp == NULL || !srcNp->connected || !srcNp->currAreaSyncValid) { 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, &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) { LOG_ERROR("Receiving 'client location request' with the wrong location!"); return; @@ -192,20 +185,66 @@ void network_send_location_response(u8 destGlobalIndex) { packet_write(&p, &gMarioStates[0].numCoins, sizeof(s16)); + // static spawn removal packet_write(&p, &sStaticSpawnRemovalIndex, sizeof(u8)); for (int i = 0; i < sStaticSpawnRemovalIndex; i++) { packet_write(&p, &sStaticSpawnRemoval[i], sizeof(u8)); } + // coin collection packet_write(&p, &sCoinCollectionIndex, sizeof(u8)); for (int i = 0; i < sCoinCollectionIndex; i++) { 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); + // 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++) { struct SyncObject* so = &gSyncObjects[i]; 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, &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) { LOG_ERROR("Receiving 'location response' with the wrong location!"); 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) { LOG_ERROR("Receiving 'location response' when our location is already valid!"); 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; gNetworkPlayerLocal->currAreaSyncValid = true; - //LOG_INFO("set currAreaSyncValid to true (2)"); + if (gNetworkType != NT_SERVER) { network_send_level_area_valid(0); } - //LOG_INFO("network_receive_location_response() ==> valid"); } \ No newline at end of file diff --git a/src/pc/network/packets/packet_object.c b/src/pc/network/packets/packet_object.c index 2c6682d2..ad5a366e 100644 --- a/src/pc/network/packets/packet_object.c +++ b/src/pc/network/packets/packet_object.c @@ -155,6 +155,10 @@ void network_set_sync_id(struct Object* o) { o->oSyncID = nextSyncID; 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); } @@ -241,7 +245,6 @@ static struct SyncObject* packet_read_object_header(struct Packet* p, u8* fromLo return NULL; } 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)); - network_forget_sync_object(so); return NULL; } @@ -373,7 +376,6 @@ void network_send_object(struct Object* o) { if (so == NULL) { return; } if (o != so->o) { LOG_ERROR("object mismatch for %d", o->oSyncID); - network_forget_sync_object(so); return; } 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 (o != so->o) { LOG_ERROR("object mismatch for %d", o->oSyncID); - network_forget_sync_object(so); return; } 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 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); continue; } diff --git a/src/pc/network/packets/packet_spawn_objects.c b/src/pc/network/packets/packet_spawn_objects.c index 10079f17..f90af742 100644 --- a/src/pc/network/packets/packet_spawn_objects.c +++ b/src/pc/network/packets/packet_spawn_objects.c @@ -5,6 +5,8 @@ #include "src/game/object_helpers.h" #include "behavior_data.h" #include "behavior_table.h" +//#define DISABLE_MODULE_LOG 1 +#include "pc/debuglog.h" #define MAX_SPAWN_OBJECTS_PER_PACKET 8 @@ -17,13 +19,16 @@ struct SpawnObjectData { 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]; // special case if the parent is itself if (o->parentObj == o) { return (u8)-1; } if (onIndex == 0) { + if (sanitize && o->parentObj->oSyncID == 0) { + return (u8)-1; + } assert(o->parentObj->oSyncID != 0); 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) { + 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); 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++) { struct Object* o = objects[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); packet_write(&p, &parentId, sizeof(u8)); 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)); } - network_send(&p); + if (sendToLocalIndex == PACKET_DESTINATION_BROADCAST) { + network_send(&p); + } else { + network_send_to(sendToLocalIndex, &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); struct Object* o = spawn_object(parentObj, data.model, behavior); + o->createdThroughNetwork = true; memcpy(o->rawData.asU32, data.rawData, sizeof(u32) * 80); 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 if (data.parentId == (u8)-1) { o->parentObj = o; } - // they've allocated one of their reserved sync objects - if (o->oSyncID != 0 && gSyncObjects[o->oSyncID].reserved == reserveId) { - gSyncObjects[o->oSyncID].o = o; - gSyncObjects[o->oSyncID].reserved = 0; - receivedReservedSyncObject = true; + if (o->oSyncID != 0) { + // 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].reserved = 0; + } } spawned[i] = o;