Reorganized and cleaned up the solution.

This commit is contained in:
HikikoMarmy
2026-03-02 12:37:07 +00:00
parent 8012f30170
commit d4dfbddf69
175 changed files with 1516 additions and 1136 deletions

View File

@@ -0,0 +1,43 @@
#pragma once
#include <string>
#include <memory>
#include <unordered_map>
#include "CharacterSaveTask.hpp"
class CharacterSaveManager {
public:
CharacterSaveManager();
~CharacterSaveManager();
CharacterSaveManager( const CharacterSaveManager & ) = delete;
CharacterSaveManager &operator=( const CharacterSaveManager & ) = delete;
static CharacterSaveManager &Get()
{
static CharacterSaveManager instance;
return instance;
}
bool BeginSaveTask(
const sptr_user user,
const uint32_t characterId,
const CharacterSlotData &metaData,
const CharacterSaveType saveType );
bool BeginSaveTask(
const sptr_user m_owner,
const sptr_user m_target,
const uint32_t characterId,
const CharacterSlotData &metaData,
const CharacterSaveType saveType );
void AppendSaveData( const std::wstring &sessionId, const std::vector<uint8_t> &data, bool endOfData );
bool CommitSaveTask( const std::wstring &sessionId );
void RemoveSaveTask( const std::wstring &sessionId );
sptr_character_save_task FindSaveTask( const std::wstring &sessionId );
public:
std::unordered_map< std::wstring, sptr_character_save_task > m_tasks;
};

View File

@@ -0,0 +1,43 @@
#pragma once
#include <array>
#include <string>
#include <vector>
#include <unordered_map>
#include "Common/Constant.hpp"
#include "Common/ByteStream.hpp"
#include "RealmUser.hpp"
#include "RealmCharacterMetaKV.hpp"
enum class CharacterSaveType : uint8_t
{
NEW_CHARACTER,
SAVE_CHARACTER
};
class CharacterSaveTask {
public:
CharacterSaveTask( CharacterSaveType Type, uint32_t characterId = 0 );
~CharacterSaveTask();
void SetMetaData( const CharacterSlotData &metaData );
bool AppendData( const std::vector< uint8_t > &data );
bool Validate();
const std::vector< uint8_t >& GetData() const;
public:
CharacterSaveType m_saveType;
sptr_user m_ownerUser;
sptr_user m_targetUser;
uint32_t m_characterId;
uint32_t m_writePosition;
CharacterSlotData m_meta;
std::vector< uint8_t > m_data;
};
using sptr_character_save_task = std::shared_ptr< CharacterSaveTask >;

View File

@@ -0,0 +1,42 @@
#pragma once
#include <memory>
#include <mutex>
#include <string>
#include <map>
#include "ChatRoomSession.hpp"
class ChatRoomManager {
private:
int32_t m_roomIndex = 0;
std::map< int32_t, sptr_chat_room_session > m_chatSessionList;
void CreatePublicRooms();
public:
ChatRoomManager();
~ChatRoomManager();
ChatRoomManager( const ChatRoomManager & ) = delete;
ChatRoomManager &operator=( const ChatRoomManager & ) = delete;
static ChatRoomManager &Get()
{
static ChatRoomManager instance;
return instance;
}
std::vector< sptr_chat_room_session > GetPublicRoomList() const;
bool JoinRoom( sptr_user user, const std::wstring &roomName );
bool LeaveRoom( sptr_user user, const std::wstring &roomName );
bool LeaveRoom( sptr_user user, const int32_t roomId );
void OnDisconnectUser( sptr_user user );
bool CreateGameChatSession( sptr_user user, const std::wstring roomName );
bool CloseGameChatSession( const std::wstring roomName );
void SendMessageToRoom( const std::wstring roomName, const std::wstring handle, const std::wstring message );
sptr_chat_room_session FindRoom( const std::wstring &roomName );
sptr_chat_room_session FindRoom( const int32_t roomId );
};

View File

@@ -0,0 +1,36 @@
#pragma once
#include <memory>
#include <string>
#include <vector>
#include "RealmUser.hpp"
class ChatRoomSession {
public:
ChatRoomSession();
~ChatRoomSession();
bool AddMember( sptr_user user );
bool RemoveMember( sptr_user user );
bool IsMember( sptr_user user );
bool IsPublic() const;
bool IsPrivate() const;
enum class RoomType {
Public,
Private
};
RoomType m_type;
int32_t m_index;
std::wstring m_name;
std::wstring m_banner;
wptr_user m_owner;
std::vector< wptr_user > m_members;
std::vector< wptr_user > m_moderators;
};
typedef std::shared_ptr< ChatRoomSession > sptr_chat_room_session;

