From 35049d530e6fccdd5a0b5993cf90359a346b09db Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 11 Oct 2014 01:14:11 -0400 Subject: [PATCH] Implement Raid MOTD for UF Don't forget to source 2014_10_11_RaidMOTD.sql SoD and RoF implementations still to come --- changelog.txt | 4 ++ common/eq_packet_structs.h | 4 ++ common/patches/underfoot.cpp | 51 +++++++++++++++--- common/patches/underfoot_structs.h | 5 ++ common/servertalk.h | 6 +++ .../sql/git/required/2014_10_11_RaidMOTD.sql | 1 + world/zoneserver.cpp | 8 +++ zone/client_packet.cpp | 18 ++++++- zone/raids.cpp | 52 ++++++++++++++++++- zone/raids.h | 9 +++- zone/worldserver.cpp | 12 +++++ 11 files changed, 158 insertions(+), 12 deletions(-) create mode 100644 utils/sql/git/required/2014_10_11_RaidMOTD.sql diff --git a/changelog.txt b/changelog.txt index 76bef57e4..2461b4a36 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,9 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 10/11/2014 == +demonstar55: Implement Raid MOTD for UF + Don't forget 2014_10_11_RaidMOTD.sql! + == 10/09/2014 == Uleat: Added 'BOTS' conversion code to supplement the database 'PlayerProfile' blob conversion that Akkadius recently implemented. Note: This automatic conversion uses the view `vwbotcharactermobs` as an update vector. If you need/would like for the converter to run on diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index f49c0106c..eda2a5ce8 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -3929,6 +3929,10 @@ struct RaidAddMember_Struct { /*139*/ uint8 flags[5]; //no idea if these are needed... }; +struct RaidMOTD_Struct { +/*000*/ RaidGeneral_Struct general; // leader_name and action only used +/*136*/ char motd[0]; // max size is 1024, but reply is variable +}; struct RaidAdd_Struct { /*000*/ uint32 action; //=0 diff --git a/common/patches/underfoot.cpp b/common/patches/underfoot.cpp index 1caf65bf3..03ef16a2a 100644 --- a/common/patches/underfoot.cpp +++ b/common/patches/underfoot.cpp @@ -1929,6 +1929,17 @@ namespace Underfoot add_member->flags[4] = in_add_member->flags[4]; dest->FastQueuePacket(&outapp); } + else if (raid_gen->action == 35) + { + RaidMOTD_Struct *inmotd = (RaidMOTD_Struct *)__emu_buffer; + EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidMOTD_Struct) + strlen(inmotd->motd) + 1); + structs::RaidMOTD_Struct *outmotd = (structs::RaidMOTD_Struct *)outapp->pBuffer; + + outmotd->general.action = inmotd->general.action; + strn0cpy(outmotd->general.player_name, inmotd->general.player_name, 64); + strn0cpy(outmotd->motd, inmotd->motd, strlen(inmotd->motd) + 1); + dest->FastQueuePacket(&outapp); + } else { RaidGeneral_Struct* in_raid_general = (RaidGeneral_Struct*)__emu_buffer; @@ -3367,15 +3378,41 @@ namespace Underfoot DECODE(OP_RaidInvite) { - DECODE_LENGTH_EXACT(structs::RaidGeneral_Struct); - SETUP_DIRECT_DECODE(RaidGeneral_Struct, structs::RaidGeneral_Struct); + DECODE_LENGTH_ATLEAST(structs::RaidGeneral_Struct); - strn0cpy(emu->leader_name, eq->leader_name, 64); - strn0cpy(emu->player_name, eq->player_name, 64); - IN(action); - IN(parameter); + // This is a switch on the RaidGeneral action + switch (*(uint32 *)__packet->pBuffer) { + case 35: { // raidMOTD + // we don't have a nice macro for this + structs::RaidMOTD_Struct *__eq_buffer = (structs::RaidMOTD_Struct *)__packet->pBuffer; + __eq_buffer->motd[1023] = '\0'; + size_t motd_size = strlen(__eq_buffer->motd) + 1; + __packet->size = sizeof(RaidMOTD_Struct) + motd_size; + __packet->pBuffer = new unsigned char[__packet->size]; + RaidMOTD_Struct *emu = (RaidMOTD_Struct *)__packet->pBuffer; + structs::RaidMOTD_Struct *eq = (structs::RaidMOTD_Struct *)__eq_buffer; + strn0cpy(emu->general.player_name, eq->general.player_name, 64); + strn0cpy(emu->motd, eq->motd, motd_size); + IN(general.action); + IN(general.parameter); + FINISH_DIRECT_DECODE(); + break; + } + case 36: { // raidPlayerNote unhandled + break; + } + default: { + DECODE_LENGTH_EXACT(structs::RaidGeneral_Struct); + SETUP_DIRECT_DECODE(RaidGeneral_Struct, structs::RaidGeneral_Struct); + strn0cpy(emu->leader_name, eq->leader_name, 64); + strn0cpy(emu->player_name, eq->player_name, 64); + IN(action); + IN(parameter); + FINISH_DIRECT_DECODE(); + break; + } + } - FINISH_DIRECT_DECODE(); } DECODE(OP_ReadBook) diff --git a/common/patches/underfoot_structs.h b/common/patches/underfoot_structs.h index 89101ca2e..f331d5dbc 100644 --- a/common/patches/underfoot_structs.h +++ b/common/patches/underfoot_structs.h @@ -3623,6 +3623,11 @@ struct RaidAddMember_Struct { /*139*/ uint8 flags[5]; //no idea if these are needed... }; +struct RaidMOTD_Struct { +/*000*/ RaidGeneral_Struct general; // leader_name and action only used +/*140*/ char motd[0]; // max size 1024, but reply is variable +}; + struct RaidAdd_Struct { /*000*/ uint32 action; //=0 /*004*/ char player_name[64]; //should both be the player's name diff --git a/common/servertalk.h b/common/servertalk.h index 8c30715d9..f458c758e 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -104,6 +104,7 @@ #define ServerOP_GroupFollow 0x0110 #define ServerOP_GroupFollowAck 0x0111 #define ServerOP_GroupCancelInvite 0x0112 +#define ServerOP_RaidMOTD 0x0113 #define ServerOP_InstanceUpdateTime 0x014F #define ServerOP_AdventureRequest 0x0150 @@ -854,6 +855,11 @@ struct ServerRaidMessage_Struct { char message[0]; }; +struct ServerRaidMOTD_Struct { + uint32 rid; + char motd[0]; +}; + struct ServerLFGMatchesRequest_Struct { uint32 FromID; uint8 QuerierLevel; diff --git a/utils/sql/git/required/2014_10_11_RaidMOTD.sql b/utils/sql/git/required/2014_10_11_RaidMOTD.sql new file mode 100644 index 000000000..39fccd311 --- /dev/null +++ b/utils/sql/git/required/2014_10_11_RaidMOTD.sql @@ -0,0 +1 @@ +ALTER TABLE `raid_details` ADD `motd` varchar(1024); diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index 1023dbe69..b94bda20a 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -409,6 +409,14 @@ bool ZoneServer::Process() { break; } + case ServerOP_RaidMOTD: { + if (pack->size < sizeof(ServerRaidMOTD_Struct)) + break; + + zoneserver_list.SendPacket(pack); + break; + } + case ServerOP_SpawnCondition: { if(pack->size != sizeof(ServerSpawnCondition_Struct)) break; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 2eb67ced4..03d44c903 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -565,6 +565,7 @@ void Client::CompleteConnect() raid->SendRaidAdd(GetName(), this); raid->SendBulkRaid(this); raid->SendGroupUpdate(this); + raid->SendRaidMOTD(this); uint32 grpID = raid->GetGroup(GetName()); if (grpID < 12){ raid->SendRaidGroupRemove(GetName(), grpID); @@ -10656,8 +10657,8 @@ void Client::Handle_OP_PVPLeaderBoardRequest(const EQApplicationPacket *app) void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) { - if (app->size != sizeof(RaidGeneral_Struct)) { - LogFile->write(EQEMuLog::Error, "Wrong size: OP_RaidCommand, size=%i, expected %i", app->size, sizeof(RaidGeneral_Struct)); + if (app->size < sizeof(RaidGeneral_Struct)) { + LogFile->write(EQEMuLog::Error, "Wrong size: OP_RaidCommand, size=%i, expected at least %i", app->size, sizeof(RaidGeneral_Struct)); DumpPacket(app); return; } @@ -11219,6 +11220,19 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) break; } + case RaidCommandSetMotd: + { + Raid *r = entity_list.GetRaidByClient(this); + if (!r) + break; + // we don't use the RaidGeneral here! + RaidMOTD_Struct *motd = (RaidMOTD_Struct *)app->pBuffer; + r->SetRaidMOTD(std::string(motd->motd)); + r->SaveRaidMOTD(); + r->SendRaidMOTDToWorld(); + break; + } + default: { Message(13, "Raid command (%d) NYI", ri->action); break; diff --git a/zone/raids.cpp b/zone/raids.cpp index 1e8e23f8d..f22267a2f 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -89,6 +89,7 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo SendRaidAddAll(c->GetName()); c->SetRaidGrouped(true); + SendRaidMOTD(c); ServerPacket *pack = new ServerPacket(ServerOP_RaidAdd, sizeof(ServerRaidGeneralAction_Struct)); ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer; @@ -1205,6 +1206,44 @@ void Raid::SendRaidGroupRemove(const char *who, uint32 gid) safe_delete(pack); } +void Raid::SendRaidMOTD(Client *c) +{ + if (!c || motd.empty()) + return; + + size_t size = motd.size() + 1; + EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidMOTD_Struct) + size); + RaidMOTD_Struct *rmotd = (RaidMOTD_Struct *)outapp->pBuffer; + rmotd->general.action = raidSetMotd; + strn0cpy(rmotd->general.player_name, c->GetName(), 64); + strn0cpy(rmotd->motd, motd.c_str(), size); + c->FastQueuePacket(&outapp); +} + +void Raid::SendRaidMOTD() +{ + if (motd.empty()) + return; + + for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++) + if (members[i].member) + SendRaidMOTD(members[i].member); +} + +void Raid::SendRaidMOTDToWorld() +{ + if (motd.empty()) + return; + + size_t size = motd.size() + 1; + ServerPacket *pack = new ServerPacket(ServerOP_RaidMOTD, sizeof(ServerRaidMOTD_Struct) + size); + ServerRaidMOTD_Struct *smotd = (ServerRaidMOTD_Struct *)pack->pBuffer; + smotd->rid = GetID(); + strn0cpy(smotd->motd, motd.c_str(), size); + worldserver.SendPacket(pack); + safe_delete(pack); +} + void Raid::LockRaid(bool lockFlag) { std::string query = StringFormat("UPDATE raid_details SET locked = %d WHERE raidid = %lu", @@ -1229,14 +1268,14 @@ void Raid::LockRaid(bool lockFlag) void Raid::SetRaidDetails() { - std::string query = StringFormat("INSERT INTO raid_details SET raidid = %lu, loottype = 4, locked = 0", + std::string query = StringFormat("INSERT INTO raid_details SET raidid = %lu, loottype = 4, locked = 0, motd = ''", (unsigned long)GetID()); auto results = database.QueryDatabase(query); } void Raid::GetRaidDetails() { - std::string query = StringFormat("SELECT locked, loottype FROM raid_details WHERE raidid = %lu", + std::string query = StringFormat("SELECT locked, loottype, motd FROM raid_details WHERE raidid = %lu", (unsigned long)GetID()); auto results = database.QueryDatabase(query); if (!results.Success()) @@ -1251,6 +1290,15 @@ void Raid::GetRaidDetails() locked = atoi(row[0]); LootType = atoi(row[1]); + motd = std::string(row[2]); +} + +void Raid::SaveRaidMOTD() +{ + std::string query = StringFormat("UPDATE raid_details SET motd = '%s' WHERE raidid = %lu", + EscapeString(motd).c_str(), (unsigned long)GetID()); + + auto results = database.QueryDatabase(query); } bool Raid::LearnMembers() diff --git a/zone/raids.h b/zone/raids.h index be12788e6..44952e5da 100644 --- a/zone/raids.h +++ b/zone/raids.h @@ -38,7 +38,7 @@ enum { //raid packet types: raidMembers = 6, //len 395+, details + members list raidNoAssignLeadership = 7, raidCreate = 8, //len 72 - raidUnknown = 9, + raidUnknown = 9, // unused? raidNoRaid = 10, //parameter=0 raidChangeLootType = 11, raidStringID = 12, @@ -130,6 +130,8 @@ public: void AddRaidLooter(const char* looter); void RemoveRaidLooter(const char* looter); + inline void SetRaidMOTD(std::string in_motd) { motd = in_motd; }; + //util func //keeps me from having to keep iterating through the list //when I want lots of data from the same entry @@ -160,6 +162,7 @@ public: //also learns raid structure based on db. void SetRaidDetails(); void GetRaidDetails(); + void SaveRaidMOTD(); bool LearnMembers(); void VerifyRaid(); void MemberZoned(Client *c); @@ -194,6 +197,9 @@ public: void SendMakeGroupLeaderPacketAll(); void SendMakeGroupLeaderPacket(const char *who); //13 void SendMakeGroupLeaderPacketTo(const char *who, Client *to); + void SendRaidMOTD(Client *c); + void SendRaidMOTD(); + void SendRaidMOTDToWorld(); void QueuePacket(const EQApplicationPacket *app, bool ack_req = true); @@ -206,6 +212,7 @@ protected: uint32 LootType; bool disbandCheck; bool forceDisband; + std::string motd; }; diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index a1100b7cb..1ff42cd02 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -1372,6 +1372,18 @@ void WorldServer::Process() { break; } + case ServerOP_RaidMOTD: { + ServerRaidMOTD_Struct *rmotd = (ServerRaidMOTD_Struct *)pack->pBuffer; + if (!zone) + break; + Raid *r = entity_list.GetRaidByID(rmotd->rid); + if (!r) + break; + r->SetRaidMOTD(std::string(rmotd->motd)); + r->SendRaidMOTD(); + break; + } + case ServerOP_SpawnPlayerCorpse: { SpawnPlayerCorpse_Struct* s = (SpawnPlayerCorpse_Struct*)pack->pBuffer; Corpse* NewCorpse = database.LoadPlayerCorpse(s->player_corpse_id);