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,95 @@
#pragma once
#include <vector>
#include <cstdint>
#include <stdexcept>
#include <cstring>
class ByteBufferReader {
public:
ByteBufferReader( const uint8_t *data, size_t size )
: buffer( data ), bufferSize( size ), offset( 0 )
{
}
explicit ByteBufferReader( const std::vector<uint8_t> &vec )
: ByteBufferReader( vec.data(), vec.size() )
{
}
template<typename T>
T read()
{
if( offset + sizeof( T ) > bufferSize )
throw std::out_of_range( "BufferReader: read out of bounds" );
T value;
std::memcpy( &value, buffer + offset, sizeof( T ) );
offset += sizeof( T );
return value;
}
void readBytes( void *dest, size_t size )
{
if( offset + size > bufferSize )
throw std::out_of_range( "BufferReader: readBytes out of bounds" );
std::memcpy( dest, buffer + offset, size );
offset += size;
}
std::string readString( size_t length )
{
if( offset + length > bufferSize )
throw std::out_of_range( "BufferReader: readString out of bounds" );
std::string str( reinterpret_cast< const char * >( buffer + offset ), length );
offset += length;
return str;
}
template<typename T, size_t N>
std::array<T, N> readArray()
{
std::array<T, N> arr;
for( size_t i = 0; i < N; ++i )
arr[ i ] = read<T>();
return arr;
}
void skip( size_t count )
{
if( offset + count > bufferSize )
throw std::out_of_range( "BufferReader: skip out of bounds" );
offset += count;
}
template<typename T>
T peek() const
{
if( offset + sizeof( T ) > bufferSize )
throw std::out_of_range( "BufferReader: peek out of bounds" );
T value;
std::memcpy( &value, buffer + offset, sizeof( T ) );
return value;
}
bool eof() const
{
return offset >= bufferSize;
}
size_t tell() const
{
return offset;
}
size_t remaining() const
{
return bufferSize - offset;
}
private:
const uint8_t *buffer;
size_t bufferSize;
size_t offset;
};

View File

@@ -0,0 +1,85 @@
#pragma once
#include <vector>
#include <string>
#include <memory>
#include <iterator>
#include <optional>
#include "Utility.hpp"
#include "../Crypto/RealmCrypt.hpp"
class ByteBuffer {
public:
ByteBuffer( const std::vector< uint8_t > &data );
ByteBuffer( const std::string &data );
ByteBuffer( const uint8_t *data, uint32_t length );
ByteBuffer( uint32_t length );
ByteBuffer();
~ByteBuffer();
void resize( uint32_t size );
void shrink_to_fit();
template < typename T >
void write( T value );
template < typename T >
T read();
void forward( uint32_t length ) {
m_position += length;
if ( m_position > m_buffer.size() ) {
m_position = m_buffer.size();
}
}
void write_u8( uint8_t value );
void write_u16( uint16_t value );
void write_u32( uint32_t value );
void write_i8( int8_t value );
void write_i16( int16_t value );
void write_i32( int32_t value );
void write_f32( float_t value );
void write_utf8( const std::string &str, std::optional<uint32_t> length = std::nullopt );
void write_utf16( const std::wstring &str, std::optional<uint32_t> length = std::nullopt );
void write_sz_utf8( const std::string &str, std::optional<uint32_t> length = std::nullopt );
void write_sz_utf16( const std::wstring &str, std::optional<uint32_t> length = std::nullopt );
void write_encrypted_utf8( const std::string &str );
void write_encrypted_utf16( const std::wstring &str );
uint8_t read_u8();
uint16_t read_u16();
uint32_t read_u32();
int8_t read_i8();
int16_t read_i16();
int32_t read_i32();
float_t read_f32();
std::string read_utf8( std::optional<uint32_t> length = std::nullopt );
std::wstring read_utf16( std::optional<uint32_t> length = std::nullopt );
std::string read_sz_utf8();
std::wstring read_sz_utf16();
std::string read_encrypted_utf8( bool hasBlockLength = true );
std::wstring read_encrypted_utf16( bool hasBlockLength = true );
void write_bytes( const std::vector< uint8_t > &value );
void write_bytes( const uint8_t *value, uint32_t length );
void write_encrypted_bytes( const std::vector< uint8_t > &value );
std::vector< uint8_t > read_bytes( uint32_t length );
std::vector< uint8_t > read_encrypted_bytes( uint32_t length );
std::vector< uint8_t > get_buffer() const;
size_t get_length() const;
size_t get_position() const;
void set_position( size_t where );
std::vector< uint8_t > m_buffer;
size_t m_position;
};
typedef std::shared_ptr< ByteBuffer > sptr_byte_stream;