View File

@@ -0,0 +1,65 @@
#pragma once
#include <array>
#include <vector>
#include <string>
#include <memory>
#include "RealmUser.hpp"
class GameSession {
public:
enum class GameType {
Public,
Private
};
enum class GameState {
NotReady,
Open,
Started
};
GameSession( uint32_t index );
~GameSession();
bool IsJoinable( sptr_user user = nullptr ) const;
sptr_user GetOwner() const;
sptr_user GetMember( int32_t index ) const;
sptr_user GetMemberBySessionId( const std::wstring &sessionId ) const;
std::vector< sptr_user > GetMembers() const;
bool AddMember( sptr_user user );
bool RemoveMember( sptr_user user );
public:
GameType m_type;
GameState m_state;
std::array< wptr_user, 4 > m_members;
int32_t m_gameId;
std::wstring m_gameName;
std::wstring m_ownerName;
std::wstring m_playerCount;
std::string m_gameData;
std::string m_description;
std::string m_hostLocalAddr;
std::string m_hostExternalAddr;
int32_t m_hostLocalPort;
int32_t m_hostNatPort;
int8_t m_currentPlayers;
int8_t m_maximumPlayers;
int8_t m_difficulty;
int8_t m_gameMode;
int8_t m_mission;
int8_t m_unknown;
int8_t m_networkSave;
};
typedef std::shared_ptr< GameSession > sptr_game_session;

View File

@@ -0,0 +1,67 @@
#pragma once
#include <memory>
#include <mutex>
#include <vector>
#include "GameSession.hpp"
#include "Common/Constant.hpp"
class GameSessionManager {
private:
static inline std::unique_ptr< GameSessionManager > m_instance;
static inline std::mutex m_mutex;
static inline std::mutex m_dataMutex;
int32_t m_uniqueGameIndex;
std::vector< sptr_game_session > m_gameSessionList[ 2 ];
public:
GameSessionManager();
~GameSessionManager();
GameSessionManager( const GameSessionManager & ) = delete;
GameSessionManager &operator=( const GameSessionManager & ) = delete;
static GameSessionManager &Get()
{
std::lock_guard< std::mutex > lock( m_mutex );
if( m_instance == nullptr )
{
m_instance.reset( new GameSessionManager() );
}
return *m_instance;
}
void OnDisconnectUser( sptr_user user );
bool CreateGameSession_CON( sptr_user user,
const std::wstring gameInfo,
const std::wstring name,
const std::wstring stage,
const bool isPrivateGame );
bool CreateGameSession_RTA( sptr_user user,
const std::wstring gameInfo,
const std::wstring name,
const std::array< int8_t, 5 > &attributes,
const bool isPrivateGame );
bool ForceTerminateGame( const int32_t gameId, RealmGameType clientType );
sptr_game_session FindGame( const int32_t gameId, RealmGameType clientType );
sptr_game_session FindGame( const std::wstring &gameName, RealmGameType clientType );
bool RequestOpen( sptr_user user );
bool RequestCancel( sptr_user user );
bool RequestJoin( sptr_user user );
bool RequestStart( sptr_user user );
std::vector< sptr_game_session > GetAvailableGameSessionList( const RealmGameType clientType ) const;
std::vector< sptr_game_session > GetPublicGameSessionList( const RealmGameType clientType ) const;
std::vector< sptr_game_session > GetPrivateGameSessionList( const RealmGameType clientType ) const;
private:
void ProcessJoinNorrath( sptr_user join, sptr_user host );
void ProcessJoinArms( sptr_user join, sptr_user host );
};

View File

