Complete rewrite of entity ID reservation system

Now "syncId"s can only be reserved at ID 127+. This ensures that static level
objects and spawned reserved objects never clash. The server keeps track of
every player's list of reserved IDs, as well as when an ID is used, or when
an entity using that ID is destroyed. This is much more complicated than it
used to be, but this complication is required due to players being allowed to
be in different areas of the game.
This commit is contained in:
MysterD 2021-06-13 16:04:28 -07:00
parent fde6eaf0a3
commit 7ae26b3ea0
20 changed files with 692 additions and 146 deletions

View file

@ -3859,6 +3859,7 @@
<ClCompile Include="..\src\game\interaction.c" />
<ClCompile Include="..\src\game\level_geo.c" />
<ClCompile Include="..\src\game\level_update.c" />
<ClCompile Include="..\src\game\macro_presets.c" />
<ClCompile Include="..\src\game\macro_special_objects.c" />
<ClCompile Include="..\src\game\main.c" />
<ClCompile Include="..\src\game\mario.c" />
@ -3962,31 +3963,41 @@
<ClCompile Include="..\src\pc\network\network.c" />
<ClCompile Include="..\src\pc\network\network_player.c" />
<ClCompile Include="..\src\pc\network\packets\packet.c" />
<ClCompile Include="..\src\pc\network\packets\packet_area.c" />
<ClCompile Include="..\src\pc\network\packets\packet_area_request.c" />
<ClCompile Include="..\src\pc\network\packets\packet_change_area.c" />
<ClCompile Include="..\src\pc\network\packets\packet_level.c" />
<ClCompile Include="..\src\pc\network\packets\packet_level_area_inform.c" />
<ClCompile Include="..\src\pc\network\packets\packet_level_request.c" />
<ClCompile Include="..\src\pc\network\packets\packet_change_level.c" />
<ClCompile Include="..\src\pc\network\packets\packet_chat.c" />
<ClCompile Include="..\src\pc\network\packets\packet_collect_coin.c" />
<ClCompile Include="..\src\pc\network\packets\packet_collect_item.c" />
<ClCompile Include="..\src\pc\network\packets\packet_collect_star.c" />
<ClCompile Include="..\src\pc\network\packets\packet_custom.c" />
<ClCompile Include="..\src\pc\network\packets\packet_death.c" />
<ClCompile Include="..\src\pc\network\packets\packet_location_request.c" />
<ClCompile Include="..\src\pc\network\packets\packet_level_area_request.c" />
<ClCompile Include="..\src\pc\network\packets\packet_kick.c" />
<ClCompile Include="..\src\pc\network\packets\packet_join.c" />
<ClCompile Include="..\src\pc\network\packets\packet_keep_alive.c" />
<ClCompile Include="..\src\pc\network\packets\packet_leaving.c" />
<ClCompile Include="..\src\pc\network\packets\packet_level_area.c" />
<ClCompile Include="..\src\pc\network\packets\packet_location_request_client.c" />
<ClCompile Include="..\src\pc\network\packets\packet_location_response.c" />
<ClCompile Include="..\src\pc\network\packets\packet_macro_deletions.c" />
<ClCompile Include="..\src\pc\network\packets\packet_level_macro.c" />
<ClCompile Include="..\src\pc\network\packets\packet_level_respawn_info.c" />
<ClCompile Include="..\src\pc\network\packets\packet_network_players.c" />
<ClCompile Include="..\src\pc\network\packets\packet_object.c" />
<ClCompile Include="..\src\pc\network\packets\packet_ordered.c" />
<ClCompile Include="..\src\pc\network\packets\packet_player.c" />
<ClCompile Include="..\src\pc\network\packets\packet_read_write.c" />
<ClCompile Include="..\src\pc\network\packets\packet_reliable.c" />
<ClCompile Include="..\src\pc\network\packets\packet_reservation.c" />
<ClCompile Include="..\src\pc\network\packets\packet_reservation_list.c" />
<ClCompile Include="..\src\pc\network\packets\packet_reservation_release.c" />
<ClCompile Include="..\src\pc\network\packets\packet_reservation_use.c" />
<ClCompile Include="..\src\pc\network\packets\packet_save_file.c" />
<ClCompile Include="..\src\pc\network\packets\packet_spawn_info_deletions.c" />
<ClCompile Include="..\src\pc\network\packets\packet_level_spawn_info.c" />
<ClCompile Include="..\src\pc\network\packets\packet_spawn_objects.c" />
<ClCompile Include="..\src\pc\network\packets\packet_spawn_star.c" />
<ClCompile Include="..\src\pc\network\packets\packet_sync_valid.c" />
<ClCompile Include="..\src\pc\network\reservation_area.c" />
<ClCompile Include="..\src\pc\network\socket\socket.c" />
<ClCompile Include="..\src\pc\network\socket\socket_linux.c" />
<ClCompile Include="..\src\pc\network\socket\socket_windows.c" />
@ -4348,6 +4359,7 @@
<ClInclude Include="..\src\pc\network\discord\user.h" />
<ClInclude Include="..\src\pc\network\network.h" />
<ClInclude Include="..\src\pc\network\network_player.h" />
<ClInclude Include="..\src\pc\network\reservation_area.h" />
<ClInclude Include="..\src\pc\network\socket\socket.h" />
<ClInclude Include="..\src\pc\network\socket\socket_linux.h" />
<ClInclude Include="..\src\pc\network\socket\socket_windows.h" />

View file

