aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/updates/world/2015_02_02_00_world_from_335.sql16
-rw-r--r--sql/updates/world/2015_02_02_01_world.sql33
-rw-r--r--src/server/game/Entities/Object/Object.cpp2
-rw-r--r--src/server/game/Entities/Player/Player.cpp39
-rw-r--r--src/server/game/Entities/Player/Player.h4
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp49
-rw-r--r--src/server/game/Handlers/TicketHandler.cpp19
-rw-r--r--src/server/game/Server/Packets/TicketPackets.cpp82
-rw-r--r--src/server/game/Server/Packets/TicketPackets.h135
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp11
-rw-r--r--src/server/game/Server/WorldSession.h14
-rw-r--r--src/server/game/Spells/SpellEffects.cpp2
-rw-r--r--src/server/game/Spells/SpellMgr.cpp2
-rw-r--r--src/server/game/Tickets/TicketMgr.cpp51
-rw-r--r--src/server/game/Tickets/TicketMgr.h2
-rw-r--r--src/server/game/World/World.cpp8
-rw-r--r--src/server/game/World/World.h4
-rw-r--r--src/server/shared/DataStores/DB2Store.h3
-rw-r--r--src/server/shared/Database/DatabaseWorkerPool.h9
-rw-r--r--src/server/shared/Database/MySQLConnection.cpp12
-rw-r--r--src/server/shared/Database/MySQLConnection.h2
-rw-r--r--src/server/shared/Database/Transaction.cpp8
-rw-r--r--src/server/shared/Packets/ByteBuffer.h6
-rw-r--r--src/server/worldserver/worldserver.conf.dist25
24 files changed, 402 insertions, 136 deletions
diff --git a/sql/updates/world/2015_02_02_00_world_from_335.sql b/sql/updates/world/2015_02_02_00_world_from_335.sql
new file mode 100644
index 00000000000..84d31ef7be1
--- /dev/null
+++ b/sql/updates/world/2015_02_02_00_world_from_335.sql
@@ -0,0 +1,16 @@
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=22 AND `SourceEntry` IN(29491,28994,28721,28725,33027,28727,28715,28714,28726,29523,28989,28997,28723,28718);
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(22, 1, 29491, 0, 0, 31, 0, 4, 0, 0, 0, 0, 0, '', 'Karandonna - Only run SAI if invoker is player'),
+(22, 1, 28994, 0, 0, 31, 0, 4, 0, 0, 0, 0, 0, '', 'Abra Cadabra - Only run SAI if invoker is player'),
+(22, 1, 28721, 0, 0, 31, 0, 4, 0, 0, 0, 0, 0, '', 'Tiffany Cartier - Only run SAI if invoker is player'),
+(22, 1, 28725, 0, 0, 31, 0, 4, 0, 0, 0, 0, 0, '', 'Patricia Egan - Only run SAI if invoker is player'),
+(22, 1, 33027, 0, 0, 31, 0, 4, 0, 0, 0, 0, 0, '', 'Jessica Sellers - Only run SAI if invoker is player'),
+(22, 1, 28727, 0, 0, 31, 0, 4, 0, 0, 0, 0, 0, '', 'Edward Egan - Only run SAI if invoker is player'),
+(22, 1, 28714, 0, 0, 31, 0, 4, 0, 0, 0, 0, 0, '', 'Ildine Sorrowspear - Only run SAI if invoker is player'),
+(22, 1, 28715, 0, 0, 31, 0, 4, 0, 0, 0, 0, 0, '', 'Endora Moorehead - Only run SAI if invoker is player'),
+(22, 1, 28726, 0, 0, 31, 0, 4, 0, 0, 0, 0, 0, '', 'Dominique Stefano - Only run SAI if invoker is player'),
+(22, 1, 29523, 0, 0, 31, 0, 4, 0, 0, 0, 0, 0, '', 'Bragund Brightlink - Only run SAI if invoker is player'),
+(22, 1, 28997, 0, 0, 31, 0, 4, 0, 0, 0, 0, 0, '', 'Griselda Hunderland - Only run SAI if invoker is player'),
+(22, 1, 28989, 0, 0, 31, 0, 4, 0, 0, 0, 0, 0, '', 'Aemara - Only run SAI if invoker is player'),
+(22, 1, 28723, 0, 0, 31, 0, 4, 0, 0, 0, 0, 0, '', 'Larana Drome - Only run SAI if invoker is player'),
+(22, 1, 28718, 0, 0, 31, 0, 4, 0, 0, 0, 0, 0, '', 'Ranid Glowergold - Only run SAI if invoker is player');
diff --git a/sql/updates/world/2015_02_02_01_world.sql b/sql/updates/world/2015_02_02_01_world.sql
index 48b4cc32950..3683d2db6af 100644
--- a/sql/updates/world/2015_02_02_01_world.sql
+++ b/sql/updates/world/2015_02_02_01_world.sql
@@ -4415,36 +4415,3 @@ INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language
(18230, 0, 3, 'When I catch you, I''m going to disenchant your components, so help me...', 12, 1, 100, 0, 0, 0, 15015, 'Trayanise'),
(18230, 0, 4, 'Get back here, you little...', 12, 1, 100, 0, 0, 0, 15012, 'Trayanise'),
(18230, 0, 5, 'You stay out of the regent lord''s way! I mean it!', 12, 1, 100, 0, 0, 0, 15014, 'Trayanise');
-
-DELETE FROM `creature_text` WHERE `entry` IN(37158,37704);
-DELETE FROM `creature_text` WHERE `entry`=37225 AND `groupid` > 15;
-INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `comment`, `BroadcastTextID`) VALUES
-(37158, 0, 0, '%s prepares to attack!', 41, 0, 100, 0, 0, 0, 'Quel''Delar', 37211),
-(37704, 0, 0, 'Quel''Delar leaps to life in the presence of Frostmourne!', 41, 0, 100, 0, 0, 0, 'Frostmourne Altar Bunny (Quel''Delar)', 37645),
--- Uther
-(37225, 16, 0, 'Halt! Do not carry that blade any further!', 14, 0, 100, 25, 0, 16675, 'Uther the Lightbringer', 37201),
-(37225, 17, 0, 'Do you realize what you''ve done?', 14, 0, 100, 5, 0, 16676, 'Uther the Lightbringer', 37202),
-(37225, 18, 0, 'You have forged this blade from saronite, the very blood of an old god. The power of the Lich King calls to this weapon.', 12, 0, 100, 1, 0, 16677, 'Uther the Lightbringer', 37204),
-(37225, 19, 0, 'Each moment you tarry here, Quel''Delar drinks in the evil of this place.', 12, 0, 100, 1, 0, 16678, 'Uther the Lightbringer', 38442),
-(37225, 20, 0, 'There is only one way to cleanse this sword. Make haste for the Sunwell and immerse the blade in its waters.', 12, 0, 100, 25, 0, 16679, 'Uther the Lightbringer', 37205),
-(37225, 21, 0, 'I can resist Frostmourne''s call no more...', 12, 0, 100, 1, 0, 16680, 'Uther the Lightbringer', 37206);
-
-UPDATE `creature_template` SET `unit_flags`=768, `flags_extra`=0, `ScriptName`='npc_quel_delar_sword', `InhabitType`=7 WHERE `entry`=37158;
-UPDATE `creature_template` SET `ScriptName`='npc_uther_quel_delar' WHERE `entry`=37225;
-
-DELETE FROM `areatrigger_scripts` WHERE `entry`=5660;
-INSERT INTO `areatrigger_scripts` (`entry`,`ScriptName`) VALUES
-(5660, 'at_hor_uther_quel_delar_start');
-
-DELETE FROM `spell_target_position` WHERE `ID` IN(70719,70700);
-INSERT INTO `spell_target_position` (`ID`,`MapID`,`PositionX`,`PositionY`,`PositionZ`) VALUES
-(70719, 668, 5302, 1989, 708),
-(70700, 668, 5298, 1995, 708);
-
-DELETE FROM `creature_loot_template` WHERE `entry` = 37158 AND `item` = 50254;
-INSERT INTO `creature_loot_template` (`Entry`, `Item`, `Chance`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`) VALUES
-(37158, 50254, 100, 1, 0, 1, 1);
-
-DELETE FROM `conditions` WHERE `SourceEntry` = 73035 AND `SourceTypeOrReferenceId` = 13;
-INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `Comment`) VALUES
-(13,1,73035,0,0,31,0,3,37704,0,0,0,0,'Essence of the Captured (73035) only hits Frostmourne Altar Bunny (Quel''Delar)');
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index 5e419c2017f..335df6505a6 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -1401,7 +1401,7 @@ void Object::AddDynamicValue(uint16 index, uint32 value)
if (mask.GetCount() < values.size())
mask.AddBlock();
- mask.SetBit(values.size());
+ mask.SetBit(values.size() - 1);
if (m_inWorld && !m_objectUpdated)
{
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 0a95fed3138..46e455765d3 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -2935,6 +2935,7 @@ void Player::GiveLevel(uint8 level)
SetLevel(level);
UpdateSkillsForLevel();
+ LearnSpecializationSpells();
// save base values (bonuses already included in stored stats
for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
@@ -3046,6 +3047,7 @@ void Player::InitStatsForLevel(bool reapplyMods)
SetUInt32Value(UNIT_FIELD_AURASTATE, 0);
UpdateSkillsForLevel();
+ LearnSpecializationSpells();
// set default cast time multiplier
SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f);
@@ -4141,12 +4143,6 @@ bool Player::ResetTalents(bool noCost)
RemoveTalent(talentInfo);
}
- // Remove spec specific spells
- RemoveSpecializationSpells();
-
- SetSpecId(GetActiveTalentGroup(), 0);
- SetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID, 0);
-
SQLTransaction trans = CharacterDatabase.BeginTransaction();
_SaveTalents(trans);
_SaveSpells(trans);
@@ -27163,25 +27159,28 @@ Difficulty Player::CheckLoadedLegacyRaidDifficultyID(Difficulty difficulty)
SpellInfo const* Player::GetCastSpellInfo(SpellInfo const* spellInfo) const
{
- auto range = m_overrideSpells.equal_range(spellInfo->Id);
- for (auto itr = range.first; itr != range.second; ++itr)
- if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo(itr->second))
+ auto overrides = m_overrideSpells.find(spellInfo->Id);
+ for (uint32 spellId : overrides->second)
+ if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo(spellId))
return Unit::GetCastSpellInfo(newInfo);
return Unit::GetCastSpellInfo(spellInfo);
}
+void Player::AddOverrideSpell(uint32 overridenSpellId, uint32 newSpellId)
+{
+ m_overrideSpells[overridenSpellId].insert(newSpellId);
+}
+
void Player::RemoveOverrideSpell(uint32 overridenSpellId, uint32 newSpellId)
{
- auto range = m_overrideSpells.equal_range(overridenSpellId);
- for (auto itr = range.first; itr != range.second; ++itr)
- {
- if (itr->second == newSpellId)
- {
- m_overrideSpells.erase(itr);
- break;
- }
- }
+ auto overrides = m_overrideSpells.find(overridenSpellId);
+ if (overrides == m_overrideSpells.end())
+ return;
+
+ overrides->second.erase(newSpellId);
+ if (overrides->second.empty())
+ m_overrideSpells.erase(overrides);
}
void Player::LearnSpecializationSpells()
@@ -27191,6 +27190,10 @@ void Player::LearnSpecializationSpells()
for (size_t j = 0; j < specSpells->size(); ++j)
{
SpecializationSpellsEntry const* specSpell = specSpells->at(j);
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(specSpell->SpellID);
+ if (!spellInfo || spellInfo->SpellLevel > getLevel())
+ continue;
+
LearnSpell(specSpell->SpellID, false);
if (specSpell->OverridesSpellID)
AddOverrideSpell(specSpell->OverridesSpellID, specSpell->SpellID);
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 064fba79fb1..7366bde52d7 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1837,7 +1837,7 @@ class Player : public Unit, public GridObject<Player>
void LearnSpellHighestRank(uint32 spellid);
void AddTemporarySpell(uint32 spellId);
void RemoveTemporarySpell(uint32 spellId);
- void AddOverrideSpell(uint32 overridenSpellId, uint32 newSpellId) { m_overrideSpells.emplace(overridenSpellId, newSpellId); }
+ void AddOverrideSpell(uint32 overridenSpellId, uint32 newSpellId);
void RemoveOverrideSpell(uint32 overridenSpellId, uint32 newSpellId);
void LearnSpecializationSpells();
void RemoveSpecializationSpells();
@@ -2795,7 +2795,7 @@ class Player : public Unit, public GridObject<Player>
PlayerMails m_mail;
PlayerSpellMap m_spells;
- std::unordered_multimap<uint32 /*overridenSpellId*/, uint32 /*newSpellId*/> m_overrideSpells;
+ std::unordered_map<uint32 /*overridenSpellId*/, std::unordered_set<uint32> /*newSpellId*/> m_overrideSpells;
uint32 m_lastPotionId; // last used health/mana potion in combat, that block next potion use
GlobalCooldownMgr m_GlobalCooldownMgr;
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index 16fb72c88a4..f121eefa71c 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -867,24 +867,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder)
SendPacket(accountDataTimes.Write());
- /// Send FeatureSystemStatus
- {
- WorldPackets::System::FeatureSystemStatus features;
-
- /// START OF DUMMY VALUES
- features.ComplaintStatus = 2;
- features.ScrollOfResurrectionRequestsRemaining = 1;
- features.ScrollOfResurrectionMaxRequestsPerDay = 1;
- features.CfgRealmID = 2;
- features.CfgRealmRecID = 0;
- features.VoiceEnabled = false;
- /// END OF DUMMY VALUES
-
- features.CharUndeleteEnabled = sWorld->getBoolConfig(CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_ENABLED);
- features.BpayStoreEnabled = sWorld->getBoolConfig(CONFIG_FEATURE_SYSTEM_BPAY_STORE_ENABLED);
-
- SendPacket(features.Write());
- }
+ SendFeatureSystemStatus();
// Send MOTD
{
@@ -1091,10 +1074,36 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder)
delete holder;
}
-void WorldSession::HandleSetFactionAtWar(WorldPacket& recvData)
+void WorldSession::SendFeatureSystemStatus()
{
- TC_LOG_DEBUG("network", "WORLD: Received CMSG_SET_FACTION_AT_WAR");
+ WorldPackets::System::FeatureSystemStatus features;
+
+ /// START OF DUMMY VALUES
+ features.ComplaintStatus = 2;
+ features.ScrollOfResurrectionRequestsRemaining = 1;
+ features.ScrollOfResurrectionMaxRequestsPerDay = 1;
+ features.CfgRealmID = 2;
+ features.CfgRealmRecID = 0;
+ features.VoiceEnabled = false;
+ features.BrowserEnabled = false; // Has to be false, otherwise client will crash if "Customer Support" is opened
+
+ features.EuropaTicketSystemStatus.HasValue = true;
+ features.EuropaTicketSystemStatus.Value.ThrottleState.MaxTries = 5;
+ features.EuropaTicketSystemStatus.Value.ThrottleState.PerMilliseconds = 5;
+ features.EuropaTicketSystemStatus.Value.ThrottleState.TryCount = 0;
+ features.EuropaTicketSystemStatus.Value.ThrottleState.LastResetTimeBeforeNow = time(nullptr) - 5000;
+ /// END OF DUMMY VALUES
+
+ features.EuropaTicketSystemStatus.Value.SubmitBugEnabled = sWorld->getBoolConfig(CONFIG_TICKET_SUBMIT_BUG);
+ features.EuropaTicketSystemStatus.Value.TicketSystemEnabled = sWorld->getBoolConfig(CONFIG_TICKET_SUBMIT_TICKET);
+ features.CharUndeleteEnabled = sWorld->getBoolConfig(CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_ENABLED);
+ features.BpayStoreEnabled = sWorld->getBoolConfig(CONFIG_FEATURE_SYSTEM_BPAY_STORE_ENABLED);
+
+ SendPacket(features.Write());
+}
+void WorldSession::HandleSetFactionAtWar(WorldPacket& recvData)
+{
uint32 repListID;
uint8 flag;
diff --git a/src/server/game/Handlers/TicketHandler.cpp b/src/server/game/Handlers/TicketHandler.cpp
index a6b58f18ef4..5b2e197ae7a 100644
--- a/src/server/game/Handlers/TicketHandler.cpp
+++ b/src/server/game/Handlers/TicketHandler.cpp
@@ -23,6 +23,7 @@
#include "Opcodes.h"
#include "Player.h"
#include "TicketMgr.h"
+#include "TicketPackets.h"
#include "Util.h"
#include "World.h"
#include "WorldPacket.h"
@@ -156,13 +157,19 @@ void WorldSession::HandleGMTicketDeleteOpcode(WorldPacket & /*recvData*/)
}
}
-void WorldSession::HandleGMTicketGetTicketOpcode(WorldPacket & /*recvData*/)
+void WorldSession::HandleGMTicketGetCaseStatusOpcode(WorldPackets::Ticket::GMTicketGetCaseStatus& /*packet*/)
+{
+ // TODO: Implement GmCase and handle this packet correctly
+}
+
+void WorldSession::HandleGMTicketGetTicketOpcode(WorldPackets::Ticket::GMTicketGetTicket& /*packet*/)
{
SendQueryTimeResponse();
if (GmTicket* ticket = sTicketMgr->GetTicketByPlayer(GetPlayer()->GetGUID()))
{
if (ticket->IsCompleted())
+ // TODO: Update SMSG_GM_TICKET_RESPONSE
ticket->SendResponse(this);
else
sTicketMgr->SendTicket(this, ticket);
@@ -171,13 +178,13 @@ void WorldSession::HandleGMTicketGetTicketOpcode(WorldPacket & /*recvData*/)
sTicketMgr->SendTicket(this, NULL);
}
-void WorldSession::HandleGMTicketSystemStatusOpcode(WorldPacket & /*recvData*/)
+void WorldSession::HandleGMTicketSystemStatusOpcode(WorldPackets::Ticket::GMTicketGetSystemStatus& /*packet*/)
{
// Note: This only disables the ticket UI at client side and is not fully reliable
- // are we sure this is a uint32? Should ask Zor
- WorldPacket data(SMSG_GM_TICKET_SYSTEM_STATUS, 4);
- data << uint32(sTicketMgr->GetStatus() ? GMTICKET_QUEUE_STATUS_ENABLED : GMTICKET_QUEUE_STATUS_DISABLED);
- SendPacket(&data);
+ // Note: This disables the whole customer support UI after trying to send a ticket in disabled state (MessageBox: "GM Help Tickets are currently unavaiable."). UI remains disabled until the character relogs.
+ WorldPackets::Ticket::GMTicketSystemStatus response;
+ response.Status = sTicketMgr->GetStatus() ? GMTICKET_QUEUE_STATUS_ENABLED : GMTICKET_QUEUE_STATUS_DISABLED;
+ SendPacket(response.Write());
}
void WorldSession::HandleGMSurveySubmit(WorldPacket& recvData)
diff --git a/src/server/game/Server/Packets/TicketPackets.cpp b/src/server/game/Server/Packets/TicketPackets.cpp
new file mode 100644
index 00000000000..8567cebd736
--- /dev/null
+++ b/src/server/game/Server/Packets/TicketPackets.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program 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 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "TicketPackets.h"
+
+WorldPacket const* WorldPackets::Ticket::GMTicketSystemStatus::Write()
+{
+ _worldPacket << int32(Status);
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Ticket::GMTicketCaseStatus::Write()
+{
+ _worldPacket.AppendPackedTime(OldestTicketTime);
+ _worldPacket.AppendPackedTime(UpdateTime);
+
+ _worldPacket << int32(Cases.size());
+
+ for (auto const& c : Cases)
+ {
+ _worldPacket << int32(c.CaseID);
+ _worldPacket << int32(c.CaseOpened);
+ _worldPacket << int32(c.CaseStatus);
+ _worldPacket << int16(c.CfgRealmID);
+ _worldPacket << int64(c.CharacterID);
+ _worldPacket << int32(c.WaitTimeOverrideMinutes);
+
+ _worldPacket.WriteBits(c.Url.size(), 11);
+ _worldPacket.WriteBits(c.WaitTimeOverrideMessage.size(), 10);
+ }
+
+ _worldPacket.FlushBits();
+ return &_worldPacket;
+}
+
+void WorldPackets::Ticket::GMTicketAcknowledgeSurvey::Read()
+{
+ _worldPacket >> CaseID;
+}
+
+WorldPacket const* WorldPackets::Ticket::GMTicketGetTicketResponse::Write()
+{
+ _worldPacket << Result;
+ _worldPacket.WriteBit(Info.HasValue);
+
+ if (Info.HasValue)
+ {
+ _worldPacket << int32(Info.Value.TicketID);
+ _worldPacket << uint8(Info.Value.Category);
+ _worldPacket.AppendPackedTime(Info.Value.TicketOpenTime);
+ _worldPacket.AppendPackedTime(Info.Value.OldestTicketTime);
+ _worldPacket.AppendPackedTime(Info.Value.UpdateTime);
+ _worldPacket << uint8(Info.Value.AssignedToGM);
+ _worldPacket << uint8(Info.Value.OpenedByGM);
+ _worldPacket << int32(Info.Value.WaitTimeOverrideMinutes);
+
+ _worldPacket.WriteBits(Info.Value.TicketDescription.size(), 11);
+ _worldPacket.WriteBits(Info.Value.WaitTimeOverrideMessage.size(), 10);
+
+ _worldPacket.WriteString(Info.Value.TicketDescription);
+ _worldPacket.WriteString(Info.Value.WaitTimeOverrideMessage);
+ }
+
+ _worldPacket.FlushBits();
+
+ return &_worldPacket;
+}
diff --git a/src/server/game/Server/Packets/TicketPackets.h b/src/server/game/Server/Packets/TicketPackets.h
new file mode 100644
index 00000000000..076db67fb96
--- /dev/null
+++ b/src/server/game/Server/Packets/TicketPackets.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program 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 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TicketPackets_h__
+#define TicketPackets_h__
+
+#include "Packet.h"
+
+namespace WorldPackets
+{
+ namespace Ticket
+ {
+ class GMTicketGetSystemStatus final : public ClientPacket
+ {
+ public:
+ GMTicketGetSystemStatus(WorldPacket&& packet) : ClientPacket(CMSG_GM_TICKET_GET_SYSTEM_STATUS, std::move(packet)) { }
+
+ void Read() override { };
+ };
+
+ class GMTicketSystemStatus final : public ServerPacket
+ {
+ public:
+ GMTicketSystemStatus() : ServerPacket(SMSG_GM_TICKET_SYSTEM_STATUS, 4) { }
+
+ WorldPacket const* Write() override;
+
+ int32 Status = 0;
+ };
+
+ class GMTicketGetCaseStatus final : public ClientPacket
+ {
+ public:
+ GMTicketGetCaseStatus(WorldPacket&& packet) : ClientPacket(CMSG_GM_TICKET_GET_CASE_STATUS, std::move(packet)) { }
+
+ void Read() override { };
+ };
+
+ class GMTicketCaseStatus final : public ServerPacket
+ {
+ public:
+ struct GMTicketCase
+ {
+ int32 CaseID = 0;
+ int32 CaseOpened = 0;
+ int32 CaseStatus = 0;
+ int16 CfgRealmID = 0;
+ int64 CharacterID = 0;
+ int32 WaitTimeOverrideMinutes = 0;
+ std::string Url;
+ std::string WaitTimeOverrideMessage;
+
+ bool operator<(GMTicketCase const& right) const
+ {
+ return CaseID < right.CaseID;
+ }
+ };
+
+ GMTicketCaseStatus() : ServerPacket(SMSG_GM_TICKET_CASE_STATUS, 12) { }
+
+ WorldPacket const* Write() override;
+
+ time_t OldestTicketTime = 0;
+ time_t UpdateTime = 0;
+ std::set<GMTicketCase> Cases;
+ };
+
+ class GMTicketGetTicket final : public ClientPacket
+ {
+ public:
+ GMTicketGetTicket(WorldPacket&& packet) : ClientPacket(CMSG_GM_TICKET_GET_TICKET, std::move(packet)) { }
+
+ void Read() override { }
+ };
+
+ class GMTicketGetTicketResponse final : public ServerPacket
+ {
+ public:
+ struct GMTicketInfo
+ {
+ int32 TicketID = 0;
+ std::string TicketDescription;
+ uint8 Category = 0;
+ time_t TicketOpenTime = 0;
+ time_t OldestTicketTime = 0;
+ time_t UpdateTime = 0;
+ uint8 AssignedToGM = 0;
+ uint8 OpenedByGM = 0;
+ std::string WaitTimeOverrideMessage;
+ int32 WaitTimeOverrideMinutes = 0;
+ };
+
+ GMTicketGetTicketResponse() : ServerPacket(SMSG_GM_TICKET_GET_TICKET_RESPONSE, 5) { }
+
+ WorldPacket const* Write() override;
+
+ int32 Result = 0;
+ Optional<GMTicketInfo> Info;
+ };
+
+ class GMTicketAcknowledgeSurvey final : public ClientPacket
+ {
+ public:
+ GMTicketAcknowledgeSurvey(WorldPacket&& packet) : ClientPacket(CMSG_GM_TICKET_ACKNOWLEDGE_SURVEY, std::move(packet)) { }
+
+ void Read() override;
+
+ int32 CaseID;
+ };
+
+ class GMTicketResponseError final : public ServerPacket
+ {
+ public:
+ GMTicketResponseError() : ServerPacket(SMSG_GM_TICKET_RESPONSE_ERROR, 0) { }
+
+ WorldPacket const* Write() { return &_worldPacket; }
+ };
+ }
+}
+
+#endif // TicketPackets_h__
diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp
index 0cdd9ffa1fe..0dfb5b9d016 100644
--- a/src/server/game/Server/Protocol/Opcodes.cpp
+++ b/src/server/game/Server/Protocol/Opcodes.cpp
@@ -40,6 +40,7 @@
#include "Packets/QuestPackets.h"
#include "Packets/TalentPackets.h"
#include "Packets/TradePackets.h"
+#include "Packets/TicketPackets.h"
template<class PacketClass, void(WorldSession::*HandlerFunction)(PacketClass&)>
class PacketHandler : public ClientOpcodeHandler
@@ -387,11 +388,13 @@ void OpcodeTable::Initialize()
DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_SET_SECURITY_GROUP, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_SURVEY_SUBMIT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGMSurveySubmit );
DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_TICKET_ACKNOWLEDGE_SURVEY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
+ //DEFINE_HANDLER(CMSG_GM_TICKET_ACKNOWLEDGE_SURVEY, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Ticket::GMTicketAcknowledgeSurvey, &WorldSession::HandleGMTicketAcknowledgeSurveyOpcode);
DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_TICKET_CREATE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGMTicketCreateOpcode );
DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_TICKET_DELETE_TICKET, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGMTicketDeleteOpcode );
DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_TICKET_GET_CASE_STATUS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
- DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_TICKET_GET_SYSTEM_STATUS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGMTicketSystemStatusOpcode);
- DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_TICKET_GET_TICKET, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGMTicketGetTicketOpcode );
+ //DEFINE_HANDLER(CMSG_GM_TICKET_GET_CASE_STATUS, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Ticket::GMTicketGetCaseStatus, &WorldSession::HandleGMTicketGetCaseStatusOpcode);
+ DEFINE_HANDLER(CMSG_GM_TICKET_GET_SYSTEM_STATUS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Ticket::GMTicketGetSystemStatus, &WorldSession::HandleGMTicketSystemStatusOpcode);
+ DEFINE_HANDLER(CMSG_GM_TICKET_GET_TICKET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Ticket::GMTicketGetTicket, &WorldSession::HandleGMTicketGetTicketOpcode);
DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_TICKET_RESPONSE_RESOLVE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGMResponseResolve );
DEFINE_OPCODE_HANDLER_OLD(CMSG_GM_TICKET_UPDATE_TEXT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGMTicketUpdateOpcode );
DEFINE_HANDLER(CMSG_GOSSIP_HELLO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::NPC::Hello, &WorldSession::HandleGossipHelloOpcode);
@@ -1277,12 +1280,12 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_PLAYER_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_REQUEST_PLAYER_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_CASE_STATUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_GET_TICKET_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_GET_TICKET_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_RESOLVE_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_RESPONSE_ERROR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_STATUS_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_SYSTEM_STATUS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_SYSTEM_STATUS, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GOD_MODE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GOSSIP_COMPLETE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index a97acc23ead..2b54b5d794d 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -267,6 +267,14 @@ namespace WorldPackets
class LearnTalents;
}
+ namespace Ticket
+ {
+ class GMTicketGetSystemStatus;
+ class GMTicketGetCaseStatus;
+ class GMTicketGetTicket;
+ class GMTicketAcknowledgeSurvey;
+ }
+
namespace Trade
{
class CancelTrade;
@@ -510,6 +518,7 @@ class WorldSession
void SendAuthWaitQue(uint32 position);
void SendSetTimeZoneInformation();
+ void SendFeatureSystemStatus();
void SendFeatureSystemStatusGlueScreen();
void SendNameQueryOpcode(ObjectGuid guid);
@@ -736,8 +745,9 @@ class WorldSession
void HandleGMTicketCreateOpcode(WorldPacket& recvPacket);
void HandleGMTicketUpdateOpcode(WorldPacket& recvPacket);
void HandleGMTicketDeleteOpcode(WorldPacket& recvPacket);
- void HandleGMTicketGetTicketOpcode(WorldPacket& recvPacket);
- void HandleGMTicketSystemStatusOpcode(WorldPacket& recvPacket);
+ void HandleGMTicketGetCaseStatusOpcode(WorldPackets::Ticket::GMTicketGetCaseStatus& packet);
+ void HandleGMTicketGetTicketOpcode(WorldPackets::Ticket::GMTicketGetTicket& packet);
+ void HandleGMTicketSystemStatusOpcode(WorldPackets::Ticket::GMTicketGetSystemStatus& packet);
void HandleGMSurveySubmit(WorldPacket& recvPacket);
void HandleReportLag(WorldPacket& recvPacket);
void HandleGMResponseResolve(WorldPacket& recvPacket);
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 7c5ab810ce4..4e52adf9944 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -5769,7 +5769,7 @@ void Spell::EffectCreateAreaTrigger(SpellEffIndex /*effIndex*/)
delete areaTrigger;
}
-void Spell::EffectRemoveTalent(SpellEffIndex effIndex)
+void Spell::EffectRemoveTalent(SpellEffIndex /*effIndex*/)
{
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
return;
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index d0eff5fff00..5dd41eb9bcf 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -3072,6 +3072,8 @@ void SpellMgr::LoadSpellInfoCorrections()
case 45976: // Muru Portal Channel
case 52124: // Sky Darkener Assault
case 53096: // Quetz'lun's Judgment
+ case 70743: // AoD Special
+ case 70614: // AoD Special - Vegard
case 52479: // Gift of the Harvester
case 61588: // Blazing Harpoon
spellInfo->MaxAffectedTargets = 1;
diff --git a/src/server/game/Tickets/TicketMgr.cpp b/src/server/game/Tickets/TicketMgr.cpp
index 7cd27fdaa62..84dac6cc175 100644
--- a/src/server/game/Tickets/TicketMgr.cpp
+++ b/src/server/game/Tickets/TicketMgr.cpp
@@ -18,6 +18,7 @@
#include "Common.h"
#include "TicketMgr.h"
+#include "TicketPackets.h"
#include "DatabaseEnv.h"
#include "Log.h"
#include "Language.h"
@@ -28,7 +29,7 @@
#include "Player.h"
#include "Opcodes.h"
-inline float GetAge(uint64 t) { return float(time(NULL) - t) / DAY; }
+inline time_t GetAge(uint64 t) { return (time(NULL) - t) / DAY; }
///////////////////////////////////////////////////////////////////////////////////////////////////
// GM ticket
@@ -113,30 +114,6 @@ void GmTicket::DeleteFromDB()
CharacterDatabase.Execute(stmt);
}
-void GmTicket::WritePacket(WorldPacket& data) const
-{
- data << uint32(GMTICKET_STATUS_HASTEXT);
- data << uint32(_id);
- data << _message;
- data << uint8(_needMoreHelp);
- data << GetAge(_lastModifiedTime);
- if (GmTicket* ticket = sTicketMgr->GetOldestOpenTicket())
- data << GetAge(ticket->GetLastModifiedTime());
- else
- data << float(0);
-
- // I am not sure how blizzlike this is, and we don't really have a way to find out
- data << GetAge(sTicketMgr->GetLastChange());
-
- data << uint8(std::min(_escalatedStatus, TICKET_IN_ESCALATION_QUEUE)); // escalated data
- data << uint8(_viewed ? GMTICKET_OPENEDBYGM_STATUS_OPENED : GMTICKET_OPENEDBYGM_STATUS_NOT_OPENED); // whether or not it has been viewed
-
- // TODO: implement these
- std::string waitTimeOverrideMessage = "";
- data << waitTimeOverrideMessage;
- data << uint32(0); // waitTimeOverrideMinutes
-}
-
void GmTicket::SendResponse(WorldSession* session) const
{
WorldPacket data(SMSG_GM_TICKET_RESPONSE);
@@ -267,7 +244,7 @@ TicketMgr::~TicketMgr()
void TicketMgr::Initialize()
{
- SetStatus(sWorld->getBoolConfig(CONFIG_ALLOW_TICKETS));
+ SetStatus(sWorld->getBoolConfig(CONFIG_TICKET_SYSTEM_STATUS));
}
void TicketMgr::ResetTickets()
@@ -408,12 +385,26 @@ void TicketMgr::ShowEscalatedList(ChatHandler& handler) const
void TicketMgr::SendTicket(WorldSession* session, GmTicket* ticket) const
{
- WorldPacket data(SMSG_GM_TICKET_GET_TICKET_RESPONSE, (ticket ? (4 + 4 + 1 + 4 + 4 + 4 + 1 + 1) : 4));
+ WorldPackets::Ticket::GMTicketGetTicketResponse response;
if (ticket)
- ticket->WritePacket(data);
+ {
+ response.Result = GMTICKET_STATUS_HASTEXT;
+ response.Info.HasValue = true;
+
+ response.Info.Value.TicketID = ticket->GetId();
+ response.Info.Value.TicketDescription = ticket->GetMessage();
+ response.Info.Value.Category = ticket->GetNeedMoreHelp();
+ response.Info.Value.TicketOpenTime = GetAge(ticket->GetLastModifiedTime());
+ response.Info.Value.OldestTicketTime = sTicketMgr->GetOldestOpenTicket() ? GetAge(sTicketMgr->GetOldestOpenTicket()->GetLastModifiedTime()) : float(0);
+ response.Info.Value.UpdateTime = GetAge(sTicketMgr->GetLastChange());
+ response.Info.Value.AssignedToGM = ticket->IsAssigned();
+ response.Info.Value.OpenedByGM = ticket->IsViewed();
+ response.Info.Value.WaitTimeOverrideMessage = "";
+ response.Info.Value.WaitTimeOverrideMinutes = 0;
+ }
else
- data << uint32(GMTICKET_STATUS_DEFAULT);
+ response.Result = GMTICKET_STATUS_DEFAULT;
- session->SendPacket(&data);
+ session->SendPacket(response.Write());
}
diff --git a/src/server/game/Tickets/TicketMgr.h b/src/server/game/Tickets/TicketMgr.h
index 4dd94cc1762..578d93bb128 100644
--- a/src/server/game/Tickets/TicketMgr.h
+++ b/src/server/game/Tickets/TicketMgr.h
@@ -90,11 +90,13 @@ public:
bool IsAssigned() const { return !_assignedTo.IsEmpty(); }
bool IsAssignedTo(ObjectGuid guid) const { return guid == _assignedTo; }
bool IsAssignedNotTo(ObjectGuid guid) const { return IsAssigned() && !IsAssignedTo(guid); }
+ bool IsViewed() const { return _viewed; }
uint32 GetId() const { return _id; }
Player* GetPlayer() const { return ObjectAccessor::FindPlayer(_playerGuid); }
std::string const& GetPlayerName() const { return _playerName; }
std::string const& GetMessage() const { return _message; }
+ bool const GetNeedMoreHelp() const { return _needMoreHelp; }
Player* GetAssignedPlayer() const { return ObjectAccessor::FindPlayer(_assignedTo); }
ObjectGuid GetAssignedToGUID() const { return _assignedTo; }
std::string GetAssignedToName() const
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index fe3c4b76167..7885819af9f 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -278,6 +278,7 @@ void World::AddSession_(WorldSession* s)
s->SendAuthResponse(AUTH_OK, false);
s->SendSetTimeZoneInformation();
+ s->SendFeatureSystemStatus();
s->SendFeatureSystemStatusGlueScreen();
s->SendAddonsInfo();
@@ -377,6 +378,7 @@ bool World::RemoveQueuedPlayer(WorldSession* sess)
pop_sess->SendAuthWaitQue(0);
pop_sess->SendSetTimeZoneInformation();
+ pop_sess->SendFeatureSystemStatus();
pop_sess->SendFeatureSystemStatusGlueScreen();
pop_sess->SendAddonsInfo();
@@ -428,7 +430,11 @@ void World::LoadConfigSettings(bool reload)
SetMotd(sConfigMgr->GetStringDefault("Motd", "Welcome to a Trinity Core Server."));
///- Read ticket system setting from the config file
- m_bool_configs[CONFIG_ALLOW_TICKETS] = sConfigMgr->GetBoolDefault("AllowTickets", true);
+ m_bool_configs[CONFIG_TICKET_SYSTEM_STATUS] = sConfigMgr->GetBoolDefault("Ticket.SystemStatus", true);
+ if (reload)
+ sTicketMgr->SetStatus(m_bool_configs[CONFIG_TICKET_SYSTEM_STATUS]);
+ m_bool_configs[CONFIG_TICKET_SUBMIT_TICKET] = sConfigMgr->GetBoolDefault("Ticket.SubmitTicket", false);
+ m_bool_configs[CONFIG_TICKET_SUBMIT_BUG] = sConfigMgr->GetBoolDefault("Ticket.SubmitBug", false);
///- Get string for new logins (newly created characters)
SetNewCharString(sConfigMgr->GetStringDefault("PlayerStart.String", ""));
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 2526516d778..c30d4f6ca35 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -151,7 +151,9 @@ enum WorldBoolConfigs
CONFIG_SHOW_MUTE_IN_WORLD,
CONFIG_SHOW_BAN_IN_WORLD,
CONFIG_AUTOBROADCAST,
- CONFIG_ALLOW_TICKETS,
+ CONFIG_TICKET_SYSTEM_STATUS,
+ CONFIG_TICKET_SUBMIT_TICKET,
+ CONFIG_TICKET_SUBMIT_BUG,
CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES,
CONFIG_PRESERVE_CUSTOM_CHANNELS,
CONFIG_PDUMP_NO_PATHS,
diff --git a/src/server/shared/DataStores/DB2Store.h b/src/server/shared/DataStores/DB2Store.h
index c4ca929065b..9514f34b294 100644
--- a/src/server/shared/DataStores/DB2Store.h
+++ b/src/server/shared/DataStores/DB2Store.h
@@ -80,8 +80,7 @@ void WriteDB2RecordToPacket(DB2Storage<T> const& store, uint32 id, uint32 locale
char const* str = locStr->Str[locale];
size_t len = strlen(str);
buffer << uint16(len);
- if (len)
- buffer << str;
+ buffer.WriteString(str, len);
entry += sizeof(char*);
break;
}
diff --git a/src/server/shared/Database/DatabaseWorkerPool.h b/src/server/shared/Database/DatabaseWorkerPool.h
index 5a06ad69a1d..f0ddbe91ad8 100644
--- a/src/server/shared/Database/DatabaseWorkerPool.h
+++ b/src/server/shared/Database/DatabaseWorkerPool.h
@@ -29,6 +29,8 @@
#include "QueryHolder.h"
#include "AdhocStatement.h"
+#include <mysqld_error.h>
+
#define MIN_MYSQL_SERVER_VERSION 50100u
#define MIN_MYSQL_CLIENT_VERSION 50100u
@@ -368,7 +370,8 @@ class DatabaseWorkerPool
void DirectCommitTransaction(SQLTransaction& transaction)
{
T* con = GetFreeConnection();
- if (con->ExecuteTransaction(transaction))
+ int errorCode = con->ExecuteTransaction(transaction);
+ if (!errorCode)
{
con->Unlock(); // OK, operation succesful
return;
@@ -376,12 +379,12 @@ class DatabaseWorkerPool
//! Handle MySQL Errno 1213 without extending deadlock to the core itself
/// @todo More elegant way
- if (con->GetLastError() == 1213)
+ if (errorCode == ER_LOCK_DEADLOCK)
{
uint8 loopBreaker = 5;
for (uint8 i = 0; i < loopBreaker; ++i)
{
- if (con->ExecuteTransaction(transaction))
+ if (!con->ExecuteTransaction(transaction))
break;
}
}
diff --git a/src/server/shared/Database/MySQLConnection.cpp b/src/server/shared/Database/MySQLConnection.cpp
index bea229df184..1a9f973d47b 100644
--- a/src/server/shared/Database/MySQLConnection.cpp
+++ b/src/server/shared/Database/MySQLConnection.cpp
@@ -359,11 +359,11 @@ void MySQLConnection::CommitTransaction()
Execute("COMMIT");
}
-bool MySQLConnection::ExecuteTransaction(SQLTransaction& transaction)
+int MySQLConnection::ExecuteTransaction(SQLTransaction& transaction)
{
std::list<SQLElementData> const& queries = transaction->m_queries;
if (queries.empty())
- return false;
+ return -1;
BeginTransaction();
@@ -380,8 +380,9 @@ bool MySQLConnection::ExecuteTransaction(SQLTransaction& transaction)
if (!Execute(stmt))
{
TC_LOG_WARN("sql.sql", "Transaction aborted. %u queries not executed.", (uint32)queries.size());
+ int errorCode = GetLastError();
RollbackTransaction();
- return false;
+ return errorCode;
}
}
break;
@@ -392,8 +393,9 @@ bool MySQLConnection::ExecuteTransaction(SQLTransaction& transaction)
if (!Execute(sql))
{
TC_LOG_WARN("sql.sql", "Transaction aborted. %u queries not executed.", (uint32)queries.size());
+ int errorCode = GetLastError();
RollbackTransaction();
- return false;
+ return errorCode;
}
}
break;
@@ -406,7 +408,7 @@ bool MySQLConnection::ExecuteTransaction(SQLTransaction& transaction)
// and not while iterating over every element.
CommitTransaction();
- return true;
+ return 0;
}
MySQLPreparedStatement* MySQLConnection::GetPreparedStatement(uint32 index)
diff --git a/src/server/shared/Database/MySQLConnection.h b/src/server/shared/Database/MySQLConnection.h
index 33f17d02228..d486f5b4679 100644
--- a/src/server/shared/Database/MySQLConnection.h
+++ b/src/server/shared/Database/MySQLConnection.h
@@ -86,7 +86,7 @@ class MySQLConnection
void BeginTransaction();
void RollbackTransaction();
void CommitTransaction();
- bool ExecuteTransaction(SQLTransaction& transaction);
+ int ExecuteTransaction(SQLTransaction& transaction);
operator bool () const { return m_Mysql != NULL; }
void Ping() { mysql_ping(m_Mysql); }
diff --git a/src/server/shared/Database/Transaction.cpp b/src/server/shared/Database/Transaction.cpp
index 3dee865267b..b83b787a106 100644
--- a/src/server/shared/Database/Transaction.cpp
+++ b/src/server/shared/Database/Transaction.cpp
@@ -17,6 +17,7 @@
#include "DatabaseEnv.h"
#include "Transaction.h"
+#include <mysqld_error.h>
//- Append a raw ad-hoc query to the transaction
void Transaction::Append(const char* sql)
@@ -74,14 +75,15 @@ void Transaction::Cleanup()
bool TransactionTask::Execute()
{
- if (m_conn->ExecuteTransaction(m_trans))
+ int errorCode = m_conn->ExecuteTransaction(m_trans);
+ if (!errorCode)
return true;
- if (m_conn->GetLastError() == 1213)
+ if (errorCode == ER_LOCK_DEADLOCK)
{
uint8 loopBreaker = 5; // Handle MySQL Errno 1213 without extending deadlock to the core itself
for (uint8 i = 0; i < loopBreaker; ++i)
- if (m_conn->ExecuteTransaction(m_trans))
+ if (!m_conn->ExecuteTransaction(m_trans))
return true;
}
diff --git a/src/server/shared/Packets/ByteBuffer.h b/src/server/shared/Packets/ByteBuffer.h
index 1063883d217..afa10207321 100644
--- a/src/server/shared/Packets/ByteBuffer.h
+++ b/src/server/shared/Packets/ByteBuffer.h
@@ -544,6 +544,12 @@ class ByteBuffer
append(str.c_str(), len);
}
+ void WriteString(char const* str, size_t len)
+ {
+ if (len)
+ append(str, len);
+ }
+
uint32 ReadPackedTime()
{
uint32 packedDate = read<uint32>();
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index 9cb25475ecf..0327d0f8884 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -1060,12 +1060,31 @@ Server.LoginInfo = 0
Command.LookupMaxResults = 0
#
-# AllowTickets
-# Description: Allow/disallow sending new tickets.
+# Ticket.SystemStatus
+# Description: Enable/disable the ticket system. This disables the whole customer
+# support UI after trying to send a ticket in disabled state
+# (MessageBox: "GM Help Tickets are currently unavailable.").
+# UI remains disabled until the character relogs.
# Default: 1 - (Enabled)
# 0 - (Disabled)
-AllowTickets = 1
+Ticket.SystemStatus = 1
+
+#
+# Ticket.SubmitTicket
+# Description: Allow/disallow opening new tickets.
+# Default: 0 - (Disabled)
+# 1 - (Enabled, Experimental)
+
+Ticket.SubmitTicket = 0
+
+#
+# Ticket.SubmitBug
+# Description: Allow/disallow opening new bug reports.
+# Default: 0 - (Disabled)
+# 1 - (Enabled, Experimental)
+
+Ticket.SubmitBug = 0
#
# DungeonFinder.OptionsMask