@@ -0,0 +1,170 @@
#pragma once
#include <array>
#include <string>
#include <vector>
#include <unordered_map>
#include "Common/Constant.hpp"
#include "Common/ByteStream.hpp"
#include "RealmCharacterMetaKV.hpp"
constexpr size_t MAX_NUMBER_OF_CHARACTERS = 12;
constexpr size_t CHARACTER_DATA_SIZE = 19504;
using ItemData = std::array< uint8_t, 72 >;
using AttackData = std::array< float_t, 4 >;
class RealmCharacter {
public:
RealmCharacter();
RealmCharacter( const int32_t id, const CharacterSlotData meta, const std::vector< uint8_t > data );
~RealmCharacter();
void Initialize();
const std::vector< uint8_t > Serialize() const;
void Deserialize( const std::vector< uint8_t > &data );
bool ValidateData();
CharacterSlotData GetMetaData() const;
void SetMetaData( sptr_byte_stream stream );
std::vector< uint8_t > Unpack();
public:
uint32_t m_characterId;
CharacterSlotData m_metaData;
std::vector< uint8_t > m_data;
public:
std::string name;
uint8_t unknown_000[ 4 ];
std::string unknown_str;
int32_t unknown_004[ 3 ];
CharacterClass character_class;
CharacterRace character_race;
uint8_t current_level;
uint8_t pending_level; // Waiting to spend points, basically.
uint16_t unknown_009;
int32_t experience;
int32_t unknown_010[ 6 ];
struct s_stats {
int32_t strength, intelligence, dexterity, stamina, unknown_a, unknown_b;
} stats[ 2 ];
int32_t unknown_016;
float_t current_hp, maximum_hp;
int32_t unknown_017, unknown_018, unknown_019;
float_t current_mana, maximum_mana;
int32_t unknown_020;
int32_t attack_power, minimum_damage, maximum_damage;
int32_t unknown_021, unknown_022;
uint8_t unknown_023, unknown_024, unknown_025, unknown_026;
int32_t current_gold, current_skill_points;
int16_t current_ability_points;
int16_t has_spent_remaining_points;
int32_t unknown_029, unknown_030, unknown_031, unknown_032;
int32_t unknown_033, unknown_034, unknown_035, unknown_036;
int32_t unknown_037, unknown_038, unknown_039, unknown_040;
float_t weight, max_weight;
int32_t unknown_041, unknown_042;
std::array<ItemData, 64> item_data;
int32_t num_armor_item, unknown_043;
std::array<ItemData, 64> armor_item_data;
int32_t num_weapon_item, unknown_044;
std::array<ItemData, 64> weapon_item_data;
int32_t num_consumable_item, unknown_045;
std::array< uint8_t, 2696 > unknown_046;
struct s_quest {
char name[ 32 ];
char description[ 32 ];
};
std::array<s_quest, 8> quest_string;
int32_t num_quests;
int32_t unknown_048;
int32_t unknown_049;
int32_t unknown_050;
int32_t unknown_051;
int32_t unknown_052;
int32_t unknown_053;
int32_t unknown_054;
std::array< int32_t, 20 > equipment;
struct s_new_style {
char name[ 32 ]; // "newstyle"
int id;
uint8_t active_flag;
uint8_t type;
uint8_t unknown_a;
uint8_t unknown_b;
uint8_t reserved[ 64 ];
};
std::array<s_new_style, 15> newStyle;
int32_t unknown_075;
float_t unknown_076;
int32_t
unknown_077, unknown_078, unknown_079,
unknown_080, unknown_081, unknown_082,
unknown_083, unknown_084, unknown_085;
uint8_t skill_slot[ 2 ];
uint8_t unknown_087, unknown_088;
std::array< AttackData, 8> attackData;
struct s_skill {
int16_t skill_id;
int16_t skill_level;
};
std::array<s_skill, 48> skills;
int32_t unknown_091;
struct s_difficulty_progress {
uint8_t mission_na;
uint8_t mission_War;
uint8_t mission_Innovation;
uint8_t mission_PitOfIllOmen;
uint8_t mission_PlaneOfWater;
uint8_t mission_Torment;
uint8_t mission_Disease;
uint8_t mission_Valor;
uint8_t mission_Fire;
uint8_t mission_Storms;
uint8_t mission_Faydark;
uint8_t mission_Nightmares;
uint8_t mission_Fear;
};
std::array<s_difficulty_progress, 5> mission_progress;
std::array< uint8_t, 13 > mission_medals;
uint8_t evil_bitflag, good_bitflag;
int32_t unknown_101;
float_t movement_speed;
uint8_t unknown_102, unknown_103, unknown_104, unknown_105;
uint8_t unknown_106, unknown_107, unknown_108, unknown_109;
int32_t unknown_110;
};
using sptr_realm_character = std::shared_ptr< RealmCharacter >;

View File

