/* EQ2Emulator: Everquest II Server Emulator Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net) This file is part of EQ2Emulator. EQ2Emulator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. EQ2Emulator is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with EQ2Emulator. If not, see . */ #ifndef EQ_SOPCODES_H #define EQ_SOPCODES_H #define EQEMU_PROTOCOL_VERSION "0.5.0" #include "types.h" #include "packet_functions.h" #include #define SERVER_TIMEOUT 45000 // how often keepalive gets sent #define INTERSERVER_TIMER 10000 #define LoginServer_StatusUpdateInterval 15000 #define LoginServer_AuthStale 60000 #define AUTHCHANGE_TIMEOUT 900 // in seconds #define ServerOP_KeepAlive 0x0001 // packet to test if port is still open #define ServerOP_ChannelMessage 0x0002 // broadcast/guildsay #define ServerOP_SetZone 0x0003 // client -> server zoneinfo #define ServerOP_ShutdownAll 0x0004 // exit(0); #define ServerOP_ZoneShutdown 0x0005 // unload all data, goto sleep mode #define ServerOP_ZoneBootup 0x0006 // come out of sleep mode and load zone specified #define ServerOP_ZoneStatus 0x0007 // Shows status of all zones #define ServerOP_SetConnectInfo 0x0008 // Tells server address and port # #define ServerOP_EmoteMessage 0x0009 // Worldfarts #define ServerOP_ClientList 0x000A // Update worldserver's client list, for #whos #define ServerOP_Who 0x000B // #who #define ServerOP_ZonePlayer 0x000C // #zone, or #summon #define ServerOP_KickPlayer 0x000D // #kick #define ServerOP_RefreshGuild 0x000E // Notice to all zoneservers to refresh their guild cache for ID# in packet #define ServerOP_GuildKickAll 0x000F // Remove all clients from this guild #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 // GM Flag updated for character, refresh the memory cache #define ServerOP_GMGoto 0x0019 #define ServerOP_MultiLineMsg 0x001A #define ServerOP_Lock 0x001B // For #lock/#unlock inside server #define ServerOP_Motd 0x001C // For changing MoTD inside server. #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 // Incomming client #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 // for disbanding out of zone folks #define ServerOP_RezzPlayerAccept 0x0033 #define ServerOP_SpawnCondition 0x0034 #define ServerOP_SpawnEvent 0x0035 #define UpdateServerOP_Verified 0x5090 #define UpdateServerOP_DisplayMsg 0x5091 #define UpdateServerOP_Completed 0x5092 #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 #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 #define ServerOP_UsertoWorldReq 0xAB00 #define ServerOP_UsertoWorldResp 0xAB01 #define ServerOP_EncapPacket 0x2007 // Packet within a packet #define ServerOP_WorldListUpdate 0x2008 #define ServerOP_WorldListRemove 0x2009 #define ServerOP_TriggerWorldListRefresh 0x200A #define ServerOP_WhoAll 0x0210 #define ServerOP_SetWorldTime 0x200B #define ServerOP_GetWorldTime 0x200C #define ServerOP_SyncWorldTime 0x200E //EQ2 Opcodes #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 // updates charater select screen item appearances (gear appear) #define ServerOP_CharacterPicture 0x201E /************ PACKET RELATED STRUCT ************/ class ServerPacket { public: ~ServerPacket() { safe_delete_array(pBuffer); } ServerPacket(int16 in_opcode = 0, int32 in_size = 0) { this->compressed = false; size = in_size; opcode = in_opcode; if (size == 0) { pBuffer = 0; } else { pBuffer = new uchar[size]; memset(pBuffer, 0, size); } destination = 0; InflatedSize = 0; } ServerPacket* Copy() { if (this == 0) { return 0; } ServerPacket* ret = new ServerPacket(this->opcode, this->size); if (this->size) memcpy(ret->pBuffer, this->pBuffer, this->size); ret->compressed = this->compressed; ret->InflatedSize = this->InflatedSize; return ret; } bool Deflate() { if (compressed) return false; if ((!this->pBuffer) || (!this->size)) return false; uchar* tmp = new uchar[this->size + 128]; int32 tmpsize = DeflatePacket(this->pBuffer, this->size, tmp, this->size + 128); if (!tmpsize) { safe_delete_array(tmp); return false; } this->compressed = true; this->InflatedSize = this->size; this->size = tmpsize; uchar* new_buffer = new uchar[this->size]; memcpy(new_buffer, tmp, this->size); safe_delete_array(tmp); uchar* tmpdel = this->pBuffer; this->pBuffer = new_buffer; safe_delete_array(tmpdel); return true; } bool Inflate() { if (!compressed) return false; if ((!this->pBuffer) || (!this->size)) return false; uchar* tmp = new uchar[InflatedSize]; int32 tmpsize = InflatePacket(this->pBuffer, this->size, tmp, InflatedSize); if (!tmpsize) { safe_delete_array(tmp); return false; } compressed = false; this->size = tmpsize; uchar* tmpdel = this->pBuffer; this->pBuffer = tmp; safe_delete_array(tmpdel); return true; } int32 size; int16 opcode; uchar* pBuffer; bool compressed; int32 InflatedSize; int32 destination; }; #pragma pack(1) struct GetLatestTables_Struct{ float table_version; float data_version; }; struct ServerLSInfo_Struct { char name[201]; // name the worldserver wants char address[250]; // DNS address of the server char account[31]; // account name for the worldserver char password[31]; // password for the name char protocolversion[25]; // Major protocol version number char serverversion[64]; // minor server software version number int8 servertype; // 0=world, 1=chat, 2=login, 3=MeshLogin, 4=World Debug int32 dbversion; // database major+minor version from version.h (for PatchServer) }; struct ServerLSStatus_Struct { sint32 status; sint32 num_players; sint32 num_zones; int8 world_max_level; }; struct ServerSystemwideMessage { int32 lsaccount_id; char key[30]; // sessionID key for verification int32 type; char message[0]; }; struct ServerSyncWorldList_Struct { int32 RemoteID; int32 ip; sint32 status; char name[201]; char address[250]; char account[31]; int32 accountid; int8 authlevel; int8 servertype; // 0=world, 1=chat, 2=login int32 adminid; int8 showdown; sint32 num_players; sint32 num_zones; bool placeholder; }; struct UsertoWorldRequest_Struct { int32 lsaccountid; int32 char_id; int32 worldid; int32 FromID; int32 ToID; char ip_address[21]; }; struct UsertoWorldResponse_Struct { int32 lsaccountid; int32 char_id; int32 worldid; int32 access_key; int8 response; char ip_address[80]; int32 port; int32 FromID; int32 ToID; }; struct ServerEncapPacket_Struct { int32 ToID; // ID number of the LWorld on the other server int16 opcode; int16 size; uchar data[0]; }; struct ServerEmoteMessage_Struct { char to[64]; int32 guilddbid; sint16 minstatus; int32 type; char message[0]; }; /*struct TableVersion{ char name[64]; int32 version; int32 max_table_version; int32 max_data_version; sint32 data_version; int8 last; char column_names[1000]; };*/ typedef struct { char name[256]; unsigned int name_len; unsigned int version; unsigned int data_version; } TableVersion; template void AddPtrData(string* buffer, Type& data){ buffer->append((char*)&data, sizeof(Type)); } template void AddPtrData(string* buffer, Type* data, int16 size){ buffer->append(data, size); } class LatestTableVersions { public: LatestTableVersions(){ tables = 0; current_index = 0; total_tables = 0; data_version = 0; } ~LatestTableVersions(){ safe_delete_array(tables); } void SetTableSize(int16 size){ total_tables = size; tables = new TableVersion[total_tables]; } void AddTable(char* name, int32 version, int32 data_version){ strcpy(tables[current_index].name, name); tables[current_index].version = version; tables[current_index].data_version = data_version; current_index++; } int16 GetTotalSize(){ return total_tables * sizeof(TableVersion) + sizeof(int16); } int16 GetTotalTables(){ return total_tables; } TableVersion* GetTables(){ return tables; } TableVersion GetTable(int16 index){ return tables[index]; } string Serialize(){ AddPtrData(&buffer, total_tables); for(int16 i=0;i tmp_queries; }; class TableDataQuery{ public: TableDataQuery(char* table_name){ if( strlen(table_name) >= sizeof(tablename) ) return; strcpy(tablename, table_name); num_queries = 0; columns_size = 0; columns = 0; version = 0; table_size = 0; } TableDataQuery(){ num_queries = 0; columns_size = 0; columns = 0; version = 0; table_size = 0; } ~TableDataQuery(){ safe_delete_array(columns); for(int32 i=0;iquery); safe_delete(queries[i]); } } int32 GetTotalQueries(){ return num_queries; } string* Serialize(){ buffer = ""; num_queries = queries.size(); if(GetTotalQueries() == 0) return 0; table_size = 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); vector::iterator query_iterator; 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); safe_delete_array(queries[i]->query); safe_delete(queries[i]); queries.pop_back(); count++; } return &buffer; } void DeSerialize(uchar* data){ uchar* ptr = data; memcpy(&table_size, ptr, sizeof(table_size)); ptr+= sizeof(table_size); memcpy(&tablename, ptr, table_size + 1); ptr+= table_size + 1; memcpy(&version, ptr, sizeof(version)); ptr+= sizeof(version); memcpy(&num_queries, ptr, sizeof(num_queries)); ptr+= sizeof(num_queries); memcpy(&columns_size, ptr, sizeof(columns_size)); ptr+= sizeof(columns_size); columns = new char[columns_size + 1]; memcpy(columns, ptr, columns_size + 1); ptr+= columns_size; for(int32 i=0;isize, ptr, sizeof(new_query->size)); ptr+= sizeof(new_query->size); new_query->query = new char[new_query->size + 1]; memcpy(new_query->query, ptr, new_query->size); ptr+= new_query->size; queries.push_back(new_query); } catch( bad_alloc &ba ) { cout << ba.what() << endl; if( NULL != new_query ) delete new_query; } } } string buffer; int32 num_queries; int32 version; int16 table_size; char tablename[64]; int16 columns_size; char* columns; vector queries; }; // Max number of equipment updates to send at once struct EquipmentUpdateRequest_Struct { int16 max_per_batch; }; // Login's structure of equipment data struct LoginEquipmentUpdate { int32 world_char_id; int16 equip_type; int8 red; int8 green; int8 blue; int8 highlight_red; int8 highlight_green; int8 highlight_blue; int32 slot; }; // World's structure of equipment data struct EquipmentUpdate_Struct { int32 id; // unique record identifier per world int32 world_char_id; int16 equip_type; int8 red; int8 green; int8 blue; int8 highlight_red; int8 highlight_green; int8 highlight_blue; int32 slot; }; // How many equipmment updates are there to send? struct EquipmentUpdateList_Struct { sint16 total_updates; }; struct ZoneUpdateRequest_Struct{ int16 max_per_batch; }; struct LoginZoneUpdate{ string name; string description; }; struct ZoneUpdate_Struct{ int32 zone_id; int8 zone_name_length; int8 zone_desc_length; char data[0]; }; struct ZoneUpdateList_Struct{ sint16 total_updates; char data[0]; }; //EQ2 Specific Structures Login -> World (Image) struct CharacterTimeStamp_Struct { int32 char_id; int32 account_id; int32 unix_timestamp; }; //EQ2 Specific Structures World -> Login (Image) /**UPDATE_FIELD TYPES** These will be stored beside the timestamp on the world server to determine what has changed on between the timestamp, when the update is sent, it will remove the flag. 8 bits in a byte: Example: 01001100 0 Level Flag 1 Race Flag 0 Class Flag 0 Gender Flag 1 Zone Flag 1 Armor Flag 0 Name Flag 0 Delete Flag **/ #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 //This structure used for basic changes such as level,class,gender, and deletes that are not able to be backed up struct CharDataUpdate_Struct { int32 account_id; int32 char_id; int8 update_field; int32 update_data; }; struct BugReport{ char category[64]; char subcategory[64]; char causes_crash[64]; char reproducible[64]; char summary[128]; char description[2000]; char version[32]; char player[64]; int32 account_id; char spawn_name[64]; int32 spawn_id; int32 zone_id; }; struct RaceUpdate_Struct { int32 account_id; int32 char_id; int16 model_type; int8 race; }; //If this structure comes in with more than 74 bytes, should probably discard (leaves 65 bytes for new_name) #define CHARNAMEUPDATESTRUCT_MAXSIZE 74 struct CharNameUpdate_Struct { int32 account_id; int32 char_id; int8 name_length; // If its longer than 64, something is wrong :-/ char new_name[0]; }; //If this structure comes in with more than 78 bytes, should probably discard (leaves 65 bytes for new_zone) #define CHARZONESTRUCT_MAXSIZE 78 struct CharZoneUpdate_Struct { int32 account_id; int32 char_id; int32 zone_id; int8 zone_length; // If its longer than 64, something is wrong :-/ char new_zone[0]; }; struct WorldCharCreate_Struct { int32 account_id; int32 char_id; int16 model_type; int16 char_size; uchar character[0]; }; struct WorldCharNameFilter_Struct { int32 account_id; int16 name_length; uchar name[0]; }; struct WorldCharNameFilterResponse_Struct { int32 account_id; int32 char_id; int8 response; }; #define CHARPICSTRUCT_MINSIZE 10 // Should only be used for the headshot picture struct CharPictureUpdate_Struct { int32 account_id; int32 char_id; int16 pic_size; char pic[0]; }; #pragma pack() #endif