@ -3436,6 +3436,15 @@
<Filter Include="Source Files\src\pc\utils">
<UniqueIdentifier>{451cd85d-8a2c-4aa5-87c7-d1415974ba96}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\src\pc\network\packets\location">
<UniqueIdentifier>{8503d4ed-8d6c-4888-a861-c50644924389}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\src\pc\network\packets\fundamental">
<UniqueIdentifier>{2ffc6d25-bc31-400f-b587-58a915c565e1}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\src\pc\network\packets\reservation-area">
<UniqueIdentifier>{9ddfaa87-399e-4f61-aae3-f91af79e14cc}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\actors\amp\anims\anim_0800401C.inc.c">
@ -14964,12 +14973,6 @@
<ClCompile Include="..\src\pc\network\packets\packet_player.c">
<Filter>Source Files\src\pc\network\packets</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_read_write.c">
<Filter>Source Files\src\pc\network\packets</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_reliable.c">
<Filter>Source Files\src\pc\network\packets</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_collect_star.c">
<Filter>Source Files\src\pc\network\packets</Filter>
</ClCompile>
@ -15006,9 +15009,6 @@
<ClCompile Include="..\actors\luigi\model.inc.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_reservation.c">
<Filter>Source Files\src\pc\network\packets</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_custom.c">
<Filter>Source Files\src\pc\network\packets</Filter>
</ClCompile>
@ -15051,9 +15051,6 @@
<ClCompile Include="..\src\pc\network\packets\packet_join.c">
<Filter>Source Files\src\pc\network\packets</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet.c">
<Filter>Source Files\src\pc\network\packets</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_keep_alive.c">
<Filter>Source Files\src\pc\network\packets</Filter>
</ClCompile>
@ -15081,6 +15078,69 @@
<ClCompile Include="..\src\pc\network\packets\packet_death.c">
<Filter>Source Files\src\pc\network\packets</Filter>
</ClCompile>
<ClCompile Include="..\src\game\macro_presets.c">
<Filter>Source Files\src\game</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_level.c">
<Filter>Source Files\src\pc\network\packets\location</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_level_request.c">
<Filter>Source Files\src\pc\network\packets\location</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_sync_valid.c">
<Filter>Source Files\src\pc\network\packets\location</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_change_level.c">
<Filter>Source Files\src\pc\network\packets\location</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_level_area_request.c">
<Filter>Source Files\src\pc\network\packets\location</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_area.c">
<Filter>Source Files\src\pc\network\packets\location</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_level_area_inform.c">
<Filter>Source Files\src\pc\network\packets\location</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_change_area.c">
<Filter>Source Files\src\pc\network\packets\location</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_area_request.c">
<Filter>Source Files\src\pc\network\packets\location</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_level_macro.c">
<Filter>Source Files\src\pc\network\packets\location</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_level_spawn_info.c">
<Filter>Source Files\src\pc\network\packets\location</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_level_respawn_info.c">
<Filter>Source Files\src\pc\network\packets\location</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet.c">
<Filter>Source Files\src\pc\network\packets\fundamental</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_ordered.c">
<Filter>Source Files\src\pc\network\packets\fundamental</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_reliable.c">
<Filter>Source Files\src\pc\network\packets\fundamental</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_read_write.c">
<Filter>Source Files\src\pc\network\packets\fundamental</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_reservation_use.c">
<Filter>Source Files\src\pc\network\packets\reservation-area</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_reservation_release.c">
<Filter>Source Files\src\pc\network\packets\reservation-area</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_reservation_list.c">
<Filter>Source Files\src\pc\network\packets\reservation-area</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\reservation_area.c">
<Filter>Source Files\src\pc\network</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\actors\common0.h">
@ -16051,5 +16111,8 @@
<ClInclude Include="..\include\luigi_audio_defines.h">
<Filter>Header Files\include</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\network\reservation_area.h">
<Filter>Header Files\src\pc\network</Filter>
</ClInclude>
</ItemGroup>
</Project>

View file

