Files
Champions-Reborn-Server-Mirror/Source/Game/RealmCharacter.cpp
2026-03-02 12:37:07 +00:00

660 lines
14 KiB
C++

#include "Game/RealmCharacter.hpp"
#include "Game/CharacterSaveTask.hpp"
#include "Common/ByteBufferReader.hpp"
#include "Common/RLEZ.hpp"
#include "logging.hpp"
RealmCharacter::RealmCharacter()
{
m_characterId = 0;
m_data.clear();
Initialize();
}
RealmCharacter::RealmCharacter( const int32_t character_id, const CharacterSlotData meta, const std::vector<uint8_t> data )
{
m_characterId = character_id;
m_data = data;
m_metaData = meta;
Initialize();
}
RealmCharacter::~RealmCharacter()
{
}
void RealmCharacter::Initialize()
{
name = "";
for( auto &val : unknown_000 )
{
val = 0;
}
unknown_str = "";
for( auto &val : unknown_004 )
{
val = 0;
}
character_class = CharacterClass::WARRIOR;
character_race = CharacterRace::BARBARIAN_M;
current_level = 0;
pending_level = 0;
unknown_009 = 0;
experience = 0;
std::memset( unknown_010, 0, sizeof( unknown_010 ) );
std::memset( stats, 0, sizeof( stats ) );
unknown_016 = 0;
current_hp = 0.0f;
maximum_hp = 0.0f;
unknown_017 = 0;
unknown_018 = 0;
unknown_019 = 0;
current_mana = 0.0f;
maximum_mana = 0.0f;
unknown_020 = 0;
attack_power = 0;
minimum_damage = 0;
maximum_damage = 0;
unknown_021 = 0;
unknown_022 = 0;
unknown_023 = 0;
unknown_024 = 0;
unknown_025 = 0;
unknown_026 = 0;
current_gold = 0;
current_skill_points = 0;
current_ability_points = 0;
has_spent_remaining_points = 0;
unknown_029 = 0;
unknown_030 = 0;
unknown_031 = 0;
unknown_032 = 0;
unknown_033 = 0;
unknown_034 = 0;
unknown_035 = 0;
unknown_036 = 0;
unknown_037 = 0;
unknown_038 = 0;
unknown_039 = 0;
unknown_040 = 0;
weight = 0.0f;
max_weight = 0.0f;
unknown_041 = 0;
unknown_042 = 0;
item_data.fill( ItemData() );
num_armor_item = 0;
unknown_043 = 0;
armor_item_data.fill( ItemData() );
num_weapon_item = 0;
unknown_044 = 0;
weapon_item_data.fill( ItemData() );
num_consumable_item = 0;
unknown_045 = 0;
unknown_046.fill( 0 );
quest_string.fill( s_quest() );
num_quests = 0;
unknown_048 = 0;
unknown_049 = 0;
unknown_050 = 0;
unknown_051 = 0;
unknown_052 = 0;
unknown_053 = 0;
unknown_054 = 0;
equipment.fill( 0 );
newStyle.fill( s_new_style() );
unknown_075 = 0;
unknown_076 = 0.0f;
unknown_077 = 0;
unknown_078 = 0;
unknown_079 = 0;
unknown_080 = 0;
unknown_081 = 0;
unknown_082 = 0;
unknown_083 = 0;
unknown_084 = 0;
unknown_085 = 0;
skill_slot[ 0 ] = 0;
skill_slot[ 1 ] = 0;
unknown_087 = 0;
unknown_088 = 0;
attackData.fill( AttackData() );
skills.fill( s_skill() );
unknown_091 = 0;
mission_progress.fill( s_difficulty_progress() );
mission_medals.fill( 0 );
evil_bitflag = 0;
good_bitflag = 0;
unknown_101 = 0;
movement_speed = 0.0f;
unknown_102 = 0;
unknown_103 = 0;
unknown_104 = 0;
unknown_105 = 0;
unknown_106 = 0;
unknown_107 = 0;
unknown_108 = 0;
unknown_109 = 0;
unknown_110 = 0;
}
const std::vector< uint8_t > RealmCharacter::Serialize() const
{
auto writer = ByteBuffer( CHARACTER_DATA_SIZE );
/*writer.write_sz_utf8(name, 32);
for( const auto &val : unknown_000 )
{
writer.write_u8( val );
}
writer.write_sz_utf8( unknown_str, 32 );
for( const auto &val : unknown_004 )
{
writer.write_i32( val );
}
writer.write_i32( static_cast< int32_t >( character_class ) );
writer.write_i32( static_cast< int32_t >( character_race ) );
writer.write_u8( current_level );
writer.write_u8( pending_level );
writer.write_u16( unknown_009 );
writer.write_i32( experience );
for( const auto &val : unknown_010 )
{
writer.write_i32( val );
}
for( const auto &stat : stats )
{
writer.write( stat );
}
writer.write_i32( unknown_016 );
writer.write_f32( current_hp );
writer.write_f32( maximum_hp );
writer.write_i32( unknown_017 );
writer.write_i32( unknown_018 );
writer.write_i32( unknown_019 );
writer.write_f32( current_mana );
writer.write_f32( maximum_mana );
writer.write_i32( unknown_020 );
writer.write_i32( attack_power );
writer.write_i32( minimum_damage );
writer.write_i32( maximum_damage );
writer.write_i32( unknown_021 );
writer.write_i32( unknown_022 );
writer.write_u8( unknown_023 );
writer.write_u8( unknown_024 );
writer.write_u8( unknown_025 );
writer.write_u8( unknown_026 );
writer.write_i32( current_gold );
writer.write_i32( current_skill_points );
writer.write_i16( current_ability_points );
writer.write_i16( has_spent_remaining_points );
writer.write_i32( unknown_029 );
writer.write_i32( unknown_030 );
writer.write_i32( unknown_031 );
writer.write_i32( unknown_032 );
writer.write_i32( unknown_033 );
writer.write_i32( unknown_034 );
writer.write_i32( unknown_035 );
writer.write_i32( unknown_036 );
writer.write_i32( unknown_037 );
writer.write_i32( unknown_038 );
writer.write_i32( unknown_039 );
writer.write_i32( unknown_040 );
writer.write_f32( weight );
writer.write_f32( max_weight );
writer.write_i32( unknown_041 );
writer.write_i32( unknown_042 );
for( const auto &item : item_data )
{
writer.write( item );
}
writer.write_i32( num_armor_item );
writer.write_i32( unknown_043 );
for( const auto &item : armor_item_data )
{
writer.write( item );
}
writer.write_i32( num_weapon_item );
writer.write_i32( unknown_044 );
for( const auto &item : weapon_item_data )
{
writer.write( item );
}
writer.write_i32( num_consumable_item );
writer.write_i32( unknown_045 );
writer.forward( 2696 );
for( const auto &quest : quest_string )
{
writer.write_sz_utf8( quest.name, 32 );
writer.write_sz_utf8( quest.description, 32 );
}
writer.write_i32( num_quests );
writer.write_i32( unknown_048 );
writer.write_i32( unknown_049 );
writer.write_i32( unknown_050 );
writer.write_i32( unknown_051 );
writer.write_i32( unknown_052 );
writer.write_i32( unknown_053 );
writer.write_i32( unknown_054 );
for( const auto &slot : equipment )
{
writer.write_i32( slot );
}
for( const auto &style : newStyle )
{
writer.write< s_new_style >( style );
}
writer.write_i32( unknown_075 );
writer.write_f32( unknown_076 );
writer.write_i32( unknown_077 );
writer.write_i32( unknown_078 );
writer.write_i32( unknown_079 );
writer.write_i32( unknown_080 );
writer.write_i32( unknown_081 );
writer.write_i32( unknown_082 );
writer.write_i32( unknown_083 );
writer.write_i32( unknown_084 );
writer.write_i32( unknown_085 );
for( const auto &skill : skill_slot )
{
writer.write_u8( skill );
}
writer.write_u8( unknown_087 );
writer.write_u8( unknown_088 );
for( const auto &attack : attackData )
{
writer.write< AttackData >( attack );
}
for( const auto &skill : skills )
{
writer.write< s_skill >( skill );
}
writer.write_i32( unknown_091 );
for( const auto &progress : mission_progress )
{
writer.write< s_difficulty_progress >( progress );
}
for( const auto &medal : mission_medals )
{
writer.write_u8( medal );
}
writer.write_u8( evil_bitflag );
writer.write_u8( good_bitflag );
writer.write_i32( unknown_101 );
writer.write_f32( movement_speed );
writer.write_u8( unknown_102 );
writer.write_u8( unknown_103 );
writer.write_u8( unknown_104 );
writer.write_u8( unknown_105 );
writer.write_u8( unknown_106 );
writer.write_u8( unknown_107 );
writer.write_u8( unknown_108 );
writer.write_u8( unknown_109 );
writer.write_i32( unknown_110 );*/
return writer.get_buffer();
}
void RealmCharacter::Deserialize( const std::vector<uint8_t> &data )
{
ByteBufferReader reader( data );
/*try
{
name = reader.readString( 32 );
for( auto &val : unknown_000 )
{
val = reader.read< uint8_t >();
}
unknown_str = reader.readString( 32 );
for( auto &val : unknown_004 )
{
val = reader.read< int32_t >();
}
character_class = static_cast< CharacterClass >( reader.read< int32_t >() );
character_race = static_cast< CharacterRace >( reader.read< int32_t >() );
current_level = reader.read< uint8_t >();
pending_level = reader.read< uint8_t >();
unknown_009 = reader.read< uint16_t >();
experience = reader.read< int32_t >();
for( auto &val : unknown_010 )
{
val = reader.read< int32_t >();
}
for( auto &stat : stats )
{
stat = reader.read< s_stats >();
}
unknown_016 = reader.read< int32_t >();
current_hp = reader.read< float_t >();
maximum_hp = reader.read< float_t >();
unknown_017 = reader.read< int32_t >();
unknown_018 = reader.read< int32_t >();
unknown_019 = reader.read< int32_t >();
current_mana = reader.read< float_t >();
maximum_mana = reader.read< float_t >();
unknown_020 = reader.read< int32_t >();
attack_power = reader.read< int32_t >();
minimum_damage = reader.read< int32_t >();
maximum_damage = reader.read< int32_t >();
unknown_021 = reader.read< int32_t >();
unknown_022 = reader.read< int32_t >();
unknown_023 = reader.read< uint8_t >();
unknown_024 = reader.read< uint8_t >();
unknown_025 = reader.read< uint8_t >();
unknown_026 = reader.read< uint8_t >();
current_gold = reader.read< int32_t >();
current_skill_points = reader.read< int32_t >();
current_ability_points = reader.read< int16_t >();
has_spent_remaining_points = reader.read< int16_t >();
//
unknown_029 = reader.read< int32_t >();
unknown_030 = reader.read< int32_t >();
unknown_031 = reader.read< int32_t >();
unknown_032 = reader.read< int32_t >();
//
unknown_033 = reader.read< int32_t >();
unknown_034 = reader.read< int32_t >();
unknown_035 = reader.read< int32_t >();
unknown_036 = reader.read< int32_t >();
//
unknown_037 = reader.read< int32_t >();
unknown_038 = reader.read< int32_t >();
unknown_039 = reader.read< int32_t >();
unknown_040 = reader.read< int32_t >();
weight = reader.read< float_t >();
max_weight = reader.read< float_t >();
unknown_041 = reader.read< int32_t >();
unknown_042 = reader.read< int32_t >();
item_data = reader.readArray< ItemData, 64>();
num_armor_item = reader.read< int32_t >();
unknown_043 = reader.read< int32_t >();
armor_item_data = reader.readArray< ItemData, 64>();
num_weapon_item = reader.read< int32_t >();
unknown_044 = reader.read< int32_t >();
weapon_item_data = reader.readArray< ItemData, 64>();
num_consumable_item = reader.read< int32_t >();
unknown_045 = reader.read< int32_t >();
unknown_046.fill( 0x00 ); // Fill with zeros, size is 2696 bytes
for( auto &quest : quest_string )
{
quest = reader.read< s_quest >();
}
num_quests = reader.read< int32_t >();
unknown_048 = reader.read< int32_t >();
unknown_049 = reader.read< int32_t >();
unknown_050 = reader.read< int32_t >();
unknown_051 = reader.read< int32_t >();
unknown_052 = reader.read< int32_t >();
unknown_053 = reader.read< int32_t >();
unknown_054 = reader.read< int32_t >();
for( auto &slot : equipment )
{
slot = reader.read< int32_t >();
}
for( auto &style : newStyle )
{
style = reader.read< s_new_style >();
}
unknown_075 = reader.read< int32_t >();
unknown_076 = reader.read< float_t >();
unknown_077 = reader.read< int32_t >();
unknown_078 = reader.read< int32_t >();
unknown_079 = reader.read< int32_t >();
unknown_080 = reader.read< int32_t >();
unknown_081 = reader.read< int32_t >();
unknown_082 = reader.read< int32_t >();
unknown_083 = reader.read< int32_t >();
unknown_084 = reader.read< int32_t >();
unknown_085 = reader.read< int32_t >();
for( auto &skill : skill_slot )
{
skill = reader.read< uint8_t >();
}
unknown_087 = reader.read< uint8_t >();
unknown_088 = reader.read< uint8_t >();
for( auto &attack : attackData )
{
attack = reader.read< AttackData >();
}
for( auto &skill : skills )
{
skill.skill_id = reader.read< int16_t >();
skill.skill_level = reader.read< int16_t >();
}
unknown_091 = reader.read< int32_t >();
for( auto &val : mission_progress )
{
val = reader.read< s_difficulty_progress >();
}
for( auto &val : mission_medals )
{
val = reader.read< uint8_t >();
}
evil_bitflag = reader.read< uint8_t >();
good_bitflag = reader.read< uint8_t >();
unknown_101 = reader.read< int32_t >();
movement_speed = reader.read< float_t >();
unknown_102 = reader.read< uint8_t >();
unknown_103 = reader.read< uint8_t >();
unknown_104 = reader.read< uint8_t >();
unknown_105 = reader.read< uint8_t >();
unknown_106 = reader.read< uint8_t >();
unknown_107 = reader.read< uint8_t >();
unknown_108 = reader.read< uint8_t >();
unknown_109 = reader.read< uint8_t >();
unknown_110 = reader.read< int32_t >();
}
catch( const std::out_of_range &e )
{
Log::Error( "Failed to deserialize RealmCharacter: %s", e.what() );
return;
}*/
}
bool RealmCharacter::ValidateData()
{
if( m_data.empty() || m_data.size() < CHARACTER_DATA_SIZE )
{
Log::Error( "Character data is invalid or too small!" );
return false;
}
if( current_level < 1 || current_level > 80 )
{
Log::Error( "Invalid character level: %d", current_level );
return false;
}
if( current_hp < 1.0f || current_hp > maximum_hp )
{
Log::Error( "Invalid HP values: current %f, maximum %f", current_hp, maximum_hp );
return false;
}
if( current_mana < 0.0f || current_mana > maximum_mana )
{
Log::Error( "Invalid mana values: current %f, maximum %f", current_mana, maximum_mana );
return false;
}
if( weight < 0.0f || weight > max_weight )
{
Log::Error( "Invalid weight values: current %f, maximum %f", weight, max_weight );
return false;
}
if( movement_speed <= 0.0f )
{
Log::Error( "Invalid movement speed: %f", movement_speed );
return false;
}
for( const auto &mission : mission_progress )
{
if( mission.mission_na < 0 || mission.mission_na > 3 )
{
Log::Error( "Invalid mission NA value: %d", mission.mission_na );
return false;
}
if( mission.mission_Disease < 0 || mission.mission_Disease > 3 )
{
Log::Error( "Invalid mission Disease value: %d", mission.mission_Disease );
return false;
}
if( mission.mission_Fear < 0 || mission.mission_Fear > 3 )
{
Log::Error( "Invalid mission Fear value: %d", mission.mission_Fear );
return false;
}
}
return true;
}
CharacterSlotData RealmCharacter::GetMetaData() const
{
return m_metaData;
}
void RealmCharacter::SetMetaData( sptr_byte_stream stream )
{
m_metaData.Deserialize( stream );
}
std::vector<uint8_t> RealmCharacter::Unpack()
{
std::vector< uint8_t > output;
size_t read = 4;
while( read < m_data.size() )
{
uint8_t byte = m_data[ read++ ];
output.push_back( byte );
if( byte == 0x00 )
{
if( read >= m_data.size() )
{
break;
}
uint8_t count = m_data[ read++ ];
output.insert( output.end(), count, 0x00 );
}
}
return output;
}