Use OE for storing client ID, remove remaining game state touch point in network thread (#5969)
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
#include <libultraship/libultraship.h>
|
#include <libultraship/libultraship.h>
|
||||||
#include "soh/OTRGlobals.h"
|
#include "soh/OTRGlobals.h"
|
||||||
#include "soh/Enhancements/nametag.h"
|
#include "soh/Enhancements/nametag.h"
|
||||||
|
#include "soh/ObjectExtension/ObjectExtension.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "variables.h"
|
#include "variables.h"
|
||||||
@@ -143,6 +144,21 @@ void Anchor::ProcessIncomingPacketQueue() {
|
|||||||
// MARK: - Misc/Helpers
|
// MARK: - Misc/Helpers
|
||||||
|
|
||||||
// Kills all existing anchor actors and respawns them with the new client data
|
// Kills all existing anchor actors and respawns them with the new client data
|
||||||
|
|
||||||
|
struct DummyPlayerClientId {
|
||||||
|
uint32_t clientId = 0;
|
||||||
|
};
|
||||||
|
static ObjectExtension::Register<DummyPlayerClientId> DummyPlayerClientIdRegister;
|
||||||
|
|
||||||
|
uint32_t Anchor::GetDummyPlayerClientId(const Actor* actor) {
|
||||||
|
const DummyPlayerClientId* clientId = ObjectExtension::GetInstance().Get<DummyPlayerClientId>(actor);
|
||||||
|
return clientId != nullptr ? clientId->clientId : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Anchor::SetDummyPlayerClientId(const Actor* actor, uint32_t clientId) {
|
||||||
|
ObjectExtension::GetInstance().Set<DummyPlayerClientId>(actor, DummyPlayerClientId{ clientId });
|
||||||
|
}
|
||||||
|
|
||||||
void Anchor::RefreshClientActors() {
|
void Anchor::RefreshClientActors() {
|
||||||
if (!IsSaveLoaded()) {
|
if (!IsSaveLoaded()) {
|
||||||
return;
|
return;
|
||||||
@@ -158,23 +174,21 @@ void Anchor::RefreshClientActors() {
|
|||||||
actor = actor->next;
|
actor = actor->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
actorIndexToClientId.clear();
|
|
||||||
refreshingActors = true;
|
|
||||||
for (auto& [clientId, client] : clients) {
|
for (auto& [clientId, client] : clients) {
|
||||||
if (!client.online || client.self) {
|
if (!client.online || client.self) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
actorIndexToClientId.push_back(clientId);
|
spawningDummyPlayerForClientId = clientId;
|
||||||
// We are using a hook `ShouldActorInit` to override the init/update/draw/destroy functions of the Player we
|
// We are using a hook `ShouldActorInit` to override the init/update/draw/destroy functions of the Player we
|
||||||
// spawn We quickly store a mapping of "index" to clientId, then within the init function we use this to get the
|
// spawn We quickly store a mapping of "index" to clientId, then within the init function we use this to get the
|
||||||
// clientId and store it on player->zTargetActiveTimer (unused s32 for the dummy) for convenience
|
// clientId and store it on player->zTargetActiveTimer (unused s32 for the dummy) for convenience
|
||||||
auto dummy = Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_PLAYER, client.posRot.pos.x,
|
auto dummy =
|
||||||
client.posRot.pos.y, client.posRot.pos.z, client.posRot.rot.x, client.posRot.rot.y,
|
Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_PLAYER, client.posRot.pos.x, client.posRot.pos.y,
|
||||||
client.posRot.rot.z, actorIndexToClientId.size() - 1, false);
|
client.posRot.pos.z, client.posRot.rot.x, client.posRot.rot.y, client.posRot.rot.z, 0, false);
|
||||||
client.player = (Player*)dummy;
|
client.player = (Player*)dummy;
|
||||||
}
|
}
|
||||||
refreshingActors = false;
|
spawningDummyPlayerForClientId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Anchor::IsSaveLoaded() {
|
bool Anchor::IsSaveLoaded() {
|
||||||
|
|||||||
@@ -63,7 +63,8 @@ typedef struct {
|
|||||||
|
|
||||||
class Anchor : public Network {
|
class Anchor : public Network {
|
||||||
private:
|
private:
|
||||||
bool refreshingActors = false;
|
uint32_t spawningDummyPlayerForClientId = 0;
|
||||||
|
bool shouldRefreshActors = false;
|
||||||
bool justLoadedSave = false;
|
bool justLoadedSave = false;
|
||||||
bool isHandlingUpdateTeamState = false;
|
bool isHandlingUpdateTeamState = false;
|
||||||
bool isProcessingIncomingPacket = false;
|
bool isProcessingIncomingPacket = false;
|
||||||
@@ -74,6 +75,8 @@ class Anchor : public Network {
|
|||||||
nlohmann::json PrepRoomState();
|
nlohmann::json PrepRoomState();
|
||||||
void RegisterHooks();
|
void RegisterHooks();
|
||||||
void RefreshClientActors();
|
void RefreshClientActors();
|
||||||
|
void SetDummyPlayerClientId(const Actor* actor, uint32_t clientId);
|
||||||
|
|
||||||
void HandlePacket_AllClientState(nlohmann::json payload);
|
void HandlePacket_AllClientState(nlohmann::json payload);
|
||||||
void HandlePacket_ConsumeAdultTradeItem(nlohmann::json payload);
|
void HandlePacket_ConsumeAdultTradeItem(nlohmann::json payload);
|
||||||
void HandlePacket_DamagePlayer(nlohmann::json payload);
|
void HandlePacket_DamagePlayer(nlohmann::json payload);
|
||||||
@@ -125,7 +128,6 @@ class Anchor : public Network {
|
|||||||
|
|
||||||
static Anchor* Instance;
|
static Anchor* Instance;
|
||||||
std::map<uint32_t, AnchorClient> clients;
|
std::map<uint32_t, AnchorClient> clients;
|
||||||
std::vector<uint32_t> actorIndexToClientId;
|
|
||||||
RoomState roomState;
|
RoomState roomState;
|
||||||
|
|
||||||
void Enable();
|
void Enable();
|
||||||
@@ -138,6 +140,7 @@ class Anchor : public Network {
|
|||||||
void SendJsonToRemote(nlohmann::json packet);
|
void SendJsonToRemote(nlohmann::json packet);
|
||||||
bool IsSaveLoaded();
|
bool IsSaveLoaded();
|
||||||
bool CanTeleportTo(uint32_t clientId);
|
bool CanTeleportTo(uint32_t clientId);
|
||||||
|
uint32_t GetDummyPlayerClientId(const Actor* actor);
|
||||||
|
|
||||||
void SendPacket_ClearTeamState(std::string teamId);
|
void SendPacket_ClearTeamState(std::string teamId);
|
||||||
void SendPacket_DamagePlayer(u32 clientId, u8 damageEffect, u8 damage);
|
void SendPacket_DamagePlayer(u32 clientId, u8 damageEffect, u8 damage);
|
||||||
|
|||||||
@@ -12,9 +12,6 @@ void Player_UseItem(PlayState* play, Player* player, s32 item);
|
|||||||
void Player_Draw(Actor* actor, PlayState* play);
|
void Player_Draw(Actor* actor, PlayState* play);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hijacking player->zTargetActiveTimer (unused s32 for the dummy) to store the clientId for convenience
|
|
||||||
#define DUMMY_CLIENT_ID player->zTargetActiveTimer
|
|
||||||
|
|
||||||
static DamageTable DummyPlayerDamageTable = {
|
static DamageTable DummyPlayerDamageTable = {
|
||||||
/* Deku nut */ DMG_ENTRY(0, DUMMY_PLAYER_HIT_RESPONSE_STUN),
|
/* Deku nut */ DMG_ENTRY(0, DUMMY_PLAYER_HIT_RESPONSE_STUN),
|
||||||
/* Deku stick */ DMG_ENTRY(2, DUMMY_PLAYER_HIT_RESPONSE_NORMAL),
|
/* Deku stick */ DMG_ENTRY(2, DUMMY_PLAYER_HIT_RESPONSE_NORMAL),
|
||||||
@@ -53,15 +50,14 @@ static DamageTable DummyPlayerDamageTable = {
|
|||||||
void DummyPlayer_Init(Actor* actor, PlayState* play) {
|
void DummyPlayer_Init(Actor* actor, PlayState* play) {
|
||||||
Player* player = (Player*)actor;
|
Player* player = (Player*)actor;
|
||||||
|
|
||||||
uint32_t clientId = Anchor::Instance->actorIndexToClientId[actor->params];
|
uint32_t clientId = Anchor::Instance->GetDummyPlayerClientId(actor);
|
||||||
DUMMY_CLIENT_ID = clientId;
|
|
||||||
|
|
||||||
if (!Anchor::Instance->clients.contains(DUMMY_CLIENT_ID)) {
|
if (!Anchor::Instance->clients.contains(clientId)) {
|
||||||
Actor_Kill(actor);
|
Actor_Kill(actor);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AnchorClient& client = Anchor::Instance->clients[DUMMY_CLIENT_ID];
|
AnchorClient& client = Anchor::Instance->clients[clientId];
|
||||||
|
|
||||||
// Hack to account for usage of gSaveContext in Player_Init
|
// Hack to account for usage of gSaveContext in Player_Init
|
||||||
s32 originalAge = gSaveContext.linkAge;
|
s32 originalAge = gSaveContext.linkAge;
|
||||||
@@ -104,12 +100,14 @@ void Math_Vec3s_Copy(Vec3s* dest, Vec3s* src) {
|
|||||||
void DummyPlayer_Update(Actor* actor, PlayState* play) {
|
void DummyPlayer_Update(Actor* actor, PlayState* play) {
|
||||||
Player* player = (Player*)actor;
|
Player* player = (Player*)actor;
|
||||||
|
|
||||||
if (!Anchor::Instance->clients.contains(DUMMY_CLIENT_ID)) {
|
uint32_t clientId = Anchor::Instance->GetDummyPlayerClientId(actor);
|
||||||
|
|
||||||
|
if (!Anchor::Instance->clients.contains(clientId)) {
|
||||||
Actor_Kill(actor);
|
Actor_Kill(actor);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AnchorClient& client = Anchor::Instance->clients[DUMMY_CLIENT_ID];
|
AnchorClient& client = Anchor::Instance->clients[clientId];
|
||||||
|
|
||||||
if (client.sceneNum != gPlayState->sceneNum || !client.online || !client.isSaveLoaded) {
|
if (client.sceneNum != gPlayState->sceneNum || !client.online || !client.isSaveLoaded) {
|
||||||
actor->world.pos.x = -9999.0f;
|
actor->world.pos.x = -9999.0f;
|
||||||
@@ -195,12 +193,14 @@ void DummyPlayer_Update(Actor* actor, PlayState* play) {
|
|||||||
void DummyPlayer_Draw(Actor* actor, PlayState* play) {
|
void DummyPlayer_Draw(Actor* actor, PlayState* play) {
|
||||||
Player* player = (Player*)actor;
|
Player* player = (Player*)actor;
|
||||||
|
|
||||||
if (!Anchor::Instance->clients.contains(DUMMY_CLIENT_ID)) {
|
uint32_t clientId = Anchor::Instance->GetDummyPlayerClientId(actor);
|
||||||
|
|
||||||
|
if (!Anchor::Instance->clients.contains(clientId)) {
|
||||||
Actor_Kill(actor);
|
Actor_Kill(actor);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AnchorClient& client = Anchor::Instance->clients[DUMMY_CLIENT_ID];
|
AnchorClient& client = Anchor::Instance->clients[clientId];
|
||||||
|
|
||||||
if (client.sceneNum != gPlayState->sceneNum || !client.online || !client.isSaveLoaded) {
|
if (client.sceneNum != gPlayState->sceneNum || !client.online || !client.isSaveLoaded) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -67,7 +67,9 @@ void Anchor::RegisterHooks() {
|
|||||||
COND_ID_HOOK(ShouldActorInit, ACTOR_PLAYER, isConnected, [&](void* actorRef, bool* should) {
|
COND_ID_HOOK(ShouldActorInit, ACTOR_PLAYER, isConnected, [&](void* actorRef, bool* should) {
|
||||||
Actor* actor = (Actor*)actorRef;
|
Actor* actor = (Actor*)actorRef;
|
||||||
|
|
||||||
if (refreshingActors) {
|
if (spawningDummyPlayerForClientId != 0) {
|
||||||
|
SetDummyPlayerClientId(actor, spawningDummyPlayerForClientId);
|
||||||
|
|
||||||
// By the time we get here, the actor was already added to the ACTORCAT_PLAYER list, so we need to move it
|
// By the time we get here, the actor was already added to the ACTORCAT_PLAYER list, so we need to move it
|
||||||
Actor_ChangeCategory(gPlayState, &gPlayState->actorCtx, actor, ACTORCAT_NPC);
|
Actor_ChangeCategory(gPlayState, &gPlayState->actorCtx, actor, ACTORCAT_NPC);
|
||||||
actor->id = ACTOR_EN_OE2;
|
actor->id = ACTOR_EN_OE2;
|
||||||
@@ -84,6 +86,12 @@ void Anchor::RegisterHooks() {
|
|||||||
justLoadedSave = false;
|
justLoadedSave = false;
|
||||||
SendPacket_RequestTeamState();
|
SendPacket_RequestTeamState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shouldRefreshActors) {
|
||||||
|
shouldRefreshActors = false;
|
||||||
|
RefreshClientActors();
|
||||||
|
}
|
||||||
|
|
||||||
SendPacket_PlayerUpdate();
|
SendPacket_PlayerUpdate();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -77,8 +77,6 @@ void Anchor::SendPacket_PlayerUpdate() {
|
|||||||
void Anchor::HandlePacket_PlayerUpdate(nlohmann::json payload) {
|
void Anchor::HandlePacket_PlayerUpdate(nlohmann::json payload) {
|
||||||
uint32_t clientId = payload["clientId"].get<uint32_t>();
|
uint32_t clientId = payload["clientId"].get<uint32_t>();
|
||||||
|
|
||||||
bool shouldRefreshActors = false;
|
|
||||||
|
|
||||||
if (clients.contains(clientId)) {
|
if (clients.contains(clientId)) {
|
||||||
auto& client = clients[clientId];
|
auto& client = clients[clientId];
|
||||||
|
|
||||||
@@ -110,8 +108,4 @@ void Anchor::HandlePacket_PlayerUpdate(nlohmann::json payload) {
|
|||||||
client.unk_862 = payload["unk_862"].get<s16>();
|
client.unk_862 = payload["unk_862"].get<s16>();
|
||||||
client.actionVar1 = payload["actionVar1"].get<s8>();
|
client.actionVar1 = payload["actionVar1"].get<s8>();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldRefreshActors) {
|
|
||||||
RefreshClientActors();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user