mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-12 15:53:44 +00:00
Live sent PlayerReachedRespawnCheckpoint right after ServerDoneLoadingAllObjects on 143 of 157 captured loads, with a rotation: the spawn point the player arrived at, or a checkpoint they had reached before. DLU sent it before constructing the zone's objects, only when a checkpoint was saved for the zone, and always unrotated. It now goes right after ServerDoneLoadingAllObjects on every load: the saved checkpoint when there is one (DLU saves no rotation for it, so that one stays unrotated), otherwise the position and facing the player loaded in at. Inferred: that the loaded-in spot matches live's spawn point choice (live's is the spawn point object, a few tenths of a unit from the player's start). Check: log in fresh to a zone, die before touching any checkpoint and respawn: you come back where you arrived, facing the same way; reach a checkpoint, change zones and come back, die: you respawn at that checkpoint. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
126 lines
5.5 KiB
C++
126 lines
5.5 KiB
C++
#ifndef ZONEMESSAGES_H
|
|
#define ZONEMESSAGES_H
|
|
|
|
#include "GameMessages.h"
|
|
#include "eObjectWorldState.h"
|
|
|
|
#include <string>
|
|
|
|
// Game messages for a player's zone lifecycle: loading in, zone summaries, level ups, announcements.
|
|
// Fields are listed in wire order; names follow the client (legouniverse.exe 1.10.64) where known.
|
|
namespace GameMessages {
|
|
// Client -> server. The client finished loading the zone and its player.
|
|
struct PlayerLoaded : public NetGameMsg {
|
|
PlayerLoaded() : NetGameMsg(MessageType::Game::PLAYER_LOADED) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
void Handle(Entity& entity, const SystemAddress& sysAddr) override;
|
|
|
|
LWOOBJID playerID{};
|
|
};
|
|
|
|
// Client -> server. The client finished loading an object. Nothing to do.
|
|
struct ReadyForUpdates : public NetGameMsg {
|
|
ReadyForUpdates() : NetGameMsg(MessageType::Game::READY_FOR_UPDATES) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
|
|
LWOOBJID objectID{};
|
|
};
|
|
|
|
// Server -> client, to one client. No payload.
|
|
struct PlayerReady : public NetGameMsg {
|
|
PlayerReady() : NetGameMsg(MessageType::Game::PLAYER_READY) {}
|
|
};
|
|
|
|
// Answers PlayerLoaded the way live did (235 of 237 loads): PlayerReady to the player, then to the zone control
|
|
// object, whose client scripts wait for it. zoneControl is LWOOBJID_EMPTY when the zone has none.
|
|
void SendPlayerReady(LWOOBJID player, LWOOBJID zoneControl, const SystemAddress& sysAddr);
|
|
|
|
// Server -> client, to one client. No payload.
|
|
struct RestoreToPostLoadStats : public NetGameMsg {
|
|
RestoreToPostLoadStats() : NetGameMsg(MessageType::Game::RESTORE_TO_POST_LOAD_STATS) {}
|
|
};
|
|
|
|
// Server -> client, to one client. No payload.
|
|
struct ServerDoneLoadingAllObjects : public NetGameMsg {
|
|
ServerDoneLoadingAllObjects() : NetGameMsg(MessageType::Game::SERVER_DONE_LOADING_ALL_OBJECTS) {}
|
|
};
|
|
|
|
/**
|
|
* Ends a player's load the way live did: ServerDoneLoadingAllObjects, then PlayerReachedRespawnCheckpoint with where
|
|
* the player respawns in this zone (143 of 157 captured loads send the pair back to back, with a rotation).
|
|
* That is their saved checkpoint for the zone when they have one (DLU saves no rotation for it, so it goes
|
|
* unrotated), otherwise the spot and facing they loaded in at.
|
|
*/
|
|
void SendDoneLoading(LWOOBJID player, const NiPoint3& savedCheckpoint, const NiPoint3& spawnPosition, const NiQuaternion& spawnRotation, const SystemAddress& sysAddr);
|
|
|
|
// Server -> client, to one client.
|
|
struct InvalidZoneTransferList : public NetGameMsg {
|
|
InvalidZoneTransferList() : NetGameMsg(MessageType::Game::INVALID_ZONE_TRANSFER_LIST) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
|
|
std::u16string customerFeedbackURL{};
|
|
std::u16string invalidMapTransferList{};
|
|
bool bCustomerFeedbackOnExit{};
|
|
bool bCustomerFeedbackOnInvalidMapTransfer{};
|
|
};
|
|
|
|
// Server -> client, to one client (UNASSIGNED broadcasts).
|
|
struct DisplayZoneSummary : public NetGameMsg {
|
|
DisplayZoneSummary() : NetGameMsg(MessageType::Game::DISPLAY_ZONE_SUMMARY) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
|
|
bool isPropertyMap{ false };
|
|
bool isZoneStart{ false };
|
|
LWOOBJID sender{ LWOOBJID_EMPTY }; // optional
|
|
};
|
|
|
|
// Client -> server.
|
|
struct ZoneSummaryDismissed : public NetGameMsg {
|
|
ZoneSummaryDismissed() : NetGameMsg(MessageType::Game::ZONE_SUMMARY_DISMISSED) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
void Handle(Entity& entity, const SystemAddress& sysAddr) override;
|
|
|
|
LWOOBJID playerID{};
|
|
};
|
|
|
|
// Client -> server. No payload. The client finished showing a level up.
|
|
struct NotifyServerLevelProcessingComplete : public NetGameMsg {
|
|
NotifyServerLevelProcessingComplete() : NetGameMsg(MessageType::Game::NOTIFY_SERVER_LEVEL_PROCESSING_COMPLETE) {}
|
|
void Handle(Entity& entity, const SystemAddress& sysAddr) override;
|
|
};
|
|
|
|
// Server -> client, to one client (UNASSIGNED broadcasts). newState is optional (a flag, then the state when it
|
|
// isn't INWORLD), as live sent it (e.g. 80 80 00 00 00 for ATTACHED).
|
|
struct ChangeObjectWorldState : public NetGameMsg {
|
|
ChangeObjectWorldState() : NetGameMsg(MessageType::Game::CHANGE_OBJECT_WORLD_STATE) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
|
|
eObjectWorldState newState{ eObjectWorldState::INWORLD }; // optional
|
|
};
|
|
|
|
// Server -> client, to one client. The client looks both strings up in its locale (falling back to the text
|
|
// itself) and shows the announcement popup. Client Deserialize: 0x00f23c50.
|
|
struct LocalizedAnnouncementServerToSingleClient : public NetGameMsg {
|
|
LocalizedAnnouncementServerToSingleClient() : NetGameMsg(MessageType::Game::LOCALIZED_ANNOUNCEMENT_SERVER_TO_SINGLE_CLIENT) {}
|
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
|
|
|
// Name-value (LDF) text: u32 character count, then that many characters plus a null terminator when not empty.
|
|
std::u16string bodyParams{};
|
|
bool bForceOpenChatBox{ false };
|
|
bool bShowAnnouncement{ true };
|
|
bool bShowInChat{ true };
|
|
std::u16string body{};
|
|
std::u16string title{};
|
|
std::u16string titleParams{}; // name-value (LDF) text, as bodyParams
|
|
};
|
|
}
|
|
|
|
#endif // ZONEMESSAGES_H
|