View File

@@ -0,0 +1,66 @@
#pragma once
constexpr int32_t MAX_SESSION_ID_LENGTH = 16;
enum RealmGameType {
CHAMPIONS_OF_NORRATH = 0,
RETURN_TO_ARMS = 1,
};
enum class CharacterClass : int32_t {
WARRIOR,
CLERIC,
SHADOW_KNIGHT,
RANGER,
WIZARD,
BERSERKER,
SHAMAN,
NUM_CLASSES
};
enum class CharacterRace : int32_t {
BARBARIAN_M,
BARNARIAN_F,
WOOD_ELF_M,
WOOD_ELF_F,
HIGH_ELF_M,
HIGH_ELF_F,
ERUDITE_WIZARD_M,
ERUDITE_WIZARD_F,
DARK_ELF_M,
DARK_ELF_F,
VAH_SHIR_BERSERKER,
IKSAR_SHAMAN,
NUM_RACES
};
enum class EquipmentSlot : int32_t {
PRIMARY_WEAPON = 0,
UNKNOWN_01 = 1,
SECONDARY_WEAPON = 2,
SHIELD = 3,
TORSO = 4,
RING_1 = 5,
RING_2 = 6,
CHOKER = 7,
QUIVER = 8,
GLOVES = 9,
BOOTS = 10,
HEAD = 11,
LEGGINGS = 12,
UNKNOWN_13 = 13,
EARRING = 14,
UNKNOWN_15 = 15,
UNKNOWN_16 = 16,
PRIMARY_WEAPON_2 = 17,
SECONDARY_WEAPON_2 = 18,
UNKNOWN_19 = 19,
NUM_EQUIPMENT_SLOTS
};

View File

@@ -0,0 +1,22 @@
#pragma once
#include <memory>
class RealmUser;
using sptr_user = std::shared_ptr< RealmUser >;
using wptr_user = std::weak_ptr< RealmUser >;
class GameSession;
using sptr_game_session = std::shared_ptr< GameSession >;
class RealmSocket;
using sptr_socket = std::shared_ptr< RealmSocket >;
class ByteBuffer;
using sptr_byte_stream = std::shared_ptr< ByteBuffer >;
class ChatRoomSession;
using sptr_chat_room_session = std::shared_ptr< ChatRoomSession >;
class RealmCharacter;
using sptr_realm_character = std::shared_ptr< RealmCharacter >;

65
Include/Common/RLEZ.hpp Normal file
View File

@@ -0,0 +1,65 @@
#pragma once
#include <vector>
#include <stdexcept>
#include <cstdint>
namespace RLEZ
{
inline std::vector<uint8_t> Decompress( const std::vector<uint8_t> &input )
{
std::vector< uint8_t > output;
size_t read = 0;
while( read < input.size() )
{
uint8_t byte = input[ read++ ];
output.push_back( byte );
if( byte == 0x00 )
{
if( read >= input.size() )
{
break;
}
uint8_t count = input[ read++ ];
output.insert( output.end(), count, 0x00 );
}
}
return output;
}
inline std::vector<uint8_t> Compress( const std::vector<uint8_t> &input )
{
std::vector< uint8_t > output;
size_t i = 0;
while( i < input.size() )
{
if( input[ i ] != 0x00 )
{
output.push_back( input[ i ] );
++i;
}
else
{
size_t zeroCount = 0;
i++;
// Count all proceeding 00's
while( i < input.size() && input[ i ] == 0x00 && zeroCount < 255 )
{
++i;
++zeroCount;
}
output.push_back( 0x00 );
output.push_back( static_cast< uint8_t >( zeroCount ) );
}
}
return output;
}
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include <cstdint>
#include <string>
#include <WinSock2.h>
namespace Util
{
int32_t round_up( int32_t numToRound, int32_t multiple );
int32_t round_down( int32_t numToRound, int32_t multiple );
uint16_t ByteSwap( uint16_t val );
uint32_t ByteSwap( uint32_t val );
template <typename T>
bool IsInRange( T value, T min, T max )
{
return ( value >= min && value <= max );
}
std::string IPFromAddr( const sockaddr_in &addr );
std::string WideToUTF8( const std::wstring &wstr );
std::wstring UTF8ToWide( const std::string &str );
}