mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-11-25 21:45:12 +00:00
Synchronized respawners and entities created after level load
This commit is contained in:
parent
5db1a9e827
commit
33fbed94e4
8 changed files with 125 additions and 36 deletions
|
@ -220,6 +220,7 @@ struct Object
|
|||
/*0x218*/ void *collisionData;
|
||||
/*0x21C*/ Mat4 transform;
|
||||
/*0x25C*/ void *respawnInfo;
|
||||
/*?????*/ u8 createdThroughNetwork;
|
||||
};
|
||||
|
||||
struct ObjectHitbox
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -354,6 +354,8 @@ struct Object *create_object(const BehaviorScript *bhvScript) {
|
|||
break;
|
||||
}
|
||||
|
||||
obj->createdThroughNetwork = false;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue