eq2go/old/common/servertalk.hpp
2025-08-06 19:00:30 -05:00

1047 lines
26 KiB
C++

// Copyright (C) 2007 EQ2EMulator Development Team - GNU GPL v3
#pragma once
#define EQEMU_PROTOCOL_VERSION "0.5.0"
#include <vector>
#include <string>
#include <memory>
#include <cstring>
#include <iostream>
#include "types.hpp"
#include "packet/packet_functions.hpp"
// Server timing constants
#define SERVER_TIMEOUT 45000
#define INTERSERVER_TIMER 10000
#define LoginServer_StatusUpdateInterval 15000
#define LoginServer_AuthStale 60000
#define AUTHCHANGE_TIMEOUT 900
// Server operation codes
#define ServerOP_KeepAlive 0x0001
#define ServerOP_ChannelMessage 0x0002
#define ServerOP_SetZone 0x0003
#define ServerOP_ShutdownAll 0x0004
#define ServerOP_ZoneShutdown 0x0005
#define ServerOP_ZoneBootup 0x0006
#define ServerOP_ZoneStatus 0x0007
#define ServerOP_SetConnectInfo 0x0008
#define ServerOP_EmoteMessage 0x0009
#define ServerOP_ClientList 0x000A
#define ServerOP_Who 0x000B
#define ServerOP_ZonePlayer 0x000C
#define ServerOP_KickPlayer 0x000D
#define ServerOP_RefreshGuild 0x000E
#define ServerOP_GuildKickAll 0x000F
#define ServerOP_GuildInvite 0x0010
#define ServerOP_GuildRemove 0x0011
#define ServerOP_GuildPromote 0x0012
#define ServerOP_GuildDemote 0x0013
#define ServerOP_GuildLeader 0x0014
#define ServerOP_GuildGMSet 0x0015
#define ServerOP_GuildGMSetRank 0x0016
#define ServerOP_FlagUpdate 0x0018
#define ServerOP_GMGoto 0x0019
#define ServerOP_MultiLineMsg 0x001A
#define ServerOP_Lock 0x001B
#define ServerOP_Motd 0x001C
#define ServerOP_Uptime 0x001D
#define ServerOP_Petition 0x001E
#define ServerOP_KillPlayer 0x001F
#define ServerOP_UpdateGM 0x0020
#define ServerOP_RezzPlayer 0x0021
#define ServerOP_ZoneReboot 0x0022
#define ServerOP_ZoneToZoneRequest 0x0023
#define ServerOP_AcceptWorldEntrance 0x0024
#define ServerOP_ZAAuth 0x0025
#define ServerOP_ZAAuthFailed 0x0026
#define ServerOP_ZoneIncClient 0x0027
#define ServerOP_ClientListKA 0x0028
#define ServerOP_ChangeWID 0x0029
#define ServerOP_IPLookup 0x002A
#define ServerOP_LockZone 0x002B
#define ServerOP_ItemStatus 0x002C
#define ServerOP_OOCMute 0x002D
#define ServerOP_Revoke 0x002E
#define ServerOP_GuildJoin 0x002F
#define ServerOP_GroupIDReq 0x0030
#define ServerOP_GroupIDReply 0x0031
#define ServerOP_GroupLeave 0x0032
#define ServerOP_RezzPlayerAccept 0x0033
#define ServerOP_SpawnCondition 0x0034
#define ServerOP_SpawnEvent 0x0035
// Update server operation codes
#define UpdateServerOP_Verified 0x5090
#define UpdateServerOP_DisplayMsg 0x5091
#define UpdateServerOP_Completed 0x5092
// Login server operation codes
#define ServerOP_LSInfo 0x1000
#define ServerOP_LSStatus 0x1001
#define ServerOP_LSClientAuth 0x1002
#define ServerOP_LSFatalError 0x1003
#define ServerOP_SystemwideMessage 0x1005
#define ServerOP_ListWorlds 0x1006
#define ServerOP_PeerConnect 0x1007
// Login server zone operation codes
#define ServerOP_LSZoneInfo 0x3001
#define ServerOP_LSZoneStart 0x3002
#define ServerOP_LSZoneBoot 0x3003
#define ServerOP_LSZoneShutdown 0x3004
#define ServerOP_LSZoneSleep 0x3005
#define ServerOP_LSPlayerLeftWorld 0x3006
#define ServerOP_LSPlayerJoinWorld 0x3007
#define ServerOP_LSPlayerZoneChange 0x3008
// User to world operation codes
#define ServerOP_UsertoWorldReq 0xAB00
#define ServerOP_UsertoWorldResp 0xAB01
// Packet operation codes
#define ServerOP_EncapPacket 0x2007
#define ServerOP_WorldListUpdate 0x2008
#define ServerOP_WorldListRemove 0x2009
#define ServerOP_TriggerWorldListRefresh 0x200A
#define ServerOP_WhoAll 0x0210
// Time operation codes
#define ServerOP_SetWorldTime 0x200B
#define ServerOP_GetWorldTime 0x200C
#define ServerOP_SyncWorldTime 0x200E
// EQ2 specific operation codes
#define ServerOP_CharTimeStamp 0x200F
#define ServerOP_NameFilterCheck 0x2011
#define ServerOP_BasicCharUpdate 0x2012
#define ServerOP_CharacterCreate 0x2013
#define ServerOP_NameCharUpdate 0x2014
#define ServerOP_GetLatestTables 0x2015
#define ServerOP_GetTableQuery 0x2016
#define ServerOP_GetTableData 0x2017
#define ServerOP_RaceUpdate 0x2018
#define ServerOP_ZoneUpdate 0x2019
#define ServerOP_BugReport 0x201A
#define ServerOP_ResetDatabase 0x201B
#define ServerOP_ZoneUpdates 0x201C
#define ServerOP_LoginEquipment 0x201D
#define ServerOP_CharacterPicture 0x201E
// Character update flags
#define LEVEL_UPDATE_FLAG 1
#define RACE_UPDATE_FLAG 2
#define CLASS_UPDATE_FLAG 4
#define GENDER_UPDATE_FLAG 8
#define ZONE_UPDATE_FLAG 16
#define ARMOR_UPDATE_FLAG 32
#define NAME_UPDATE_FLAG 64
#define DELETE_UPDATE_FLAG 128
// Structure size limits
#define CHARNAMEUPDATESTRUCT_MAXSIZE 74
#define CHARZONESTRUCT_MAXSIZE 78
#define CHARPICSTRUCT_MINSIZE 10
/**
* Core server packet class for inter-server communication
* Handles packet creation, compression, and memory management
*/
class ServerPacket
{
public:
/**
* Constructor - Creates a new server packet with specified opcode and size
* @param in_opcode - The operation code for this packet
* @param in_size - The size of the packet data buffer
*/
ServerPacket(int16 in_opcode = 0, int32 in_size = 0)
{
compressed = false;
size = in_size;
opcode = in_opcode;
if (size == 0) {
pBuffer = nullptr;
} else {
pBuffer = new uchar[size];
std::memset(pBuffer, 0, size);
}
destination = 0;
InflatedSize = 0;
}
/**
* Destructor - Cleans up packet buffer memory
*/
~ServerPacket()
{
delete[] pBuffer;
}
/**
* Creates a deep copy of this packet
* @return New ServerPacket instance with copied data, or nullptr if this packet is null
*/
ServerPacket* Copy()
{
if (this == nullptr) {
return nullptr;
}
ServerPacket* ret = new ServerPacket(this->opcode, this->size);
if (this->size) {
std::memcpy(ret->pBuffer, this->pBuffer, this->size);
}
ret->compressed = this->compressed;
ret->InflatedSize = this->InflatedSize;
return ret;
}
/**
* Compresses the packet data using deflate algorithm
* @return true if compression successful, false if already compressed or invalid data
*/
bool Deflate()
{
if (compressed) {
return false;
}
if (!pBuffer || !size) {
return false;
}
uchar* tmp = new uchar[size + 128];
int32 tmpsize = DeflatePacket(pBuffer, size, tmp, size + 128);
if (!tmpsize) {
delete[] tmp;
return false;
}
compressed = true;
InflatedSize = size;
size = tmpsize;
uchar* new_buffer = new uchar[size];
std::memcpy(new_buffer, tmp, size);
delete[] tmp;
delete[] pBuffer;
pBuffer = new_buffer;
return true;
}
/**
* Decompresses the packet data using inflate algorithm
* @return true if decompression successful, false if not compressed or invalid data
*/
bool Inflate()
{
if (!compressed) {
return false;
}
if (!pBuffer || !size) {
return false;
}
uchar* tmp = new uchar[InflatedSize];
int32 tmpsize = InflatePacket(pBuffer, size, tmp, InflatedSize);
if (!tmpsize) {
delete[] tmp;
return false;
}
compressed = false;
size = tmpsize;
delete[] pBuffer;
pBuffer = tmp;
return true;
}
int32 size; // Current size of packet buffer
int16 opcode; // Operation code identifying packet type
uchar* pBuffer; // Raw packet data buffer
bool compressed; // Flag indicating if packet is compressed
int32 InflatedSize; // Original size before compression
int32 destination; // Target server ID for routing
};
#pragma pack(1)
/**
* Structure for requesting latest table versions
*/
struct GetLatestTables_Struct
{
float table_version; // Current table version
float data_version; // Current data version
};
/**
* Login server information structure
*/
struct ServerLSInfo_Struct
{
char name[201]; // Server name identifier
char address[250]; // DNS address of the server
char account[31]; // Account name for authentication
char password[256]; // Password for authentication
char protocolversion[25]; // Protocol version string
char serverversion[64]; // Server software version
int8 servertype; // Server type: 0=world, 1=chat, 2=login, 3=MeshLogin, 4=World Debug
int32 dbversion; // Database version for compatibility
};
/**
* Login server status information
*/
struct ServerLSStatus_Struct
{
sint32 status; // Current server status
sint32 num_players; // Number of connected players
sint32 num_zones; // Number of active zones
int8 world_max_level; // Maximum character level allowed
};
/**
* System-wide message structure
*/
struct ServerSystemwideMessage
{
int32 lsaccount_id; // Login server account ID
char key[30]; // Session ID key for verification
int32 type; // Message type identifier
char message[0]; // Variable length message data
};
/**
* World list synchronization structure
*/
struct ServerSyncWorldList_Struct
{
int32 RemoteID; // Remote server identifier
int32 ip; // Server IP address
sint32 status; // Server status code
char name[201]; // Server name
char address[250]; // Server address
char account[31]; // Account name
int32 accountid; // Account ID
int8 authlevel; // Authorization level
int8 servertype; // Server type classification
int32 adminid; // Administrator ID
int8 showdown; // Shutdown flag
sint32 num_players; // Current player count
sint32 num_zones; // Current zone count
bool placeholder; // Placeholder server flag
};
/**
* User to world request structure
*/
struct UsertoWorldRequest_Struct
{
int32 lsaccountid; // Login server account ID
int32 char_id; // Character ID
int32 worldid; // Target world ID
int32 FromID; // Source server ID
int32 ToID; // Destination server ID
char ip_address[21]; // Client IP address
};
/**
* User to world response structure
*/
struct UsertoWorldResponse_Struct
{
int32 lsaccountid; // Login server account ID
int32 char_id; // Character ID
int32 worldid; // World ID
int32 access_key; // Access key for authentication
int8 response; // Response code
char ip_address[80]; // Server IP address
int32 port; // Server port
int32 FromID; // Source server ID
int32 ToID; // Destination server ID
};
/**
* Encapsulated packet structure for packet forwarding
*/
struct ServerEncapPacket_Struct
{
int32 ToID; // Target server ID
int16 opcode; // Encapsulated packet opcode
int16 size; // Encapsulated packet size
uchar data[0]; // Variable length packet data
};
/**
* Emote message structure
*/
struct ServerEmoteMessage_Struct
{
char to[64]; // Target recipient
int32 guilddbid; // Guild database ID
sint16 minstatus; // Minimum status required
int32 type; // Emote type
char message[0]; // Variable length message
};
/**
* Table version information structure
*/
typedef struct
{
char name[256]; // Table name
unsigned int name_len; // Length of table name
unsigned int version; // Table version number
unsigned int data_version; // Data version number
} TableVersion;
/**
* Helper template function to append data to string buffer
*/
template<class Type>
void AddPtrData(std::string* buffer, Type& data)
{
buffer->append(reinterpret_cast<char*>(&data), sizeof(Type));
}
/**
* Helper template function to append array data to string buffer
*/
template<class Type>
void AddPtrData(std::string* buffer, Type* data, int16 size)
{
buffer->append(reinterpret_cast<char*>(data), size);
}
/**
* Class for managing latest table versions across servers
* Handles serialization and deserialization of table version data
*/
class LatestTableVersions
{
public:
/**
* Constructor - Initializes empty table version list
*/
LatestTableVersions()
{
tables = nullptr;
current_index = 0;
total_tables = 0;
data_version = 0;
}
/**
* Destructor - Cleans up allocated table array
*/
~LatestTableVersions()
{
delete[] tables;
}
/**
* Allocates memory for specified number of tables
* @param size - Number of tables to allocate space for
*/
void SetTableSize(int16 size)
{
total_tables = size;
tables = new TableVersion[total_tables];
}
/**
* Adds a table version entry to the collection
* @param name - Table name
* @param version - Table version number
* @param data_version - Data version number
*/
void AddTable(char* name, int32 version, int32 data_version)
{
std::strcpy(tables[current_index].name, name);
tables[current_index].version = version;
tables[current_index].data_version = data_version;
current_index++;
}
/**
* Calculates total serialized size of all table data
* @return Total size in bytes
*/
int16 GetTotalSize()
{
return total_tables * sizeof(TableVersion) + sizeof(int16);
}
/**
* Gets total number of tables in collection
* @return Number of tables
*/
int16 GetTotalTables()
{
return total_tables;
}
/**
* Gets pointer to table array
* @return Pointer to TableVersion array
*/
TableVersion* GetTables()
{
return tables;
}
/**
* Gets specific table by index
* @param index - Index of table to retrieve
* @return TableVersion structure
*/
TableVersion GetTable(int16 index)
{
return tables[index];
}
/**
* Serializes all table data into string buffer
* @return Serialized data string
*/
std::string Serialize()
{
AddPtrData(&buffer, total_tables);
for (int16 i = 0; i < total_tables; i++) {
AddPtrData(&buffer, tables[i].name, sizeof(tables[i].name));
AddPtrData(&buffer, tables[i].version);
AddPtrData(&buffer, tables[i].data_version);
}
return buffer;
}
/**
* Deserializes table data from byte array
* @param data - Raw byte data to deserialize
*/
void DeSerialize(uchar* data)
{
uchar* ptr = data;
std::memcpy(&total_tables, ptr, sizeof(total_tables));
ptr += sizeof(total_tables);
tables = new TableVersion[total_tables];
for (int16 i = 0; i < total_tables; i++) {
std::memcpy(&tables[i].name, ptr, sizeof(tables[i].name));
ptr += sizeof(tables[i].name);
std::memcpy(&tables[i].version, ptr, sizeof(tables[i].version));
ptr += sizeof(tables[i].version);
std::memcpy(&tables[i].data_version, ptr, sizeof(tables[i].data_version));
ptr += sizeof(tables[i].data_version);
}
}
int32 data_version; // Global data version
private:
int16 current_index; // Current insertion index
int16 total_tables; // Total number of tables allocated
TableVersion* tables; // Array of table versions
std::string buffer; // Serialization buffer
};
/**
* Structure for table data queries
*/
struct TableData
{
int16 size; // Size of query string
char* query; // SQL query string
};
/**
* Class for managing table query operations
* Handles multiple SQL queries with version tracking
*/
class TableQuery
{
public:
/**
* Constructor - Initializes empty query collection
*/
TableQuery()
{
try_delete = true;
num_queries = 0;
data_version = 0;
current_index = 0;
latest_version = 0;
your_version = 0;
total_size = sizeof(num_queries) + sizeof(latest_version) + sizeof(your_version) + sizeof(tablename);
}
/**
* Destructor - Cleans up query strings if owned
*/
~TableQuery()
{
if (try_delete) {
for (size_t i = 0; i < tmp_queries.size(); i++) {
delete[] tmp_queries[i];
}
}
}
/**
* Concatenates all queries into single string
* @return Combined query string with newline separators
*/
std::string GetQueriesString()
{
std::string query_string;
for (size_t i = 0; i < tmp_queries.size(); i++) {
query_string.append(tmp_queries[i]).append("\n");
}
return query_string;
}
/**
* Adds a query string to the collection
* @param query - SQL query string to add
*/
void AddQuery(char* query)
{
num_queries++;
total_size += std::strlen(query) + 1;
tmp_queries.push_back(query);
}
/**
* Gets total serialized size of query collection
* @return Total size in bytes
*/
int16 GetTotalSize()
{
return total_size;
}
/**
* Gets number of queries in collection
* @return Query count
*/
int16 GetTotalQueries()
{
return num_queries;
}
/**
* Gets specific query by index
* @param index - Index of query to retrieve
* @return Query string pointer
*/
char* GetQuery(int16 index)
{
return tmp_queries[index];
}
/**
* Serializes query collection to string buffer
* @return Serialized data string
*/
std::string Serialize()
{
num_queries = tmp_queries.size();
AddPtrData(&buffer, num_queries);
AddPtrData(&buffer, latest_version);
AddPtrData(&buffer, your_version);
AddPtrData(&buffer, data_version);
AddPtrData(&buffer, tablename, sizeof(tablename));
for (int16 i = 0; i < GetTotalQueries(); i++) {
AddPtrData(&buffer, tmp_queries[i], std::strlen(tmp_queries[i]) + 1);
}
return buffer;
}
/**
* Deserializes query data from byte array
* @param data - Raw byte data to deserialize
*/
void DeSerialize(uchar* data)
{
try_delete = false;
uchar* ptr = data;
std::memcpy(&num_queries, ptr, sizeof(num_queries));
ptr += sizeof(num_queries);
std::memcpy(&latest_version, ptr, sizeof(latest_version));
ptr += sizeof(latest_version);
std::memcpy(&your_version, ptr, sizeof(your_version));
ptr += sizeof(your_version);
std::memcpy(&data_version, ptr, sizeof(data_version));
ptr += sizeof(data_version);
std::memcpy(&tablename, ptr, sizeof(tablename));
ptr += sizeof(tablename);
for (int16 i = 0; i < GetTotalQueries(); i++) {
tmp_queries.push_back(reinterpret_cast<char*>(ptr));
ptr += std::strlen(reinterpret_cast<char*>(ptr)) + 1;
}
}
int16 current_index; // Current processing index
int16 num_queries; // Number of queries in collection
int32 latest_version; // Latest available version
int32 your_version; // Client's current version
int32 data_version; // Data version number
bool try_delete; // Flag to control memory cleanup
char tablename[64]; // Associated table name
int32 total_size; // Total serialized size
std::string buffer; // Serialization buffer
private:
std::vector<char*> tmp_queries; // Collection of query strings
};
/**
* Class for managing table data queries with column information
* Handles database query results with metadata
*/
class TableDataQuery
{
public:
/**
* Constructor - Initializes with table name
* @param table_name - Name of the associated table
*/
TableDataQuery(char* table_name)
{
if (std::strlen(table_name) >= sizeof(tablename)) {
return;
}
std::strcpy(tablename, table_name);
num_queries = 0;
columns_size = 0;
columns = nullptr;
version = 0;
table_size = 0;
}
/**
* Default constructor
*/
TableDataQuery()
{
num_queries = 0;
columns_size = 0;
columns = nullptr;
version = 0;
table_size = 0;
}
/**
* Destructor - Cleans up column data and queries
*/
~TableDataQuery()
{
delete[] columns;
for (int32 i = 0; i < num_queries; i++) {
delete[] queries[i]->query;
delete queries[i];
}
}
/**
* Gets total number of queries
* @return Query count
*/
int32 GetTotalQueries()
{
return num_queries;
}
/**
* Serializes query data to string buffer with query limit
* @return Pointer to serialized data string, or nullptr if no queries
*/
std::string* Serialize()
{
buffer = "";
num_queries = queries.size();
if (GetTotalQueries() == 0) {
return nullptr;
}
table_size = std::strlen(tablename);
AddPtrData(&buffer, table_size);
AddPtrData(&buffer, tablename, table_size + 1);
AddPtrData(&buffer, version);
if (num_queries > 200) {
int32 max_queries = 200;
AddPtrData(&buffer, max_queries);
} else {
AddPtrData(&buffer, num_queries);
}
AddPtrData(&buffer, columns_size);
AddPtrData(&buffer, columns, columns_size);
// Process queries in reverse order with limit of 200
int16 count = 0;
for (int i = GetTotalQueries() - 1; i >= 0 && count < 200; i--) {
AddPtrData(&buffer, queries[i]->size);
AddPtrData(&buffer, queries[i]->query, queries[i]->size);
delete[] queries[i]->query;
delete queries[i];
queries.pop_back();
count++;
}
return &buffer;
}
/**
* Deserializes query data from byte array
* @param data - Raw byte data to deserialize
*/
void DeSerialize(uchar* data)
{
uchar* ptr = data;
std::memcpy(&table_size, ptr, sizeof(table_size));
ptr += sizeof(table_size);
std::memcpy(&tablename, ptr, table_size + 1);
ptr += table_size + 1;
std::memcpy(&version, ptr, sizeof(version));
ptr += sizeof(version);
std::memcpy(&num_queries, ptr, sizeof(num_queries));
ptr += sizeof(num_queries);
std::memcpy(&columns_size, ptr, sizeof(columns_size));
ptr += sizeof(columns_size);
columns = new char[columns_size + 1];
std::memcpy(columns, ptr, columns_size + 1);
ptr += columns_size;
for (int32 i = 0; i < GetTotalQueries(); i++) {
TableData* new_query = new TableData;
try {
std::memcpy(&new_query->size, ptr, sizeof(new_query->size));
ptr += sizeof(new_query->size);
new_query->query = new char[new_query->size + 1];
std::memcpy(new_query->query, ptr, new_query->size);
ptr += new_query->size;
queries.push_back(new_query);
} catch (const std::bad_alloc& ba) {
std::cout << ba.what() << std::endl;
delete new_query;
}
}
}
std::string buffer; // Serialization buffer
int32 num_queries; // Number of queries in collection
int32 version; // Table version number
int16 table_size; // Size of table name string
char tablename[64]; // Associated table name
int16 columns_size; // Size of column definition string
char* columns; // Column definitions
std::vector<TableData*> queries; // Collection of table data queries
};
/**
* Equipment update request structure
*/
struct EquipmentUpdateRequest_Struct
{
int16 max_per_batch; // Maximum updates per batch
};
/**
* Login server equipment update structure
*/
struct LoginEquipmentUpdate
{
int32 world_char_id; // Character ID
int16 equip_type; // Equipment type identifier
int8 red; // Red color component
int8 green; // Green color component
int8 blue; // Blue color component
int8 highlight_red; // Highlight red component
int8 highlight_green; // Highlight green component
int8 highlight_blue; // Highlight blue component
int32 slot; // Equipment slot identifier
};
/**
* World server equipment update structure
*/
struct EquipmentUpdate_Struct
{
int32 id; // Unique record identifier
int32 world_char_id; // Character ID
int16 equip_type; // Equipment type identifier
int8 red; // Red color component
int8 green; // Green color component
int8 blue; // Blue color component
int8 highlight_red; // Highlight red component
int8 highlight_green; // Highlight green component
int8 highlight_blue; // Highlight blue component
int32 slot; // Equipment slot identifier
};
/**
* Equipment update list structure
*/
struct EquipmentUpdateList_Struct
{
sint16 total_updates; // Total number of updates available
};
/**
* Zone update request structure
*/
struct ZoneUpdateRequest_Struct
{
int16 max_per_batch; // Maximum updates per batch
};
/**
* Login server zone update structure
*/
struct LoginZoneUpdate
{
std::string name; // Zone name
std::string description; // Zone description
};
/**
* Zone update structure with variable data
*/
struct ZoneUpdate_Struct
{
int32 zone_id; // Zone identifier
int8 zone_name_length; // Length of zone name
int8 zone_desc_length; // Length of zone description
char data[0]; // Variable length name and description data
};
/**
* Zone update list structure
*/
struct ZoneUpdateList_Struct
{
uint16 total_updates; // Total number of zone updates
char data[0]; // Variable length update data
};
/**
* Character timestamp structure for EQ2
*/
struct CharacterTimeStamp_Struct
{
int32 char_id; // Character identifier
int32 account_id; // Account identifier
int32 unix_timestamp; // Unix timestamp of last update
};
/**
* Character data update structure for basic changes
*/
struct CharDataUpdate_Struct
{
int32 account_id; // Account identifier
int32 char_id; // Character identifier
int8 update_field; // Bitfield of updated fields
int32 update_data; // Updated data value
};
/**
* Bug report structure
*/
struct BugReport
{
char category[64]; // Bug category
char subcategory[64]; // Bug subcategory
char causes_crash[64]; // Crash information
char reproducible[64]; // Reproducibility info
char summary[128]; // Bug summary
char description[2000]; // Detailed description
char version[32]; // Game version
char player[64]; // Player name
int32 account_id; // Account identifier
char spawn_name[64]; // Associated spawn name
int32 spawn_id; // Spawn identifier
int32 zone_id; // Zone identifier
};
/**
* Race update structure
*/
struct RaceUpdate_Struct
{
int32 account_id; // Account identifier
int32 char_id; // Character identifier
int16 model_type; // Character model type
int8 race; // Race identifier
};
/**
* Character name update structure
*/
struct CharNameUpdate_Struct
{
int32 account_id; // Account identifier
int32 char_id; // Character identifier
int8 name_length; // Length of new name
char new_name[0]; // Variable length new name
};
/**
* Character zone update structure
*/
struct CharZoneUpdate_Struct
{
int32 account_id; // Account identifier
int32 char_id; // Character identifier
int32 zone_id; // Zone identifier
int8 zone_length; // Length of zone name
char new_zone[0]; // Variable length zone name
};
/**
* World character creation structure
*/
struct WorldCharCreate_Struct
{
int32 account_id; // Account identifier
int32 char_id; // Character identifier
int16 model_type; // Character model type
int16 char_size; // Size of character data
uchar character[0]; // Variable length character data
};
/**
* Character name filter request structure
*/
struct WorldCharNameFilter_Struct
{
int32 account_id; // Account identifier
int16 name_length; // Length of name to filter
uchar name[0]; // Variable length name data
};
/**
* Character name filter response structure
*/
struct WorldCharNameFilterResponse_Struct
{
int32 account_id; // Account identifier
int32 char_id; // Character identifier
int8 response; // Filter result code
};
/**
* Character picture update structure
*/
struct CharPictureUpdate_Struct
{
int32 account_id; // Account identifier
int32 char_id; // Character identifier
int16 pic_size; // Size of picture data
char pic[0]; // Variable length picture data
};
#pragma pack()