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;
/*0x21C*/ Mat4 transform;
/*0x25C*/ void *respawnInfo;
/*?????*/ u8 createdThroughNetwork;
};
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.
// 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;
}

View file

@ -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;
}

View file

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

View file

@ -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

View file

@ -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");
}

View file

@ -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;
}

View file

@ -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;