@@ -0,0 +1,50 @@
#pragma once
#include <string>
#include <vector>
#include <utility>
#include "Common/ByteStream.hpp"
using CharacterAttributeKV = std::pair<std::wstring, std::wstring>;
class CharacterSlotData {
private:
std::vector<CharacterAttributeKV> m_metaData;
public:
CharacterSlotData() = default;
CharacterSlotData( const std::vector< uint8_t > &data );
void Deserialize( const std::vector< uint8_t > &data );
void Deserialize( const sptr_byte_stream stream );
std::vector<uint8_t> Serialize() const;
bool empty() const
{
return m_metaData.empty();
}
const std::vector<CharacterAttributeKV> &GetMetaData() const
{
return m_metaData;
}
void SetMetaData( const std::vector<CharacterAttributeKV> &metaData )
{
m_metaData = metaData;
}
std::wstring GetValue( std::wstring key )
{
for( const auto &kv : m_metaData )
{
if( kv.first == key )
{
return kv.second;
}
}
return L"";
}
};

View File

@@ -0,0 +1,68 @@
#pragma once
#include <string>
#include <memory>
#include <array>
#include "RealmCharacter.hpp"
#include "Common/Constant.hpp"
#include "../Network/RealmSocket.hpp"
class RealmUser {
public:
RealmUser();
~RealmUser();
bool operator==( const RealmUser &other ) const
{
return m_accountId == other.m_accountId || sock->fd == other.sock->fd;
}
bool operator<( const RealmUser &other ) const
{
if( m_sessionId != other.m_sessionId )
return m_sessionId < other.m_sessionId;
return m_accountId < other.m_accountId;
}
bool IsFriend( const std::wstring &handle ) const
{
return std::find( m_friendList.begin(), m_friendList.end(), handle ) != m_friendList.end();
}
bool IsIgnored( const std::wstring &handle ) const
{
return std::find( m_ignoreList.begin(), m_ignoreList.end(), handle ) != m_ignoreList.end();
}
public:
sptr_socket sock; // For Realm Lobby
RealmGameType m_gameType; // Champions of Norrath or Return to Arms
int64_t m_accountId; // Unique ID of the account
std::wstring m_sessionId; // Temporary Session ID
std::wstring m_username; // Username of the user
std::wstring m_chatHandle; // Chat handle for the user, used in chat rooms
bool m_isLoggedIn; // True if the user has successfully authenticated and logged in
bool m_isHost; // True if this user is the host of a realm
int32_t m_gameId; // Unique ID of the realm
int32_t m_publicRoomId; // Used for public chat rooms
int32_t m_privateRoomId; // Used for private chat rooms
std::string m_localAddr; // Local IP address of the user, passed from the client during Realm creation.
int32_t m_localPort;
std::string m_discoveryAddr;
int32_t m_discoveryPort;
int32_t m_characterId;
sptr_realm_character m_character;
std::vector< std::wstring > m_friendList; // List of friends for this user
std::vector< std::wstring > m_ignoreList; // List of ignored users
};
using sptr_user = std::shared_ptr< RealmUser >;
using wptr_user = std::weak_ptr< RealmUser >;

View File

@@ -0,0 +1,46 @@
#pragma once
#include <memory>
#include <mutex>
#include <vector>
#include <string>
#include <random>
#include "RealmUser.hpp"
class UserManager {
private:
public:
static UserManager &Get()
{
static UserManager instance;
return instance;
}
UserManager( const UserManager & ) = delete;
UserManager &operator=( const UserManager & ) = delete;
UserManager();
~UserManager();
std::wstring GenerateSessionId();
sptr_user CreateUser( sptr_socket socket, RealmGameType clientType );
void RemoveUser( sptr_user user );
void RemoveUser( const std::wstring &sessionId );
void RemoveUser( const sptr_socket socket );
void Disconnect( sptr_socket socket, const std::string reason );
void Disconnect( sptr_user user, const std::string reason );
sptr_user FindUserBySessionId( const std::wstring &sessionId );
sptr_user FindUserBySocket( const sptr_socket &socket );
sptr_user FindUserByChatHandle( const std::wstring &handle );
int32_t GetUserCount() const;
std::vector< sptr_user > GetUserList();
void NotifyFriendsOnlineStatus( const sptr_user &user, bool onlineStatus );
private:
std::mutex m_mutex;
std::vector< sptr_user > m_users;
std::mt19937 rng;
};