@ -5,6 +5,12 @@
#include "game/mario.h"
#include "sm64.h"
#include "object_fields.h"
#include "object_constants.h"
#include "src/game/object_helpers.h"
#include "behavior_data.h"
#include "behavior_table.h"
#ifdef DEBUG
static u8 warpToLevel = LEVEL_CCM;
@ -107,6 +113,15 @@ static void debug_suicide(void) {
gMarioStates[0].hurtCounter = 31;
}
static void debug_spawn_object(void) {
struct Object* box = spawn_object(gMarioStates[0].marioObj, MODEL_BREAKABLE_BOX_SMALL, bhvBreakableBoxSmall);
network_set_sync_id(box);
struct Object* spawn_objects[] = { box };
u32 models[] = { MODEL_BREAKABLE_BOX_SMALL };
network_send_spawn_objects(spawn_objects, models, 1);
}
void debug_keyboard_on_key_down(int scancode) {
scancode = scancode;
switch (scancode & 0xFF) {
@ -114,6 +129,7 @@ void debug_keyboard_on_key_down(int scancode) {
#ifdef DEVELOPMENT
case SCANCODE_6: debug_warp_level(warpToLevel); break;
case SCANCODE_7: debug_warp_area(); break;
case SCANCODE_8: debug_spawn_object(); break;
case SCANCODE_9: debug_warp_to(); break;
case SCANCODE_0: debug_suicide(); break;
#endif

View file

@ -112,11 +112,6 @@ void network_on_loaded_level(void) {
network_send_change_level();
}
}
// request my chunk of reserved sync ids
if (gNetworkType == NT_CLIENT) {
network_send_reservation_request();
}
}
void network_send_to(u8 localIndex, struct Packet* p) {

View file

@ -43,7 +43,6 @@ struct NetworkSystem {
struct SyncObject {
struct Object* o;
u16 reserved;
float maxSyncDistance;
bool owned;
bool staticLevelSpawn;

View file

@ -2,6 +2,7 @@
#include "network_player.h"
#include "game/chat.h"
#include "game/mario_misc.h"
#include "reservation_area.h"
#include "pc/debuglog.h"
struct NetworkPlayer gNetworkPlayers[MAX_PLAYERS] = { 0 };
@ -190,6 +191,7 @@ u8 network_player_disconnected(u8 globalIndex) {
LOG_INFO("player disconnected, local %d, global %d", i, globalIndex);
chat_add_message_ext("player disconnected", CMT_SYSTEM, get_player_color(globalIndex, 0));
packet_ordered_clear(globalIndex);
reservation_area_change(np);
return i;
}
return UNKNOWN_GLOBAL_INDEX;

View file

@ -13,8 +13,8 @@ void packet_process(struct Packet* p) {
case PACKET_COLLECT_STAR: network_receive_collect_star(p); break;
case PACKET_COLLECT_COIN: network_receive_collect_coin(p); break;
case PACKET_COLLECT_ITEM: network_receive_collect_item(p); break;
case PACKET_RESERVATION_REQUEST: network_receive_reservation_request(p); break;
case PACKET_RESERVATION: network_receive_reservation(p); break;
case PACKET_UNUSED1: break;
case PACKET_UNUSED2: break;
case PACKET_JOIN_REQUEST: network_receive_join_request(p); break;
case PACKET_JOIN: network_receive_join(p); break;
case PACKET_CHAT: network_receive_chat(p); break;
@ -25,7 +25,12 @@ void packet_process(struct Packet* p) {
case PACKET_NETWORK_PLAYERS: network_receive_network_players(p); break;
case PACKET_DEATH: network_receive_death(p); break;
// location
// reservation area
case PACKET_RESERVATION_LIST: network_receive_reservation_list(p); break;
case PACKET_RESERVATION_USE: network_receive_reservation_use(p); break;
case PACKET_RESERVATION_RELEASE: network_receive_reservation_release(p); break;
// location
case PACKET_CHANGE_LEVEL: network_receive_change_level(p); break;
case PACKET_CHANGE_AREA: network_receive_change_area(p); break;
case PACKET_LEVEL_AREA_REQUEST: network_receive_level_area_request(p); break;
@ -39,7 +44,7 @@ void packet_process(struct Packet* p) {
case PACKET_LEVEL_AREA_INFORM: network_receive_level_area_inform(p); break;
case PACKET_LEVEL_RESPAWN_INFO: network_receive_level_respawn_info(p); break;
// custom
// custom
case PACKET_CUSTOM: network_receive_custom(p); break;
default: LOG_ERROR("received unknown packet: %d", p->buffer[0]);
}

View file

@ -22,8 +22,8 @@ enum PacketType {
PACKET_COLLECT_STAR,
PACKET_COLLECT_COIN,
PACKET_COLLECT_ITEM,
PACKET_RESERVATION_REQUEST,
PACKET_RESERVATION,
PACKET_UNUSED1,
PACKET_UNUSED2,
PACKET_JOIN_REQUEST,
PACKET_JOIN,
PACKET_CHAT,
@ -34,6 +34,10 @@ enum PacketType {
PACKET_NETWORK_PLAYERS,
PACKET_DEATH,
PACKET_RESERVATION_LIST,
PACKET_RESERVATION_USE,
PACKET_RESERVATION_RELEASE,
PACKET_CHANGE_LEVEL,
PACKET_CHANGE_AREA,
PACKET_LEVEL_AREA_REQUEST,
@ -148,12 +152,6 @@ void network_receive_collect_coin(struct Packet* p);
void network_send_collect_item(struct Object* o);
void network_receive_collect_item(struct Packet* p);
// packet_reservation.c
void network_send_reservation_request(void);
void network_receive_reservation_request(struct Packet* p);
void network_send_reservation(u8 toLocalIndex);
void network_receive_reservation(struct Packet* p);
// packet_join.c
void network_send_join_request(void);
void network_receive_join_request(struct Packet* p);
@ -241,4 +239,16 @@ void network_receive_level_area_inform(struct Packet* p);
void network_send_level_respawn_info(struct Object* o, u8 respawnInfoBits);
void network_receive_level_respawn_info(struct Packet* p);
// packet_reservation_list.c
void network_send_reservation_list(struct NetworkPlayer* np, u8 syncIds[]);
void network_receive_reservation_list(struct Packet* p);
// packet_reservation_use.c
void network_send_reservation_use(u8 syncId);
void network_receive_reservation_use(struct Packet* p);
// packet_reservation_release.c
void network_send_reservation_release(u8 syncId);
void network_receive_reservation_release(struct Packet* p);
#endif

View file

@ -1,5 +1,6 @@
#include <stdio.h>
#include "../network.h"
#include "../reservation_area.h"
#include "level_table.h"
//#define DISABLE_MODULE_LOG 1
#include "pc/debuglog.h"
@ -12,6 +13,7 @@ static void player_changed_area(struct NetworkPlayer* np, s16 courseNum, s16 act
np->currAreaIndex = areaIndex;
np->currAreaSyncValid = false;
network_send_level_area_inform(np);
reservation_area_change(np);
// find a NetworkPlayer at that area
struct NetworkPlayer* npLevelAreaMatch = get_network_player_from_area(courseNum, actNum, levelNum, areaIndex);

View file

@ -1,5 +1,6 @@
#include <stdio.h>
#include "../network.h"
#include "../reservation_area.h"
#include "level_table.h"
//#define DISABLE_MODULE_LOG 1
#include "pc/debuglog.h"
@ -13,6 +14,7 @@ static void player_changed_level(struct NetworkPlayer* np, s16 courseNum, s16 ac
np->currLevelSyncValid = false;
np->currAreaSyncValid = false;
network_send_level_area_inform(np);
reservation_area_change(np);
// find a NetworkPlayer around that location
struct NetworkPlayer* npLevelAreaMatch = get_network_player_from_area(courseNum, actNum, levelNum, areaIndex);

View file

@ -1,5 +1,6 @@
#include <stdio.h>
#include "../network.h"
#include "../reservation_area.h"
#include "game/chat.h"
#include "pc/debuglog.h"
@ -39,6 +40,7 @@ void network_send_chat(char* message, u8 rgb[3]) {
#ifdef DEVELOPMENT
print_network_player_table();
reservation_area_debug();
#endif
}
@ -55,8 +57,9 @@ void network_receive_chat(struct Packet* p) {
// add the message
chat_add_message_ext(remoteMessage, CMT_REMOTE, rgb);
LOG_INFO("rx chat: %s", remoteMessage);
/*
#ifdef DEVELOPMENT
print_network_player_table();
#endif
*/
}

View file

@ -1,6 +1,7 @@
#include <stdio.h>
#include <limits.h>
#include "../network.h"
#include "../reservation_area.h"
#include "object_fields.h"
#include "object_constants.h"
#include "behavior_data.h"
@ -10,7 +11,6 @@
#include "src/game/obj_behaviors.h"
#include "pc/debuglog.h"
static u8 nextSyncID = 1;
struct SyncObject gSyncObjects[MAX_SYNC_OBJECTS] = { 0 };
struct Packet sLastSyncEntReliablePacket[MAX_SYNC_OBJECTS] = { 0 };
@ -77,7 +77,6 @@ struct SyncObject* network_init_object(struct Object *o, float maxSyncDistance)
// set default values for sync object
struct SyncObject* so = &gSyncObjects[o->oSyncID];
so->o = o;
so->reserved = 0;
so->maxSyncDistance = maxSyncDistance;
so->owned = false;
so->clockSinceUpdate = clock();
@ -143,22 +142,28 @@ void network_clear_sync_objects(void) {
for (u16 i = 0; i < MAX_SYNC_OBJECTS; i++) {
network_forget_sync_object(&gSyncObjects[i]);
}
nextSyncID = 1;
}
void network_set_sync_id(struct Object* o) {
if (o->oSyncID != 0) { return; }
u8 reserveId = gNetworkLevelLoaded ? gNetworkPlayerLocal->globalIndex : 0;
for (u16 i = 0; i < MAX_SYNC_OBJECTS; i++) {
if (gSyncObjects[nextSyncID].reserved == reserveId && gSyncObjects[nextSyncID].o == NULL) { break; }
nextSyncID = (nextSyncID + 1) % MAX_SYNC_OBJECTS;
u8 syncId = 0;
if (!gNetworkLevelLoaded) {
// while loading, just fill in sync ids from 1 to MAX_SYNC_OBJECTS
for (int i = 1; i < MAX_SYNC_OBJECTS; i++) {
if (gSyncObjects[i].o != NULL) { continue; }
syncId = i;
break;
}
} else {
// no longer loading, require reserved id
syncId = reservation_area_local_grab_id();
}
assert(gSyncObjects[nextSyncID].o == NULL);
assert(gSyncObjects[nextSyncID].reserved == reserveId);
o->oSyncID = nextSyncID;
nextSyncID = (nextSyncID + 1) % MAX_SYNC_OBJECTS;
assert(syncId != 0);
assert(gSyncObjects[syncId].o == NULL);
o->oSyncID = syncId;
if (gNetworkLevelLoaded) {
LOG_INFO("set sync id for object w/behavior %d", get_id_from_behavior(o->behavior));
@ -398,14 +403,15 @@ void network_send_object(struct Object* o) {
void network_send_object_reliability(struct Object* o, bool reliable) {
// sanity check SyncObject
if (!network_sync_object_initialized(o)) { return; }
struct SyncObject* so = &gSyncObjects[o->oSyncID];
u8 syncId = o->oSyncID;
struct SyncObject* so = &gSyncObjects[syncId];
if (so == NULL) { return; }
if (o != so->o) {
LOG_ERROR("object mismatch for %d", o->oSyncID);
LOG_ERROR("object mismatch for %d", syncId);
return;
}
if (o->behavior != so->behavior && !allowable_behavior_change(so, so->behavior)) {
LOG_ERROR("behavior mismatch for %d: %04X vs %04X", o->oSyncID, get_id_from_behavior(o->behavior), get_id_from_behavior(so->behavior));
LOG_ERROR("behavior mismatch for %d: %04X vs %04X", syncId, get_id_from_behavior(o->behavior), get_id_from_behavior(so->behavior));
network_forget_sync_object(so);
return;
}
@ -426,9 +432,14 @@ void network_send_object_reliability(struct Object* o, bool reliable) {
// check for object death
if (o->activeFlags == ACTIVE_FLAG_DEACTIVATED) {
network_forget_sync_object(so);
if (gNetworkType == NT_SERVER) {
reservation_area_release(gNetworkPlayerLocal, syncId);
} else {
network_send_reservation_release(syncId);
}
} else {
// remember packet
packet_duplicate(&p, &sLastSyncEntReliablePacket[o->oSyncID]);
packet_duplicate(&p, &sLastSyncEntReliablePacket[syncId]);
}
// send the packet out
@ -511,12 +522,11 @@ void network_forget_sync_object(struct SyncObject* so) {
so->o = NULL;
so->behavior = NULL;
so->reserved = 0;
so->owned = false;
}
void network_update_objects(void) {
for (u32 i = 1; i < nextSyncID; i++) {
for (u32 i = 1; i < MAX_SYNC_OBJECTS; i++) {
struct SyncObject* so = &gSyncObjects[i];
if (so->o == NULL) { continue; }

View file

@ -1,73 +0,0 @@
#include <stdio.h>
#include "../network.h"
#include "object_fields.h"
#include "object_constants.h"
#include "behavior_table.h"
#include "course_table.h"
#include "src/game/interaction.h"
#include "src/engine/math_util.h"
#define DISABLE_MODULE_LOG 1
#include "pc/debuglog.h"
#define RESERVATION_COUNT 5
void network_send_reservation_request(void) {
assert(gNetworkType == NT_CLIENT);
struct Packet p;
packet_init(&p, PACKET_RESERVATION_REQUEST, true, false);
network_send_to(gNetworkPlayerServer->localIndex , &p);
}
void network_receive_reservation_request(struct Packet* p) {
assert(gNetworkType == NT_SERVER);
network_send_reservation(p->localIndex);
}
void network_send_reservation(u8 toLocalIndex) {
assert(gNetworkType == NT_SERVER);
assert(toLocalIndex != 0);
// find all reserved objects
u8 reservedObjs[RESERVATION_COUNT] = { 0 };
u16 reservedIndex = 0;
for (u16 i = 1; i < MAX_SYNC_OBJECTS; i++) {
if (gSyncObjects[i].reserved == toLocalIndex) {
reservedObjs[reservedIndex++] = i;
if (reservedIndex >= RESERVATION_COUNT) { break; }
}
}
if (reservedIndex < RESERVATION_COUNT) {
// reserve the rest
for (u16 i = MAX_SYNC_OBJECTS - 1; i > 0; i--) {
if (gSyncObjects[i].o != NULL) { continue; }
if (gSyncObjects[i].reserved != 0) { continue; }
gSyncObjects[i].reserved = toLocalIndex;
reservedObjs[reservedIndex++] = i;
if (reservedIndex >= RESERVATION_COUNT) { break; }
}
}
struct Packet p;
packet_init(&p, PACKET_RESERVATION, true, false);
packet_write(&p, reservedObjs, sizeof(u8) * RESERVATION_COUNT);
network_send_to(toLocalIndex, &p);
LOG_INFO("sent reservation list to %d", toLocalIndex);
}
void network_receive_reservation(struct Packet* p) {
assert(gNetworkType == NT_CLIENT);
// find all reserved objects
u8 reservedObjs[RESERVATION_COUNT] = { 0 };
packet_read(p, reservedObjs, sizeof(u8) * RESERVATION_COUNT);
for (u16 i = 0; i < RESERVATION_COUNT; i++) {
u16 index = reservedObjs[i];
if (index == 0) { continue; }
if (gSyncObjects[index].o != NULL) { continue; }
gSyncObjects[index].reserved = gNetworkPlayerLocal->globalIndex;
}
LOG_INFO("received reservation list");
}

View file

@ -0,0 +1,52 @@
#include <stdio.h>
#include "../network.h"
#include "../reservation_area.h"
#include "object_fields.h"
#include "object_constants.h"
#include "behavior_table.h"
#include "course_table.h"
#include "src/game/interaction.h"
#include "src/engine/math_util.h"
#define DISABLE_MODULE_LOG 1
#include "pc/debuglog.h"
void network_send_reservation_list(struct NetworkPlayer* np, u8 syncIds[]) {
assert(gNetworkType == NT_SERVER);
struct Packet p;
packet_init(&p, PACKET_RESERVATION_LIST, true, false);
packet_write(&p, &np->currCourseNum, sizeof(u8));
packet_write(&p, &np->currActNum, sizeof(u8));
packet_write(&p, &np->currLevelNum, sizeof(u8));
packet_write(&p, &np->currAreaIndex, sizeof(u8));
for (int i = 0; i < RESERVED_IDS_PER_PLAYER_COUNT; i++) {
packet_write(&p, &syncIds[i], sizeof(u8));
}
network_send_to(np->localIndex, &p);
}
void network_receive_reservation_list(struct Packet* p) {
assert(gNetworkType == NT_CLIENT);
u8 courseNum, actNum, levelNum, areaIndex;
packet_read(p, &courseNum, sizeof(u8));
packet_read(p, &actNum, sizeof(u8));
packet_read(p, &levelNum, sizeof(u8));
packet_read(p, &areaIndex, sizeof(u8));
extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex;
if (courseNum != gCurrCourseNum || actNum != gCurrActNum || levelNum != gCurrLevelNum || areaIndex != gCurrAreaIndex) {
LOG_ERROR("received an improper location");
return;
}
u8 syncIds[RESERVED_IDS_PER_PLAYER_COUNT];
for (int i = 0; i < RESERVED_IDS_PER_PLAYER_COUNT; i++) {
packet_read(p, &syncIds[i], sizeof(u8));
}
reservation_area_local_update(courseNum, actNum, levelNum, areaIndex, syncIds);
}

View file

@ -0,0 +1,58 @@
#include <stdio.h>
#include "../network.h"
#include "../reservation_area.h"
#include "object_fields.h"
#include "object_constants.h"
#include "behavior_table.h"
#include "course_table.h"
#include "src/game/interaction.h"
#include "src/engine/math_util.h"
#define DISABLE_MODULE_LOG 1
#include "pc/debuglog.h"
void network_send_reservation_release(u8 syncId) {
assert(gNetworkType == NT_CLIENT);
// make sure this is a reserved id
if (syncId < RESERVED_IDS_SYNC_OBJECT_OFFSET) { return; }
struct Packet p;
packet_init(&p, PACKET_RESERVATION_RELEASE, true, false);
extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex;
packet_write(&p, &gCurrCourseNum, sizeof(u8));
packet_write(&p, &gCurrActNum, sizeof(u8));
packet_write(&p, &gCurrLevelNum, sizeof(u8));
packet_write(&p, &gCurrAreaIndex, sizeof(u8));
packet_write(&p, &syncId, sizeof(u8));
network_send_to(gNetworkPlayerServer->localIndex, &p);
}
void network_receive_reservation_release(struct Packet* p) {
assert(gNetworkType == NT_SERVER);
struct NetworkPlayer* np = &gNetworkPlayers[p->localIndex];
if (np == NULL || np->localIndex == UNKNOWN_LOCAL_INDEX || !np->connected) {
LOG_ERROR("Receiving from inactive player!");
return;
}
u8 courseNum, actNum, levelNum, areaIndex;
packet_read(p, &courseNum, sizeof(u8));
packet_read(p, &actNum, sizeof(u8));
packet_read(p, &levelNum, sizeof(u8));
packet_read(p, &areaIndex, sizeof(u8));
extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex;
if (courseNum != gCurrCourseNum || actNum != gCurrActNum || levelNum != gCurrLevelNum || areaIndex != gCurrAreaIndex) {
LOG_ERROR("received an improper location");
return;
}
u8 syncId;
packet_read(p, &syncId, sizeof(u8));
reservation_area_release(np, syncId);
}

View file

@ -0,0 +1,58 @@
#include <stdio.h>
#include "../network.h"
#include "../reservation_area.h"
#include "object_fields.h"
#include "object_constants.h"
#include "behavior_table.h"
#include "course_table.h"
#include "src/game/interaction.h"
#include "src/engine/math_util.h"
#define DISABLE_MODULE_LOG 1
#include "pc/debuglog.h"
void network_send_reservation_use(u8 syncId) {
assert(gNetworkType == NT_CLIENT);
// make sure this is a reserved id
if (syncId < RESERVED_IDS_SYNC_OBJECT_OFFSET) { return; }
struct Packet p;
packet_init(&p, PACKET_RESERVATION_USE, true, false);
extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex;
packet_write(&p, &gCurrCourseNum, sizeof(u8));
packet_write(&p, &gCurrActNum, sizeof(u8));
packet_write(&p, &gCurrLevelNum, sizeof(u8));
packet_write(&p, &gCurrAreaIndex, sizeof(u8));
packet_write(&p, &syncId, sizeof(u8));
network_send_to(gNetworkPlayerServer->localIndex, &p);
}
void network_receive_reservation_use(struct Packet* p) {
assert(gNetworkType == NT_SERVER);
struct NetworkPlayer* np = &gNetworkPlayers[p->localIndex];
if (np == NULL || np->localIndex == UNKNOWN_LOCAL_INDEX || !np->connected) {
LOG_ERROR("Receiving from inactive player!");
return;
}
u8 courseNum, actNum, levelNum, areaIndex;
packet_read(p, &courseNum, sizeof(u8));
packet_read(p, &actNum, sizeof(u8));
packet_read(p, &levelNum, sizeof(u8));
packet_read(p, &areaIndex, sizeof(u8));
extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex;
if (courseNum != gCurrCourseNum || actNum != gCurrActNum || levelNum != gCurrLevelNum || areaIndex != gCurrAreaIndex) {
LOG_ERROR("received an improper location");
return;
}
u8 syncId;
packet_read(p, &syncId, sizeof(u8));
reservation_area_use(np, syncId);
}

View file

@ -1,5 +1,6 @@
#include <stdio.h>
#include "../network.h"
#include "../reservation_area.h"
#include "object_fields.h"
#include "object_constants.h"
#include "src/game/object_helpers.h"
@ -48,7 +49,16 @@ void network_send_spawn_objects_to(u8 sendToLocalIndex, struct Object* objects[]
assert(objectCount < MAX_SPAWN_OBJECTS_PER_PACKET);
struct Packet p;
packet_init(&p, PACKET_SPAWN_OBJECTS, true, true);
packet_init(&p, PACKET_SPAWN_OBJECTS, true, false);
// level location
extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex;
packet_write(&p, &gCurrCourseNum, sizeof(s16));
packet_write(&p, &gCurrActNum, sizeof(s16));
packet_write(&p, &gCurrLevelNum, sizeof(s16));
packet_write(&p, &gCurrAreaIndex, sizeof(s16));
// objects
packet_write(&p, &objectCount, sizeof(u8));
for (u8 i = 0; i < objectCount; i++) {
@ -74,13 +84,22 @@ void network_send_spawn_objects_to(u8 sendToLocalIndex, struct Object* objects[]
}
void network_receive_spawn_objects(struct Packet* p) {
// read level location
s16 courseNum, actNum, levelNum, areaIndex;
packet_read(p, &courseNum, sizeof(s16));
packet_read(p, &actNum, sizeof(s16));
packet_read(p, &levelNum, sizeof(s16));
packet_read(p, &areaIndex, sizeof(s16));
extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex;
if (courseNum != gCurrCourseNum || actNum != gCurrActNum || levelNum != gCurrLevelNum || areaIndex != gCurrAreaIndex) {
LOG_ERROR("received an improper location");
return;
}
u8 objectCount = 0;
packet_read(p, &objectCount, sizeof(u8));
u8 reserveId = gNetworkLevelLoaded ? gNetworkPlayers[p->localIndex].globalIndex : 0;
bool receivedReservedSyncObject = false;
struct Object* spawned[MAX_SPAWN_OBJECTS_PER_PACKET] = { 0 };
for (u8 i = 0; i < objectCount; i++) {
struct SpawnObjectData data = { 0 };
@ -129,20 +148,11 @@ void network_receive_spawn_objects(struct Packet* p) {
// correct the temporary parent with the object itself
if (data.parentId == (u8)-1) { o->parentObj = o; }
if (o->oSyncID != 0) {
if (o->oSyncID != 0 && o->oSyncID >= RESERVED_IDS_SYNC_OBJECT_OFFSET) {
// 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;
}
gSyncObjects[o->oSyncID].o = o;
}
spawned[i] = o;
}
// update their block of reserved ids
if (gNetworkType == NT_SERVER && receivedReservedSyncObject) {
network_send_reservation(p->localIndex);
}
}

View file

@ -0,0 +1,300 @@
#include <stdio.h>
#include "reservation_area.h"
#include "network.h"
#include "object_fields.h"
#include "object_constants.h"
#include "behavior_table.h"
#include "course_table.h"
#include "src/game/interaction.h"
#include "src/engine/math_util.h"
//#define DISABLE_MODULE_LOG 1
#include "pc/debuglog.h"
#define RESERVED_IDS_PER_AREA 127
#define RESERVED_IDS_UNRESERVED ((u8)-1)
#define RESERVED_IDS_USED ((u8)-2)
struct ReservationArea {
u8 courseNum;
u8 actNum;
u8 levelNum;
u8 areaIndex;
u8 playersActive;
u8 reservedIds[RESERVED_IDS_PER_AREA];
struct ReservationArea* next;
};
struct ReservationArea* sReservationAreas = NULL;
struct ReservationArea* sReservationAreaPerPlayer[MAX_PLAYERS] = { NULL };
struct LocalReservationArea {
u8 courseNum;
u8 actNum;
u8 levelNum;
u8 areaIndex;
u8 reservedIds[RESERVED_IDS_PER_PLAYER_COUNT];
};
struct LocalReservationArea sLocalReservationArea = { 0 };
void reservation_area_debug(void) {
printf("\n============ %02d ============\n", gNetworkPlayerLocal->globalIndex);
printf("reservation area per player:\n");
for (int i = 0; i < MAX_PLAYERS; i++) {
struct ReservationArea* ra = sReservationAreaPerPlayer[i];
if (ra != NULL) {
printf(" %d : (%d, %d, %d, %d)\n", i, ra->courseNum, ra->actNum, ra->levelNum, ra->areaIndex);
}
}
printf("\n");
printf("reservation areas:\n");
struct ReservationArea* ra = sReservationAreas;
while (ra != NULL) {
printf(" (%d, %d, %d, %d) : %d\n", ra->courseNum, ra->actNum, ra->levelNum, ra->areaIndex, ra->playersActive);
printf(" ");
u8 idsUntilBreak = 10;
for (int i = 0; i < RESERVED_IDS_PER_AREA; i++) {
switch (ra->reservedIds[i])
{
case RESERVED_IDS_UNRESERVED: printf("UNR "); break;
case RESERVED_IDS_USED: printf("USD "); break;
default: printf("%03d ", ra->reservedIds[i]); break;
}
if (--idsUntilBreak == 0) {
printf("\n ");
idsUntilBreak = 10;
}
}
printf("\n\n");
ra = ra->next;
}
printf("local reservation area:\n");
struct LocalReservationArea* la = &sLocalReservationArea;
printf(" (%d, %d, %d, %d) : ", la->courseNum, la->actNum, la->levelNum, la->areaIndex);
for (int i = 0; i < RESERVED_IDS_PER_PLAYER_COUNT; i++) {
switch (la->reservedIds[i])
{
case RESERVED_IDS_UNRESERVED: printf("UNR "); break;
case RESERVED_IDS_USED: printf("USD "); break;
default: printf("%03d ", la->reservedIds[i]); break;
}
}
printf("\n\n");
}
static void reservation_area_refresh_ids(struct NetworkPlayer* np) {
bool informPlayer = false;
// make sure player has a RA
struct ReservationArea* ra = sReservationAreaPerPlayer[np->globalIndex];
if (ra == NULL) { return; }
// count current reserved ids
u8 reservedIds[RESERVED_IDS_PER_PLAYER_COUNT] = { RESERVED_IDS_UNRESERVED };
u8 reservedIdCount = 0;
for (int i = 0; i < RESERVED_IDS_PER_AREA; i++) {
if (ra->reservedIds[i] != np->globalIndex) { continue; }
reservedIds[reservedIdCount] = i + RESERVED_IDS_SYNC_OBJECT_OFFSET;
reservedIdCount++;
}
// fill in missing reserved ids
if (reservedIdCount < RESERVED_IDS_PER_PLAYER_COUNT) {
for (int i = 0; i < RESERVED_IDS_PER_AREA; i++) {
if (ra->reservedIds[i] != RESERVED_IDS_UNRESERVED) { continue; }
ra->reservedIds[i] = np->globalIndex;
informPlayer = true;
reservedIds[reservedIdCount] = i + RESERVED_IDS_SYNC_OBJECT_OFFSET;
reservedIdCount++;
if (reservedIdCount >= RESERVED_IDS_PER_PLAYER_COUNT) { break; }
}
}
if (gNetworkType == NT_SERVER && np == gNetworkPlayerLocal) {
// refresh server's local
sLocalReservationArea.courseNum = np->currCourseNum;
sLocalReservationArea.actNum = np->currActNum;
sLocalReservationArea.levelNum = np->currLevelNum;
sLocalReservationArea.areaIndex = np->currAreaIndex;
for (int i = 0; i < RESERVED_IDS_PER_PLAYER_COUNT; i++) {
sLocalReservationArea.reservedIds[i] = reservedIds[i];
}
} else if (informPlayer) {
// inform remote player of reservation list
network_send_reservation_list(np, reservedIds);
}
}
static void reservation_area_unload(struct ReservationArea* unloadRa) {
struct ReservationArea* ra = sReservationAreas;
struct ReservationArea* lastRa = NULL;
while (ra != NULL) {
if (ra == unloadRa) {
if (lastRa == NULL) {
sReservationAreas = ra->next;
} else {
lastRa->next = ra->next;
}
free(unloadRa);
return;
}
lastRa = ra;
ra = ra->next;
}
assert(false);
}
static void reservation_area_player_left(struct NetworkPlayer* np) {
// make sure player has a RA
struct ReservationArea* ra = sReservationAreaPerPlayer[np->globalIndex];
if (ra == NULL) { return; }
// remove player's reserved ids
for (int i = 0; i < RESERVED_IDS_PER_AREA; i++) {
if (ra->reservedIds[i] == np->globalIndex) {
ra->reservedIds[i] = RESERVED_IDS_UNRESERVED;
}
}
// remove player from RA, unload if sensible
ra->playersActive--;
if (ra->playersActive == 0) {
reservation_area_unload(ra);
}
sReservationAreaPerPlayer[np->globalIndex] = NULL;
}
void reservation_area_change(struct NetworkPlayer* np) {
// check for disconnection
if (!np->connected) {
reservation_area_player_left(np);
return;
}
// make sure the location actually changed
struct ReservationArea* ra = sReservationAreaPerPlayer[np->globalIndex];
if (ra != NULL && ra->courseNum == np->currCourseNum && ra->actNum == np->currActNum && ra->levelNum == np->currLevelNum && ra->areaIndex == np->currAreaIndex) {
return;
}
// remove from the old reservation area
reservation_area_player_left(np);
// find the reservation area
ra = sReservationAreas;
struct ReservationArea* lastRa = ra;
while (ra != NULL) {
if (ra->courseNum == np->currCourseNum && ra->actNum == np->currActNum && ra->levelNum == np->currLevelNum && ra->areaIndex == np->currAreaIndex) {
// add to new reservation area
ra->playersActive++;
sReservationAreaPerPlayer[np->globalIndex] = ra;
reservation_area_refresh_ids(np);
return;
}
lastRa = ra;
ra = ra->next;
}
// allocate the reservation area
ra = malloc(sizeof(struct ReservationArea));
ra->courseNum = np->currCourseNum;
ra->actNum = np->currActNum;
ra->levelNum = np->currLevelNum;
ra->areaIndex = np->currAreaIndex;
for (int i = 0; i < RESERVED_IDS_PER_AREA; i++) {
ra->reservedIds[i] = RESERVED_IDS_UNRESERVED;
}
ra->playersActive = 1;
ra->next = NULL;
sReservationAreaPerPlayer[np->globalIndex] = ra;
// fix up linked list
if (lastRa == NULL) {
sReservationAreas = ra;
} else {
lastRa->next = ra;
}
// refresh ids
reservation_area_refresh_ids(np);
}
void reservation_area_use(struct NetworkPlayer* np, u8 syncId) {
// make sure player has a RA
struct ReservationArea* ra = sReservationAreaPerPlayer[np->globalIndex];
if (ra == NULL) { return; }
u8 offset = syncId - RESERVED_IDS_SYNC_OBJECT_OFFSET;
// sanity check
if (offset >= RESERVED_IDS_PER_AREA) { return; }
ra->reservedIds[offset] = RESERVED_IDS_USED;
reservation_area_refresh_ids(np);
}
void reservation_area_release(struct NetworkPlayer* np, u8 syncId) {
// make sure player has a RA
struct ReservationArea* ra = sReservationAreaPerPlayer[np->globalIndex];
if (ra == NULL) { return; }
u8 offset = syncId - RESERVED_IDS_SYNC_OBJECT_OFFSET;
// sanity check
if (offset >= RESERVED_IDS_PER_AREA) { return; }
ra->reservedIds[offset] = RESERVED_IDS_UNRESERVED;
reservation_area_refresh_ids(np);
}
void reservation_area_local_update(u8 courseNum, u8 actNum, u8 levelNum, u8 areaIndex, u8 syncIds[]) {
sLocalReservationArea.courseNum = courseNum;
sLocalReservationArea.actNum = actNum;
sLocalReservationArea.levelNum = levelNum;
sLocalReservationArea.areaIndex = areaIndex;
for (int i = 0; i < RESERVED_IDS_PER_PLAYER_COUNT; i++) {
sLocalReservationArea.reservedIds[i] = syncIds[i];
}
}
u8 reservation_area_local_grab_id(void) {
struct LocalReservationArea* la = &sLocalReservationArea;
extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex;
if (la->courseNum != gCurrCourseNum || la->actNum != gCurrActNum || la->levelNum != gCurrLevelNum || la->areaIndex != gCurrAreaIndex) {
// invalid location
return 0;
}
// grab a sync id from reserved list
u8 syncId = 0;
for (int i = 0; i < RESERVED_IDS_PER_PLAYER_COUNT; i++) {
if (la->reservedIds[i] == 0 || la->reservedIds[i] == RESERVED_IDS_UNRESERVED || la->reservedIds[i] == RESERVED_IDS_USED) { continue; }
// found one
syncId = la->reservedIds[i];
la->reservedIds[i] = 0;
break;
}
// sanity check
if (syncId == 0) { return 0; }
// inform the server that we used that id
if (gNetworkType == NT_SERVER) {
reservation_area_use(gNetworkPlayerLocal, syncId);
} else {
network_send_reservation_use(syncId);
}
return syncId;
}

View file

@ -0,0 +1,22 @@
#ifndef RESERVATION_AREA_H
#define RESERVATION_AREA_H
#include "PR/ultratypes.h"
#include <time.h>
#include <types.h>
#include <assert.h>
#include <stdbool.h>
#define RESERVED_IDS_PER_PLAYER_COUNT 5
#define RESERVED_IDS_SYNC_OBJECT_OFFSET 127
struct NetworkPlayer;
void reservation_area_debug(void);
void reservation_area_change(struct NetworkPlayer* np);
void reservation_area_use(struct NetworkPlayer* np, u8 syncId);
void reservation_area_release(struct NetworkPlayer* np, u8 syncId);
void reservation_area_local_update(u8 courseNum, u8 actNum, u8 levelNum, u8 areaIndex, u8 syncIds[]);
u8 reservation_area_local_grab_id(void);
#endif

View file

@ -2,7 +2,7 @@
#define VERSION_H
#define UNSTABLE_BRANCH
#define VERSION_NUMBER 3
#define VERSION_NUMBER 4
#define MAX_VERSION_LENGTH 10
char* get_version(void);