feat(Core/Opcodes): Implement CMSG_COMPLAIN & CMSG_CALENDAR_COMPLAIN (#25329)

Co-authored-by: Dmitri Petmanson <53072+laizerox@users.noreply.github.com>
Co-authored-by: Benjamin Jackson <38561765+heyitsbench@users.noreply.github.com>
This commit is contained in:
Kitzunu
2026-04-03 20:49:14 +02:00
committed by GitHub
parent 161abfdc85
commit ab2f9524c1
11 changed files with 72 additions and 16 deletions
@@ -0,0 +1,18 @@
--
CREATE TABLE `spam_reports` (
`ID` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`SpamType` TINYINT UNSIGNED NOT NULL COMMENT '0 = mail, 1 = chat, 2 = calendar',
`SpammerGuid` INT UNSIGNED NOT NULL DEFAULT '0',
`Unk1` INT UNSIGNED NULL DEFAULT '0',
`MailIdOrMessageType` INT UNSIGNED NULL DEFAULT '0',
`ChannelId` INT UNSIGNED NULL COMMENT 'Only used if SpamType = 1',
`SecondsSinceMessage` INT UNSIGNED NULL COMMENT 'Only used if SpamType = 1',
`Description` LONGTEXT NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci',
`Time` INT NULL DEFAULT NULL COMMENT 'Time of report',
PRIMARY KEY (`ID`) USING BTREE
)
CHARSET = utf8mb4
COLLATE = utf8mb4_unicode_ci
ENGINE = InnoDB
ROW_FORMAT = DEFAULT
;
@@ -612,6 +612,15 @@ AllowLoggingIPAddressesInDatabase = 1
Allow.IP.Based.Action.Logging = 0
#
# LogSpamReports
# Description: Allow logging spam reports from players in the chat, mail or calendar into the database.
# Default: 1 - (Enabled)
# 0 - (Disabled)
#
LogSpamReports = 1
#
# Appender config values: Given an appender "name"
# Appender.name
@@ -353,6 +353,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_UPD_REM_AT_LOGIN_FLAG, "UPDATE characters set at_login = at_login & ~ ? WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_ALL_AT_LOGIN_FLAGS, "UPDATE characters SET at_login = at_login | ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_BUG_REPORT, "INSERT INTO bugreport (type, content) VALUES(?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_SPAM_REPORT, "INSERT INTO spam_reports (SpamType, SpammerGuid, Unk1, MailIdOrMessageType, ChannelId, SecondsSinceMessage, Description, Time) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_PETITION_NAME, "UPDATE petition SET name = ? WHERE petition_id = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_PETITION_SIGNATURE, "INSERT INTO petition_sign (ownerguid, petition_id, playerguid, player_account) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_ACCOUNT_ONLINE, "UPDATE characters SET online = 0 WHERE account = ?", CONNECTION_ASYNC);
@@ -277,6 +277,7 @@ enum CharacterDatabaseStatements : uint32
CHAR_UPD_REM_AT_LOGIN_FLAG,
CHAR_UPD_ALL_AT_LOGIN_FLAGS,
CHAR_INS_BUG_REPORT,
CHAR_INS_SPAM_REPORT,
CHAR_UPD_PETITION_NAME,
CHAR_INS_PETITION_SIGNATURE,
CHAR_UPD_ACCOUNT_ONLINE,
+13 -3
View File
@@ -754,11 +754,21 @@ void WorldSession::HandleCalendarEventModeratorStatus(WorldPacket& recvData)
void WorldSession::HandleCalendarComplain(WorldPackets::Calendar::CalendarComplain& packet)
{
ObjectGuid guid = _player->GetGUID();
if (sWorld->getBoolConfig(CONFIG_LOGSPAMREPORTS))
{
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_SPAM_REPORT);
LOG_DEBUG("network", "CMSG_CALENDAR_COMPLAIN [{}] EventId [{}] guid [{}]", guid.ToString(), packet.EventId, packet.ComplainGuid.ToString());
stmt->SetData(0, 2); // SpamType 2 = Calendar
stmt->SetData(1, packet.ComplainGuid.GetCounter());
stmt->SetData(2, 0);
stmt->SetData(3, 0);
stmt->SetData(4, 0);
stmt->SetData(5, 0);
stmt->SetData(6, "EventId: " + std::to_string(packet.EventId));
stmt->SetData(7, GameTime::GetGameTime().count());
// what to do with complains?
CharacterDatabase.Execute(stmt);
}
}
void WorldSession::HandleCalendarGetNumPending(WorldPacket& /*recvData*/)
+15 -2
View File
@@ -1157,8 +1157,21 @@ void WorldSession::HandleComplainOpcode(WorldPackets::Misc::Complain& packet)
// Complaint Received message
SendPacket(WorldPackets::Misc::ComplainResult().Write());
LOG_DEBUG("network", "REPORT SPAM: type {}, {}, unk1 {}, unk2 {}, unk3 {}, unk4 {}, message {}",
packet.SpamType, packet.SpammerGuid.ToString(), packet.Unk1, packet.Unk2, packet.Unk3, packet.Unk4, packet.Description);
if (sWorld->getBoolConfig(CONFIG_LOGSPAMREPORTS))
{
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_SPAM_REPORT);
stmt->SetData(0, packet.SpamType);
stmt->SetData(1, packet.SpammerGuid.GetCounter());
stmt->SetData(2, packet.Unk1);
stmt->SetData(3, packet.MailIdOrMessageType);
stmt->SetData(4, packet.ChannelId);
stmt->SetData(5, packet.SecondsSinceMessage);
stmt->SetData(6, packet.Description);
stmt->SetData(7, GameTime::GetGameTime().count());
CharacterDatabase.Execute(stmt);
}
}
void WorldSession::HandleRealmSplitOpcode(WorldPacket& recv_data)
@@ -16,6 +16,7 @@
*/
#include "CalendarPackets.h"
#include "Packet.h"
void WorldPackets::Calendar::GetEvent::Read()
{
@@ -149,14 +149,14 @@ void WorldPackets::Misc::Complain::Read()
{
case 0:
_worldPacket >> Unk1; // const 0
_worldPacket >> Unk2; // probably mail id
_worldPacket >> Unk3; // const 0
_worldPacket >> MailIdOrMessageType; // probably mail id
_worldPacket >> ChannelId; // const 0
break;
case 1:
_worldPacket >> Unk1; // probably language
_worldPacket >> Unk2; // message type?
_worldPacket >> Unk3; // probably channel id
_worldPacket >> Unk4; // unk random value
_worldPacket >> MailIdOrMessageType;
_worldPacket >> ChannelId;
_worldPacket >> SecondsSinceMessage;
_worldPacket >> Description; // spam description string (messagetype, channel name, player name, message)
break;
}
+6 -6
View File
@@ -218,13 +218,13 @@ namespace WorldPackets
void Read() override;
uint8 SpamType = 0; // 0 - mail, 1 - chat
uint8 SpamType = 0; // 0 - mail, 1 - chat
ObjectGuid SpammerGuid;
uint32 Unk1 = 0;
uint32 Unk2 = 0;
uint32 Unk3 = 0;
uint32 Unk4 = 0;
std::string Description = "";
uint32 Unk1 = 0;
uint32 MailIdOrMessageType = 0;
uint32 ChannelId = 0;
uint32 SecondsSinceMessage = 0;
std::string Description = "";
};
class ComplainResult final : public ServerPacket
+2
View File
@@ -603,6 +603,8 @@ void WorldConfig::BuildConfigCache()
SetConfigValue<bool>(CONFIG_IP_BASED_ACTION_LOGGING, "Allow.IP.Based.Action.Logging", false);
SetConfigValue<bool>(CONFIG_LOGSPAMREPORTS, "LogSpamReports", true);
// Whether to use LoS from game objects
SetConfigValue<bool>(CONFIG_CHECK_GOBJECT_LOS, "CheckGameObjectLoS", true);
+1
View File
@@ -112,6 +112,7 @@ enum ServerConfigs
CONFIG_ENABLE_CONTINENT_TRANSPORT_PRELOADING,
CONFIG_MINIGOB_MANABONK,
CONFIG_IP_BASED_ACTION_LOGGING,
CONFIG_LOGSPAMREPORTS,
CONFIG_CALCULATE_CREATURE_ZONE_AREA_DATA,
CONFIG_CALCULATE_GAMEOBJECT_ZONE_AREA_DATA,
CONFIG_CHECK_GOBJECT_LOS,