Ported .Net Core commits:

hondacrx:
- Initial commit: Switch to .Net Core 2.0
- Fix build and removed not needed files
Fabi:
- Updated solution platforms.
- Changed folder structure.
- Change library target framework to netstandard2.0.
- Updated solution platforms again...
- Removed windows specific kernel32 function usage (Ctrl-C handler).
This commit is contained in:
Fabian
2017-10-26 17:23:44 +02:00
parent 227702e19c
commit a3dc7b3f48
844 changed files with 26064 additions and 1824 deletions
+33
View File
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.Network.Packets;
namespace Game
{
public partial class WorldSession
{
void SendNotInArenaTeamPacket(ArenaTypes type)
{
ArenaError arenaError = new ArenaError();
arenaError.ErrorType = ArenaErrorType.NoTeam;
arenaError.TeamSize = (byte)type; // team type (2=2v2, 3=3v3, 5=5v5), can be used for custom types...
SendPacket(arenaError);
}
}
}
+236
View File
@@ -0,0 +1,236 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.DataStorage;
using Game.Entities;
using Game.Network;
using Game.Network.Packets;
using System;
using System.Collections.Generic;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.ArtifactAddPower)]
void HandleArtifactAddPower(ArtifactAddPower artifactAddPower)
{
if (!_player.GetGameObjectIfCanInteractWith(artifactAddPower.ForgeGUID, GameObjectTypes.ArtifactForge))
return;
Item artifact = _player.GetItemByGuid(artifactAddPower.ArtifactGUID);
if (!artifact)
return;
ulong xpCost = 0;
GtArtifactLevelXPRecord cost = CliDB.ArtifactLevelXPGameTable.GetRow(artifact.GetTotalPurchasedArtifactPowers() + 1);
if (cost != null)
xpCost = (ulong)(artifact.GetModifier(ItemModifier.ArtifactTier) == 1 ? cost.XP2 : cost.XP);
if (xpCost > artifact.GetUInt64Value(ItemFields.ArtifactXp))
return;
if (artifactAddPower.PowerChoices.Empty())
return;
ItemDynamicFieldArtifactPowers artifactPower = artifact.GetArtifactPower(artifactAddPower.PowerChoices[0].ArtifactPowerID);
if (artifactPower == null)
return;
ArtifactPowerRecord artifactPowerEntry = CliDB.ArtifactPowerStorage.LookupByKey(artifactPower.ArtifactPowerId);
if (artifactPowerEntry == null)
return;
if (artifactAddPower.PowerChoices[0].Rank != artifactPower.PurchasedRank + 1 ||
artifactAddPower.PowerChoices[0].Rank > artifactPowerEntry.MaxRank)
return;
var artifactPowerLinks = Global.DB2Mgr.GetArtifactPowerLinks(artifactPower.ArtifactPowerId);
if (artifactPowerLinks != null)
{
bool hasAnyLink = false;
foreach (uint artifactPowerLinkId in artifactPowerLinks)
{
ArtifactPowerRecord artifactPowerLink = CliDB.ArtifactPowerStorage.LookupByKey(artifactPowerLinkId);
if (artifactPowerLink == null)
continue;
ItemDynamicFieldArtifactPowers artifactPowerLinkLearned = artifact.GetArtifactPower(artifactPowerLinkId);
if (artifactPowerLinkLearned == null)
continue;
if (artifactPowerLinkLearned.PurchasedRank >= artifactPowerLink.MaxRank)
{
hasAnyLink = true;
break;
}
}
if (!hasAnyLink)
return;
}
ArtifactPowerRankRecord artifactPowerRank = Global.DB2Mgr.GetArtifactPowerRank(artifactPower.ArtifactPowerId, (byte)(artifactPower.CurrentRankWithBonus + 1 - 1)); // need data for next rank, but -1 because of how db2 data is structured
if (artifactPowerRank == null)
return;
ItemDynamicFieldArtifactPowers newPower = artifactPower;
++newPower.PurchasedRank;
++newPower.CurrentRankWithBonus;
artifact.SetArtifactPower(newPower);
if (artifact.IsEquipped())
{
_player.ApplyArtifactPowerRank(artifact, artifactPowerRank, true);
foreach (ItemDynamicFieldArtifactPowers power in artifact.GetArtifactPowers())
{
ArtifactPowerRecord scaledArtifactPowerEntry = CliDB.ArtifactPowerStorage.LookupByKey(power.ArtifactPowerId);
if (!scaledArtifactPowerEntry.Flags.HasAnyFlag(ArtifactPowerFlag.ScalesWithNumPowers))
continue;
ArtifactPowerRankRecord scaledArtifactPowerRank = Global.DB2Mgr.GetArtifactPowerRank(scaledArtifactPowerEntry.Id, 0);
if (scaledArtifactPowerRank == null)
continue;
ItemDynamicFieldArtifactPowers newScaledPower = power;
++newScaledPower.CurrentRankWithBonus;
artifact.SetArtifactPower(newScaledPower);
_player.ApplyArtifactPowerRank(artifact, scaledArtifactPowerRank, false);
_player.ApplyArtifactPowerRank(artifact, scaledArtifactPowerRank, true);
}
}
artifact.SetUInt64Value(ItemFields.ArtifactXp, artifact.GetUInt64Value(ItemFields.ArtifactXp) - xpCost);
artifact.SetState(ItemUpdateState.Changed, _player);
}
[WorldPacketHandler(ClientOpcodes.ArtifactSetAppearance)]
void HandleArtifactSetAppearance(ArtifactSetAppearance artifactSetAppearance)
{
if (!_player.GetGameObjectIfCanInteractWith(artifactSetAppearance.ForgeGUID, GameObjectTypes.ArtifactForge))
return;
ArtifactAppearanceRecord artifactAppearance = CliDB.ArtifactAppearanceStorage.LookupByKey(artifactSetAppearance.ArtifactAppearanceID);
if (artifactAppearance == null)
return;
Item artifact = _player.GetItemByGuid(artifactSetAppearance.ArtifactGUID);
if (!artifact)
return;
ArtifactAppearanceSetRecord artifactAppearanceSet = CliDB.ArtifactAppearanceSetStorage.LookupByKey(artifactAppearance.ArtifactAppearanceSetID);
if (artifactAppearanceSet == null || artifactAppearanceSet.ArtifactID != artifact.GetTemplate().GetArtifactID())
return;
PlayerConditionRecord playerCondition = CliDB.PlayerConditionStorage.LookupByKey(artifactAppearance.PlayerConditionID);
if (playerCondition != null)
if (!ConditionManager.IsPlayerMeetingCondition(_player, playerCondition))
return;
artifact.SetAppearanceModId(artifactAppearance.AppearanceModID);
artifact.SetModifier(ItemModifier.ArtifactAppearanceId, artifactAppearance.Id);
artifact.SetState(ItemUpdateState.Changed, _player);
Item childItem = _player.GetChildItemByGuid(artifact.GetChildItem());
if (childItem)
{
childItem.SetAppearanceModId(artifactAppearance.AppearanceModID);
childItem.SetState(ItemUpdateState.Changed, _player);
}
if (artifact.IsEquipped())
{
// change weapon appearance
_player.SetVisibleItemSlot(artifact.GetSlot(), artifact);
if (childItem)
_player.SetVisibleItemSlot(childItem.GetSlot(), childItem);
// change druid form appearance
if (artifactAppearance.ShapeshiftDisplayID != 0 && artifactAppearance.ModifiesShapeshiftFormDisplay != 0 && _player.GetShapeshiftForm() == (ShapeShiftForm)artifactAppearance.ModifiesShapeshiftFormDisplay)
_player.RestoreDisplayId();
}
}
[WorldPacketHandler(ClientOpcodes.ConfirmArtifactRespec)]
void HandleConfirmArtifactRespec(ConfirmArtifactRespec confirmArtifactRespec)
{
if (!_player.GetNPCIfCanInteractWith(confirmArtifactRespec.NpcGUID, NPCFlags.ArtifactPowerRespec))
return;
Item artifact = _player.GetItemByGuid(confirmArtifactRespec.ArtifactGUID);
if (!artifact)
return;
ulong xpCost = 0;
GtArtifactLevelXPRecord cost = CliDB.ArtifactLevelXPGameTable.GetRow(artifact.GetTotalPurchasedArtifactPowers() + 1);
if (cost != null)
xpCost = (ulong)(artifact.GetModifier(ItemModifier.ArtifactTier) == 1 ? cost.XP2 : cost.XP);
if (xpCost > artifact.GetUInt64Value(ItemFields.ArtifactXp))
return;
ulong newAmount = artifact.GetUInt64Value(ItemFields.ArtifactXp) - xpCost;
for (uint i = 0; i <= artifact.GetTotalPurchasedArtifactPowers(); ++i)
{
GtArtifactLevelXPRecord cost1 = CliDB.ArtifactLevelXPGameTable.GetRow(i);
if (cost1 != null)
newAmount += (ulong)(artifact.GetModifier(ItemModifier.ArtifactTier) == 1 ? cost1.XP2 : cost1.XP);
}
foreach (ItemDynamicFieldArtifactPowers artifactPower in artifact.GetArtifactPowers())
{
byte oldPurchasedRank = artifactPower.PurchasedRank;
if (oldPurchasedRank == 0)
continue;
ItemDynamicFieldArtifactPowers newPower = artifactPower;
newPower.PurchasedRank -= oldPurchasedRank;
newPower.CurrentRankWithBonus -= oldPurchasedRank;
artifact.SetArtifactPower(newPower);
if (artifact.IsEquipped())
{
ArtifactPowerRankRecord artifactPowerRank = Global.DB2Mgr.GetArtifactPowerRank(artifactPower.ArtifactPowerId, 0);
if (artifactPowerRank != null)
_player.ApplyArtifactPowerRank(artifact, artifactPowerRank, false);
}
}
foreach (ItemDynamicFieldArtifactPowers power in artifact.GetArtifactPowers())
{
ArtifactPowerRecord scaledArtifactPowerEntry = CliDB.ArtifactPowerStorage.LookupByKey(power.ArtifactPowerId);
if (!scaledArtifactPowerEntry.Flags.HasAnyFlag(ArtifactPowerFlag.ScalesWithNumPowers))
continue;
ArtifactPowerRankRecord scaledArtifactPowerRank = Global.DB2Mgr.GetArtifactPowerRank(scaledArtifactPowerEntry.Id, 0);
if (scaledArtifactPowerRank == null)
continue;
ItemDynamicFieldArtifactPowers newScaledPower = power;
newScaledPower.CurrentRankWithBonus = 0;
artifact.SetArtifactPower(newScaledPower);
_player.ApplyArtifactPowerRank(artifact, scaledArtifactPowerRank, false);
}
artifact.SetUInt64Value(ItemFields.ArtifactXp, newAmount);
artifact.SetState(ItemUpdateState.Changed, _player);
}
}
}
+673
View File
@@ -0,0 +1,673 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Framework.Database;
using Framework.Dynamic;
using Game.DataStorage;
using Game.Entities;
using Game.Mails;
using Game.Network;
using Game.Network.Packets;
using System;
using System.Collections.Generic;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.AuctionHelloRequest)]
void HandleAuctionHelloOpcode(AuctionHelloRequest packet)
{
Creature unit = GetPlayer().GetNPCIfCanInteractWith(packet.Guid, NPCFlags.Auctioneer);
if (!unit)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleAuctionHelloOpcode - {0} not found or you can't interact with him.", packet.Guid.ToString());
return;
}
// remove fake death
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
SendAuctionHello(packet.Guid, unit);
}
public void SendAuctionHello(ObjectGuid guid, Creature unit)
{
if (GetPlayer().getLevel() < WorldConfig.GetIntValue(WorldCfg.AuctionLevelReq))
{
SendNotification(Global.ObjectMgr.GetCypherString(CypherStrings.AuctionReq), WorldConfig.GetIntValue(WorldCfg.AuctionLevelReq));
return;
}
AuctionHouseRecord ahEntry = Global.AuctionMgr.GetAuctionHouseEntry(unit.getFaction());
if (ahEntry == null)
return;
AuctionHelloResponse packet = new AuctionHelloResponse();
packet.Guid = guid;
packet.OpenForBusiness = true; // 3.3.3: 1 - AH enabled, 0 - AH disabled
SendPacket(packet);
}
public void SendAuctionCommandResult(AuctionEntry auction, AuctionAction action, AuctionError errorCode, uint bidError = 0)
{
AuctionCommandResult auctionCommandResult = new AuctionCommandResult();
auctionCommandResult.InitializeAuction(auction);
auctionCommandResult.Command = action;
auctionCommandResult.ErrorCode = errorCode;
SendPacket(auctionCommandResult);
}
public void SendAuctionOutBidNotification(AuctionEntry auction, Item item)
{
AuctionOutBidNotification packet = new AuctionOutBidNotification();
packet.BidAmount = auction.bid;
packet.MinIncrement = auction.GetAuctionOutBid();
packet.Info.Initialize(auction, item);
SendPacket(packet);
}
public void SendAuctionClosedNotification(AuctionEntry auction, float mailDelay, bool sold, Item item)
{
AuctionClosedNotification packet = new AuctionClosedNotification();
packet.Info.Initialize(auction, item);
packet.ProceedsMailDelay = mailDelay;
packet.Sold = sold;
SendPacket(packet);
}
public void SendAuctionWonNotification(AuctionEntry auction, Item item)
{
AuctionWonNotification packet = new AuctionWonNotification();
packet.Info.Initialize(auction, item);
SendPacket(packet);
}
public void SendAuctionOwnerBidNotification(AuctionEntry auction, Item item)
{
AuctionOwnerBidNotification packet = new AuctionOwnerBidNotification();
packet.Info.Initialize(auction, item);
packet.Bidder = ObjectGuid.Create(HighGuid.Player, auction.bidder);
packet.MinIncrement = auction.GetAuctionOutBid();
SendPacket(packet);
}
[WorldPacketHandler(ClientOpcodes.AuctionSellItem)]
void HandleAuctionSellItem(AuctionSellItem packet)
{
foreach (var aitem in packet.Items)
if (aitem.Guid.IsEmpty() || aitem.UseCount == 0 || aitem.UseCount > 1000)
return;
if (packet.MinBid == 0 || packet.RunTime == 0)
return;
if (packet.MinBid > PlayerConst.MaxMoneyAmount || packet.BuyoutPrice > PlayerConst.MaxMoneyAmount)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleAuctionSellItem - Player {0} ({1}) attempted to sell item with higher price than max gold amount.", GetPlayer().GetName(), GetPlayer().GetGUID().ToString());
SendAuctionCommandResult(null, AuctionAction.SellItem, AuctionError.DatabaseError);
return;
}
Creature creature = GetPlayer().GetNPCIfCanInteractWith(packet.Auctioneer, NPCFlags.Auctioneer);
if (!creature)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleAuctionSellItem - {0} not found or you can't interact with him.", packet.Auctioneer.ToString());
return;
}
uint houseId = 0;
AuctionHouseRecord auctionHouseEntry = Global.AuctionMgr.GetAuctionHouseEntry(creature.getFaction(), ref houseId);
if (auctionHouseEntry == null)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleAuctionSellItem - {0} has wrong faction.", packet.Auctioneer.ToString());
return;
}
packet.RunTime *= Time.Minute;
switch (packet.RunTime)
{
case 1 * SharedConst.MinAuctionTime:
case 2 * SharedConst.MinAuctionTime:
case 4 * SharedConst.MinAuctionTime:
break;
default:
return;
}
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
uint finalCount = 0;
foreach (var packetItem in packet.Items)
{
Item aitem = GetPlayer().GetItemByGuid(packetItem.Guid);
if (!aitem)
{
SendAuctionCommandResult(null, AuctionAction.SellItem, AuctionError.ItemNotFound);
return;
}
if (Global.AuctionMgr.GetAItem(aitem.GetGUID().GetCounter()) || !aitem.CanBeTraded() || aitem.IsNotEmptyBag() ||
aitem.GetTemplate().GetFlags().HasAnyFlag(ItemFlags.Conjured) || aitem.GetUInt32Value(ItemFields.Duration) != 0 ||
aitem.GetCount() < packetItem.UseCount)
{
SendAuctionCommandResult(null, AuctionAction.SellItem, AuctionError.DatabaseError);
return;
}
finalCount += packetItem.UseCount;
}
if (packet.Items.Empty())
{
SendAuctionCommandResult(null, AuctionAction.SellItem, AuctionError.DatabaseError);
return;
}
if (finalCount == 0)
{
SendAuctionCommandResult(null, AuctionAction.SellItem, AuctionError.DatabaseError);
return;
}
// check if there are 2 identical guids, in this case user is most likely cheating
for (int i = 0; i < packet.Items.Count; ++i)
{
for (int j = i + 1; j < packet.Items.Count; ++j)
{
if (packet.Items[i].Guid == packet.Items[j].Guid)
{
SendAuctionCommandResult(null, AuctionAction.SellItem, AuctionError.DatabaseError);
return;
}
}
}
foreach (var packetItem in packet.Items)
{
Item aitem = GetPlayer().GetItemByGuid(packetItem.Guid);
if (aitem.GetMaxStackCount() < finalCount)
{
SendAuctionCommandResult(null, AuctionAction.SellItem, AuctionError.DatabaseError);
return;
}
}
Item item = GetPlayer().GetItemByGuid(packet.Items[0].Guid);
uint auctionTime = (uint)(packet.RunTime * WorldConfig.GetFloatValue(WorldCfg.RateAuctionTime));
AuctionHouseObject auctionHouse = Global.AuctionMgr.GetAuctionsMap(creature.getFaction());
ulong deposit = Global.AuctionMgr.GetAuctionDeposit(auctionHouseEntry, packet.RunTime, item, finalCount);
if (!GetPlayer().HasEnoughMoney(deposit))
{
SendAuctionCommandResult(null, AuctionAction.SellItem, AuctionError.NotEnoughtMoney);
return;
}
AuctionEntry AH = new AuctionEntry();
SQLTransaction trans;
if (WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionAuction))
AH.auctioneer = 23442; ///@TODO - HARDCODED DB GUID, BAD BAD BAD
else
AH.auctioneer = creature.GetSpawnId();
// Required stack size of auction matches to current item stack size, just move item to auctionhouse
if (packet.Items.Count == 1 && item.GetCount() == packet.Items[0].UseCount)
{
if (HasPermission(RBACPermissions.LogGmTrade))
{
Log.outCommand(GetAccountId(), "GM {0} (Account: {1}) create auction: {2} (Entry: {3} Count: {4})",
GetPlayerName(), GetAccountId(), item.GetTemplate().GetName(), item.GetEntry(), item.GetCount());
}
AH.Id = Global.ObjectMgr.GenerateAuctionID();
AH.itemGUIDLow = item.GetGUID().GetCounter();
AH.itemEntry = item.GetEntry();
AH.itemCount = item.GetCount();
AH.owner = GetPlayer().GetGUID().GetCounter();
AH.startbid = (uint)packet.MinBid;
AH.bidder = 0;
AH.bid = 0;
AH.buyout = (uint)packet.BuyoutPrice;
AH.expire_time = Time.UnixTime + auctionTime;
AH.deposit = deposit;
AH.etime = packet.RunTime;
AH.auctionHouseEntry = auctionHouseEntry;
Log.outInfo(LogFilter.Network, "CMSG_AUCTION_SELL_ITEM: {0} {1} is selling item {2} {3} to auctioneer {4} with count {5} with initial bid {6} with buyout {7} and with time {8} (in sec) in auctionhouse {9}",
GetPlayer().GetGUID().ToString(), GetPlayer().GetName(), item.GetGUID().ToString(), item.GetTemplate().GetName(), AH.auctioneer, item.GetCount(), packet.MinBid, packet.BuyoutPrice, auctionTime, AH.GetHouseId());
Global.AuctionMgr.AddAItem(item);
auctionHouse.AddAuction(AH);
GetPlayer().MoveItemFromInventory(item.GetBagSlot(), item.GetSlot(), true);
trans = new SQLTransaction();
item.DeleteFromInventoryDB(trans);
item.SaveToDB(trans);
AH.SaveToDB(trans);
GetPlayer().SaveInventoryAndGoldToDB(trans);
DB.Characters.CommitTransaction(trans);
SendAuctionCommandResult(AH, AuctionAction.SellItem, AuctionError.Ok);
GetPlayer().UpdateCriteria(CriteriaTypes.CreateAuction, 1);
}
else // Required stack size of auction does not match to current item stack size, clone item and set correct stack size
{
Item newItem = item.CloneItem(finalCount, GetPlayer());
if (!newItem)
{
Log.outError(LogFilter.Network, "CMSG_AuctionAction.SellItem: Could not create clone of item {0}", item.GetEntry());
SendAuctionCommandResult(null, AuctionAction.SellItem, AuctionError.DatabaseError);
return;
}
if (HasPermission(RBACPermissions.LogGmTrade))
{
Log.outCommand(GetAccountId(), "GM {0} (Account: {1}) create auction: {2} (Entry: {3} Count: {4})",
GetPlayerName(), GetAccountId(), newItem.GetTemplate().GetName(), newItem.GetEntry(), newItem.GetCount());
}
AH.Id = Global.ObjectMgr.GenerateAuctionID();
AH.itemGUIDLow = newItem.GetGUID().GetCounter();
AH.itemEntry = newItem.GetEntry();
AH.itemCount = newItem.GetCount();
AH.owner = GetPlayer().GetGUID().GetCounter();
AH.startbid = (uint)packet.MinBid;
AH.bidder = 0;
AH.bid = 0;
AH.buyout = (uint)packet.BuyoutPrice;
AH.expire_time = Time.UnixTime + auctionTime;
AH.deposit = deposit;
AH.etime = packet.RunTime;
AH.auctionHouseEntry = auctionHouseEntry;
Log.outInfo(LogFilter.Network, "CMSG_AuctionAction.SellItem: {0} {1} is selling {2} {3} to auctioneer {4} with count {5} with initial bid {6} with buyout {7} and with time {8} (in sec) in auctionhouse {9}",
GetPlayer().GetGUID().ToString(), GetPlayer().GetName(), newItem.GetGUID().ToString(), newItem.GetTemplate().GetName(), AH.auctioneer, newItem.GetCount(), packet.MinBid, packet.BuyoutPrice, auctionTime, AH.GetHouseId());
Global.AuctionMgr.AddAItem(newItem);
auctionHouse.AddAuction(AH);
foreach (var packetItem in packet.Items)
{
Item item2 = GetPlayer().GetItemByGuid(packetItem.Guid);
// Item stack count equals required count, ready to delete item - cloned item will be used for auction
if (item2.GetCount() == packetItem.UseCount)
{
GetPlayer().MoveItemFromInventory(item2.GetBagSlot(), item2.GetSlot(), true);
trans = new SQLTransaction();
item2.DeleteFromInventoryDB(trans);
item2.DeleteFromDB(trans);
DB.Characters.CommitTransaction(trans);
}
else // Item stack count is bigger than required count, update item stack count and save to database - cloned item will be used for auction
{
item2.SetCount(item2.GetCount() - packetItem.UseCount);
item2.SetState(ItemUpdateState.Changed, GetPlayer());
GetPlayer().ItemRemovedQuestCheck(item2.GetEntry(), packetItem.UseCount);
item2.SendUpdateToPlayer(GetPlayer());
trans = new SQLTransaction();
item2.SaveToDB(trans);
DB.Characters.CommitTransaction(trans);
}
}
trans = new SQLTransaction();
newItem.SaveToDB(trans);
AH.SaveToDB(trans);
GetPlayer().SaveInventoryAndGoldToDB(trans);
DB.Characters.CommitTransaction(trans);
SendAuctionCommandResult(AH, AuctionAction.SellItem, AuctionError.Ok);
GetPlayer().UpdateCriteria(CriteriaTypes.CreateAuction, 1);
}
GetPlayer().ModifyMoney(-(long)deposit);
}
[WorldPacketHandler(ClientOpcodes.AuctionPlaceBid)]
void HandleAuctionPlaceBid(AuctionPlaceBid packet)
{
if (packet.AuctionItemID == 0 || packet.BidAmount == 0)
return; // check for cheaters
Creature creature = GetPlayer().GetNPCIfCanInteractWith(packet.Auctioneer, NPCFlags.Auctioneer);
if (!creature)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleAuctionPlaceBid - {0} not found or you can't interact with him.", packet.Auctioneer.ToString());
return;
}
// remove fake death
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
AuctionHouseObject auctionHouse = Global.AuctionMgr.GetAuctionsMap(creature.getFaction());
AuctionEntry auction = auctionHouse.GetAuction(packet.AuctionItemID);
Player player = GetPlayer();
if (auction == null || auction.owner == player.GetGUID().GetCounter())
{
//you cannot bid your own auction:
SendAuctionCommandResult(null, AuctionAction.PlaceBid, AuctionError.BidOwn);
return;
}
// impossible have online own another character (use this for speedup check in case online owner)
ObjectGuid ownerGuid = ObjectGuid.Create(HighGuid.Player, auction.owner);
Player auction_owner = Global.ObjAccessor.FindPlayer(ownerGuid);
if (!auction_owner && ObjectManager.GetPlayerAccountIdByGUID(ownerGuid) == player.GetSession().GetAccountId())
{
//you cannot bid your another character auction:
SendAuctionCommandResult(null, AuctionAction.PlaceBid, AuctionError.BidOwn);
return;
}
// cheating
if (packet.BidAmount <= auction.bid || packet.BidAmount < auction.startbid)
return;
// price too low for next bid if not buyout
if ((packet.BidAmount < auction.buyout || auction.buyout == 0) && packet.BidAmount < auction.bid + auction.GetAuctionOutBid())
{
// client already test it but just in case ...
SendAuctionCommandResult(auction, AuctionAction.PlaceBid, AuctionError.HigherBid);
return;
}
if (!player.HasEnoughMoney(packet.BidAmount))
{
// client already test it but just in case ...
SendAuctionCommandResult(auction, AuctionAction.PlaceBid, AuctionError.NotEnoughtMoney);
return;
}
SQLTransaction trans = new SQLTransaction();
if (packet.BidAmount < auction.buyout || auction.buyout == 0)
{
if (auction.bidder > 0)
{
if (auction.bidder == player.GetGUID().GetCounter())
player.ModifyMoney(-(long)(packet.BidAmount - auction.bid));
else
{
// mail to last bidder and return money
Global.AuctionMgr.SendAuctionOutbiddedMail(auction, packet.BidAmount, GetPlayer(), trans);
player.ModifyMoney(-(long)packet.BidAmount);
}
}
else
player.ModifyMoney(-(long)packet.BidAmount);
auction.bidder = player.GetGUID().GetCounter();
auction.bid = (uint)packet.BidAmount;
GetPlayer().UpdateCriteria(CriteriaTypes.HighestAuctionBid, packet.BidAmount);
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_AUCTION_BID);
stmt.AddValue(0, auction.bidder);
stmt.AddValue(1, auction.bid);
stmt.AddValue(2, auction.Id);
trans.Append(stmt);
SendAuctionCommandResult(auction, AuctionAction.PlaceBid, AuctionError.Ok);
// Not sure if we must send this now.
Player owner = Global.ObjAccessor.FindConnectedPlayer(ObjectGuid.Create(HighGuid.Player, auction.owner));
Item item = Global.AuctionMgr.GetAItem(auction.itemGUIDLow);
if (owner && item)
owner.GetSession().SendAuctionOwnerBidNotification(auction, item);
}
else
{
//buyout:
if (player.GetGUID().GetCounter() == auction.bidder)
player.ModifyMoney(-(long)(auction.buyout - auction.bid));
else
{
player.ModifyMoney(-(long)auction.buyout);
if (auction.bidder != 0) //buyout for bidded auction ..
Global.AuctionMgr.SendAuctionOutbiddedMail(auction, auction.buyout, GetPlayer(), trans);
}
auction.bidder = player.GetGUID().GetCounter();
auction.bid = auction.buyout;
GetPlayer().UpdateCriteria(CriteriaTypes.HighestAuctionBid, auction.buyout);
SendAuctionCommandResult(auction, AuctionAction.PlaceBid, AuctionError.Ok);
//- Mails must be under transaction control too to prevent data loss
Global.AuctionMgr.SendAuctionSalePendingMail(auction, trans);
Global.AuctionMgr.SendAuctionSuccessfulMail(auction, trans);
Global.AuctionMgr.SendAuctionWonMail(auction, trans);
auction.DeleteFromDB(trans);
Global.AuctionMgr.RemoveAItem(auction.itemGUIDLow);
auctionHouse.RemoveAuction(auction);
}
player.SaveInventoryAndGoldToDB(trans);
DB.Characters.CommitTransaction(trans);
}
[WorldPacketHandler(ClientOpcodes.AuctionRemoveItem)]
void HandleAuctionRemoveItem(AuctionRemoveItem packet)
{
Creature creature = GetPlayer().GetNPCIfCanInteractWith(packet.Auctioneer, NPCFlags.Auctioneer);
if (!creature)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleAuctionRemoveItem - {0} not found or you can't interact with him.", packet.Auctioneer.ToString());
return;
}
// remove fake death
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
AuctionHouseObject auctionHouse = Global.AuctionMgr.GetAuctionsMap(creature.getFaction());
AuctionEntry auction = auctionHouse.GetAuction((uint)packet.AuctionItemID);
Player player = GetPlayer();
SQLTransaction trans = new SQLTransaction();
if (auction != null && auction.owner == player.GetGUID().GetCounter())
{
Item pItem = Global.AuctionMgr.GetAItem(auction.itemGUIDLow);
if (pItem)
{
if (auction.bidder > 0) // If we have a bidder, we have to send him the money he paid
{
ulong auctionCut = auction.GetAuctionCut();
if (!player.HasEnoughMoney(auctionCut)) //player doesn't have enough money, maybe message needed
return;
Global.AuctionMgr.SendAuctionCancelledToBidderMail(auction, trans);
player.ModifyMoney(-(long)auctionCut);
}
// item will deleted or added to received mail list
new MailDraft(auction.BuildAuctionMailSubject(MailAuctionAnswers.Canceled), AuctionEntry.BuildAuctionMailBody(0, 0, auction.buyout, auction.deposit, 0))
.AddItem(pItem)
.SendMailTo(trans, new MailReceiver(player), new MailSender(auction), MailCheckMask.Copied);
}
else
{
Log.outError(LogFilter.Network, "Auction id: {0} got non existing item (item guid : {1})!", auction.Id, auction.itemGUIDLow);
SendAuctionCommandResult(null, AuctionAction.Cancel, AuctionError.DatabaseError);
return;
}
}
else
{
SendAuctionCommandResult(null, AuctionAction.Cancel, AuctionError.DatabaseError);
//this code isn't possible ... maybe there should be assert
Log.outError(LogFilter.Network, "CHEATER: {0} tried to cancel auction (id: {1}) of another player or auction is null", player.GetGUID().ToString(), packet.AuctionItemID);
return;
}
//inform player, that auction is removed
SendAuctionCommandResult(auction, AuctionAction.Cancel, AuctionError.Ok);
// Now remove the auction
player.SaveInventoryAndGoldToDB(trans);
auction.DeleteFromDB(trans);
DB.Characters.CommitTransaction(trans);
Global.AuctionMgr.RemoveAItem(auction.itemGUIDLow);
auctionHouse.RemoveAuction(auction);
}
[WorldPacketHandler(ClientOpcodes.AuctionListBidderItems)]
void HandleAuctionListBidderItems(AuctionListBidderItems packet)
{
Creature creature = GetPlayer().GetNPCIfCanInteractWith(packet.Auctioneer, NPCFlags.Auctioneer);
if (!creature)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleAuctionListBidderItems - {0} not found or you can't interact with him.", packet.Auctioneer.ToString());
return;
}
// remove fake death
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
AuctionHouseObject auctionHouse = Global.AuctionMgr.GetAuctionsMap(creature.getFaction());
AuctionListBidderItemsResult result = new AuctionListBidderItemsResult();
Player player = GetPlayer();
auctionHouse.BuildListBidderItems(result, player, ref result.TotalCount);
result.DesiredDelay = 300;
SendPacket(result);
}
[WorldPacketHandler(ClientOpcodes.AuctionListOwnerItems)]
void HandleAuctionListOwnerItems(AuctionListOwnerItems packet)
{
Creature creature = GetPlayer().GetNPCIfCanInteractWith(packet.Auctioneer, NPCFlags.Auctioneer);
if (!creature)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleAuctionListOwnerItems - {0} not found or you can't interact with him.", packet.Auctioneer.ToString());
return;
}
// remove fake death
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
AuctionHouseObject auctionHouse = Global.AuctionMgr.GetAuctionsMap(creature.getFaction());
AuctionListOwnerItemsResult result = new AuctionListOwnerItemsResult();
auctionHouse.BuildListOwnerItems(result, GetPlayer(), ref result.TotalCount);
result.DesiredDelay = 300;
SendPacket(result);
}
[WorldPacketHandler(ClientOpcodes.AuctionListItems)]
void HandleAuctionListItems(AuctionListItems packet)
{
Creature creature = GetPlayer().GetNPCIfCanInteractWith(packet.Auctioneer, NPCFlags.Auctioneer);
if (!creature)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleAuctionListItems - {0} not found or you can't interact with him.", packet.Auctioneer.ToString());
return;
}
// remove fake death
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
AuctionHouseObject auctionHouse = Global.AuctionMgr.GetAuctionsMap(creature.getFaction());
Optional<AuctionSearchFilters> filters = new Optional<AuctionSearchFilters>();
AuctionListItemsResult result = new AuctionListItemsResult();
if (!packet.ClassFilters.Empty())
{
filters.HasValue = true;
foreach (var classFilter in packet.ClassFilters)
{
if (!classFilter.SubClassFilters.Empty())
{
foreach (var subClassFilter in classFilter.SubClassFilters)
{
filters.Value.Classes[classFilter.ItemClass].SubclassMask |= (AuctionSearchFilters.FilterType)(1 << subClassFilter.ItemSubclass);
filters.Value.Classes[classFilter.ItemClass].InvTypes[subClassFilter.ItemSubclass] = subClassFilter.InvTypeMask;
}
}
else
filters.Value.Classes[classFilter.ItemClass].SubclassMask = AuctionSearchFilters.FilterType.SkipSubclass;
}
}
auctionHouse.BuildListAuctionItems(result, GetPlayer(), packet.Name.ToLower(), packet.Offset, packet.MinLevel, packet.MaxLevel, packet.OnlyUsable, filters, packet.Quality);
result.DesiredDelay = WorldConfig.GetUIntValue(WorldCfg.AuctionSearchDelay);
result.OnlyUsable = packet.OnlyUsable;
SendPacket(result);
}
[WorldPacketHandler(ClientOpcodes.AuctionListPendingSales)]
void HandleAuctionListPendingSales(AuctionListPendingSales packet)
{
AuctionListPendingSalesResult result = new AuctionListPendingSalesResult();
result.TotalNumRecords = 0;
SendPacket(result);
}
[WorldPacketHandler(ClientOpcodes.AuctionReplicateItems)]
void HandleReplicateItems(AuctionReplicateItems packet)
{
/* Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(packet.Auctioneer, UNIT_NPC_FLAG_AUCTIONEER);
if (!creature)
{
TC_LOG_DEBUG("network", "WORLD: HandleReplicateItems - {0} not found or you can't interact with him.", packet.Auctioneer.ToString().c_str());
return;
}
// remove fake death
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction());
WorldPackets::AuctionHouse::AuctionReplicateResponse response;
auctionHouse->BuildReplicate(response, GetPlayer(), packet.ChangeNumberGlobal, packet.ChangeNumberCursor, packet.ChangeNumberTombstone, packet.Count);
*/
//@todo implement this properly
AuctionReplicateResponse response = new AuctionReplicateResponse();
response.ChangeNumberCursor = packet.ChangeNumberCursor;
response.ChangeNumberGlobal = packet.ChangeNumberGlobal;
response.ChangeNumberTombstone = packet.ChangeNumberTombstone;
response.DesiredDelay = WorldConfig.GetUIntValue(WorldCfg.AuctionSearchDelay) * 5;
response.Result = 0;
SendPacket(response);
}
}
}
@@ -0,0 +1,104 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.Network.Packets;
namespace Game
{
public partial class WorldSession
{
public void SendAuthResponse(BattlenetRpcErrorCode code, bool queued, uint queuePos = 0)
{
AuthResponse response = new AuthResponse();
response.Result = code;
if (code == BattlenetRpcErrorCode.Ok)
{
response.SuccessInfo.HasValue = true;
response.SuccessInfo.Value = new AuthResponse.AuthSuccessInfo();
response.SuccessInfo.Value.AccountExpansionLevel = (byte)GetExpansion();
response.SuccessInfo.Value.ActiveExpansionLevel = (byte)GetExpansion();
response.SuccessInfo.Value.VirtualRealmAddress = Global.WorldMgr.GetVirtualRealmAddress();
response.SuccessInfo.Value.Time = (uint)Time.UnixTime;
var realm = Global.WorldMgr.GetRealm();
// Send current home realm. Also there is no need to send it later in realm queries.
response.SuccessInfo.Value.VirtualRealms.Add(new VirtualRealmInfo(realm.Id.GetAddress(), true, false, realm.Name, realm.NormalizedName));
if (HasPermission(RBACPermissions.UseCharacterTemplates))
foreach (var templ in Global.CharacterTemplateDataStorage.GetCharacterTemplates().Values)
response.SuccessInfo.Value.Templates.Add(templ);
response.SuccessInfo.Value.AvailableClasses = Global.ObjectMgr.GetClassExpansionRequirements();
response.SuccessInfo.Value.AvailableRaces = Global.ObjectMgr.GetRaceExpansionRequirements();
}
if (queued)
{
response.WaitInfo.HasValue = true;
response.WaitInfo.Value.WaitCount = queuePos;
}
SendPacket(response);
}
public void SendAuthWaitQue(uint position)
{
if (position != 0)
{
WaitQueueUpdate waitQueueUpdate = new WaitQueueUpdate();
waitQueueUpdate.WaitInfo.WaitCount = position;
waitQueueUpdate.WaitInfo.WaitTime = 0;
waitQueueUpdate.WaitInfo.HasFCM = false;
SendPacket(waitQueueUpdate);
}
else
SendPacket(new WaitQueueFinish());
}
public void SendClientCacheVersion(uint version)
{
ClientCacheVersion cache = new ClientCacheVersion();
cache.CacheVersion = version;
SendPacket(cache);//enabled it
}
public void SendSetTimeZoneInformation()
{
/// @todo: replace dummy values
SetTimeZoneInformation packet = new SetTimeZoneInformation();
packet.ServerTimeTZ = "Europe/Paris";
packet.GameTimeTZ = "Europe/Paris";
SendPacket(packet);//enabled it
}
public void SendFeatureSystemStatusGlueScreen()
{
FeatureSystemStatusGlueScreen features = new FeatureSystemStatusGlueScreen();
features.BpayStoreAvailable = false;
features.BpayStoreDisabledByParentalControls = false;
features.CharUndeleteEnabled = WorldConfig.GetBoolValue(WorldCfg.FeatureSystemCharacterUndeleteEnabled);
features.BpayStoreEnabled = WorldConfig.GetBoolValue(WorldCfg.FeatureSystemBpayStoreEnabled);
SendPacket(features);
}
}
}
+151
View File
@@ -0,0 +1,151 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.DataStorage;
using Game.Entities;
using Game.Network;
using Game.Network.Packets;
using System.Collections.Generic;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.AutobankItem)]
void HandleAutoBankItem(AutoBankItem packet)
{
if (!CanUseBank())
{
Log.outDebug(LogFilter.Network, "WORLD: HandleAutoBankItemOpcode - {0} not found or you can't interact with him.", m_currentBankerGUID.ToString());
return;
}
Item item = GetPlayer().GetItemByPos(packet.Bag, packet.Slot);
if (!item)
return;
List<ItemPosCount> dest = new List<ItemPosCount>();
InventoryResult msg = GetPlayer().CanBankItem(ItemConst.NullBag, ItemConst.NullSlot, dest, item, false);
if (msg != InventoryResult.Ok)
{
GetPlayer().SendEquipError(msg, item);
return;
}
if (dest.Count == 1 && dest[0].pos == item.GetPos())
{
GetPlayer().SendEquipError(InventoryResult.CantSwap, item);
return;
}
GetPlayer().RemoveItem(packet.Bag, packet.Slot, true);
GetPlayer().ItemRemovedQuestCheck(item.GetEntry(), item.GetCount());
GetPlayer().BankItem(dest, item, true);
}
[WorldPacketHandler(ClientOpcodes.BankerActivate)]
void HandleBankerActivate(Hello packet)
{
Creature unit = GetPlayer().GetNPCIfCanInteractWith(packet.Unit, NPCFlags.Banker);
if (!unit)
{
Log.outError(LogFilter.Network, "HandleBankerActivate: {0} not found or you can not interact with him.", packet.Unit.ToString());
return;
}
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
SendShowBank(packet.Unit);
}
[WorldPacketHandler(ClientOpcodes.AutostoreBankItem)]
void HandleAutoStoreBankItem(AutoStoreBankItem packet)
{
if (!CanUseBank())
{
Log.outDebug(LogFilter.Network, "WORLD: HandleAutoBankItemOpcode - {0} not found or you can't interact with him.", m_currentBankerGUID.ToString());
return;
}
Item item = GetPlayer().GetItemByPos(packet.Bag, packet.Slot);
if (!item)
return;
if (Player.IsBankPos(packet.Bag, packet.Slot)) // moving from bank to inventory
{
List<ItemPosCount> dest = new List<ItemPosCount>();
InventoryResult msg = GetPlayer().CanStoreItem(ItemConst.NullBag, ItemConst.NullSlot, dest, item, false);
if (msg != InventoryResult.Ok)
{
GetPlayer().SendEquipError(msg, item);
return;
}
GetPlayer().RemoveItem(packet.Bag, packet.Slot, true);
Item storedItem = GetPlayer().StoreItem(dest, item, true);
if (storedItem)
GetPlayer().ItemAddedQuestCheck(storedItem.GetEntry(), storedItem.GetCount());
}
else // moving from inventory to bank
{
List<ItemPosCount> dest = new List<ItemPosCount>();
InventoryResult msg = GetPlayer().CanBankItem(ItemConst.NullBag, ItemConst.NullSlot, dest, item, false);
if (msg != InventoryResult.Ok)
{
GetPlayer().SendEquipError(msg, item);
return;
}
GetPlayer().RemoveItem(packet.Bag, packet.Slot, true);
GetPlayer().BankItem(dest, item, true);
}
}
[WorldPacketHandler(ClientOpcodes.BuyBankSlot)]
void HandleBuyBankSlot(BuyBankSlot packet)
{
if (!CanUseBank(packet.Guid))
Log.outDebug(LogFilter.Network, "WORLD: HandleBuyBankSlot - {0} not found or you can't interact with him.", packet.Guid.ToString());
uint slot = GetPlayer().GetBankBagSlotCount();
// next slot
++slot;
BankBagSlotPricesRecord slotEntry = CliDB.BankBagSlotPricesStorage.LookupByKey(slot);
if (slotEntry == null)
return;
uint price = slotEntry.Cost;
if (!GetPlayer().HasEnoughMoney(price))
return;
GetPlayer().SetBankBagSlotCount((byte)slot);
GetPlayer().ModifyMoney(-price);
GetPlayer().UpdateCriteria(CriteriaTypes.BuyBankSlot);
}
public void SendShowBank(ObjectGuid guid)
{
m_currentBankerGUID = guid;
ShowBank packet = new ShowBank();
packet.Guid = guid;
SendPacket(packet);
}
}
}
+156
View File
@@ -0,0 +1,156 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.BattleFields;
using Game.Network.Packets;
namespace Game
{
public partial class WorldSession
{
/// <summary>
/// This send to player windows for invite player to join the war.
/// </summary>
/// <param name="queueId">The queue id of Bf</param>
/// <param name="zoneId">The zone where the battle is (4197 for wg)</param>
/// <param name="acceptTime">Time in second that the player have for accept</param>
public void SendBfInvitePlayerToWar(ulong queueId, uint zoneId, uint acceptTime)
{
BFMgrEntryInvite bfMgrEntryInvite = new BFMgrEntryInvite();
bfMgrEntryInvite.QueueID = queueId;
bfMgrEntryInvite.AreaID = (int)zoneId;
bfMgrEntryInvite.ExpireTime = Time.UnixTime + acceptTime;
SendPacket(bfMgrEntryInvite);
}
/// <summary>
/// This send invitation to player to join the queue.
/// </summary>
/// <param name="queueId">The queue id of Bf</param>
/// <param name="battleState">Battlefield State</param>
public void SendBfInvitePlayerToQueue(ulong queueId, BattlefieldState battleState)
{
BFMgrQueueInvite bfMgrQueueInvite = new BFMgrQueueInvite();
bfMgrQueueInvite.QueueID = queueId;
bfMgrQueueInvite.BattleState = battleState;
SendPacket(bfMgrQueueInvite);
}
/// <summary>
/// This send packet for inform player that he join queue.
/// </summary>
/// <param name="queueId">The queue id of Bf</param>
/// <param name="zoneId">The zone where the battle is (4197 for wg)</param>
/// <param name="battleStatus">Battlefield status</param>
/// <param name="canQueue">if able to queue</param>
/// <param name="loggingIn">on log in send queue status</param>
public void SendBfQueueInviteResponse(ulong queueId, uint zoneId, BattlefieldState battleStatus, bool canQueue = true, bool loggingIn = false)
{
BFMgrQueueRequestResponse bfMgrQueueRequestResponse = new BFMgrQueueRequestResponse();
bfMgrQueueRequestResponse.QueueID = queueId;
bfMgrQueueRequestResponse.AreaID = (int)zoneId;
bfMgrQueueRequestResponse.Result = (sbyte)(canQueue ? 1 : 0);
bfMgrQueueRequestResponse.BattleState = battleStatus;
bfMgrQueueRequestResponse.LoggingIn = loggingIn;
SendPacket(bfMgrQueueRequestResponse);
}
/// <summary>
/// This is call when player accept to join war.
/// </summary>
/// <param name="queueId">The queue id of Bf</param>
/// <param name="relocated">Whether player is added to Bf on the spot or teleported from queue</param>
/// <param name="onOffense">Whether player belongs to attacking team or not</param>
public void SendBfEntered(ulong queueId, bool relocated, bool onOffense)
{
BFMgrEntering bfMgrEntering = new BFMgrEntering();
bfMgrEntering.ClearedAFK = _player.isAFK();
bfMgrEntering.Relocated = relocated;
bfMgrEntering.OnOffense = onOffense;
bfMgrEntering.QueueID = queueId;
SendPacket(bfMgrEntering);
}
/// <summary>
/// This is call when player leave battlefield zone.
/// </summary>
/// <param name="queueId">The queue id of Bf</param>
/// <param name="queueId">The queue id of Bf</param>
/// <param name="battleState">Battlefield status</param>
/// <param name="relocated">Whether player is added to Bf on the spot or teleported from queue</param>
/// <param name="reason">Reason why player left battlefield</param>
public void SendBfLeaveMessage(ulong queueId, BattlefieldState battleState, bool relocated, BFLeaveReason reason = BFLeaveReason.Exited)
{
BFMgrEjected bfMgrEjected = new BFMgrEjected();
bfMgrEjected.QueueID = queueId;
bfMgrEjected.Reason = reason;
bfMgrEjected.BattleState = battleState;
bfMgrEjected.Relocated = relocated;
SendPacket(bfMgrEjected);
}
/// <summary>
/// Send by client on clicking in accept or refuse of invitation windows for join game.
/// </summary>
//[WorldPacketHandler(ClientOpcodes.BfMgrEntryInviteResponse)]
void HandleBfEntryInviteResponse(BFMgrEntryInviteResponse bfMgrEntryInviteResponse)
{
BattleField bf = Global.BattleFieldMgr.GetBattlefieldByQueueId(bfMgrEntryInviteResponse.QueueID);
if (bf == null)
return;
// If player accept invitation
if (bfMgrEntryInviteResponse.AcceptedInvite)
{
bf.PlayerAcceptInviteToWar(GetPlayer());
}
else
{
if (GetPlayer().GetZoneId() == bf.GetZoneId())
bf.KickPlayerFromBattlefield(GetPlayer().GetGUID());
}
}
/// <summary>
/// Send by client when he click on accept for queue.
/// </summary>
//[WorldPacketHandler(ClientOpcodes.BfMgrQueueInviteResponse)]
void HandleBfQueueInviteResponse(BFMgrQueueInviteResponse bfMgrQueueInviteResponse)
{
BattleField bf = Global.BattleFieldMgr.GetBattlefieldByQueueId(bfMgrQueueInviteResponse.QueueID);
if (bf == null)
return;
if (bfMgrQueueInviteResponse.AcceptedInvite)
bf.PlayerAcceptInviteToQueue(GetPlayer());
}
/// <summary>
/// Send by client when exited battlefield
/// </summary>
//[WorldPacketHandler(ClientOpcodes.BfMgrQueueExitRequest)]
void HandleBfExitRequest(BFMgrQueueExitRequest bfMgrQueueExitRequest)
{
BattleField bf = Global.BattleFieldMgr.GetBattlefieldByQueueId(bfMgrQueueExitRequest.QueueID);
if (bf == null)
return;
bf.AskToLeaveQueue(GetPlayer());
}
}
}
+694
View File
@@ -0,0 +1,694 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.Arenas;
using Game.BattleFields;
using Game.BattleGrounds;
using Game.DataStorage;
using Game.Entities;
using Game.Groups;
using Game.Network;
using Game.Network.Packets;
using System;
using System.Collections.Generic;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.BattlemasterHello)]
void HandleBattlemasterHello(Hello hello)
{
Creature unit = GetPlayer().GetNPCIfCanInteractWith(hello.Unit, NPCFlags.BattleMaster);
if (!unit)
return;
// Stop the npc if moving
unit.StopMoving();
BattlegroundTypeId bgTypeId = Global.BattlegroundMgr.GetBattleMasterBG(unit.GetEntry());
if (!GetPlayer().GetBGAccessByLevel(bgTypeId))
{
// temp, must be gossip message...
SendNotification(CypherStrings.YourBgLevelReqError);
return;
}
Global.BattlegroundMgr.SendBattlegroundList(GetPlayer(), hello.Unit, bgTypeId);
}
[WorldPacketHandler(ClientOpcodes.BattlemasterJoin)]
void HandleBattlemasterJoin(BattlemasterJoin battlemasterJoin)
{
bool isPremade = false;
Group grp = null;
BattlefieldStatusFailed battlefieldStatusFailed;
uint bgTypeId_ = (uint)(battlemasterJoin.QueueID & 0xFFFF);
if (!CliDB.BattlemasterListStorage.ContainsKey(bgTypeId_))
{
Log.outError(LogFilter.Network, "Battleground: invalid bgtype ({0}) received. possible cheater? player guid {1}", bgTypeId_, GetPlayer().GetGUID().ToString());
return;
}
if (Global.DisableMgr.IsDisabledFor(DisableType.Battleground, bgTypeId_, null))
{
GetPlayer().SendSysMessage(CypherStrings.BgDisabled);
return;
}
BattlegroundTypeId bgTypeId = (BattlegroundTypeId)bgTypeId_;
// can do this, since it's Battleground, not arena
BattlegroundQueueTypeId bgQueueTypeId = Global.BattlegroundMgr.BGQueueTypeId(bgTypeId, 0);
BattlegroundQueueTypeId bgQueueTypeIdRandom = Global.BattlegroundMgr.BGQueueTypeId(BattlegroundTypeId.RB, 0);
// ignore if player is already in BG
if (GetPlayer().InBattleground())
return;
// get bg instance or bg template if instance not found
Battleground bg = Global.BattlegroundMgr.GetBattlegroundTemplate(bgTypeId);
if (!bg)
return;
// expected bracket entry
PvpDifficultyRecord bracketEntry = Global.DB2Mgr.GetBattlegroundBracketByLevel(bg.GetMapId(), GetPlayer().getLevel());
if (bracketEntry == null)
return;
GroupJoinBattlegroundResult err = GroupJoinBattlegroundResult.None;
// check queue conditions
if (!battlemasterJoin.JoinAsGroup)
{
if (GetPlayer().isUsingLfg())
{
Global.BattlegroundMgr.BuildBattlegroundStatusFailed(out battlefieldStatusFailed, bg, GetPlayer(), 0, 0, GroupJoinBattlegroundResult.LfgCantUseBattleground);
SendPacket(battlefieldStatusFailed);
return;
}
// check Deserter debuff
if (!GetPlayer().CanJoinToBattleground(bg))
{
Global.BattlegroundMgr.BuildBattlegroundStatusFailed(out battlefieldStatusFailed, bg, GetPlayer(), 0, 0, GroupJoinBattlegroundResult.Deserters);
SendPacket(battlefieldStatusFailed);
return;
}
if (GetPlayer().GetBattlegroundQueueIndex(bgQueueTypeIdRandom) < SharedConst.MaxPlayerBGQueues)
{
// player is already in random queue
Global.BattlegroundMgr.BuildBattlegroundStatusFailed(out battlefieldStatusFailed, bg, GetPlayer(), 0, 0, GroupJoinBattlegroundResult.InRandomBg);
SendPacket(battlefieldStatusFailed);
return;
}
if (GetPlayer().InBattlegroundQueue() && bgTypeId == BattlegroundTypeId.RB)
{
// player is already in queue, can't start random queue
Global.BattlegroundMgr.BuildBattlegroundStatusFailed(out battlefieldStatusFailed, bg, GetPlayer(), 0, 0, GroupJoinBattlegroundResult.InNonRandomBg);
SendPacket(battlefieldStatusFailed);
return;
}
// check if already in queue
if (GetPlayer().GetBattlegroundQueueIndex(bgQueueTypeId) < SharedConst.MaxPlayerBGQueues)
return; // player is already in this queue
// check if has free queue slots
if (!GetPlayer().HasFreeBattlegroundQueueId())
{
Global.BattlegroundMgr.BuildBattlegroundStatusFailed(out battlefieldStatusFailed, bg, GetPlayer(), 0, 0, GroupJoinBattlegroundResult.TooManyQueues);
SendPacket(battlefieldStatusFailed);
return;
}
// check Freeze debuff
if (_player.HasAura(9454))
return;
BattlegroundQueue bgQueue = Global.BattlegroundMgr.GetBattlegroundQueue(bgQueueTypeId);
GroupQueueInfo ginfo = bgQueue.AddGroup(GetPlayer(), null, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0);
uint avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry.GetBracketId());
uint queueSlot = GetPlayer().AddBattlegroundQueueId(bgQueueTypeId);
BattlefieldStatusQueued battlefieldStatusQueued;
Global.BattlegroundMgr.BuildBattlegroundStatusQueued(out battlefieldStatusQueued, bg, GetPlayer(), queueSlot, ginfo.JoinTime, avgTime, ginfo.ArenaType, false);
SendPacket(battlefieldStatusQueued);
Log.outDebug(LogFilter.Battleground, "Battleground: player joined queue for bg queue type {0} bg type {1}: GUID {2}, NAME {3}",
bgQueueTypeId, bgTypeId, GetPlayer().GetGUID().ToString(), GetPlayer().GetName());
}
else
{
grp = GetPlayer().GetGroup();
if (!grp)
return;
if (grp.GetLeaderGUID() != GetPlayer().GetGUID())
return;
ObjectGuid errorGuid;
err = grp.CanJoinBattlegroundQueue(bg, bgQueueTypeId, 0, bg.GetMaxPlayersPerTeam(), false, 0, out errorGuid);
isPremade = (grp.GetMembersCount() >= bg.GetMinPlayersPerTeam());
BattlegroundQueue bgQueue = Global.BattlegroundMgr.GetBattlegroundQueue(bgQueueTypeId);
GroupQueueInfo ginfo = null;
uint avgTime = 0;
if (err == 0)
{
Log.outDebug(LogFilter.Battleground, "Battleground: the following players are joining as group:");
ginfo = bgQueue.AddGroup(GetPlayer(), grp, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0);
avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry.GetBracketId());
}
for (GroupReference refe = grp.GetFirstMember(); refe != null; refe = refe.next())
{
Player member = refe.GetSource();
if (!member)
continue; // this should never happen
if (err != 0)
{
BattlefieldStatusFailed battlefieldStatus;
Global.BattlegroundMgr.BuildBattlegroundStatusFailed(out battlefieldStatus, bg, GetPlayer(), 0, 0, err, errorGuid);
member.SendPacket(battlefieldStatus);
continue;
}
// add to queue
uint queueSlot = member.AddBattlegroundQueueId(bgQueueTypeId);
BattlefieldStatusQueued battlefieldStatusQueued;
Global.BattlegroundMgr.BuildBattlegroundStatusQueued(out battlefieldStatusQueued, bg, member, queueSlot, ginfo.JoinTime, avgTime, ginfo.ArenaType, true);
member.SendPacket(battlefieldStatusQueued);
Log.outDebug(LogFilter.Battleground, "Battleground: player joined queue for bg queue type {0} bg type {1}: GUID {2}, NAME {3}",
bgQueueTypeId, bgTypeId, member.GetGUID().ToString(), member.GetName());
}
Log.outDebug(LogFilter.Battleground, "Battleground: group end");
}
Global.BattlegroundMgr.ScheduleQueueUpdate(0, 0, bgQueueTypeId, bgTypeId, bracketEntry.GetBracketId());
}
[WorldPacketHandler(ClientOpcodes.PvpLogData)]
void HandlePVPLogData(PVPLogDataRequest packet)
{
Battleground bg = GetPlayer().GetBattleground();
if (!bg)
return;
// Prevent players from sending BuildPvpLogDataPacket in an arena except for when sent in Battleground.EndBattleground.
if (bg.isArena())
return;
PVPLogData pvpLogData;
bg.BuildPvPLogDataPacket(out pvpLogData);
SendPacket(pvpLogData);
}
[WorldPacketHandler(ClientOpcodes.BattlefieldList)]
void HandleBattlefieldList(BattlefieldListRequest battlefieldList)
{
BattlemasterListRecord bl = CliDB.BattlemasterListStorage.LookupByKey(battlefieldList.ListID);
if (bl == null)
{
Log.outDebug(LogFilter.Battleground, "BattlegroundHandler: invalid bgtype ({0}) with player (Name: {1}, GUID: {2}) received.", battlefieldList.ListID, GetPlayer().GetName(), GetPlayer().GetGUID().ToString());
return;
}
Global.BattlegroundMgr.SendBattlegroundList(GetPlayer(), ObjectGuid.Empty, (BattlegroundTypeId)battlefieldList.ListID);
}
[WorldPacketHandler(ClientOpcodes.BattlefieldPort)]
void HandleBattleFieldPort(BattlefieldPort battlefieldPort)
{
if (!GetPlayer().InBattlegroundQueue())
{
Log.outDebug(LogFilter.Battleground, "CMSG_BATTLEFIELD_PORT {0} Slot: {1}, Unk: {2}, Time: {3}, AcceptedInvite: {4}. Player not in queue!",
GetPlayerInfo(), battlefieldPort.Ticket.Id, battlefieldPort.Ticket.Type, battlefieldPort.Ticket.Time, battlefieldPort.AcceptedInvite);
return;
}
BattlegroundQueueTypeId bgQueueTypeId = GetPlayer().GetBattlegroundQueueTypeId(battlefieldPort.Ticket.Id);
if (bgQueueTypeId == BattlegroundQueueTypeId.None)
{
Log.outDebug(LogFilter.Battleground, "CMSG_BATTLEFIELD_PORT {0} Slot: {1}, Unk: {2}, Time: {3}, AcceptedInvite: {4}. Invalid queueSlot!",
GetPlayerInfo(), battlefieldPort.Ticket.Id, battlefieldPort.Ticket.Type, battlefieldPort.Ticket.Time, battlefieldPort.AcceptedInvite);
return;
}
BattlegroundQueue bgQueue = Global.BattlegroundMgr.GetBattlegroundQueue(bgQueueTypeId);
//we must use temporary variable, because GroupQueueInfo pointer can be deleted in BattlegroundQueue.RemovePlayer() function
GroupQueueInfo ginfo;
if (!bgQueue.GetPlayerGroupInfoData(GetPlayer().GetGUID(), out ginfo))
{
Log.outDebug(LogFilter.Battleground, "CMSG_BATTLEFIELD_PORT {0} Slot: {1}, Unk: {2}, Time: {3}, AcceptedInvite: {4}. Player not in queue (No player Group Info)!",
GetPlayerInfo(), battlefieldPort.Ticket.Id, battlefieldPort.Ticket.Type, battlefieldPort.Ticket.Time, battlefieldPort.AcceptedInvite);
return;
}
// if action == 1, then instanceId is required
if (ginfo.IsInvitedToBGInstanceGUID == 0 && battlefieldPort.AcceptedInvite)
{
Log.outDebug(LogFilter.Battleground, "CMSG_BATTLEFIELD_PORT {0} Slot: {1}, Unk: {2}, Time: {3}, AcceptedInvite: {4}. Player is not invited to any bg!",
GetPlayerInfo(), battlefieldPort.Ticket.Id, battlefieldPort.Ticket.Type, battlefieldPort.Ticket.Time, battlefieldPort.AcceptedInvite);
return;
}
BattlegroundTypeId bgTypeId = Global.BattlegroundMgr.BGTemplateId(bgQueueTypeId);
// BGTemplateId returns Battleground_AA when it is arena queue.
// Do instance id search as there is no AA bg instances.
Battleground bg = Global.BattlegroundMgr.GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId == BattlegroundTypeId.AA ? BattlegroundTypeId.None : bgTypeId);
if (!bg)
{
if (battlefieldPort.AcceptedInvite)
{
Log.outDebug(LogFilter.Battleground, "CMSG_BATTLEFIELD_PORT {0} Slot: {1}, Unk: {2}, Time: {3}, AcceptedInvite: {4}. Cant find BG with id {5}!",
GetPlayerInfo(), battlefieldPort.Ticket.Id, battlefieldPort.Ticket.Type, battlefieldPort.Ticket.Time, battlefieldPort.AcceptedInvite, ginfo.IsInvitedToBGInstanceGUID);
return;
}
bg = Global.BattlegroundMgr.GetBattlegroundTemplate(bgTypeId);
if (!bg)
{
Log.outError(LogFilter.Network, "BattlegroundHandler: bg_template not found for type id {0}.", bgTypeId);
return;
}
}
// get real bg type
bgTypeId = bg.GetTypeID();
// expected bracket entry
PvpDifficultyRecord bracketEntry = Global.DB2Mgr.GetBattlegroundBracketByLevel(bg.GetMapId(), GetPlayer().getLevel());
if (bracketEntry == null)
return;
//some checks if player isn't cheating - it is not exactly cheating, but we cannot allow it
if (battlefieldPort.AcceptedInvite && ginfo.ArenaType == 0)
{
//if player is trying to enter Battleground(not arena!) and he has deserter debuff, we must just remove him from queue
if (!GetPlayer().CanJoinToBattleground(bg))
{
// send bg command result to show nice message
BattlefieldStatusFailed battlefieldStatus;
Global.BattlegroundMgr.BuildBattlegroundStatusFailed(out battlefieldStatus, bg, GetPlayer(), battlefieldPort.Ticket.Id, 0, GroupJoinBattlegroundResult.Deserters);
SendPacket(battlefieldStatus);
battlefieldPort.AcceptedInvite = false;
Log.outDebug(LogFilter.Battleground, "Player {0} ({1}) has a deserter debuff, do not port him to Battleground!", GetPlayer().GetName(), GetPlayer().GetGUID().ToString());
}
//if player don't match Battlegroundmax level, then do not allow him to enter! (this might happen when player leveled up during his waiting in queue
if (GetPlayer().getLevel() > bg.GetMaxLevel())
{
Log.outDebug(LogFilter.Network, "Player {0} ({1}) has level ({2}) higher than maxlevel ({3}) of Battleground({4})! Do not port him to Battleground!",
GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), GetPlayer().getLevel(), bg.GetMaxLevel(), bg.GetTypeID());
battlefieldPort.AcceptedInvite = false;
}
}
if (battlefieldPort.AcceptedInvite)
{
// check Freeze debuff
if (GetPlayer().HasAura(9454))
return;
if (!GetPlayer().IsInvitedForBattlegroundQueueType(bgQueueTypeId))
return; // cheating?
if (!GetPlayer().InBattleground())
GetPlayer().SetBattlegroundEntryPoint();
// resurrect the player
if (!GetPlayer().IsAlive())
{
GetPlayer().ResurrectPlayer(1.0f);
GetPlayer().SpawnCorpseBones();
}
// stop taxi flight at port
if (GetPlayer().IsInFlight())
{
GetPlayer().GetMotionMaster().MovementExpired();
GetPlayer().CleanupAfterTaxiFlight();
}
BattlefieldStatusActive battlefieldStatus;
Global.BattlegroundMgr.BuildBattlegroundStatusActive(out battlefieldStatus, bg, GetPlayer(), battlefieldPort.Ticket.Id, GetPlayer().GetBattlegroundQueueJoinTime(bgQueueTypeId), bg.GetArenaType());
SendPacket(battlefieldStatus);
// remove BattlegroundQueue status from BGmgr
bgQueue.RemovePlayer(GetPlayer().GetGUID(), false);
// this is still needed here if Battleground"jumping" shouldn't add deserter debuff
// also this is required to prevent stuck at old Battlegroundafter SetBattlegroundId set to new
Battleground currentBg = GetPlayer().GetBattleground();
if (currentBg)
currentBg.RemovePlayerAtLeave(GetPlayer().GetGUID(), false, true);
// set the destination instance id
GetPlayer().SetBattlegroundId(bg.GetInstanceID(), bgTypeId);
// set the destination team
GetPlayer().SetBGTeam(ginfo.Team);
Global.BattlegroundMgr.SendToBattleground(GetPlayer(), ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
Log.outDebug(LogFilter.Battleground, "Battleground: player {0} ({1}) joined battle for bg {2}, bgtype {3}, queue type {4}.", GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), bg.GetInstanceID(), bg.GetTypeID(), bgQueueTypeId);
}
else // leave queue
{
// if player leaves rated arena match before match start, it is counted as he played but he lost
if (ginfo.IsRated && ginfo.IsInvitedToBGInstanceGUID != 0)
{
ArenaTeam at = Global.ArenaTeamMgr.GetArenaTeamById((uint)ginfo.Team);
if (at != null)
{
Log.outDebug(LogFilter.Battleground, "UPDATING memberLost's personal arena rating for {0} by opponents rating: {1}, because he has left queue!", GetPlayer().GetGUID().ToString(), ginfo.OpponentsTeamRating);
at.MemberLost(GetPlayer(), ginfo.OpponentsMatchmakerRating);
at.SaveToDB();
}
}
BattlefieldStatusNone battlefieldStatus = new BattlefieldStatusNone();
battlefieldStatus.Ticket = battlefieldPort.Ticket;
SendPacket(battlefieldStatus);
GetPlayer().RemoveBattlegroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue.removeplayer, it causes bugs
bgQueue.RemovePlayer(GetPlayer().GetGUID(), true);
// player left queue, we should update it - do not update Arena Queue
if (ginfo.ArenaType == 0)
Global.BattlegroundMgr.ScheduleQueueUpdate(ginfo.ArenaMatchmakerRating, ginfo.ArenaType, bgQueueTypeId, bgTypeId, bracketEntry.GetBracketId());
Log.outDebug(LogFilter.Battleground, "Battleground: player {0} ({1}) left queue for bgtype {2}, queue type {3}.", GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), bg.GetTypeID(), bgQueueTypeId);
}
}
[WorldPacketHandler(ClientOpcodes.BattlefieldLeave)]
void HandleBattlefieldLeave(BattlefieldLeave packet)
{
// not allow leave Battlegroundin combat
if (GetPlayer().IsInCombat())
{
Battleground bg = GetPlayer().GetBattleground();
if (bg)
if (bg.GetStatus() != BattlegroundStatus.WaitLeave)
return;
}
GetPlayer().LeaveBattleground();
}
[WorldPacketHandler(ClientOpcodes.RequestBattlefieldStatus)]
void HandleRequestBattlefieldStatus(RequestBattlefieldStatus packet)
{
// we must update all queues here
Battleground bg = null;
for (byte i = 0; i < SharedConst.MaxPlayerBGQueues; ++i)
{
BattlegroundQueueTypeId bgQueueTypeId = GetPlayer().GetBattlegroundQueueTypeId(i);
if (bgQueueTypeId == 0)
continue;
BattlegroundTypeId bgTypeId = Global.BattlegroundMgr.BGTemplateId(bgQueueTypeId);
ArenaTypes arenaType = Global.BattlegroundMgr.BGArenaType(bgQueueTypeId);
if (bgTypeId == GetPlayer().GetBattlegroundTypeId())
{
bg = GetPlayer().GetBattleground();
//i cannot check any variable from player class because player class doesn't know if player is in 2v2 / 3v3 or 5v5 arena
//so i must use bg pointer to get that information
if (bg && bg.GetArenaType() == arenaType)
{
BattlefieldStatusActive battlefieldStatus;
Global.BattlegroundMgr.BuildBattlegroundStatusActive(out battlefieldStatus, bg, GetPlayer(), i, GetPlayer().GetBattlegroundQueueJoinTime(bgQueueTypeId), arenaType);
SendPacket(battlefieldStatus);
continue;
}
}
//we are sending update to player about queue - he can be invited there!
//get GroupQueueInfo for queue status
BattlegroundQueue bgQueue = Global.BattlegroundMgr.GetBattlegroundQueue(bgQueueTypeId);
GroupQueueInfo ginfo;
if (!bgQueue.GetPlayerGroupInfoData(GetPlayer().GetGUID(), out ginfo))
continue;
if (ginfo.IsInvitedToBGInstanceGUID != 0)
{
bg = Global.BattlegroundMgr.GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
if (!bg)
continue;
BattlefieldStatusNeedConfirmation battlefieldStatus;
Global.BattlegroundMgr.BuildBattlegroundStatusNeedConfirmation(out battlefieldStatus, bg, GetPlayer(), i, GetPlayer().GetBattlegroundQueueJoinTime(bgQueueTypeId), Time.GetMSTimeDiff(Time.GetMSTime(), ginfo.RemoveInviteTime), arenaType);
SendPacket(battlefieldStatus);
}
else
{
bg = Global.BattlegroundMgr.GetBattlegroundTemplate(bgTypeId);
if (!bg)
continue;
// expected bracket entry
PvpDifficultyRecord bracketEntry = Global.DB2Mgr.GetBattlegroundBracketByLevel(bg.GetMapId(), GetPlayer().getLevel());
if (bracketEntry == null)
continue;
uint avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry.GetBracketId());
BattlefieldStatusQueued battlefieldStatus;
Global.BattlegroundMgr.BuildBattlegroundStatusQueued(out battlefieldStatus, bg, GetPlayer(), i, GetPlayer().GetBattlegroundQueueJoinTime(bgQueueTypeId), avgTime, arenaType, ginfo.Players.Count > 1);
SendPacket(battlefieldStatus);
}
}
}
[WorldPacketHandler(ClientOpcodes.BattlemasterJoinArena)]
void HandleBattlemasterJoinArena(BattlemasterJoinArena packet)
{
// ignore if we already in BG or BG queue
if (GetPlayer().InBattleground())
return;
ArenaTypes arenatype = (ArenaTypes)ArenaTeam.GetTypeBySlot(packet.TeamSizeIndex);
//check existence
Battleground bg = Global.BattlegroundMgr.GetBattlegroundTemplate(BattlegroundTypeId.AA);
if (!bg)
{
Log.outError(LogFilter.Network, "Battleground: template bg (all arenas) not found");
return;
}
if (Global.DisableMgr.IsDisabledFor(DisableType.Battleground, (uint)BattlegroundTypeId.AA, null))
{
GetPlayer().SendSysMessage(CypherStrings.ArenaDisabled);
return;
}
BattlegroundTypeId bgTypeId = bg.GetTypeID();
BattlegroundQueueTypeId bgQueueTypeId = Global.BattlegroundMgr.BGQueueTypeId(bgTypeId, arenatype);
PvpDifficultyRecord bracketEntry = Global.DB2Mgr.GetBattlegroundBracketByLevel(bg.GetMapId(), GetPlayer().getLevel());
if (bracketEntry == null)
return;
Group grp = GetPlayer().GetGroup();
// no group found, error
if (!grp)
return;
if (grp.GetLeaderGUID() != GetPlayer().GetGUID())
return;
uint ateamId = GetPlayer().GetArenaTeamId(packet.TeamSizeIndex);
// check real arenateam existence only here (if it was moved to group.CanJoin .. () then we would ahve to get it twice)
ArenaTeam at = Global.ArenaTeamMgr.GetArenaTeamById(ateamId);
if (at == null)
{
GetPlayer().GetSession().SendNotInArenaTeamPacket(arenatype);
return;
}
// get the team rating for queuing
uint arenaRating = at.GetRating();
uint matchmakerRating = at.GetAverageMMR(grp);
// the arenateam id must match for everyone in the group
if (arenaRating <= 0)
arenaRating = 1;
BattlegroundQueue bgQueue = Global.BattlegroundMgr.GetBattlegroundQueue(bgQueueTypeId);
uint avgTime = 0;
GroupQueueInfo ginfo = null;
ObjectGuid errorGuid;
var err = grp.CanJoinBattlegroundQueue(bg, bgQueueTypeId, (uint)arenatype, (uint)arenatype, true, packet.TeamSizeIndex, out errorGuid);
if (err == 0)
{
Log.outDebug(LogFilter.Battleground, "Battleground: arena team id {0}, leader {1} queued with matchmaker rating {2} for type {3}", GetPlayer().GetArenaTeamId(packet.TeamSizeIndex), GetPlayer().GetName(), matchmakerRating, arenatype);
ginfo = bgQueue.AddGroup(GetPlayer(), grp, bgTypeId, bracketEntry, arenatype, true, false, arenaRating, matchmakerRating, ateamId);
avgTime = bgQueue.GetAverageQueueWaitTime(ginfo, bracketEntry.GetBracketId());
}
for (GroupReference refe = grp.GetFirstMember(); refe != null; refe = refe.next())
{
Player member = refe.GetSource();
if (!member)
continue;
if (err != 0)
{
BattlefieldStatusFailed battlefieldStatus;
Global.BattlegroundMgr.BuildBattlegroundStatusFailed(out battlefieldStatus, bg, GetPlayer(), 0, arenatype, err, errorGuid);
member.SendPacket(battlefieldStatus);
continue;
}
// add to queue
uint queueSlot = member.AddBattlegroundQueueId(bgQueueTypeId);
BattlefieldStatusQueued battlefieldStatusQueued;
Global.BattlegroundMgr.BuildBattlegroundStatusQueued(out battlefieldStatusQueued, bg, member, queueSlot, ginfo.JoinTime, avgTime, arenatype, true);
member.SendPacket(battlefieldStatusQueued);
Log.outDebug(LogFilter.Battleground, "Battleground: player joined queue for arena as group bg queue type {0} bg type {1}: GUID {2}, NAME {3}", bgQueueTypeId, bgTypeId, member.GetGUID().ToString(), member.GetName());
}
Global.BattlegroundMgr.ScheduleQueueUpdate(matchmakerRating, arenatype, bgQueueTypeId, bgTypeId, bracketEntry.GetBracketId());
}
[WorldPacketHandler(ClientOpcodes.ReportPvpPlayerAfk)]
void HandleReportPvPAFK(ReportPvPPlayerAFK reportPvPPlayerAFK)
{
Player reportedPlayer = Global.ObjAccessor.FindPlayer(reportPvPPlayerAFK.Offender);
if (!reportedPlayer)
{
Log.outDebug(LogFilter.Battleground, "WorldSession.HandleReportPvPAFK: player not found");
return;
}
Log.outDebug(LogFilter.BattlegroundReportPvpAfk, "WorldSession.HandleReportPvPAFK: {0} [IP: {1}] reported {2}", _player.GetName(), _player.GetSession().GetRemoteAddress(), reportedPlayer.GetGUID().ToString());
reportedPlayer.ReportedAfkBy(GetPlayer());
}
[WorldPacketHandler(ClientOpcodes.RequestRatedBattlefieldInfo)]
void HandleRequestRatedBattlefieldInfo(RequestRatedBattlefieldInfo packet)
{
/// @Todo: perfome research in this case
/// The unk fields are related to arenas
WorldPacket data = new WorldPacket(ServerOpcodes.RatedBattlefieldInfo);
data.WriteInt32(0); // BgWeeklyWins20vs20
data.WriteInt32(0); // BgWeeklyPlayed20vs20
data.WriteInt32(0); // BgWeeklyPlayed15vs15
data.WriteInt32(0);
data.WriteInt32(0); // BgWeeklyWins10vs10
data.WriteInt32(0);
data.WriteInt32(0);
data.WriteInt32(0);
data.WriteInt32(0); // BgWeeklyWins15vs15
data.WriteInt32(0);
data.WriteInt32(0);
data.WriteInt32(0);
data.WriteInt32(0);
data.WriteInt32(0);
data.WriteInt32(0);
data.WriteInt32(0); // BgWeeklyPlayed10vs10
data.WriteInt32(0);
data.WriteInt32(0);
//SendPacket(data);
}
[WorldPacketHandler(ClientOpcodes.GetPvpOptionsEnabled, Processing = PacketProcessing.Inplace)]
void HandleGetPVPOptionsEnabled(GetPVPOptionsEnabled packet)
{
// This packet is completely irrelevant, it triggers PVP_TYPES_ENABLED lua event but that is not handled in interface code as of 6.1.2
PVPOptionsEnabled pvpOptionsEnabled = new PVPOptionsEnabled();
pvpOptionsEnabled.PugBattlegrounds = true;
SendPacket(new PVPOptionsEnabled());
}
[WorldPacketHandler(ClientOpcodes.RequestPvpRewards)]
void HandleRequestPvpReward(RequestPVPRewards packet)
{
GetPlayer().SendPvpRewards();
}
[WorldPacketHandler(ClientOpcodes.AreaSpiritHealerQuery)]
void HandleAreaSpiritHealerQuery(AreaSpiritHealerQuery areaSpiritHealerQuery)
{
Creature unit = ObjectAccessor.GetCreature(GetPlayer(), areaSpiritHealerQuery.HealerGuid);
if (!unit)
return;
if (!unit.IsSpiritService()) // it's not spirit service
return;
Battleground bg = GetPlayer().GetBattleground();
if (bg != null)
Global.BattlegroundMgr.SendAreaSpiritHealerQuery(GetPlayer(), bg, areaSpiritHealerQuery.HealerGuid);
BattleField bf = Global.BattleFieldMgr.GetBattlefieldToZoneId(GetPlayer().GetZoneId());
if (bf != null)
bf.SendAreaSpiritHealerQuery(GetPlayer(), areaSpiritHealerQuery.HealerGuid);
}
[WorldPacketHandler(ClientOpcodes.AreaSpiritHealerQueue)]
void HandleAreaSpiritHealerQueue(AreaSpiritHealerQueue areaSpiritHealerQueue)
{
Creature unit = ObjectAccessor.GetCreature(GetPlayer(), areaSpiritHealerQueue.HealerGuid);
if (!unit)
return;
if (!unit.IsSpiritService()) // it's not spirit service
return;
Battleground bg = GetPlayer().GetBattleground();
if (bg)
bg.AddPlayerToResurrectQueue(areaSpiritHealerQueue.HealerGuid, GetPlayer().GetGUID());
BattleField bf = Global.BattleFieldMgr.GetBattlefieldToZoneId(GetPlayer().GetZoneId());
if (bf != null)
bf.AddPlayerToResurrectQueue(areaSpiritHealerQueue.HealerGuid, GetPlayer().GetGUID());
}
[WorldPacketHandler(ClientOpcodes.HearthAndResurrect)]
void HandleHearthAndResurrect(HearthAndResurrect packet)
{
if (GetPlayer().IsInFlight())
return;
BattleField bf = Global.BattleFieldMgr.GetBattlefieldToZoneId(GetPlayer().GetZoneId());
if (bf != null)
{
bf.PlayerAskToLeave(_player);
return;
}
AreaTableRecord atEntry = CliDB.AreaTableStorage.LookupByKey(GetPlayer().GetAreaId());
if (atEntry == null || !atEntry.Flags[0].HasAnyFlag(AreaFlags.CanHearthAndResurrect))
return;
GetPlayer().BuildPlayerRepop();
GetPlayer().ResurrectPlayer(1.0f);
GetPlayer().TeleportTo(GetPlayer().GetHomebind());
}
}
}
+96
View File
@@ -0,0 +1,96 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.BattlePets;
using Game.Network;
using Game.Network.Packets;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.BattlePetRequestJournal)]
void HandleBattlePetRequestJournal(BattlePetRequestJournal battlePetRequestJournal)
{
// TODO: Move this to BattlePetMgr::SendJournal() just to have all packets in one file
BattlePetJournal battlePetJournal = new BattlePetJournal();
battlePetJournal.Trap = GetBattlePetMgr().GetTrapLevel();
foreach (var battlePet in GetBattlePetMgr().GetLearnedPets())
battlePetJournal.Pets.Add(battlePet.PacketInfo);
battlePetJournal.Slots = GetBattlePetMgr().GetSlots();
SendPacket(battlePetJournal);
}
[WorldPacketHandler(ClientOpcodes.BattlePetSetBattleSlot)]
void HandleBattlePetSetBattleSlot(BattlePetSetBattleSlot battlePetSetBattleSlot)
{
BattlePetMgr.BattlePet pet = GetBattlePetMgr().GetPet(battlePetSetBattleSlot.PetGuid);
if (pet != null)
GetBattlePetMgr().GetSlot(battlePetSetBattleSlot.Slot).Pet = pet.PacketInfo;
}
[WorldPacketHandler(ClientOpcodes.BattlePetModifyName)]
void HandleBattlePetModifyName(BattlePetModifyName battlePetModifyName)
{
BattlePetMgr.BattlePet pet = GetBattlePetMgr().GetPet(battlePetModifyName.PetGuid);
if (pet != null)
{
pet.PacketInfo.Name = battlePetModifyName.Name;
if (pet.SaveInfo != BattlePetSaveInfo.New)
pet.SaveInfo = BattlePetSaveInfo.Changed;
}
}
[WorldPacketHandler(ClientOpcodes.BattlePetDeletePet)]
void HandleBattlePetDeletePet(BattlePetDeletePet battlePetDeletePet)
{
GetBattlePetMgr().RemovePet(battlePetDeletePet.PetGuid);
}
[WorldPacketHandler(ClientOpcodes.BattlePetSetFlags)]
void HandleBattlePetSetFlags(BattlePetSetFlags battlePetSetFlags)
{
var pet = GetBattlePetMgr().GetPet(battlePetSetFlags.PetGuid);
if (pet != null)
{
if (battlePetSetFlags.ControlType == FlagsControlType.Apply)
pet.PacketInfo.Flags |= (ushort)battlePetSetFlags.Flags;
else
pet.PacketInfo.Flags &= (ushort)~battlePetSetFlags.Flags;
if (pet.SaveInfo != BattlePetSaveInfo.New)
pet.SaveInfo = BattlePetSaveInfo.Changed;
}
}
[WorldPacketHandler(ClientOpcodes.CageBattlePet)]
void HandleCageBattlePet(CageBattlePet cageBattlePet)
{
GetBattlePetMgr().CageBattlePet(cageBattlePet.PetGuid);
}
[WorldPacketHandler(ClientOpcodes.BattlePetSummon, Processing = PacketProcessing.Inplace)]
void HandleBattlePetSummon(BattlePetSummon battlePetSummon)
{
GetBattlePetMgr().SummonPet(battlePetSummon.PetGuid);
}
}
}
+92
View File
@@ -0,0 +1,92 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.Network;
using Game.Network.Packets;
using Google.Protobuf;
using System;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.BattlenetRequest, Status = SessionStatus.Authed)]
void HandleBattlenetRequest(BattlenetRequest request)
{
Global.ServiceMgr.Dispatch(this, request.Method.GetServiceHash(), request.Method.Token, request.Method.GetMethodId(), new CodedInputStream(request.Data));
}
[WorldPacketHandler(ClientOpcodes.BattlenetRequestRealmListTicket, Status = SessionStatus.Authed)]
void HandleBattlenetRequestRealmListTicket(RequestRealmListTicket requestRealmListTicket)
{
SetRealmListSecret(requestRealmListTicket.Secret);
RealmListTicket realmListTicket = new RealmListTicket();
realmListTicket.Token = requestRealmListTicket.Token;
realmListTicket.Allow = true;
realmListTicket.Ticket = new Framework.IO.ByteBuffer();
realmListTicket.Ticket.WriteCString("WorldserverRealmListTicket");
SendPacket(realmListTicket);
}
public void SendBattlenetResponse(uint serviceHash, uint methodId, uint token, IMessage response)
{
Response bnetResponse = new Response();
bnetResponse.BnetStatus = BattlenetRpcErrorCode.Ok;
bnetResponse.Method.Type = MathFunctions.MakePair64(methodId, serviceHash);
bnetResponse.Method.ObjectId = 1;
bnetResponse.Method.Token = token;
if (response.CalculateSize() != 0)
bnetResponse.Data.WriteBytes(response.ToByteArray());
SendPacket(bnetResponse);
}
public void SendBattlenetResponse(uint serviceHash, uint methodId, uint token, BattlenetRpcErrorCode status)
{
Response bnetResponse = new Response();
bnetResponse.BnetStatus = status;
bnetResponse.Method.Type = MathFunctions.MakePair64(methodId, serviceHash);
bnetResponse.Method.ObjectId = 1;
bnetResponse.Method.Token = token;
SendPacket(bnetResponse);
}
public void SendBattlenetRequest(uint serviceHash, uint methodId, IMessage request, Action<CodedInputStream> callback)
{
_battlenetResponseCallbacks[_battlenetRequestToken] = callback;
SendBattlenetRequest(serviceHash, methodId, request);
}
public void SendBattlenetRequest(uint serviceHash, uint methodId, IMessage request)
{
Notification notification = new Notification();
notification.Method.Type = MathFunctions.MakePair64(methodId, serviceHash);
notification.Method.ObjectId = 1;
notification.Method.Token = _battlenetRequestToken++;
if (request.CalculateSize() != 0)
notification.Data.WriteBytes(request.ToByteArray());
SendPacket(notification);
}
}
}
+165
View File
@@ -0,0 +1,165 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Framework.Database;
using Game.BlackMarket;
using Game.Entities;
using Game.Network;
using Game.Network.Packets;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.BlackMarketOpen)]
void HandleBlackMarketOpen(BlackMarketOpen blackMarketOpen)
{
Creature unit = GetPlayer().GetNPCIfCanInteractWith(blackMarketOpen.Guid, NPCFlags.BlackMarket | NPCFlags.BlackMarketView);
if (!unit)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleBlackMarketHello - {0} not found or you can't interact with him.", blackMarketOpen.Guid.ToString());
return;
}
// remove fake death
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
SendBlackMarketOpenResult(blackMarketOpen.Guid, unit);
}
void SendBlackMarketOpenResult(ObjectGuid guid, Creature auctioneer)
{
BlackMarketOpenResult packet = new BlackMarketOpenResult();
packet.Guid = guid;
packet.Enable = Global.BlackMarketMgr.IsEnabled();
SendPacket(packet);
}
[WorldPacketHandler(ClientOpcodes.BlackMarketRequestItems)]
void HandleBlackMarketRequestItems(BlackMarketRequestItems blackMarketRequestItems)
{
if (!Global.BlackMarketMgr.IsEnabled())
return;
Creature unit = GetPlayer().GetNPCIfCanInteractWith(blackMarketRequestItems.Guid, NPCFlags.BlackMarket | NPCFlags.BlackMarketView);
if (!unit)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleBlackMarketRequestItems - {0} not found or you can't interact with him.", blackMarketRequestItems.Guid.ToString());
return;
}
BlackMarketRequestItemsResult result = new BlackMarketRequestItemsResult();
Global.BlackMarketMgr.BuildItemsResponse(result, GetPlayer());
SendPacket(result);
}
[WorldPacketHandler(ClientOpcodes.BlackMarketBidOnItem)]
void HandleBlackMarketBidOnItem(BlackMarketBidOnItem blackMarketBidOnItem)
{
if (!Global.BlackMarketMgr.IsEnabled())
return;
Player player = GetPlayer();
Creature unit = player.GetNPCIfCanInteractWith(blackMarketBidOnItem.Guid, NPCFlags.BlackMarket);
if (!unit)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleBlackMarketBidOnItem - {0} not found or you can't interact with him.", blackMarketBidOnItem.Guid.ToString());
return;
}
BlackMarketEntry entry = Global.BlackMarketMgr.GetAuctionByID(blackMarketBidOnItem.MarketID);
if (entry == null)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleBlackMarketBidOnItem - {0} (name: {1}) tried to bid on a nonexistent auction (MarketId: {2}).", player.GetGUID().ToString(), player.GetName(), blackMarketBidOnItem.MarketID);
SendBlackMarketBidOnItemResult(BlackMarketError.ItemNotFound, blackMarketBidOnItem.MarketID, blackMarketBidOnItem.Item);
return;
}
if (entry.GetBidder() == player.GetGUID().GetCounter())
{
Log.outDebug(LogFilter.Network, "WORLD: HandleBlackMarketBidOnItem - {0} (name: {1}) tried to place a bid on an item he already bid on. (MarketId: {2}).", player.GetGUID().ToString(), player.GetName(), blackMarketBidOnItem.MarketID);
SendBlackMarketBidOnItemResult(BlackMarketError.AlreadyBid, blackMarketBidOnItem.MarketID, blackMarketBidOnItem.Item);
return;
}
if (!entry.ValidateBid(blackMarketBidOnItem.BidAmount))
{
Log.outDebug(LogFilter.Network, "WORLD: HandleBlackMarketBidOnItem - {0} (name: {1}) tried to place an invalid bid. Amount: {2} (MarketId: {3}).", player.GetGUID().ToString(), player.GetName(), blackMarketBidOnItem.BidAmount, blackMarketBidOnItem.MarketID);
SendBlackMarketBidOnItemResult(BlackMarketError.HigherBid, blackMarketBidOnItem.MarketID, blackMarketBidOnItem.Item);
return;
}
if (!player.HasEnoughMoney(blackMarketBidOnItem.BidAmount))
{
Log.outDebug(LogFilter.Network, "WORLD: HandleBlackMarketBidOnItem - {0} (name: {1}) does not have enough money to place bid. (MarketId: {2}).", player.GetGUID().ToString(), player.GetName(), blackMarketBidOnItem.MarketID);
SendBlackMarketBidOnItemResult(BlackMarketError.NotEnoughMoney, blackMarketBidOnItem.MarketID, blackMarketBidOnItem.Item);
return;
}
if (entry.GetSecondsRemaining() <= 0)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleBlackMarketBidOnItem - {0} (name: {1}) tried to bid on a completed auction. (MarketId: {2}).", player.GetGUID().ToString(), player.GetName(), blackMarketBidOnItem.MarketID);
SendBlackMarketBidOnItemResult(BlackMarketError.DatabaseError, blackMarketBidOnItem.MarketID, blackMarketBidOnItem.Item);
return;
}
SQLTransaction trans = new SQLTransaction();
Global.BlackMarketMgr.SendAuctionOutbidMail(entry, trans);
entry.PlaceBid(blackMarketBidOnItem.BidAmount, player, trans);
DB.Characters.CommitTransaction(trans);
SendBlackMarketBidOnItemResult(BlackMarketError.Ok, blackMarketBidOnItem.MarketID, blackMarketBidOnItem.Item);
}
void SendBlackMarketBidOnItemResult(BlackMarketError result, uint marketId, ItemInstance item)
{
BlackMarketBidOnItemResult packet = new BlackMarketBidOnItemResult();
packet.MarketID = marketId;
packet.Item = item;
packet.Result = result;
SendPacket(packet);
}
public void SendBlackMarketWonNotification(BlackMarketEntry entry, Item item)
{
BlackMarketWon packet = new BlackMarketWon();
packet.MarketID = entry.GetMarketId();
packet.Item = new ItemInstance(item);
packet.RandomPropertiesID = item.GetItemRandomPropertyId();
SendPacket(packet);
}
public void SendBlackMarketOutbidNotification(BlackMarketTemplate templ)
{
BlackMarketOutbid packet = new BlackMarketOutbid();
packet.MarketID = templ.MarketID;
packet.Item = templ.Item;
packet.RandomPropertiesID = templ.Item.RandomPropertiesID;
SendPacket(packet);
}
}
}
+524
View File
@@ -0,0 +1,524 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Framework.Database;
using Game.Entities;
using Game.Guilds;
using Game.Maps;
using Game.Network;
using Game.Network.Packets;
using System;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.CalendarGet)]
void HandleCalendarGetCalendar(CalendarGetCalendar calendarGetCalendar)
{
ObjectGuid guid = GetPlayer().GetGUID();
long currTime = Time.UnixTime;
CalendarSendCalendar packet = new CalendarSendCalendar();
packet.ServerTime = currTime;
var invites = Global.CalendarMgr.GetPlayerInvites(guid);
foreach (var invite in invites)
{
CalendarSendCalendarInviteInfo inviteInfo = new CalendarSendCalendarInviteInfo();
inviteInfo.EventID = invite.EventId;
inviteInfo.InviteID = invite.InviteId;
inviteInfo.InviterGuid = invite.SenderGuid;
inviteInfo.Status = invite.Status;
inviteInfo.Moderator = invite.Rank;
CalendarEvent calendarEvent = Global.CalendarMgr.GetEvent(invite.EventId);
if (calendarEvent != null)
inviteInfo.InviteType = (byte)(calendarEvent.IsGuildEvent() && calendarEvent.GuildId == _player.GetGuildId() ? 1 : 0);
packet.Invites.Add(inviteInfo);
}
var playerEvents = Global.CalendarMgr.GetPlayerEvents(guid);
foreach (var calendarEvent in playerEvents)
{
CalendarSendCalendarEventInfo eventInfo;
eventInfo.EventID = calendarEvent.EventId;
eventInfo.Date = calendarEvent.Date;
Guild guild = Global.GuildMgr.GetGuildById(calendarEvent.GuildId);
eventInfo.EventGuildID = guild ? guild.GetGUID() : ObjectGuid.Empty;
eventInfo.EventName = calendarEvent.Title;
eventInfo.EventType = calendarEvent.EventType;
eventInfo.Flags = calendarEvent.Flags;
eventInfo.OwnerGuid = calendarEvent.OwnerGuid;
eventInfo.TextureID = calendarEvent.TextureId;
packet.Events.Add(eventInfo);
}
for (byte i = 0; i < (int)Difficulty.Max; ++i)
{
var boundInstances = GetPlayer().GetBoundInstances((Difficulty)i);
foreach (var pair in boundInstances)
{
if (pair.Value.perm)
{
CalendarSendCalendarRaidLockoutInfo lockoutInfo;
InstanceSave save = pair.Value.save;
lockoutInfo.MapID = (int)save.GetMapId();
lockoutInfo.DifficultyID = (uint)save.GetDifficultyID();
lockoutInfo.ExpireTime = save.GetResetTime() - currTime;
lockoutInfo.InstanceID = save.GetInstanceId(); // instance save id as unique instance copy id
packet.RaidLockouts.Add(lockoutInfo);
}
}
}
SendPacket(packet);
}
[WorldPacketHandler(ClientOpcodes.CalendarGetEvent)]
void HandleCalendarGetEvent(CalendarGetEvent calendarGetEvent)
{
CalendarEvent calendarEvent = Global.CalendarMgr.GetEvent(calendarGetEvent.EventID);
if (calendarEvent != null)
Global.CalendarMgr.SendCalendarEvent(GetPlayer().GetGUID(), calendarEvent, CalendarSendEventType.Get);
else
Global.CalendarMgr.SendCalendarCommandResult(GetPlayer().GetGUID(), CalendarError.EventInvalid);
}
[WorldPacketHandler(ClientOpcodes.CalendarGuildFilter)]
void HandleCalendarGuildFilter(CalendarGuildFilter calendarGuildFilter)
{
Guild guild = Global.GuildMgr.GetGuildById(GetPlayer().GetGuildId());
if (guild)
guild.MassInviteToEvent(this, calendarGuildFilter.MinLevel, calendarGuildFilter.MaxLevel, calendarGuildFilter.MaxRankOrder);
}
[WorldPacketHandler(ClientOpcodes.CalendarAddEvent)]
void HandleCalendarAddEvent(CalendarAddEvent calendarAddEvent)
{
ObjectGuid guid = GetPlayer().GetGUID();
// prevent events in the past
// To Do: properly handle timezones and remove the "- time_t(86400L)" hack
if (calendarAddEvent.EventInfo.Time < (Time.UnixTime - 86400L))
return;
CalendarEvent calendarEvent = new CalendarEvent(Global.CalendarMgr.GetFreeEventId(), guid, 0, (CalendarEventType)calendarAddEvent.EventInfo.EventType, calendarAddEvent.EventInfo.TextureID,
calendarAddEvent.EventInfo.Time, (CalendarFlags)calendarAddEvent.EventInfo.Flags, calendarAddEvent.EventInfo.Title, calendarAddEvent.EventInfo.Description, 0);
if (calendarEvent.IsGuildEvent() || calendarEvent.IsGuildAnnouncement())
{
Player creator = Global.ObjAccessor.FindPlayer(guid);
if (creator)
calendarEvent.GuildId = creator.GetGuildId();
}
if (calendarEvent.IsGuildAnnouncement())
{
CalendarInvite invite = new CalendarInvite(0, calendarEvent.EventId, ObjectGuid.Empty, guid, SharedConst.CalendarDefaultResponseTime, CalendarInviteStatus.NotSignedUp, CalendarModerationRank.Player, "");
// WARNING: By passing pointer to a local variable, the underlying method(s) must NOT perform any kind
// of storage of the pointer as it will lead to memory corruption
Global.CalendarMgr.AddInvite(calendarEvent, invite);
}
else
{
SQLTransaction trans = null;
if (calendarAddEvent.EventInfo.Invites.Length > 1)
trans = new SQLTransaction();
for (int i = 0; i < calendarAddEvent.EventInfo.Invites.Length; ++i)
{
CalendarInvite invite = new CalendarInvite(Global.CalendarMgr.GetFreeInviteId(), calendarEvent.EventId,
calendarAddEvent.EventInfo.Invites[i].Guid, guid, SharedConst.CalendarDefaultResponseTime, (CalendarInviteStatus)calendarAddEvent.EventInfo.Invites[i].Status,
(CalendarModerationRank)calendarAddEvent.EventInfo.Invites[i].Moderator, "");
Global.CalendarMgr.AddInvite(calendarEvent, invite, trans);
}
if (calendarAddEvent.EventInfo.Invites.Length > 1)
DB.Characters.CommitTransaction(trans);
}
Global.CalendarMgr.AddEvent(calendarEvent, CalendarSendEventType.Add);
}
[WorldPacketHandler(ClientOpcodes.CalendarUpdateEvent)]
void HandleCalendarUpdateEvent(CalendarUpdateEvent calendarUpdateEvent)
{
ObjectGuid guid = GetPlayer().GetGUID();
long oldEventTime;
// prevent events in the past
// To Do: properly handle timezones and remove the "- time_t(86400L)" hack
if (calendarUpdateEvent.EventInfo.Time < (Time.UnixTime - 86400L))
return;
CalendarEvent calendarEvent = Global.CalendarMgr.GetEvent(calendarUpdateEvent.EventInfo.EventID);
if (calendarEvent != null)
{
oldEventTime = calendarEvent.Date;
calendarEvent.EventType = (CalendarEventType)calendarUpdateEvent.EventInfo.EventType;
calendarEvent.Flags = (CalendarFlags)calendarUpdateEvent.EventInfo.Flags;
calendarEvent.Date = calendarUpdateEvent.EventInfo.Time;
calendarEvent.TextureId = (int)calendarUpdateEvent.EventInfo.TextureID;
calendarEvent.Title = calendarUpdateEvent.EventInfo.Title;
calendarEvent.Description = calendarUpdateEvent.EventInfo.Description;
Global.CalendarMgr.UpdateEvent(calendarEvent);
Global.CalendarMgr.SendCalendarEventUpdateAlert(calendarEvent, oldEventTime);
}
else
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.EventInvalid);
}
[WorldPacketHandler(ClientOpcodes.CalendarRemoveEvent)]
void HandleCalendarRemoveEvent(CalendarRemoveEvent calendarRemoveEvent)
{
ObjectGuid guid = GetPlayer().GetGUID();
Global.CalendarMgr.RemoveEvent(calendarRemoveEvent.EventID, guid);
}
[WorldPacketHandler(ClientOpcodes.CalendarCopyEvent)]
void HandleCalendarCopyEvent(CalendarCopyEvent calendarCopyEvent)
{
ObjectGuid guid = GetPlayer().GetGUID();
// prevent events in the past
// To Do: properly handle timezones and remove the "- time_t(86400L)" hack
if (calendarCopyEvent.Date < (Time.UnixTime - 86400L))
return;
CalendarEvent oldEvent = Global.CalendarMgr.GetEvent(calendarCopyEvent.EventID);
if (oldEvent == null)
{
CalendarEvent newEvent = new CalendarEvent(oldEvent, Global.CalendarMgr.GetFreeEventId());
newEvent.Date = calendarCopyEvent.Date;
Global.CalendarMgr.AddEvent(newEvent, CalendarSendEventType.Copy);
var invites = Global.CalendarMgr.GetEventInvites(calendarCopyEvent.EventID);
SQLTransaction trans = null;
if (invites.Count > 1)
trans = new SQLTransaction();
foreach (var invite in invites)
Global.CalendarMgr.AddInvite(newEvent, new CalendarInvite(invite, Global.CalendarMgr.GetFreeInviteId(), newEvent.EventId), trans);
if (invites.Count > 1)
DB.Characters.CommitTransaction(trans);
// should we change owner when somebody makes a copy of event owned by another person?
}
else
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.EventInvalid);
}
[WorldPacketHandler(ClientOpcodes.CalendarEventInvite)]
void HandleCalendarEventInvite(CalendarEventInvite calendarEventInvite)
{
ObjectGuid playerGuid = GetPlayer().GetGUID();
ObjectGuid inviteeGuid = ObjectGuid.Empty;
Team inviteeTeam = 0;
ulong inviteeGuildId = 0;
Player player = Global.ObjAccessor.FindPlayerByName(calendarEventInvite.Name);
if (player)
{
// Invitee is online
inviteeGuid = player.GetGUID();
inviteeTeam = player.GetTeam();
inviteeGuildId = player.GetGuildId();
}
else
{
// Invitee offline, get data from database
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_GUID_RACE_ACC_BY_NAME);
stmt.AddValue(0, calendarEventInvite.Name);
SQLResult result = DB.Characters.Query(stmt);
if (!result.IsEmpty())
{
inviteeGuid = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(0));
inviteeTeam = Player.TeamForRace((Race)result.Read<byte>(1));
inviteeGuildId = Player.GetGuildIdFromDB(inviteeGuid);
}
}
if (inviteeGuid.IsEmpty())
{
Global.CalendarMgr.SendCalendarCommandResult(playerGuid, CalendarError.PlayerNotFound);
return;
}
if (GetPlayer().GetTeam() != inviteeTeam && !WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionCalendar))
{
Global.CalendarMgr.SendCalendarCommandResult(playerGuid, CalendarError.NotAllied);
return;
}
SQLResult result1 = DB.Characters.Query("SELECT flags FROM character_social WHERE guid = {0} AND friend = {1}", inviteeGuid, playerGuid);
if (!result1.IsEmpty())
{
if (Convert.ToBoolean(result1.Read<byte>(0) & (byte)SocialFlag.Ignored))
{
Global.CalendarMgr.SendCalendarCommandResult(playerGuid, CalendarError.IgnoringYouS, calendarEventInvite.Name);
return;
}
}
if (!calendarEventInvite.Creating)
{
CalendarEvent calendarEvent = Global.CalendarMgr.GetEvent(calendarEventInvite.EventID);
if (calendarEvent != null)
{
if (calendarEvent.IsGuildEvent() && calendarEvent.GuildId == inviteeGuildId)
{
// we can't invite guild members to guild events
Global.CalendarMgr.SendCalendarCommandResult(playerGuid, CalendarError.NoGuildInvites);
return;
}
CalendarInvite invite = new CalendarInvite(Global.CalendarMgr.GetFreeInviteId(), calendarEventInvite.EventID, inviteeGuid, playerGuid, SharedConst.CalendarDefaultResponseTime, CalendarInviteStatus.Invited, CalendarModerationRank.Player, "");
Global.CalendarMgr.AddInvite(calendarEvent, invite);
}
else
Global.CalendarMgr.SendCalendarCommandResult(playerGuid, CalendarError.EventInvalid);
}
else
{
if (calendarEventInvite.IsSignUp && inviteeGuildId == GetPlayer().GetGuildId())
{
Global.CalendarMgr.SendCalendarCommandResult(playerGuid, CalendarError.NoGuildInvites);
return;
}
CalendarInvite invite = new CalendarInvite(calendarEventInvite.EventID, 0, inviteeGuid, playerGuid, SharedConst.CalendarDefaultResponseTime, CalendarInviteStatus.Invited, CalendarModerationRank.Player, "");
Global.CalendarMgr.SendCalendarEventInvite(invite);
}
}
[WorldPacketHandler(ClientOpcodes.CalendarEventSignUp)]
void HandleCalendarEventSignup(CalendarEventSignUp calendarEventSignUp)
{
ObjectGuid guid = GetPlayer().GetGUID();
CalendarEvent calendarEvent = Global.CalendarMgr.GetEvent(calendarEventSignUp.EventID);
if (calendarEvent != null)
{
if (calendarEvent.IsGuildEvent() && calendarEvent.GuildId != GetPlayer().GetGuildId())
{
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.GuildPlayerNotInGuild);
return;
}
CalendarInviteStatus status = calendarEventSignUp.Tentative ? CalendarInviteStatus.Tentative : CalendarInviteStatus.SignedUp;
CalendarInvite invite = new CalendarInvite(Global.CalendarMgr.GetFreeInviteId(), calendarEventSignUp.EventID, guid, guid, Time.UnixTime, status, CalendarModerationRank.Player, "");
Global.CalendarMgr.AddInvite(calendarEvent, invite);
Global.CalendarMgr.SendCalendarClearPendingAction(guid);
}
else
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.EventInvalid);
}
[WorldPacketHandler(ClientOpcodes.CalendarEventRsvp)]
void HandleCalendarEventRsvp(CalendarEventRSVP calendarEventRSVP)
{
ObjectGuid guid = GetPlayer().GetGUID();
CalendarEvent calendarEvent = Global.CalendarMgr.GetEvent(calendarEventRSVP.EventID);
if (calendarEvent != null)
{
// i think we still should be able to remove self from locked events
if (calendarEventRSVP.Status != CalendarInviteStatus.Removed && calendarEvent.IsLocked())
{
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.EventLocked);
return;
}
CalendarInvite invite = Global.CalendarMgr.GetInvite(calendarEventRSVP.InviteID);
if (invite != null)
{
invite.Status = calendarEventRSVP.Status;
invite.ResponseTime = Time.UnixTime;
Global.CalendarMgr.UpdateInvite(invite);
Global.CalendarMgr.SendCalendarEventStatus(calendarEvent, invite);
Global.CalendarMgr.SendCalendarClearPendingAction(guid);
}
else
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.NoInvite); // correct?
}
else
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.EventInvalid);
}
[WorldPacketHandler(ClientOpcodes.CalendarRemoveInvite)]
void HandleCalendarEventRemoveInvite(CalendarRemoveInvite calendarRemoveInvite)
{
ObjectGuid guid = GetPlayer().GetGUID();
CalendarEvent calendarEvent = Global.CalendarMgr.GetEvent(calendarRemoveInvite.EventID);
if (calendarEvent != null)
{
if (calendarEvent.OwnerGuid == calendarRemoveInvite.Guid)
{
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.DeleteCreatorFailed);
return;
}
Global.CalendarMgr.RemoveInvite(calendarRemoveInvite.InviteID, calendarRemoveInvite.EventID, guid);
}
else
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.NoInvite);
}
[WorldPacketHandler(ClientOpcodes.CalendarEventStatus)]
void HandleCalendarEventStatus(CalendarEventStatus calendarEventStatus)
{
ObjectGuid guid = GetPlayer().GetGUID();
CalendarEvent calendarEvent = Global.CalendarMgr.GetEvent(calendarEventStatus.EventID);
if (calendarEvent != null)
{
CalendarInvite invite = Global.CalendarMgr.GetInvite(calendarEventStatus.InviteID);
if (invite != null)
{
invite.Status = (CalendarInviteStatus)calendarEventStatus.Status;
Global.CalendarMgr.UpdateInvite(invite);
Global.CalendarMgr.SendCalendarEventStatus(calendarEvent, invite);
Global.CalendarMgr.SendCalendarClearPendingAction(calendarEventStatus.Guid);
}
else
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.NoInvite); // correct?
}
else
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.EventInvalid);
}
[WorldPacketHandler(ClientOpcodes.CalendarEventModeratorStatus)]
void HandleCalendarEventModeratorStatus(CalendarEventModeratorStatus calendarEventModeratorStatus)
{
ObjectGuid guid = GetPlayer().GetGUID();
CalendarEvent calendarEvent = Global.CalendarMgr.GetEvent(calendarEventModeratorStatus.EventID);
if (calendarEvent != null)
{
CalendarInvite invite = Global.CalendarMgr.GetInvite(calendarEventModeratorStatus.InviteID);
if (invite != null)
{
invite.Rank = (CalendarModerationRank)calendarEventModeratorStatus.Status;
Global.CalendarMgr.UpdateInvite(invite);
Global.CalendarMgr.SendCalendarEventModeratorStatusAlert(calendarEvent, invite);
}
else
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.NoInvite); // correct?
}
else
Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.EventInvalid);
}
[WorldPacketHandler(ClientOpcodes.CalendarComplain)]
void HandleCalendarComplain(CalendarComplain calendarComplain)
{
// what to do with complains?
}
[WorldPacketHandler(ClientOpcodes.CalendarGetNumPending)]
void HandleCalendarGetNumPending(CalendarGetNumPending calendarGetNumPending)
{
ObjectGuid guid = GetPlayer().GetGUID();
uint pending = Global.CalendarMgr.GetPlayerNumPending(guid);
SendPacket(new CalendarSendNumPending(pending));
}
[WorldPacketHandler(ClientOpcodes.SetSavedInstanceExtend)]
void HandleSetSavedInstanceExtend(SetSavedInstanceExtend setSavedInstanceExtend)
{
Player player = GetPlayer();
if (player)
{
InstanceBind instanceBind = player.GetBoundInstance((uint)setSavedInstanceExtend.MapID, (Difficulty)setSavedInstanceExtend.DifficultyID, setSavedInstanceExtend.Extend); // include expired instances if we are toggling extend on
if (instanceBind == null || instanceBind.save == null || !instanceBind.perm)
return;
BindExtensionState newState;
if (!setSavedInstanceExtend.Extend || instanceBind.extendState == BindExtensionState.Expired)
newState = BindExtensionState.Normal;
else
newState = BindExtensionState.Extended;
player.BindToInstance(instanceBind.save, true, newState, false);
}
/*
InstancePlayerBind* instanceBind = GetPlayer().GetBoundInstance(setSavedInstanceExtend.MapID, Difficulty(setSavedInstanceExtend.DifficultyID);
if (!instanceBind || !instanceBind.save)
return;
InstanceSave* save = instanceBind.save;
// http://www.wowwiki.com/Instance_Lock_Extension
// SendCalendarRaidLockoutUpdated(save);
*/
}
public void SendCalendarRaidLockout(InstanceSave save, bool add)
{
long currTime = Time.UnixTime;
if (add)
{
CalendarRaidLockoutAdded calendarRaidLockoutAdded = new CalendarRaidLockoutAdded();
calendarRaidLockoutAdded.InstanceID = save.GetInstanceId();
calendarRaidLockoutAdded.ServerTime = (uint)currTime;
calendarRaidLockoutAdded.MapID = (int)save.GetMapId();
calendarRaidLockoutAdded.DifficultyID = save.GetDifficultyID();
calendarRaidLockoutAdded.TimeRemaining = (int)(save.GetResetTime() - currTime);
SendPacket(calendarRaidLockoutAdded);
}
else
{
CalendarRaidLockoutRemoved calendarRaidLockoutRemoved = new CalendarRaidLockoutRemoved();
calendarRaidLockoutRemoved.InstanceID = save.GetInstanceId();
calendarRaidLockoutRemoved.MapID = (int)save.GetMapId();
calendarRaidLockoutRemoved.DifficultyID = save.GetDifficultyID();
SendPacket(calendarRaidLockoutRemoved);
}
}
public void SendCalendarRaidLockoutUpdated(InstanceSave save)
{
if (save == null)
return;
ObjectGuid guid = GetPlayer().GetGUID();
long currTime = Time.UnixTime;
CalendarRaidLockoutUpdated packet = new CalendarRaidLockoutUpdated();
packet.DifficultyID = (uint)save.GetDifficultyID();
packet.MapID = (int)save.GetMapId();
packet.NewTimeRemaining = 0; // FIXME
packet.OldTimeRemaining = (int)(save.GetResetTime() - currTime);
SendPacket(packet);
}
}
}
+200
View File
@@ -0,0 +1,200 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.Chat;
using Game.DataStorage;
using Game.Network;
using Game.Network.Packets;
using System;
using System.Collections.Generic;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.ChatJoinChannel)]
void HandleJoinChannel(JoinChannel packet)
{
AreaTableRecord zone = CliDB.AreaTableStorage.LookupByKey(GetPlayer().GetZoneId());
if (packet.ChatChannelId != 0)
{
ChatChannelsRecord channel = CliDB.ChatChannelsStorage.LookupByKey(packet.ChatChannelId);
if (channel == null)
return;
if (zone == null || !GetPlayer().CanJoinConstantChannelInZone(channel, zone))
return;
}
if (string.IsNullOrEmpty(packet.ChannelName))
return;
if (packet.ChannelName.IsNumber())
return;
ChannelManager cMgr = ChannelManager.ForTeam(GetPlayer().GetTeam());
if (cMgr != null)
{
Channel channel = cMgr.GetJoinChannel((uint)packet.ChatChannelId, packet.ChannelName, zone);
if (channel != null)
channel.JoinChannel(GetPlayer(), packet.Password);
}
}
[WorldPacketHandler(ClientOpcodes.ChatLeaveChannel)]
void HandleLeaveChannel(LeaveChannel packet)
{
if (string.IsNullOrEmpty(packet.ChannelName) && packet.ZoneChannelID == 0)
return;
AreaTableRecord zone = CliDB.AreaTableStorage.LookupByKey(GetPlayer().GetZoneId());
if (packet.ZoneChannelID != 0)
{
ChatChannelsRecord channel = CliDB.ChatChannelsStorage.LookupByKey(packet.ZoneChannelID);
if (channel == null)
return;
if (zone == null || !GetPlayer().CanJoinConstantChannelInZone(channel, zone))
return;
}
ChannelManager cMgr = ChannelManager.ForTeam(GetPlayer().GetTeam());
if (cMgr != null)
{
Channel channel = cMgr.GetChannel((uint)packet.ZoneChannelID, packet.ChannelName, GetPlayer(), true, zone);
if (channel != null)
channel.LeaveChannel(GetPlayer(), true);
if (packet.ZoneChannelID != 0)
cMgr.LeftChannel((uint)packet.ZoneChannelID, zone);
else
cMgr.LeftChannel(packet.ChannelName);
}
}
[WorldPacketHandler(ClientOpcodes.ChatChannelAnnouncements)]
[WorldPacketHandler(ClientOpcodes.ChatChannelDeclineInvite)]
[WorldPacketHandler(ClientOpcodes.ChatChannelDisplayList)]
[WorldPacketHandler(ClientOpcodes.ChatChannelList)]
[WorldPacketHandler(ClientOpcodes.ChatChannelOwner)]
void HandleChannelCommand(ChannelCommand packet)
{
Channel channel = ChannelManager.GetChannelForPlayerByNamePart(packet.ChannelName, GetPlayer());
if (channel == null)
return;
switch (packet.GetOpcode())
{
case ClientOpcodes.ChatChannelAnnouncements:
channel.Announce(GetPlayer());
break;
case ClientOpcodes.ChatChannelDeclineInvite:
channel.DeclineInvite(GetPlayer());
break;
case ClientOpcodes.ChatChannelDisplayList:
case ClientOpcodes.ChatChannelList:
channel.List(GetPlayer());
break;
case ClientOpcodes.ChatChannelOwner:
channel.SendWhoOwner(GetPlayer());
break;
}
}
[WorldPacketHandler(ClientOpcodes.ChatChannelBan)]
[WorldPacketHandler(ClientOpcodes.ChatChannelInvite)]
[WorldPacketHandler(ClientOpcodes.ChatChannelKick)]
[WorldPacketHandler(ClientOpcodes.ChatChannelModerator)]
[WorldPacketHandler(ClientOpcodes.ChatChannelMute)]
[WorldPacketHandler(ClientOpcodes.ChatChannelSetOwner)]
[WorldPacketHandler(ClientOpcodes.ChatChannelSilenceAll)]
[WorldPacketHandler(ClientOpcodes.ChatChannelUnban)]
[WorldPacketHandler(ClientOpcodes.ChatChannelUnmoderator)]
[WorldPacketHandler(ClientOpcodes.ChatChannelUnmute)]
[WorldPacketHandler(ClientOpcodes.ChatChannelUnsilenceAll)]
void HandleChannelPlayerCommand(ChannelPlayerCommand packet)
{
if (packet.Name.Length >= 49)
{
Log.outDebug(LogFilter.ChatSystem, "{0} {1} ChannelName: {2}, Name: {3}, Name too long.", packet.GetOpcode(), GetPlayerInfo(), packet.ChannelName, packet.Name);
return;
}
if (!ObjectManager.NormalizePlayerName(ref packet.Name))
return;
Channel channel = ChannelManager.GetChannelForPlayerByNamePart(packet.ChannelName, GetPlayer());
if (channel == null)
return;
switch (packet.GetOpcode())
{
case ClientOpcodes.ChatChannelBan:
channel.Ban(GetPlayer(), packet.Name);
break;
case ClientOpcodes.ChatChannelInvite:
channel.Invite(GetPlayer(), packet.Name);
break;
case ClientOpcodes.ChatChannelKick:
channel.Kick(GetPlayer(), packet.Name);
break;
case ClientOpcodes.ChatChannelModerator:
channel.SetModerator(GetPlayer(), packet.Name);
break;
case ClientOpcodes.ChatChannelMute:
channel.SetMute(GetPlayer(), packet.Name);
break;
case ClientOpcodes.ChatChannelSetOwner:
channel.SetOwner(GetPlayer(), packet.Name);
break;
case ClientOpcodes.ChatChannelSilenceAll:
channel.SilenceAll(GetPlayer(), packet.Name);
break;
case ClientOpcodes.ChatChannelUnban:
channel.UnBan(GetPlayer(), packet.Name);
break;
case ClientOpcodes.ChatChannelUnmoderator:
channel.UnsetModerator(GetPlayer(), packet.Name);
break;
case ClientOpcodes.ChatChannelUnmute:
channel.UnsetMute(GetPlayer(), packet.Name);
break;
case ClientOpcodes.ChatChannelUnsilenceAll:
channel.UnsilenceAll(GetPlayer(), packet.Name);
break;
}
}
[WorldPacketHandler(ClientOpcodes.ChatChannelPassword)]
void HandleChannelPassword(ChannelPassword packet)
{
if (packet.Password.Length > 31)
{
Log.outDebug(LogFilter.ChatSystem, "{0} {1} ChannelName: {2}, Password: {3}, Password too long.",
packet.GetOpcode(), GetPlayerInfo(), packet.ChannelName, packet.Password);
return;
}
Log.outDebug(LogFilter.ChatSystem, "{0} {1} ChannelName: {2}, Password: {3}", packet.GetOpcode(), GetPlayerInfo(), packet.ChannelName, packet.Password);
Channel channel = ChannelManager.GetChannelForPlayerByNamePart(packet.ChannelName, GetPlayer());
if (channel != null)
channel.Password(GetPlayer(), packet.Password);
}
}
}
File diff suppressed because it is too large Load Diff
+668
View File
@@ -0,0 +1,668 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.Chat;
using Game.DataStorage;
using Game.Entities;
using Game.Groups;
using Game.Guilds;
using Game.Network;
using Game.Network.Packets;
using System.Collections.Generic;
using System.Linq;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.ChatMessageGuild)]
[WorldPacketHandler(ClientOpcodes.ChatMessageOfficer)]
[WorldPacketHandler(ClientOpcodes.ChatMessageParty)]
[WorldPacketHandler(ClientOpcodes.ChatMessageRaid)]
[WorldPacketHandler(ClientOpcodes.ChatMessageRaidWarning)]
[WorldPacketHandler(ClientOpcodes.ChatMessageSay)]
[WorldPacketHandler(ClientOpcodes.ChatMessageYell)]
[WorldPacketHandler(ClientOpcodes.ChatMessageInstanceChat)]
void HandleChatMessage(ChatMessage packet)
{
ChatMsg type;
switch (packet.GetOpcode())
{
case ClientOpcodes.ChatMessageSay:
type = ChatMsg.Say;
break;
case ClientOpcodes.ChatMessageYell:
type = ChatMsg.Yell;
break;
case ClientOpcodes.ChatMessageGuild:
type = ChatMsg.Guild;
break;
case ClientOpcodes.ChatMessageOfficer:
type = ChatMsg.Officer;
break;
case ClientOpcodes.ChatMessageParty:
type = ChatMsg.Party;
break;
case ClientOpcodes.ChatMessageRaid:
type = ChatMsg.Raid;
break;
case ClientOpcodes.ChatMessageRaidWarning:
type = ChatMsg.RaidWarning;
break;
case ClientOpcodes.ChatMessageInstanceChat:
type = ChatMsg.InstanceChat;
break;
default:
Log.outError(LogFilter.Network, "HandleMessagechatOpcode : Unknown chat opcode ({0})", packet.GetOpcode());
return;
}
HandleChat(type, packet.Language, packet.Text);
}
[WorldPacketHandler(ClientOpcodes.ChatMessageWhisper)]
void HandleChatMessageWhisper(ChatMessageWhisper packet)
{
HandleChat(ChatMsg.Whisper, packet.Language, packet.Text, packet.Target);
}
[WorldPacketHandler(ClientOpcodes.ChatMessageChannel)]
void HandleChatMessageChannel(ChatMessageChannel packet)
{
HandleChat(ChatMsg.Channel, packet.Language, packet.Text, packet.Target);
}
[WorldPacketHandler(ClientOpcodes.ChatMessageEmote)]
void HandleChatMessageEmote(ChatMessageEmote packet)
{
HandleChat(ChatMsg.Emote, Language.Universal, packet.Text);
}
void HandleChat(ChatMsg type, Language lang, string msg, string target = "")
{
Player sender = GetPlayer();
if (lang == Language.Universal && type != ChatMsg.Emote)
{
Log.outError(LogFilter.Network, "CMSG_MESSAGECHAT: Possible hacking-attempt: {0} tried to send a message in universal language", GetPlayerInfo());
SendNotification(CypherStrings.UnknownLanguage);
return;
}
// prevent talking at unknown language (cheating)
LanguageDesc langDesc = ObjectManager.GetLanguageDescByID(lang);
if (langDesc == null)
{
SendNotification(CypherStrings.UnknownLanguage);
return;
}
if (langDesc.skill_id != 0 && !sender.HasSkill((SkillType)langDesc.skill_id))
{
// also check SPELL_AURA_COMPREHEND_LANGUAGE (client offers option to speak in that language)
var langAuras = sender.GetAuraEffectsByType(AuraType.ComprehendLanguage);
bool foundAura = false;
foreach (var eff in langAuras)
{
if (eff.GetMiscValue() == (int)lang)
{
foundAura = true;
break;
}
}
if (!foundAura)
{
SendNotification(CypherStrings.NotLearnedLanguage);
return;
}
}
// send in universal language if player in .gm on mode (ignore spell effects)
if (sender.IsGameMaster())
lang = Language.Universal;
else
{
// send in universal language in two side iteration allowed mode
if (HasPermission(RBACPermissions.TwoSideInteractionChat))
lang = Language.Universal;
else
{
switch (type)
{
case ChatMsg.Party:
case ChatMsg.Raid:
case ChatMsg.RaidWarning:
// allow two side chat at group channel if two side group allowed
if (WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionGroup))
lang = Language.Universal;
break;
case ChatMsg.Guild:
case ChatMsg.Officer:
// allow two side chat at guild channel if two side guild allowed
if (WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionGuild))
lang = Language.Universal;
break;
}
}
// but overwrite it by SPELL_AURA_MOD_LANGUAGE auras (only single case used)
var ModLangAuras = sender.GetAuraEffectsByType(AuraType.ModLanguage);
if (!ModLangAuras.Empty())
lang = (Language)ModLangAuras.FirstOrDefault().GetMiscValue();
}
if (!sender.CanSpeak())
{
string timeStr = Time.secsToTimeString((ulong)(m_muteTime - Time.UnixTime));
SendNotification(CypherStrings.WaitBeforeSpeaking, timeStr);
return;
}
if (sender.HasAura(1852) && type != ChatMsg.Whisper)
{
SendNotification(Global.ObjectMgr.GetCypherString(CypherStrings.GmSilence), sender.GetName());
return;
}
if (string.IsNullOrEmpty(msg))
return;
if (new CommandHandler(this).ParseCommand(msg))
return;
switch (type)
{
case ChatMsg.Say:
// Prevent cheating
if (!sender.IsAlive())
return;
if (sender.getLevel() < WorldConfig.GetIntValue(WorldCfg.ChatSayLevelReq))
{
SendNotification(Global.ObjectMgr.GetCypherString(CypherStrings.SayReq), WorldConfig.GetIntValue(WorldCfg.ChatSayLevelReq));
return;
}
sender.Say(msg, lang);
break;
case ChatMsg.Emote:
// Prevent cheating
if (!sender.IsAlive())
return;
if (sender.getLevel() < WorldConfig.GetIntValue(WorldCfg.ChatEmoteLevelReq))
{
SendNotification(Global.ObjectMgr.GetCypherString(CypherStrings.SayReq), WorldConfig.GetIntValue(WorldCfg.ChatEmoteLevelReq));
return;
}
sender.TextEmote(msg);
break;
case ChatMsg.Yell:
// Prevent cheating
if (!sender.IsAlive())
return;
if (sender.getLevel() < WorldConfig.GetIntValue(WorldCfg.ChatYellLevelReq))
{
SendNotification(Global.ObjectMgr.GetCypherString(CypherStrings.SayReq), WorldConfig.GetIntValue(WorldCfg.ChatYellLevelReq));
return;
}
sender.Yell(msg, lang);
break;
case ChatMsg.Whisper:
// @todo implement cross realm whispers (someday)
ExtendedPlayerName extName = ObjectManager.ExtractExtendedPlayerName(target);
if (!ObjectManager.NormalizePlayerName(ref extName.Name))
{
SendChatPlayerNotfoundNotice(target);
break;
}
Player receiver = Global.ObjAccessor.FindPlayerByName(extName.Name);
if (!receiver || (lang != Language.Addon && !receiver.isAcceptWhispers() && receiver.GetSession().HasPermission(RBACPermissions.CanFilterWhispers) && !receiver.IsInWhisperWhiteList(sender.GetGUID())))
{
SendChatPlayerNotfoundNotice(target);
return;
}
if (!sender.IsGameMaster() && sender.getLevel() < WorldConfig.GetIntValue(WorldCfg.ChatWhisperLevelReq) && !receiver.IsInWhisperWhiteList(sender.GetGUID()))
{
SendNotification(Global.ObjectMgr.GetCypherString(CypherStrings.WhisperReq), WorldConfig.GetIntValue(WorldCfg.ChatWhisperLevelReq));
return;
}
if (GetPlayer().GetTeam() != receiver.GetTeam() && !HasPermission(RBACPermissions.TwoSideInteractionChat) && !receiver.IsInWhisperWhiteList(sender.GetGUID()))
{
SendChatPlayerNotfoundNotice(target);
return;
}
if (GetPlayer().HasAura(1852) && !receiver.IsGameMaster())
{
SendNotification(Global.ObjectMgr.GetCypherString(CypherStrings.GmSilence), GetPlayer().GetName());
return;
}
if (receiver.getLevel() < WorldConfig.GetIntValue(WorldCfg.ChatWhisperLevelReq) ||
(HasPermission(RBACPermissions.CanFilterWhispers) && !sender.isAcceptWhispers() && !sender.IsInWhisperWhiteList(receiver.GetGUID())))
sender.AddWhisperWhiteList(receiver.GetGUID());
GetPlayer().Whisper(msg, lang, receiver);
break;
case ChatMsg.Party:
{
// if player is in Battleground, he cannot say to Battlegroundmembers by /p
Group group = GetPlayer().GetOriginalGroup();
if (!group)
{
group = GetPlayer().GetGroup();
if (!group || group.isBGGroup())
return;
}
if (group.IsLeader(GetPlayer().GetGUID()))
type = ChatMsg.PartyLeader;
Global.ScriptMgr.OnPlayerChat(GetPlayer(), type, lang, msg, group);
ChatPkt data = new ChatPkt();
data.Initialize(type, lang, sender, null, msg);
group.BroadcastPacket(data, false, group.GetMemberGroup(GetPlayer().GetGUID()));
}
break;
case ChatMsg.Guild:
if (GetPlayer().GetGuildId() != 0)
{
Guild guild = Global.GuildMgr.GetGuildById(GetPlayer().GetGuildId());
if (guild)
{
Global.ScriptMgr.OnPlayerChat(GetPlayer(), type, lang, msg, guild);
guild.BroadcastToGuild(this, false, msg, lang == Language.Addon ? Language.Addon : Language.Universal);
}
}
break;
case ChatMsg.Officer:
if (GetPlayer().GetGuildId() != 0)
{
Guild guild = Global.GuildMgr.GetGuildById(GetPlayer().GetGuildId());
if (guild)
{
Global.ScriptMgr.OnPlayerChat(GetPlayer(), type, lang, msg, guild);
guild.BroadcastToGuild(this, true, msg, lang == Language.Addon ? Language.Addon : Language.Universal);
}
}
break;
case ChatMsg.Raid:
{
Group group = GetPlayer().GetGroup();
if (!group || !group.isRaidGroup() || group.isBGGroup())
return;
if (group.IsLeader(GetPlayer().GetGUID()))
type = ChatMsg.RaidLeader;
Global.ScriptMgr.OnPlayerChat(GetPlayer(), type, lang, msg, group);
ChatPkt data = new ChatPkt();
data.Initialize(type, lang, sender, null, msg);
group.BroadcastPacket(data, false);
}
break;
case ChatMsg.RaidWarning:
{
Group group = GetPlayer().GetGroup();
if (!group || !group.isRaidGroup() || !(group.IsLeader(GetPlayer().GetGUID()) || group.IsAssistant(GetPlayer().GetGUID())) || group.isBGGroup())
return;
Global.ScriptMgr.OnPlayerChat(GetPlayer(), type, lang, msg, group);
ChatPkt data = new ChatPkt();
//in Battleground, raid warning is sent only to players in Battleground - code is ok
data.Initialize(ChatMsg.RaidWarning, lang, sender, null, msg);
group.BroadcastPacket(data, false);
}
break;
case ChatMsg.Channel:
if (!HasPermission(RBACPermissions.SkipCheckChatChannelReq))
{
if (GetPlayer().getLevel() < WorldConfig.GetIntValue(WorldCfg.ChatChannelLevelReq))
{
SendNotification(Global.ObjectMgr.GetCypherString(CypherStrings.ChannelReq), WorldConfig.GetIntValue(WorldCfg.ChatChannelLevelReq));
return;
}
}
Channel chn = ChannelManager.GetChannelForPlayerByNamePart(target, sender);
if (chn != null)
{
Global.ScriptMgr.OnPlayerChat(GetPlayer(), type, lang, msg, chn);
chn.Say(GetPlayer().GetGUID(), msg, lang);
}
break;
case ChatMsg.InstanceChat:
{
Group group = GetPlayer().GetGroup();
if (!group)
return;
if (group.IsLeader(GetPlayer().GetGUID()))
type = ChatMsg.InstanceChatLeader;
Global.ScriptMgr.OnPlayerChat(GetPlayer(), type, lang, msg, group);
ChatPkt packet = new ChatPkt();
packet.Initialize(type, lang, sender, null, msg);
group.BroadcastPacket(packet, false);
break;
}
default:
Log.outError(LogFilter.ChatSystem, "CHAT: unknown message type {0}, lang: {1}", type, lang);
break;
}
}
[WorldPacketHandler(ClientOpcodes.ChatAddonMessageGuild)]
[WorldPacketHandler(ClientOpcodes.ChatAddonMessageOfficer)]
[WorldPacketHandler(ClientOpcodes.ChatAddonMessageParty)]
[WorldPacketHandler(ClientOpcodes.ChatAddonMessageRaid)]
[WorldPacketHandler(ClientOpcodes.ChatAddonMessageInstanceChat)]
void HandleChatAddonMessage(ChatAddonMessage packet)
{
ChatMsg type;
switch (packet.GetOpcode())
{
case ClientOpcodes.ChatAddonMessageGuild:
type = ChatMsg.Guild;
break;
case ClientOpcodes.ChatAddonMessageOfficer:
type = ChatMsg.Officer;
break;
case ClientOpcodes.ChatAddonMessageParty:
type = ChatMsg.Party;
break;
case ClientOpcodes.ChatAddonMessageRaid:
type = ChatMsg.Raid;
break;
case ClientOpcodes.ChatAddonMessageInstanceChat:
type = ChatMsg.InstanceChat;
break;
default:
Log.outError(LogFilter.Network, "HandleChatAddonMessage: Unknown addon chat opcode ({0})", packet.GetOpcode());
return;
}
HandleChatAddon(type, packet.Prefix, packet.Text);
}
[WorldPacketHandler(ClientOpcodes.ChatAddonMessageWhisper)]
void HandleChatAddonMessageWhisper(ChatAddonMessageWhisper packet)
{
HandleChatAddon(ChatMsg.Whisper, packet.Prefix, packet.Text, packet.Target);
}
[WorldPacketHandler(ClientOpcodes.ChatAddonMessageChannel)]
void HandleChatAddonMessageChannel(ChatAddonMessageChannel chatAddonMessageChannel)
{
HandleChatAddon(ChatMsg.Channel, chatAddonMessageChannel.Prefix, chatAddonMessageChannel.Text, chatAddonMessageChannel.Target);
}
void HandleChatAddon(ChatMsg type, string prefix, string text, string target = "")
{
Player sender = GetPlayer();
if (string.IsNullOrEmpty(prefix) || prefix.Length > 16)
return;
// Disabled addon channel?
if (!WorldConfig.GetBoolValue(WorldCfg.AddonChannel))
return;
switch (type)
{
case ChatMsg.Guild:
case ChatMsg.Officer:
if (sender.GetGuildId() != 0)
{
Guild guild = Global.GuildMgr.GetGuildById(sender.GetGuildId());
if (guild)
guild.BroadcastAddonToGuild(this, type == ChatMsg.Officer, text, prefix);
}
break;
case ChatMsg.Whisper:
/// @todo implement cross realm whispers (someday)
ExtendedPlayerName extName = ObjectManager.ExtractExtendedPlayerName(target);
if (!ObjectManager.NormalizePlayerName(ref extName.Name))
break;
Player receiver = Global.ObjAccessor.FindPlayerByName(extName.Name);
if (!receiver)
break;
sender.WhisperAddon(text, prefix, receiver);
break;
// Messages sent to "RAID" while in a party will get delivered to "PARTY"
case ChatMsg.Party:
case ChatMsg.Raid:
case ChatMsg.InstanceChat:
{
Group group = null;
int subGroup = -1;
if (type != ChatMsg.InstanceChat)
group = sender.GetOriginalGroup();
if (!group)
{
group = sender.GetGroup();
if (!group)
break;
if (type == ChatMsg.Party)
subGroup = sender.GetSubGroup();
}
ChatPkt data = new ChatPkt();
data.Initialize(type, Language.Addon, sender, null, text, 0, "", LocaleConstant.enUS, prefix);
group.BroadcastAddonMessagePacket(data, prefix, true, subGroup, sender.GetGUID());
break;
}
case ChatMsg.Channel:
Channel chn = ChannelManager.GetChannelForPlayerByNamePart(target, sender);
if (chn != null)
chn.AddonSay(sender.GetGUID(), prefix, text);
break;
default:
Log.outError(LogFilter.Server, "HandleAddonMessagechat: unknown addon message type {0}", type);
break;
}
}
[WorldPacketHandler(ClientOpcodes.ChatMessageAfk)]
void HandleChatMessageAFK(ChatMessageAFK packet)
{
Player sender = GetPlayer();
if (sender.IsInCombat())
return;
if (sender.HasAura(1852))
{
SendNotification(CypherStrings.GmSilence, sender.GetName());
return;
}
if (sender.isAFK()) // Already AFK
{
if (string.IsNullOrEmpty(packet.Text))
sender.ToggleAFK(); // Remove AFK
else
sender.autoReplyMsg = packet.Text; // Update message
}
else // New AFK mode
{
sender.autoReplyMsg = string.IsNullOrEmpty(packet.Text) ? Global.ObjectMgr.GetCypherString(CypherStrings.PlayerAfkDefault) : packet.Text;
if (sender.isDND())
sender.ToggleDND();
sender.ToggleAFK();
}
Global.ScriptMgr.OnPlayerChat(sender, ChatMsg.Afk, Language.Universal, packet.Text);
}
[WorldPacketHandler(ClientOpcodes.ChatMessageDnd)]
void HandleChatMessageDND(ChatMessageDND packet)
{
Player sender = GetPlayer();
if (sender.IsInCombat())
return;
if (sender.HasAura(1852))
{
SendNotification(CypherStrings.GmSilence, sender.GetName());
return;
}
if (sender.isDND()) // Already DND
{
if (string.IsNullOrEmpty(packet.Text))
sender.ToggleDND(); // Remove DND
else
sender.autoReplyMsg = packet.Text; // Update message
}
else // New DND mode
{
sender.autoReplyMsg = string.IsNullOrEmpty(packet.Text) ? Global.ObjectMgr.GetCypherString(CypherStrings.PlayerDndDefault) : packet.Text;
if (sender.isAFK())
sender.ToggleAFK();
sender.ToggleDND();
}
Global.ScriptMgr.OnPlayerChat(sender, ChatMsg.Dnd, Language.Universal, packet.Text);
}
[WorldPacketHandler(ClientOpcodes.Emote)]
void HandleEmote(EmoteClient packet)
{
if (!GetPlayer().IsAlive() || GetPlayer().HasUnitState(UnitState.Died))
return;
Global.ScriptMgr.OnPlayerClearEmote(GetPlayer());
if (GetPlayer().GetUInt32Value(UnitFields.NpcEmotestate) != 0)
GetPlayer().SetUInt32Value(UnitFields.NpcEmotestate, 0);
}
[WorldPacketHandler(ClientOpcodes.SendTextEmote)]
void HandleTextEmote(CTextEmote packet)
{
if (!GetPlayer().IsAlive())
return;
if (!GetPlayer().CanSpeak())
{
string timeStr = Time.secsToTimeString((ulong)(m_muteTime - Time.UnixTime));
SendNotification(CypherStrings.WaitBeforeSpeaking, timeStr);
return;
}
Global.ScriptMgr.OnPlayerTextEmote(GetPlayer(), (uint)packet.SoundIndex, (uint)packet.EmoteID, packet.Target);
EmotesTextRecord em = CliDB.EmotesTextStorage.LookupByKey(packet.EmoteID);
if (em == null)
return;
uint emote_anim = em.EmoteID;
switch ((Emote)emote_anim)
{
case Emote.StateSleep:
case Emote.StateSit:
case Emote.StateKneel:
case Emote.OneshotNone:
break;
case Emote.StateDance:
case Emote.StateRead:
GetPlayer().SetUInt32Value(UnitFields.NpcEmotestate, emote_anim);
break;
default:
// Only allow text-emotes for "dead" entities (feign death included)
if (GetPlayer().HasUnitState(UnitState.Died))
break;
GetPlayer().HandleEmoteCommand((Emote)emote_anim);
break;
}
STextEmote textEmote = new STextEmote();
textEmote.SourceGUID = GetPlayer().GetGUID();
textEmote.SourceAccountGUID = GetAccountGUID();
textEmote.TargetGUID = packet.Target;
textEmote.EmoteID = packet.EmoteID;
textEmote.SoundIndex = packet.SoundIndex;
GetPlayer().SendMessageToSetInRange(textEmote, WorldConfig.GetFloatValue(WorldCfg.ListenRangeTextemote), true);
Unit unit = Global.ObjAccessor.GetUnit(GetPlayer(), packet.Target);
GetPlayer().UpdateCriteria(CriteriaTypes.DoEmote, (uint)packet.EmoteID, 0, 0, unit);
// Send scripted event call
if (unit)
{
Creature creature = unit.ToCreature();
if (creature)
creature.GetAI().ReceiveEmote(GetPlayer(), (TextEmotes)packet.EmoteID);
}
}
[WorldPacketHandler(ClientOpcodes.ChatReportIgnored)]
void HandleChatIgnoredOpcode(ChatReportIgnored packet)
{
Player player = Global.ObjAccessor.FindPlayer(packet.IgnoredGUID);
if (!player || player.GetSession() == null)
return;
ChatPkt data = new ChatPkt();
data.Initialize(ChatMsg.Ignored, Language.Universal, GetPlayer(), GetPlayer(), GetPlayer().GetName());
player.SendPacket(data);
}
void SendChatPlayerNotfoundNotice(string name)
{
SendPacket(new ChatPlayerNotfound(name));
}
void SendPlayerAmbiguousNotice(string name)
{
SendPacket(new ChatPlayerAmbiguous(name));
}
void SendChatRestricted(ChatRestrictionType restriction)
{
SendPacket(new ChatRestricted(restriction));
}
}
}
@@ -0,0 +1,50 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.Network;
using Game.Network.Packets;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.CollectionItemSetFavorite)]
void HandleCollectionItemSetFavorite(CollectionItemSetFavorite collectionItemSetFavorite)
{
switch (collectionItemSetFavorite.Type)
{
case CollectionType.Toybox:
GetCollectionMgr().ToySetFavorite(collectionItemSetFavorite.ID, collectionItemSetFavorite.IsFavorite);
break;
case CollectionType.Appearance:
{
var pair = GetCollectionMgr().HasItemAppearance(collectionItemSetFavorite.ID);
if (!pair.Item1 || pair.Item2)
return;
GetCollectionMgr().SetAppearanceIsFavorite(collectionItemSetFavorite.ID, collectionItemSetFavorite.IsFavorite);
break;
}
case CollectionType.TransmogSet:
break;
default:
break;
}
}
}
}
+89
View File
@@ -0,0 +1,89 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.DataStorage;
using Game.Entities;
using Game.Network;
using Game.Network.Packets;
using System;
using System.Diagnostics.Contracts;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.AttackSwing, Processing = PacketProcessing.Inplace)]
void HandleAttackSwing(AttackSwing packet)
{
Unit enemy = Global.ObjAccessor.GetUnit(GetPlayer(), packet.Victim);
if (!enemy)
{
// stop attack state at client
SendAttackStop(null);
return;
}
if (!GetPlayer().IsValidAttackTarget(enemy))
{
// stop attack state at client
SendAttackStop(enemy);
return;
}
//! Client explicitly checks the following before sending CMSG_ATTACKSWING packet,
//! so we'll place the same check here. Note that it might be possible to reuse this snippet
//! in other places as well.
Vehicle vehicle = GetPlayer().GetVehicle();
if (vehicle)
{
VehicleSeatRecord seat = vehicle.GetSeatForPassenger(GetPlayer());
Contract.Assert(seat != null);
if (!seat.Flags[0].HasAnyFlag((uint)VehicleSeatFlags.CanAttack))
{
SendAttackStop(enemy);
return;
}
}
GetPlayer().Attack(enemy, true);
}
[WorldPacketHandler(ClientOpcodes.AttackStop, Processing = PacketProcessing.Inplace)]
void HandleAttackStop(AttackStop packet)
{
GetPlayer().AttackStop();
}
[WorldPacketHandler(ClientOpcodes.SetSheathed, Processing = PacketProcessing.Inplace)]
void HandleSetSheathed(SetSheathed packet)
{
if (packet.CurrentSheathState >= (int)SheathState.Max)
{
Log.outError(LogFilter.Network, "Unknown sheath state {0} ??", packet.CurrentSheathState);
return;
}
GetPlayer().SetSheath((SheathState)packet.CurrentSheathState);
}
void SendAttackStop(Unit enemy)
{
SendPacket(new SAttackStop(GetPlayer(), enemy));
}
}
}
+103
View File
@@ -0,0 +1,103 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.Entities;
using Game.Network;
using Game.Network.Packets;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.CanDuel)]
void HandleCanDuel(CanDuel packet)
{
Player player = Global.ObjAccessor.FindPlayer(packet.TargetGUID);
if (!player)
return;
CanDuelResult response = new CanDuelResult();
response.TargetGUID = packet.TargetGUID;
response.Result = player.duel == null;
SendPacket(response);
if (response.Result)
{
if (GetPlayer().IsMounted())
GetPlayer().CastSpell(player, 62875);
else
GetPlayer().CastSpell(player, 7266);
}
}
[WorldPacketHandler(ClientOpcodes.DuelResponse)]
void HandleDuelResponse(DuelResponse duelResponse)
{
if (duelResponse.Accepted)
HandleDuelAccepted();
else
HandleDuelCancelled();
}
void HandleDuelAccepted()
{
if (GetPlayer().duel == null) // ignore accept from duel-sender
return;
Player player = GetPlayer();
Player plTarget = player.duel.opponent;
if (player == player.duel.initiator || !plTarget || player == plTarget || player.duel.startTime != 0 || plTarget.duel.startTime != 0)
return;
Log.outDebug(LogFilter.Network, "Player 1 is: {0} ({1})", player.GetGUID().ToString(), player.GetName());
Log.outDebug(LogFilter.Network, "Player 2 is: {0} ({1})", plTarget.GetGUID().ToString(), plTarget.GetName());
long now = Time.UnixTime;
player.duel.startTimer = now;
plTarget.duel.startTimer = now;
DuelCountdown packet = new DuelCountdown(3000);
player.SendPacket(packet);
plTarget.SendPacket(packet);
}
void HandleDuelCancelled()
{
// no duel requested
if (GetPlayer().duel == null)
return;
// player surrendered in a duel using /forfeit
if (GetPlayer().duel.startTime != 0)
{
GetPlayer().CombatStopWithPets(true);
if (GetPlayer().duel.opponent)
GetPlayer().duel.opponent.CombatStopWithPets(true);
GetPlayer().CastSpell(GetPlayer(), 7267, true); // beg
GetPlayer().DuelComplete(DuelCompleteType.Won);
return;
}
GetPlayer().DuelComplete(DuelCompleteType.Interrupted);
}
}
}
+73
View File
@@ -0,0 +1,73 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.Garrisons;
using Game.Network;
using Game.Network.Packets;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.GetGarrisonInfo)]
void HandleGetGarrisonInfo(GetGarrisonInfo getGarrisonInfo)
{
Garrison garrison = _player.GetGarrison();
if (garrison != null)
garrison.SendInfo();
}
[WorldPacketHandler(ClientOpcodes.GarrisonPurchaseBuilding)]
void HandleGarrisonPurchaseBuilding(GarrisonPurchaseBuilding garrisonPurchaseBuilding)
{
if (!_player.GetNPCIfCanInteractWith(garrisonPurchaseBuilding.NpcGUID, NPCFlags.GarrisonArchitect))
return;
Garrison garrison = _player.GetGarrison();
if (garrison != null)
garrison.PlaceBuilding(garrisonPurchaseBuilding.PlotInstanceID, garrisonPurchaseBuilding.BuildingID);
}
[WorldPacketHandler(ClientOpcodes.GarrisonCancelConstruction)]
void HandleGarrisonCancelConstruction(GarrisonCancelConstruction garrisonCancelConstruction)
{
if (!_player.GetNPCIfCanInteractWith(garrisonCancelConstruction.NpcGUID, NPCFlags.GarrisonArchitect))
return;
Garrison garrison = _player.GetGarrison();
if (garrison != null)
garrison.CancelBuildingConstruction(garrisonCancelConstruction.PlotInstanceID);
}
[WorldPacketHandler(ClientOpcodes.GarrisonRequestBlueprintAndSpecializationData)]
void HandleGarrisonRequestBlueprintAndSpecializationData(GarrisonRequestBlueprintAndSpecializationData garrisonRequestBlueprintAndSpecializationData)
{
Garrison garrison = _player.GetGarrison();
if (garrison != null)
garrison.SendBlueprintAndSpecializationData();
}
[WorldPacketHandler(ClientOpcodes.GarrisonGetBuildingLandmarks)]
void HandleGarrisonGetBuildingLandmarks(GarrisonGetBuildingLandmarks garrisonGetBuildingLandmarks)
{
Garrison garrison = _player.GetGarrison();
if (garrison != null)
garrison.SendBuildingLandmarks(_player);
}
}
}
+655
View File
@@ -0,0 +1,655 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.Entities;
using Game.Groups;
using Game.Network;
using Game.Network.Packets;
using System.Diagnostics.Contracts;
namespace Game
{
public partial class WorldSession
{
public void SendPartyResult(PartyOperation operation, string member, PartyResult res, uint val = 0)
{
PartyCommandResult packet = new PartyCommandResult();
packet.Name = member;
packet.Command = (byte)operation;
packet.Result = (byte)res;
packet.ResultData = val;
packet.ResultGUID = ObjectGuid.Empty;
SendPacket(packet);
}
[WorldPacketHandler(ClientOpcodes.PartyInvite)]
void HandlePartyInvite(PartyInviteClient packet)
{
Player player = Global.ObjAccessor.FindPlayerByName(packet.TargetName);
// no player
if (!player)
{
SendPartyResult(PartyOperation.Invite, packet.TargetName, PartyResult.BadPlayerNameS);
return;
}
// player trying to invite himself (most likely cheating)
if (player == GetPlayer())
{
SendPartyResult(PartyOperation.Invite, player.GetName(), PartyResult.BadPlayerNameS);
return;
}
// restrict invite to GMs
if (!WorldConfig.GetBoolValue(WorldCfg.AllowGmGroup) && !GetPlayer().IsGameMaster() && player.IsGameMaster())
{
SendPartyResult(PartyOperation.Invite, player.GetName(), PartyResult.BadPlayerNameS);
return;
}
// can't group with
if (!GetPlayer().IsGameMaster() && !WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionGroup) && GetPlayer().GetTeam() != player.GetTeam())
{
SendPartyResult(PartyOperation.Invite, player.GetName(), PartyResult.PlayerWrongFaction);
return;
}
if (GetPlayer().GetInstanceId() != 0 && player.GetInstanceId() != 0 && GetPlayer().GetInstanceId() != player.GetInstanceId() && GetPlayer().GetMapId() == player.GetMapId())
{
SendPartyResult(PartyOperation.Invite, player.GetName(), PartyResult.TargetNotInInstanceS);
return;
}
// just ignore us
if (player.GetInstanceId() != 0 && player.GetDungeonDifficultyID() != GetPlayer().GetDungeonDifficultyID())
{
SendPartyResult(PartyOperation.Invite, player.GetName(), PartyResult.IgnoringYouS);
return;
}
if (player.GetSocial().HasIgnore(GetPlayer().GetGUID()))
{
SendPartyResult(PartyOperation.Invite, player.GetName(), PartyResult.IgnoringYouS);
return;
}
if (!player.GetSocial().HasFriend(GetPlayer().GetGUID()) && GetPlayer().getLevel() < WorldConfig.GetIntValue(WorldCfg.PartyLevelReq))
{
SendPartyResult(PartyOperation.Invite, player.GetName(), PartyResult.InviteRestricted);
return;
}
Group group = GetPlayer().GetGroup();
if (group && group.isBGGroup())
group = GetPlayer().GetOriginalGroup();
Group group2 = player.GetGroup();
if (group2 && group2.isBGGroup())
group2 = player.GetOriginalGroup();
PartyInvite partyInvite;
// player already in another group or invited
if (group2 || player.GetGroupInvite())
{
SendPartyResult(PartyOperation.Invite, player.GetName(), PartyResult.AlreadyInGroupS);
if (group2)
{
// tell the player that they were invited but it failed as they were already in a group
partyInvite = new PartyInvite();
partyInvite.Initialize(GetPlayer(), packet.ProposedRoles, false);
player.SendPacket(partyInvite);
}
return;
}
if (group)
{
// not have permissions for invite
if (!group.IsLeader(GetPlayer().GetGUID()) && !group.IsAssistant(GetPlayer().GetGUID()))
{
SendPartyResult(PartyOperation.Invite, "", PartyResult.NotLeader);
return;
}
// not have place
if (group.IsFull())
{
SendPartyResult(PartyOperation.Invite, "", PartyResult.GroupFull);
return;
}
}
// ok, but group not exist, start a new group
// but don't create and save the group to the DB until
// at least one person joins
if (!group)
{
group = new Group();
// new group: if can't add then delete
if (!group.AddLeaderInvite(GetPlayer()))
return;
if (!group.AddInvite(player))
{
group.RemoveAllInvites();
return;
}
}
else
{
// already existed group: if can't add then just leave
if (!group.AddInvite(player))
return;
}
partyInvite = new PartyInvite();
partyInvite.Initialize(GetPlayer(), packet.ProposedRoles, true);
player.SendPacket(partyInvite);
SendPartyResult(PartyOperation.Invite, player.GetName(), PartyResult.Ok);
}
[WorldPacketHandler(ClientOpcodes.PartyInviteResponse)]
void HandlePartyInviteResponse(PartyInviteResponse packet)
{
Group group = GetPlayer().GetGroupInvite();
if (!group)
return;
if (packet.Accept)
{
// Remove player from invitees in any case
group.RemoveInvite(GetPlayer());
if (group.GetLeaderGUID() == GetPlayer().GetGUID())
{
Log.outError(LogFilter.Network, "HandleGroupAcceptOpcode: player {0} ({1}) tried to accept an invite to his own group", GetPlayer().GetName(), GetPlayer().GetGUID().ToString());
return;
}
// Group is full
if (group.IsFull())
{
SendPartyResult(PartyOperation.Invite, "", PartyResult.GroupFull);
return;
}
Player leader = Global.ObjAccessor.FindPlayer(group.GetLeaderGUID());
// Forming a new group, create it
if (!group.IsCreated())
{
// This can happen if the leader is zoning. To be removed once delayed actions for zoning are implemented
if (!leader)
{
group.RemoveAllInvites();
return;
}
// If we're about to create a group there really should be a leader present
Contract.Assert(leader);
group.RemoveInvite(leader);
group.Create(leader);
Global.GroupMgr.AddGroup(group);
}
// Everything is fine, do it, PLAYER'S GROUP IS SET IN ADDMEMBER!!!
if (!group.AddMember(GetPlayer()))
return;
group.BroadcastGroupUpdate();
}
else
{
// Remember leader if online (group will be invalid if group gets disbanded)
Player leader = Global.ObjAccessor.FindPlayer(group.GetLeaderGUID());
// uninvite, group can be deleted
GetPlayer().UninviteFromGroup();
if (!leader || leader.GetSession() == null)
return;
// report
GroupDecline decline = new GroupDecline(GetPlayer().GetName());
leader.SendPacket(decline);
}
}
[WorldPacketHandler(ClientOpcodes.PartyUninvite)]
void HandlePartyUninvite(PartyUninvite packet)
{
//can't uninvite yourself
if (packet.TargetGUID == GetPlayer().GetGUID())
{
Log.outError(LogFilter.Network, "HandleGroupUninviteGuidOpcode: leader {0}({1}) tried to uninvite himself from the group.",
GetPlayer().GetName(), GetPlayer().GetGUID().ToString());
return;
}
PartyResult res = GetPlayer().CanUninviteFromGroup(packet.TargetGUID);
if (res != PartyResult.Ok)
{
SendPartyResult(PartyOperation.UnInvite, "", res);
return;
}
Group grp = GetPlayer().GetGroup();
// grp is checked already above in CanUninviteFromGroup()
Contract.Assert(grp);
if (grp.IsMember(packet.TargetGUID))
{
Player.RemoveFromGroup(grp, packet.TargetGUID, RemoveMethod.Kick, GetPlayer().GetGUID(), packet.Reason);
return;
}
Player player = grp.GetInvited(packet.TargetGUID);
if (player)
{
player.UninviteFromGroup();
return;
}
SendPartyResult(PartyOperation.UnInvite, "", PartyResult.TargetNotInGroupS);
}
[WorldPacketHandler(ClientOpcodes.SetPartyLeader, Processing = PacketProcessing.Inplace)]
void HandleSetPartyLeader(SetPartyLeader packet)
{
Player player = Global.ObjAccessor.FindConnectedPlayer(packet.TargetGUID);
Group group = GetPlayer().GetGroup();
if (!group || !player)
return;
if (!group.IsLeader(GetPlayer().GetGUID()) || player.GetGroup() != group)
return;
// Everything's fine, accepted.
group.ChangeLeader(packet.TargetGUID, packet.PartyIndex);
group.SendUpdate();
}
[WorldPacketHandler(ClientOpcodes.SetRole, Processing = PacketProcessing.Inplace)]
void HandleSetRole(SetRole packet)
{
RoleChangedInform roleChangedInform = new RoleChangedInform();
Group group = GetPlayer().GetGroup();
byte oldRole = (byte)(group ? group.GetLfgRoles(packet.TargetGUID) : 0);
if (oldRole == packet.Role)
return;
roleChangedInform.PartyIndex = packet.PartyIndex;
roleChangedInform.From = GetPlayer().GetGUID();
roleChangedInform.ChangedUnit = packet.TargetGUID;
roleChangedInform.OldRole = oldRole;
roleChangedInform.NewRole = packet.Role;
if (group)
{
group.BroadcastPacket(roleChangedInform, false);
group.SetLfgRoles(packet.TargetGUID, (LfgRoles)packet.Role);
}
else
SendPacket(roleChangedInform);
}
[WorldPacketHandler(ClientOpcodes.LeaveGroup)]
void HandleLeaveGroup(LeaveGroup packet)
{
Group grp = GetPlayer().GetGroup();
if (!grp)
return;
if (GetPlayer().InBattleground())
{
SendPartyResult(PartyOperation.Invite, "", PartyResult.InviteRestricted);
return;
}
/** error handling **/
/********************/
// everything's fine, do it
SendPartyResult(PartyOperation.Leave, GetPlayer().GetName(), PartyResult.Ok);
GetPlayer().RemoveFromGroup(RemoveMethod.Leave);
}
[WorldPacketHandler(ClientOpcodes.SetLootMethod)]
void HandleSetLootMethod(SetLootMethod packet)
{
Group group = GetPlayer().GetGroup();
if (!group)
return;
/** error handling **/
if (!group.IsLeader(GetPlayer().GetGUID()))
return;
switch (packet.LootMethod)
{
case LootMethod.FreeForAll:
case LootMethod.MasterLoot:
case LootMethod.GroupLoot:
case LootMethod.PersonalLoot:
break;
default:
return;
}
if (packet.LootThreshold < ItemQuality.Uncommon || packet.LootThreshold > ItemQuality.Artifact)
return;
if (packet.LootMethod == LootMethod.MasterLoot && !group.IsMember(packet.LootMasterGUID))
return;
// everything's fine, do it
group.SetLootMethod(packet.LootMethod);
group.SetMasterLooterGuid(packet.LootMasterGUID);
group.SetLootThreshold(packet.LootThreshold);
group.SendUpdate();
}
[WorldPacketHandler(ClientOpcodes.LootRoll)]
void HandleLootRoll(LootRoll packet)
{
Group group = GetPlayer().GetGroup();
if (!group)
return;
group.CountRollVote(GetPlayer().GetGUID(), packet.LootObj, (byte)(packet.LootListID - 1), packet.RollType);
switch (packet.RollType)
{
case RollType.Need:
GetPlayer().UpdateCriteria(CriteriaTypes.RollNeed, 1);
break;
case RollType.Greed:
GetPlayer().UpdateCriteria(CriteriaTypes.RollGreed, 1);
break;
}
}
[WorldPacketHandler(ClientOpcodes.MinimapPing)]
void HandleMinimapPing(MinimapPingClient packet)
{
if (!GetPlayer().GetGroup())
return;
MinimapPing minimapPing = new MinimapPing();
minimapPing.Sender = GetPlayer().GetGUID();
minimapPing.PositionX = packet.PositionX;
minimapPing.PositionY = packet.PositionY;
GetPlayer().GetGroup().BroadcastPacket(minimapPing, true, -1, GetPlayer().GetGUID());
}
[WorldPacketHandler(ClientOpcodes.RandomRoll)]
void HandleRandomRoll(RandomRollClient packet)
{
if (packet.Min > packet.Max || packet.Max > 10000) // < 32768 for urand call
return;
GetPlayer().DoRandomRoll(packet.Min, packet.Max);
}
[WorldPacketHandler(ClientOpcodes.UpdateRaidTarget)]
void HandleUpdateRaidTarget(UpdateRaidTarget packet)
{
Group group = GetPlayer().GetGroup();
if (!group)
return;
if (packet.Symbol == -1) // target icon request
group.SendTargetIconList(this, packet.PartyIndex);
else // target icon update
{
if (group.isRaidGroup() && !group.IsLeader(GetPlayer().GetGUID()) && !group.IsAssistant(GetPlayer().GetGUID()))
return;
if (packet.Target.IsPlayer())
{
Player target = Global.ObjAccessor.FindConnectedPlayer(packet.Target);
if (!target || target.IsHostileTo(GetPlayer()))
return;
}
group.SetTargetIcon((byte)packet.Symbol, packet.Target, GetPlayer().GetGUID(), packet.PartyIndex);
}
}
[WorldPacketHandler(ClientOpcodes.ConvertRaid)]
void HandleConvertRaid(ConvertRaid packet)
{
Group group = GetPlayer().GetGroup();
if (!group)
return;
if (GetPlayer().InBattleground())
return;
// error handling
if (!group.IsLeader(GetPlayer().GetGUID()) || group.GetMembersCount() < 2)
return;
// everything's fine, do it (is it 0 (PartyOperation.Invite) correct code)
SendPartyResult(PartyOperation.Invite, "", PartyResult.Ok);
// New 4.x: it is now possible to convert a raid to a group if member count is 5 or less
if (packet.Raid)
group.ConvertToRaid();
else
group.ConvertToGroup();
}
[WorldPacketHandler(ClientOpcodes.RequestPartyJoinUpdates)]
void HandleRequestPartyJoinUpdates(RequestPartyJoinUpdates packet)
{
Group group = GetPlayer().GetGroup();
if (!group)
return;
group.SendTargetIconList(this, packet.PartyIndex);
group.SendRaidMarkersChanged(this, packet.PartyIndex);
}
[WorldPacketHandler(ClientOpcodes.ChangeSubGroup, Processing = PacketProcessing.ThreadUnsafe)]
void HandleChangeSubGroup(ChangeSubGroup packet)
{
// we will get correct for group here, so we don't have to check if group is BG raid
Group group = GetPlayer().GetGroup();
if (!group)
return;
if (packet.NewSubGroup >= MapConst.MaxRaidSubGroups)
return;
ObjectGuid senderGuid = GetPlayer().GetGUID();
if (!group.IsLeader(senderGuid) && !group.IsAssistant(senderGuid))
return;
if (!group.HasFreeSlotSubGroup(packet.NewSubGroup))
return;
group.ChangeMembersGroup(packet.TargetGUID, packet.NewSubGroup);
}
[WorldPacketHandler(ClientOpcodes.SwapSubGroups, Processing = PacketProcessing.ThreadUnsafe)]
void HandleSwapSubGroups(SwapSubGroups packet)
{
Group group = GetPlayer().GetGroup();
if (!group)
return;
ObjectGuid senderGuid = GetPlayer().GetGUID();
if (!group.IsLeader(senderGuid) && !group.IsAssistant(senderGuid))
return;
group.SwapMembersGroups(packet.FirstTarget, packet.SecondTarget);
}
[WorldPacketHandler(ClientOpcodes.SetAssistantLeader)]
void HandleSetAssistantLeader(SetAssistantLeader packet)
{
Group group = GetPlayer().GetGroup();
if (!group)
return;
if (!group.IsLeader(GetPlayer().GetGUID()))
return;
group.SetGroupMemberFlag(packet.Target, packet.Apply, GroupMemberFlags.Assistant);
}
[WorldPacketHandler(ClientOpcodes.SetPartyAssignment)]
void HandleSetPartyAssignment(SetPartyAssignment packet)
{
Group group = GetPlayer().GetGroup();
if (!group)
return;
ObjectGuid senderGuid = GetPlayer().GetGUID();
if (!group.IsLeader(senderGuid) && !group.IsAssistant(senderGuid))
return;
switch ((GroupMemberAssignment)packet.Assignment)
{
case GroupMemberAssignment.MainAssist:
group.RemoveUniqueGroupMemberFlag(GroupMemberFlags.MainAssist);
group.SetGroupMemberFlag(packet.Target, packet.Set, GroupMemberFlags.MainAssist);
break;
case GroupMemberAssignment.MainTank:
group.RemoveUniqueGroupMemberFlag(GroupMemberFlags.MainTank); // Remove main assist flag from current if any.
group.SetGroupMemberFlag(packet.Target, packet.Set, GroupMemberFlags.MainTank);
break;
}
group.SendUpdate();
}
[WorldPacketHandler(ClientOpcodes.DoReadyCheck)]
void HandleDoReadyCheckOpcode(DoReadyCheck packet)
{
Group group = GetPlayer().GetGroup();
if (!group)
return;
/** error handling **/
if (!group.IsLeader(GetPlayer().GetGUID()) && !group.IsAssistant(GetPlayer().GetGUID()))
return;
// everything's fine, do it
group.StartReadyCheck(GetPlayer().GetGUID(), packet.PartyIndex);
}
[WorldPacketHandler(ClientOpcodes.ReadyCheckResponse, Processing = PacketProcessing.Inplace)]
void HandleReadyCheckResponseOpcode(ReadyCheckResponseClient packet)
{
Group group = GetPlayer().GetGroup();
if (!group)
return;
// everything's fine, do it
group.SetMemberReadyCheck(GetPlayer().GetGUID(), packet.IsReady);
}
[WorldPacketHandler(ClientOpcodes.RequestPartyMemberStats)]
void HandleRequestPartyMemberStats(RequestPartyMemberStats packet)
{
PartyMemberState partyMemberStats = new PartyMemberState();
Player player = Global.ObjAccessor.FindConnectedPlayer(packet.TargetGUID);
if (!player)
{
partyMemberStats.MemberGuid = packet.TargetGUID;
partyMemberStats.MemberStats.Status = GroupMemberOnlineStatus.Offline;
}
else
partyMemberStats.Initialize(player);
SendPacket(partyMemberStats);
}
[WorldPacketHandler(ClientOpcodes.RequestRaidInfo)]
void HandleRequestRaidInfo(RequestRaidInfo packet)
{
// every time the player checks the character screen
GetPlayer().SendRaidInfo();
}
[WorldPacketHandler(ClientOpcodes.OptOutOfLoot)]
void HandleOptOutOfLoot(OptOutOfLoot packet)
{
// ignore if player not loaded
if (!GetPlayer()) // needed because STATUS_AUTHED
{
if (packet.PassOnLoot)
Log.outError(LogFilter.Network, "CMSG_OPT_OUT_OF_LOOT value<>0 for not-loaded character!");
return;
}
GetPlayer().SetPassOnGroupLoot(packet.PassOnLoot);
}
[WorldPacketHandler(ClientOpcodes.InitiateRolePoll)]
void HandleInitiateRolePoll(InitiateRolePoll packet)
{
Group group = GetPlayer().GetGroup();
if (!group)
return;
ObjectGuid guid = GetPlayer().GetGUID();
if (!group.IsLeader(guid) && !group.IsAssistant(guid))
return;
RolePollInform rolePollInform = new RolePollInform();
rolePollInform.From = guid;
rolePollInform.PartyIndex = packet.PartyIndex;
group.BroadcastPacket(rolePollInform, true);
}
[WorldPacketHandler(ClientOpcodes.SetEveryoneIsAssistant)]
void HandleSetEveryoneIsAssistant(SetEveryoneIsAssistant packet)
{
Group group = GetPlayer().GetGroup();
if (!group)
return;
if (!group.IsLeader(GetPlayer().GetGUID()))
return;
group.SetEveryoneIsAssistant(packet.EveryoneIsAssistant);
}
[WorldPacketHandler(ClientOpcodes.ClearRaidMarker)]
void HandleClearRaidMarker(ClearRaidMarker packet)
{
Group group = GetPlayer().GetGroup();
if (!group)
return;
if (group.isRaidGroup() && !group.IsLeader(GetPlayer().GetGUID()) && !group.IsAssistant(GetPlayer().GetGUID()))
return;
group.DeleteRaidMarker(packet.MarkerId);
}
}
}
+252
View File
@@ -0,0 +1,252 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.Entities;
using Game.Guilds;
using Game.Network;
using Game.Network.Packets;
using System;
using System.Collections.Generic;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.LfGuildAddRecruit)]
void HandleGuildFinderAddRecruit(LFGuildAddRecruit lfGuildAddRecruit)
{
if (Global.GuildFinderMgr.GetAllMembershipRequestsForPlayer(GetPlayer().GetGUID()).Count >= 10)
return;
if (!lfGuildAddRecruit.GuildGUID.IsGuild())
return;
if (!lfGuildAddRecruit.ClassRoles.HasAnyFlag((uint)GuildFinderOptionsRoles.All) || lfGuildAddRecruit.ClassRoles > (uint)GuildFinderOptionsRoles.All)
return;
if (!lfGuildAddRecruit.Availability.HasAnyFlag((uint)GuildFinderOptionsAvailability.Always) || lfGuildAddRecruit.Availability > (uint)GuildFinderOptionsAvailability.Always)
return;
if (!lfGuildAddRecruit.PlayStyle.HasAnyFlag((uint)GuildFinderOptionsInterest.All) || lfGuildAddRecruit.PlayStyle > (uint)GuildFinderOptionsInterest.All)
return;
MembershipRequest request = new MembershipRequest(GetPlayer().GetGUID(), lfGuildAddRecruit.GuildGUID, lfGuildAddRecruit.Availability,
lfGuildAddRecruit.ClassRoles, lfGuildAddRecruit.PlayStyle, lfGuildAddRecruit.Comment, Time.UnixTime);
Global.GuildFinderMgr.AddMembershipRequest(lfGuildAddRecruit.GuildGUID, request);
}
[WorldPacketHandler(ClientOpcodes.LfGuildBrowse)]
void HandleGuildFinderBrowse(LFGuildBrowse lfGuildBrowse)
{
if (!lfGuildBrowse.ClassRoles.HasAnyFlag((uint)GuildFinderOptionsRoles.All) || lfGuildBrowse.ClassRoles > (uint)GuildFinderOptionsRoles.All)
return;
if (!lfGuildBrowse.Availability.HasAnyFlag((uint)GuildFinderOptionsAvailability.Always) || lfGuildBrowse.Availability > (uint)GuildFinderOptionsAvailability.Always)
return;
if (!lfGuildBrowse.PlayStyle.HasAnyFlag((uint)GuildFinderOptionsInterest.All) || lfGuildBrowse.PlayStyle > (uint)GuildFinderOptionsInterest.All)
return;
if (lfGuildBrowse.CharacterLevel > WorldConfig.GetIntValue(WorldCfg.MaxPlayerLevel) || lfGuildBrowse.CharacterLevel < 1)
return;
Player player = GetPlayer();
LFGuildPlayer settings = new LFGuildPlayer(player.GetGUID(), lfGuildBrowse.ClassRoles, lfGuildBrowse.Availability, lfGuildBrowse.PlayStyle, (uint)GuildFinderOptionsLevel.Any);
var guildList = Global.GuildFinderMgr.GetGuildsMatchingSetting(settings, (uint)player.GetTeam());
LFGuildBrowseResult lfGuildBrowseResult = new LFGuildBrowseResult();
for (var i = 0; i < guildList.Count; ++i)
{
LFGuildSettings guildSettings = guildList[i];
LFGuildBrowseData guildData = new LFGuildBrowseData();
Guild guild = Global.GuildMgr.GetGuildByGuid(guildSettings.GetGUID());
guildData.GuildName = guild.GetName();
guildData.GuildGUID = guild.GetGUID();
guildData.GuildVirtualRealm = Global.WorldMgr.GetVirtualRealmAddress();
guildData.GuildMembers = guild.GetMembersCount();
guildData.GuildAchievementPoints = guild.GetAchievementMgr().GetAchievementPoints();
guildData.PlayStyle = guildSettings.GetInterests();
guildData.Availability = guildSettings.GetAvailability();
guildData.ClassRoles = guildSettings.GetClassRoles();
guildData.LevelRange = guildSettings.GetLevel();
guildData.EmblemStyle = guild.GetEmblemInfo().GetStyle();
guildData.EmblemColor = guild.GetEmblemInfo().GetColor();
guildData.BorderStyle = guild.GetEmblemInfo().GetBorderStyle();
guildData.BorderColor = guild.GetEmblemInfo().GetBorderColor();
guildData.Background = guild.GetEmblemInfo().GetBackgroundColor();
guildData.Comment = guildSettings.GetComment();
guildData.Cached = 0;
guildData.MembershipRequested = (sbyte)(Global.GuildFinderMgr.HasRequest(player.GetGUID(), guild.GetGUID()) ? 1 : 0);
lfGuildBrowseResult.Post.Add(guildData);
}
player.SendPacket(lfGuildBrowseResult);
}
[WorldPacketHandler(ClientOpcodes.LfGuildDeclineRecruit)]
void HandleGuildFinderDeclineRecruit(LFGuildDeclineRecruit lfGuildDeclineRecruit)
{
if (!GetPlayer().GetGuild())
return;
if (!lfGuildDeclineRecruit.RecruitGUID.IsPlayer())
return;
Global.GuildFinderMgr.RemoveMembershipRequest(lfGuildDeclineRecruit.RecruitGUID, GetPlayer().GetGuild().GetGUID());
}
[WorldPacketHandler(ClientOpcodes.LfGuildGetApplications)]
void HandleGuildFinderGetApplications(LFGuildGetApplications lfGuildGetApplications)
{
List<MembershipRequest> applicatedGuilds = Global.GuildFinderMgr.GetAllMembershipRequestsForPlayer(GetPlayer().GetGUID());
LFGuildApplications lfGuildApplications = new LFGuildApplications();
lfGuildApplications.NumRemaining = 10 - Global.GuildFinderMgr.CountRequestsFromPlayer(GetPlayer().GetGUID());
for (var i = 0; i < applicatedGuilds.Count; ++i)
{
MembershipRequest application = applicatedGuilds[i];
LFGuildApplicationData applicationData = new LFGuildApplicationData();
Guild guild = Global.GuildMgr.GetGuildByGuid(application.GetGuildGuid());
LFGuildSettings guildSettings = Global.GuildFinderMgr.GetGuildSettings(application.GetGuildGuid());
applicationData.GuildGUID = application.GetGuildGuid();
applicationData.GuildVirtualRealm = Global.WorldMgr.GetVirtualRealmAddress();
applicationData.GuildName = guild.GetName();
applicationData.ClassRoles = guildSettings.GetClassRoles();
applicationData.PlayStyle = guildSettings.GetInterests();
applicationData.Availability = guildSettings.GetAvailability();
applicationData.SecondsSinceCreated = (uint)(Time.UnixTime - application.GetSubmitTime());
applicationData.SecondsUntilExpiration = (uint)(application.GetExpiryTime() - Time.UnixTime);
applicationData.Comment = application.GetComment();
lfGuildApplications.Application.Add(applicationData);
}
GetPlayer().SendPacket(lfGuildApplications);
}
[WorldPacketHandler(ClientOpcodes.LfGuildGetGuildPost)]
void HandleGuildFinderGetGuildPost(LFGuildGetGuildPost lfGuildGetGuildPost)
{
Player player = GetPlayer();
Guild guild = player.GetGuild();
if (!guild) // Player must be in guild
return;
LFGuildPost lfGuildPost = new LFGuildPost();
if (guild.GetLeaderGUID() == player.GetGUID())
{
LFGuildSettings settings = Global.GuildFinderMgr.GetGuildSettings(guild.GetGUID());
if (settings == null)
return;
lfGuildPost.Post.HasValue = true;
lfGuildPost.Post.Value.Active = settings.IsListed();
lfGuildPost.Post.Value.PlayStyle = settings.GetInterests();
lfGuildPost.Post.Value.Availability = settings.GetAvailability();
lfGuildPost.Post.Value.ClassRoles = settings.GetClassRoles();
lfGuildPost.Post.Value.LevelRange = settings.GetLevel();
lfGuildPost.Post.Value.Comment = settings.GetComment();
}
player.SendPacket(lfGuildPost);
}
// Lists all recruits for a guild - Misses times
[WorldPacketHandler(ClientOpcodes.LfGuildGetRecruits)]
void HandleGuildFinderGetRecruits(LFGuildGetRecruits lfGuildGetRecruits)
{
Player player = GetPlayer();
Guild guild = player.GetGuild();
if (!guild)
return;
long now = Time.UnixTime;
LFGuildRecruits lfGuildRecruits = new LFGuildRecruits();
lfGuildRecruits.UpdateTime = now;
var recruitsList = Global.GuildFinderMgr.GetAllMembershipRequestsForGuild(guild.GetGUID());
if (recruitsList != null)
{
foreach (var recruitRequestPair in recruitsList)
{
LFGuildRecruitData recruitData = new LFGuildRecruitData();
recruitData.RecruitGUID = recruitRequestPair.Key;
recruitData.RecruitVirtualRealm = Global.WorldMgr.GetVirtualRealmAddress();
recruitData.Comment = recruitRequestPair.Value.GetComment();
recruitData.ClassRoles = recruitRequestPair.Value.GetClassRoles();
recruitData.PlayStyle = recruitRequestPair.Value.GetInterests();
recruitData.Availability = recruitRequestPair.Value.GetAvailability();
recruitData.SecondsSinceCreated = (uint)(now - recruitRequestPair.Value.GetSubmitTime());
recruitData.SecondsUntilExpiration = (uint)(recruitRequestPair.Value.GetExpiryTime() - now);
CharacterInfo charInfo = Global.WorldMgr.GetCharacterInfo(recruitRequestPair.Key);
if (charInfo != null)
{
recruitData.Name = charInfo.Name;
recruitData.CharacterClass = (int)charInfo.ClassID;
recruitData.CharacterGender = (int)charInfo.Sex;
recruitData.CharacterLevel = charInfo.Level;
}
lfGuildRecruits.Recruits.Add(recruitData);
}
}
player.SendPacket(lfGuildRecruits);
}
[WorldPacketHandler(ClientOpcodes.LfGuildRemoveRecruit)]
void HandleGuildFinderRemoveRecruit(LFGuildRemoveRecruit lfGuildRemoveRecruit)
{
if (!lfGuildRemoveRecruit.GuildGUID.IsGuild())
return;
Global.GuildFinderMgr.RemoveMembershipRequest(GetPlayer().GetGUID(), lfGuildRemoveRecruit.GuildGUID);
}
// Sent any time a guild master sets an option in the interface and when listing / unlisting his guild
[WorldPacketHandler(ClientOpcodes.LfGuildSetGuildPost)]
void HandleGuildFinderSetGuildPost(LFGuildSetGuildPost lfGuildSetGuildPost)
{
// Level sent is zero if untouched, force to any (from interface). Idk why
if (lfGuildSetGuildPost.LevelRange == 0)
lfGuildSetGuildPost.LevelRange = (uint)GuildFinderOptionsLevel.Any;
if (!lfGuildSetGuildPost.ClassRoles.HasAnyFlag((uint)GuildFinderOptionsRoles.All) || lfGuildSetGuildPost.ClassRoles > (uint)GuildFinderOptionsRoles.All)
return;
if (!lfGuildSetGuildPost.Availability.HasAnyFlag((uint)GuildFinderOptionsAvailability.Always) || lfGuildSetGuildPost.Availability > (uint)GuildFinderOptionsAvailability.Always)
return;
if (!lfGuildSetGuildPost.PlayStyle.HasAnyFlag((uint)GuildFinderOptionsInterest.All) || lfGuildSetGuildPost.PlayStyle > (uint)GuildFinderOptionsInterest.All)
return;
if (!lfGuildSetGuildPost.LevelRange.HasAnyFlag((uint)GuildFinderOptionsLevel.All) || lfGuildSetGuildPost.LevelRange > (uint)GuildFinderOptionsLevel.All)
return;
Player player = GetPlayer();
if (player.GetGuildId() == 0) // Player must be in guild
return;
Guild guild = Global.GuildMgr.GetGuildById(player.GetGuildId());
if (guild.GetLeaderGUID() != player.GetGUID())
return;
LFGuildSettings settings = new LFGuildSettings(lfGuildSetGuildPost.Active, (uint)player.GetTeam(), player.GetGuild().GetGUID(), lfGuildSetGuildPost.ClassRoles,
lfGuildSetGuildPost.Availability, lfGuildSetGuildPost.PlayStyle, lfGuildSetGuildPost.LevelRange, lfGuildSetGuildPost.Comment);
Global.GuildFinderMgr.SetGuildSettings(player.GetGuild().GetGUID(), settings);
}
}
}
+467
View File
@@ -0,0 +1,467 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.Entities;
using Game.Guilds;
using Game.Network;
using Game.Network.Packets;
using System.Collections.Generic;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.QueryGuildInfo, Status = SessionStatus.Authed)]
void HandleGuildQuery(QueryGuildInfo query)
{
Guild guild = Global.GuildMgr.GetGuildByGuid(query.GuildGuid);
if (guild)
{
if (guild.IsMember(query.PlayerGuid))
{
guild.SendQueryResponse(this);
return;
}
}
QueryGuildInfoResponse response = new QueryGuildInfoResponse();
response.GuildGUID = query.GuildGuid;
SendPacket(response);
}
[WorldPacketHandler(ClientOpcodes.GuildInviteByName)]
void HandleGuildInviteByName(GuildInviteByName packet)
{
if (!ObjectManager.NormalizePlayerName(ref packet.Name))
return;
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.HandleInviteMember(this, packet.Name);
}
[WorldPacketHandler(ClientOpcodes.GuildOfficerRemoveMember)]
void HandleGuildOfficerRemoveMember(GuildOfficerRemoveMember packet)
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.HandleRemoveMember(this, packet.Removee);
}
[WorldPacketHandler(ClientOpcodes.AcceptGuildInvite)]
void HandleGuildAcceptInvite(AcceptGuildInvite packet)
{
if (GetPlayer().GetGuildId() == 0)
{
Guild guild = Global.GuildMgr.GetGuildById(GetPlayer().GetGuildIdInvited());
if (guild)
guild.HandleAcceptMember(this);
}
}
[WorldPacketHandler(ClientOpcodes.GuildDeclineInvitation)]
void HandleGuildDeclineInvitation(GuildDeclineInvitation packet)
{
GetPlayer().SetGuildIdInvited(0);
GetPlayer().SetInGuild(0);
}
[WorldPacketHandler(ClientOpcodes.GuildGetRoster)]
void HandleGuildGetRoster(GuildGetRoster packet)
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.HandleRoster(this);
else
Guild.SendCommandResult(this, GuildCommandType.GetRoster, GuildCommandError.PlayerNotInGuild);
}
[WorldPacketHandler(ClientOpcodes.GuildPromoteMember)]
void HandleGuildPromoteMember(GuildPromoteMember packet)
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.HandleUpdateMemberRank(this, packet.Promotee, false);
}
[WorldPacketHandler(ClientOpcodes.GuildDemoteMember)]
void HandleGuildDemoteMember(GuildDemoteMember packet)
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.HandleUpdateMemberRank(this, packet.Demotee, true);
}
[WorldPacketHandler(ClientOpcodes.GuildAssignMemberRank)]
void HandleGuildAssignRank(GuildAssignMemberRank packet)
{
ObjectGuid setterGuid = GetPlayer().GetGUID();
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.HandleSetMemberRank(this, packet.Member, setterGuid, (byte)packet.RankOrder);
}
[WorldPacketHandler(ClientOpcodes.GuildLeave)]
void HandleGuildLeave(GuildLeave packet)
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.HandleLeaveMember(this);
}
[WorldPacketHandler(ClientOpcodes.GuildDelete)]
void HandleGuildDisband(GuildDelete packet)
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.HandleDelete(this);
}
[WorldPacketHandler(ClientOpcodes.GuildUpdateMotdText)]
void HandleGuildUpdateMotdText(GuildUpdateMotdText packet)
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.HandleSetMOTD(this, packet.MotdText);
}
[WorldPacketHandler(ClientOpcodes.GuildSetMemberNote)]
void HandleGuildSetMemberNote(GuildSetMemberNote packet)
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.HandleSetMemberNote(this, packet.Note, packet.NoteeGUID, packet.IsPublic);
}
[WorldPacketHandler(ClientOpcodes.GuildGetRanks)]
void HandleGuildGetRanks(GuildGetRanks packet)
{
Guild guild = Global.GuildMgr.GetGuildByGuid(packet.GuildGUID);
if (guild)
if (guild.IsMember(GetPlayer().GetGUID()))
guild.SendGuildRankInfo(this);
}
[WorldPacketHandler(ClientOpcodes.GuildAddRank)]
void HandleGuildAddRank(GuildAddRank packet)
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.HandleAddNewRank(this, packet.Name);
}
[WorldPacketHandler(ClientOpcodes.GuildDeleteRank)]
void HandleGuildDeleteRank(GuildDeleteRank packet)
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.HandleRemoveRank(this, (byte)packet.RankOrder);
}
[WorldPacketHandler(ClientOpcodes.GuildUpdateInfoText)]
void HandleGuildUpdateInfoText(GuildUpdateInfoText packet)
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.HandleSetInfo(this, packet.InfoText);
}
[WorldPacketHandler(ClientOpcodes.SaveGuildEmblem)]
void HandleSaveGuildEmblem(SaveGuildEmblem packet)
{
Guild.EmblemInfo emblemInfo = new Guild.EmblemInfo();
emblemInfo.ReadPacket(packet);
if (GetPlayer().GetNPCIfCanInteractWith(packet.Vendor, NPCFlags.TabardDesigner))
{
// Remove fake death
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
if (!emblemInfo.ValidateEmblemColors())
{
Guild.SendSaveEmblemResult(this, GuildEmblemError.InvalidTabardColors);
return;
}
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.HandleSetEmblem(this, emblemInfo);
else
Guild.SendSaveEmblemResult(this, GuildEmblemError.NoGuild); // "You are not part of a guild!";
}
else
Guild.SendSaveEmblemResult(this, GuildEmblemError.InvalidVendor); // "That's not an emblem vendor!"
}
[WorldPacketHandler(ClientOpcodes.GuildEventLogQuery)]
void HandleGuildEventLogQuery(GuildEventLogQuery packet)
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.SendEventLog(this);
}
[WorldPacketHandler(ClientOpcodes.GuildBankRemainingWithdrawMoneyQuery)]
void HandleGuildBankMoneyWithdrawn(GuildBankRemainingWithdrawMoneyQuery packet)
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.SendMoneyInfo(this);
}
[WorldPacketHandler(ClientOpcodes.GuildPermissionsQuery)]
void HandleGuildPermissionsQuery(GuildPermissionsQuery packet)
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.SendPermissions(this);
}
[WorldPacketHandler(ClientOpcodes.GuildBankActivate)]
void HandleGuildBankActivate(GuildBankActivate packet)
{
GameObject go = GetPlayer().GetGameObjectIfCanInteractWith(packet.Banker, GameObjectTypes.GuildBank);
if (go == null)
return;
Guild guild = GetPlayer().GetGuild();
if (guild == null)
{
Guild.SendCommandResult(this, GuildCommandType.ViewTab, GuildCommandError.PlayerNotInGuild);
return;
}
guild.SendBankList(this, 0, packet.FullUpdate);
}
[WorldPacketHandler(ClientOpcodes.GuildBankQueryTab)]
void HandleGuildBankQueryTab(GuildBankQueryTab packet)
{
if (GetPlayer().GetGameObjectIfCanInteractWith(packet.Banker, GameObjectTypes.GuildBank))
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.SendBankList(this, packet.Tab, packet.FullUpdate);
}
}
[WorldPacketHandler(ClientOpcodes.GuildBankDepositMoney)]
void HandleGuildBankDepositMoney(GuildBankDepositMoney packet)
{
if (GetPlayer().GetGameObjectIfCanInteractWith(packet.Banker, GameObjectTypes.GuildBank))
{
if (packet.Money != 0 && GetPlayer().HasEnoughMoney(packet.Money))
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.HandleMemberDepositMoney(this, packet.Money);
}
}
}
[WorldPacketHandler(ClientOpcodes.GuildBankWithdrawMoney)]
void HandleGuildBankWithdrawMoney(GuildBankWithdrawMoney packet)
{
if (packet.Money != 0 && GetPlayer().GetGameObjectIfCanInteractWith(packet.Banker, GameObjectTypes.GuildBank))
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.HandleMemberWithdrawMoney(this, packet.Money);
}
}
[WorldPacketHandler(ClientOpcodes.GuildBankSwapItems)]
void HandleGuildBankSwapItems(GuildBankSwapItems packet)
{
if (!GetPlayer().GetGameObjectIfCanInteractWith(packet.Banker, GameObjectTypes.GuildBank))
return;
Guild guild = GetPlayer().GetGuild();
if (!guild)
return;
if (packet.BankOnly)
{
guild.SwapItems(GetPlayer(), packet.BankTab1, packet.BankSlot1, packet.BankTab, packet.BankSlot, (uint)packet.StackCount);
}
else
{
// Player <-> Bank
// Allow to work with inventory only
if (!Player.IsInventoryPos(packet.ContainerSlot, packet.ContainerItemSlot) && !packet.AutoStore)
GetPlayer().SendEquipError(InventoryResult.InternalBagError);
else
guild.SwapItemsWithInventory(GetPlayer(), packet.ToSlot != 0, packet.BankTab, packet.BankSlot, packet.ContainerSlot, packet.ContainerItemSlot, (uint)packet.StackCount);
}
}
[WorldPacketHandler(ClientOpcodes.GuildBankBuyTab)]
void HandleGuildBankBuyTab(GuildBankBuyTab packet)
{
if (packet.Banker.IsEmpty() || GetPlayer().GetGameObjectIfCanInteractWith(packet.Banker, GameObjectTypes.GuildBank))
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.HandleBuyBankTab(this, packet.BankTab);
}
}
[WorldPacketHandler(ClientOpcodes.GuildBankUpdateTab)]
void HandleGuildBankUpdateTab(GuildBankUpdateTab packet)
{
if (!string.IsNullOrEmpty(packet.Name) && !string.IsNullOrEmpty(packet.Icon))
{
if (GetPlayer().GetGameObjectIfCanInteractWith(packet.Banker, GameObjectTypes.GuildBank))
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.HandleSetBankTabInfo(this, packet.BankTab, packet.Name, packet.Icon);
}
}
}
[WorldPacketHandler(ClientOpcodes.GuildBankLogQuery)]
void HandleGuildBankLogQuery(GuildBankLogQuery packet)
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.SendBankLog(this, (byte)packet.Tab);
}
[WorldPacketHandler(ClientOpcodes.GuildBankTextQuery)]
void HandleGuildBankTextQuery(GuildBankTextQuery packet)
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.SendBankTabText(this, (byte)packet.Tab);
}
[WorldPacketHandler(ClientOpcodes.GuildBankSetTabText)]
void HandleGuildBankSetTabText(GuildBankSetTabText packet)
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.SetBankTabText((byte)packet.Tab, packet.TabText);
}
[WorldPacketHandler(ClientOpcodes.GuildSetRankPermissions)]
void HandleGuildSetRankPermissions(GuildSetRankPermissions packet)
{
Guild guild = GetPlayer().GetGuild();
if (!guild)
return;
List<Guild.GuildBankRightsAndSlots> rightsAndSlots = new List<Guild.GuildBankRightsAndSlots>(GuildConst.MaxBankTabs);
for (byte tabId = 0; tabId < GuildConst.MaxBankTabs; ++tabId)
rightsAndSlots[tabId] = new Guild.GuildBankRightsAndSlots(tabId, (sbyte)packet.TabFlags[tabId], packet.TabWithdrawItemLimit[tabId]);
guild.HandleSetRankInfo(this, (byte)packet.RankOrder, packet.RankName, (GuildRankRights)packet.Flags, (uint)packet.WithdrawGoldLimit, rightsAndSlots);
}
[WorldPacketHandler(ClientOpcodes.RequestGuildPartyState)]
void HandleGuildRequestPartyState(RequestGuildPartyState packet)
{
Guild guild = Global.GuildMgr.GetGuildByGuid(packet.GuildGUID);
if (guild)
guild.HandleGuildPartyRequest(this);
}
[WorldPacketHandler(ClientOpcodes.GuildChangeNameRequest)]
void HandleGuildChallengeUpdateRequest(GuildChallengeUpdateRequest packet)
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.HandleGuildRequestChallengeUpdate(this);
}
[WorldPacketHandler(ClientOpcodes.DeclineGuildInvites)]
void HandleDeclineGuildInvites(DeclineGuildInvites packet)
{
GetPlayer().ApplyModFlag(PlayerFields.Flags, PlayerFlags.AutoDeclineGuild, packet.Allow);
}
[WorldPacketHandler(ClientOpcodes.RequestGuildRewardsList, Processing = PacketProcessing.Inplace)]
void HandleRequestGuildRewardsList(RequestGuildRewardsList packet)
{
if (Global.GuildMgr.GetGuildById(GetPlayer().GetGuildId()))
{
var rewards = Global.GuildMgr.GetGuildRewards();
GuildRewardList rewardList = new GuildRewardList();
rewardList.Version = (uint)Time.UnixTime;
for (int i = 0; i < rewards.Count; i++)
{
GuildRewardItem rewardItem = new GuildRewardItem();
rewardItem.ItemID = rewards[i].ItemID;
rewardItem.RaceMask = (uint)rewards[i].RaceMask;
rewardItem.MinGuildLevel = 0;
rewardItem.MinGuildRep = rewards[i].MinGuildRep;
rewardItem.AchievementsRequired = rewards[i].AchievementsRequired;
rewardItem.Cost = rewards[i].Cost;
rewardList.RewardItems.Add(rewardItem);
}
SendPacket(rewardList);
}
}
[WorldPacketHandler(ClientOpcodes.GuildQueryNews, Processing = PacketProcessing.Inplace)]
void HandleGuildQueryNews(GuildQueryNews packet)
{
Guild guild = GetPlayer().GetGuild();
if (guild)
if (guild.GetGUID() == packet.GuildGUID)
guild.SendNewsUpdate(this);
}
[WorldPacketHandler(ClientOpcodes.GuildNewsUpdateSticky)]
void HandleGuildNewsUpdateSticky(GuildNewsUpdateSticky packet)
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.HandleNewsSetSticky(this, (uint)packet.NewsID, packet.Sticky);
}
[WorldPacketHandler(ClientOpcodes.GuildSetGuildMaster)]
void HandleGuildSetGuildMaster(GuildSetGuildMaster packet)
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.HandleSetNewGuildMaster(this, packet.NewMasterName);
}
[WorldPacketHandler(ClientOpcodes.GuildSetAchievementTracking)]
void HandleGuildSetAchievementTracking(GuildSetAchievementTracking packet)
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.HandleSetAchievementTracking(this, packet.AchievementIDs);
}
[WorldPacketHandler(ClientOpcodes.GuildGetAchievementMembers)]
void HandleGuildGetAchievementMembers(GuildGetAchievementMembers getAchievementMembers)
{
Guild guild = GetPlayer().GetGuild();
if (guild)
guild.HandleGetAchievementMembers(this, getAchievementMembers.AchievementID);
}
}
}
+94
View File
@@ -0,0 +1,94 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.DataStorage;
using Game.Network;
using Game.Network.Packets;
using System.Collections.Generic;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.DbQueryBulk, Processing = PacketProcessing.Inplace, Status = SessionStatus.Authed)]
void HandleDBQueryBulk(DBQueryBulk dbQuery)
{
IDB2Storage store = Global.DB2Mgr.GetStorage(dbQuery.TableHash);
if (store == null)
{
Log.outError(LogFilter.Network, "CMSG_DB_QUERY_BULK: {0} requested unsupported unknown hotfix type: {1}", GetPlayerInfo(), dbQuery.TableHash);
return;
}
foreach (DBQueryBulk.DBQueryRecord record in dbQuery.Queries)
{
DBReply dbReply = new DBReply();
dbReply.TableHash = dbQuery.TableHash;
dbReply.RecordID = record.RecordID;
if (store.HasRecord(record.RecordID))
{
dbReply.Allow = true;
dbReply.Timestamp = (uint)Global.WorldMgr.GetGameTime();
store.WriteRecord(record.RecordID, GetSessionDbcLocale(), dbReply.Data);
}
else
{
Log.outTrace(LogFilter.Network, "CMSG_DB_QUERY_BULK: {0} requested non-existing entry {1} in datastore: {2}", GetPlayerInfo(), record.RecordID, dbQuery.TableHash);
dbReply.Timestamp = (uint)Time.UnixTime;
}
SendPacket(dbReply);
}
}
void SendHotfixList(int version)
{
SendPacket(new HotfixList(version, Global.DB2Mgr.GetHotfixData()));
}
[WorldPacketHandler(ClientOpcodes.HotfixQuery, Status = SessionStatus.Authed)]
void HandleHotfixQuery(HotfixQuery hotfixQuery)
{
Dictionary<ulong, int> hotfixes = Global.DB2Mgr.GetHotfixData();
HotfixQueryResponse hotfixQueryResponse = new HotfixQueryResponse();
foreach (ulong hotfixId in hotfixQuery.Hotfixes)
{
int hotfix = hotfixes.LookupByKey(hotfixId);
if (hotfix != 0)
{
var storage = Global.DB2Mgr.GetStorage(MathFunctions.Pair64_HiPart(hotfixId));
HotfixQueryResponse.HotfixData hotfixData = new HotfixQueryResponse.HotfixData();
hotfixData.ID = hotfixId;
hotfixData.RecordID = hotfix;
if (storage.HasRecord((uint)hotfixData.RecordID))
{
hotfixData.Data.HasValue = true;
storage.WriteRecord((uint)hotfixData.RecordID, GetSessionDbcLocale(), hotfixData.Data.Value);
}
hotfixQueryResponse.Hotfixes.Add(hotfixData);
}
}
SendPacket(hotfixQueryResponse);
}
}
}
+154
View File
@@ -0,0 +1,154 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.Entities;
using Game.Guilds;
using Game.Network;
using Game.Network.Packets;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.Inspect)]
void HandleInspect(Inspect inspect)
{
Player player = Global.ObjAccessor.FindPlayer(inspect.Target);
if (!player)
{
Log.outDebug(LogFilter.Network, "WorldSession.HandleInspectOpcode: Target {0} not found.", inspect.Target.ToString());
return;
}
if (!GetPlayer().IsWithinDistInMap(player, SharedConst.InspectDistance, false))
return;
if (GetPlayer().IsValidAttackTarget(player))
return;
InspectResult inspectResult = new InspectResult();
inspectResult.InspecteeGUID = inspect.Target;
for (byte i = 0; i < EquipmentSlot.End; ++i)
{
Item item = player.GetItemByPos(InventorySlots.Bag0, i);
if (item)
inspectResult.Items.Add(new InspectItemData(item, i));
}
inspectResult.ClassID = player.GetClass();
inspectResult.GenderID = (Gender)player.GetByteValue(PlayerFields.Bytes3, PlayerFieldOffsets.Bytes3OffsetGender);
if (GetPlayer().CanBeGameMaster() || WorldConfig.GetIntValue(WorldCfg.TalentsInspecting) + (GetPlayer().GetTeamId() == player.GetTeamId() ? 1 : 0) > 1)
{
var talents = player.GetTalentMap(player.GetActiveTalentGroup());
foreach (var v in talents)
{
if (v.Value != PlayerSpellState.Removed)
inspectResult.Talents.Add((ushort)v.Key);
}
}
Guild guild = Global.GuildMgr.GetGuildById(player.GetGuildId());
if (guild)
{
inspectResult.GuildData.HasValue = true;
InspectGuildData guildData = inspectResult.GuildData.Value;
guildData.GuildGUID = guild.GetGUID();
guildData.NumGuildMembers = guild.GetMembersCount();
guildData.AchievementPoints = (int)guild.GetAchievementMgr().GetAchievementPoints();
}
inspectResult.InspecteeGUID = inspect.Target;
inspectResult.SpecializationID = (int)player.GetUInt32Value(PlayerFields.CurrentSpecId);
SendPacket(inspectResult);
}
[WorldPacketHandler(ClientOpcodes.RequestHonorStats)]
void HandleRequestHonorStatsOpcode(RequestHonorStats request)
{
Player player = Global.ObjAccessor.FindPlayer(request.TargetGUID);
if (!player)
{
Log.outDebug(LogFilter.Network, "WorldSession.HandleRequestHonorStatsOpcode: Target {0} not found.", request.TargetGUID.ToString());
return;
}
if (!GetPlayer().IsWithinDistInMap(player, SharedConst.InspectDistance, false))
return;
if (GetPlayer().IsValidAttackTarget(player))
return;
InspectHonorStats honorStats = new InspectHonorStats();
honorStats.PlayerGUID = request.TargetGUID;
honorStats.LifetimeHK = player.GetUInt32Value(PlayerFields.LifetimeHonorableKills);
honorStats.YesterdayHK = player.GetUInt16Value(PlayerFields.Kills, 1);
honorStats.TodayHK = player.GetUInt16Value(PlayerFields.Kills, 0);
honorStats.LifetimeMaxRank = 0; /// @todo
SendPacket(honorStats);
}
[WorldPacketHandler(ClientOpcodes.InspectPvp)]
void HandleInspectPVP(InspectPVPRequest request)
{
/// @todo: deal with request.InspectRealmAddress
Player player = Global.ObjAccessor.FindPlayer(request.InspectTarget);
if (!player)
{
Log.outDebug(LogFilter.Network, "WorldSession.HandleInspectPVP: Target {0} not found.", request.InspectTarget.ToString());
return;
}
if (!GetPlayer().IsWithinDistInMap(player, SharedConst.InspectDistance, false))
return;
if (GetPlayer().IsValidAttackTarget(player))
return;
InspectPVPResponse response = new InspectPVPResponse();
response.ClientGUID = request.InspectTarget;
/// @todo: fill brackets
SendPacket(response);
}
[WorldPacketHandler(ClientOpcodes.QueryInspectAchievements)]
void HandleQueryInspectAchievements(QueryInspectAchievements inspect)
{
Player player = Global.ObjAccessor.FindPlayer(inspect.Guid);
if (!player)
{
Log.outDebug(LogFilter.Network, "WorldSession.HandleQueryInspectAchievements: [{0}] inspected unknown Player [{1}]", GetPlayer().GetGUID().ToString(), inspect.Guid.ToString());
return;
}
if (!GetPlayer().IsWithinDistInMap(player, SharedConst.InspectDistance, false))
return;
if (GetPlayer().IsValidAttackTarget(player))
return;
player.SendRespondInspectAchievements(GetPlayer());
}
}
}
File diff suppressed because it is too large Load Diff
+522
View File
@@ -0,0 +1,522 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.DungeonFinding;
using Game.Entities;
using Game.Groups;
using Game.Network;
using Game.Network.Packets;
using System.Collections.Generic;
using System.Linq;
using Game.DataStorage;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.DfJoin)]
void HandleLfgJoin(DFJoin dfJoin)
{
if (!Global.LFGMgr.isOptionEnabled(LfgOptions.EnableDungeonFinder | LfgOptions.EnableRaidBrowser) ||
(GetPlayer().GetGroup() && GetPlayer().GetGroup().GetLeaderGUID() != GetPlayer().GetGUID() &&
(GetPlayer().GetGroup().GetMembersCount() == MapConst.MaxGroupSize || !GetPlayer().GetGroup().isLFGGroup())))
return;
if (dfJoin.Slots.Empty())
{
Log.outDebug(LogFilter.Lfg, "CMSG_DF_JOIN {0} no dungeons selected", GetPlayerInfo());
return;
}
List<uint> newDungeons = new List<uint>();
foreach (uint slot in dfJoin.Slots)
{
uint dungeon = slot & 0x00FFFFFF;
if (CliDB.LfgDungeonsStorage.ContainsKey(dungeon))
newDungeons.Add(dungeon);
}
Log.outDebug(LogFilter.Lfg, "CMSG_DF_JOIN {0} roles: {1}, Dungeons: {2}", GetPlayerInfo(), dfJoin.Roles, newDungeons.Count);
Global.LFGMgr.JoinLfg(GetPlayer(), dfJoin.Roles, newDungeons);
}
[WorldPacketHandler(ClientOpcodes.DfLeave)]
void HandleLfgLeave(DFLeave dfLeave)
{
Group group = GetPlayer().GetGroup();
Log.outDebug(LogFilter.Lfg, "CMSG_DF_LEAVE {0} in group: {1} sent guid {2}.", GetPlayerInfo(), group ? 1 : 0, dfLeave.Ticket.RequesterGuid.ToString());
// Check cheating - only leader can leave the queue
if (!group || group.GetLeaderGUID() == dfLeave.Ticket.RequesterGuid)
Global.LFGMgr.LeaveLfg(dfLeave.Ticket.RequesterGuid);
}
[WorldPacketHandler(ClientOpcodes.DfProposalResponse)]
void HandleLfgProposalResult(DFProposalResponse dfProposalResponse)
{
Log.outDebug(LogFilter.Lfg, "CMSG_LFG_PROPOSAL_RESULT {0} proposal: {1} accept: {2}", GetPlayerInfo(), dfProposalResponse.ProposalID, dfProposalResponse.Accepted ? 1 : 0);
Global.LFGMgr.UpdateProposal(dfProposalResponse.ProposalID, GetPlayer().GetGUID(), dfProposalResponse.Accepted);
}
[WorldPacketHandler(ClientOpcodes.DfSetRoles)]
void HandleLfgSetRoles(DFSetRoles dfSetRoles)
{
ObjectGuid guid = GetPlayer().GetGUID();
Group group = GetPlayer().GetGroup();
if (!group)
{
Log.outDebug(LogFilter.Lfg, "CMSG_DF_SET_ROLES {0} Not in group",
GetPlayerInfo());
return;
}
ObjectGuid gguid = group.GetGUID();
Log.outDebug(LogFilter.Lfg, "CMSG_DF_SET_ROLES: Group {0}, Player {1}, Roles: {2}", gguid.ToString(), GetPlayerInfo(), dfSetRoles.RolesDesired);
Global.LFGMgr.UpdateRoleCheck(gguid, guid, dfSetRoles.RolesDesired);
}
[WorldPacketHandler(ClientOpcodes.DfBootPlayerVote)]
void HandleLfgSetBootVote(DFBootPlayerVote dfBootPlayerVote)
{
ObjectGuid guid = GetPlayer().GetGUID();
Log.outDebug(LogFilter.Lfg, "CMSG_LFG_SET_BOOT_VOTE {0} agree: {1}", GetPlayerInfo(), dfBootPlayerVote.Vote ? 1 : 0);
Global.LFGMgr.UpdateBoot(guid, dfBootPlayerVote.Vote);
}
[WorldPacketHandler(ClientOpcodes.DfTeleport)]
void HandleLfgTeleport(DFTeleport dfTeleport)
{
Log.outDebug(LogFilter.Lfg, "CMSG_DF_TELEPORT {0} out: {1}", GetPlayerInfo(), dfTeleport.TeleportOut ? 1 : 0);
Global.LFGMgr.TeleportPlayer(GetPlayer(), dfTeleport.TeleportOut, true);
}
[WorldPacketHandler(ClientOpcodes.DfGetSystemInfo, Processing = PacketProcessing.ThreadSafe)]
void HandleDfGetSystemInfo(DFGetSystemInfo dfGetSystemInfo)
{
Log.outDebug(LogFilter.Lfg, "CMSG_LFG_Lock_INFO_REQUEST {0} for {1}", GetPlayerInfo(), (dfGetSystemInfo.Player ? "player" : "party"));
if (dfGetSystemInfo.Player)
SendLfgPlayerLockInfo();
else
SendLfgPartyLockInfo();
}
[WorldPacketHandler(ClientOpcodes.DfGetJoinStatus, Processing = PacketProcessing.ThreadSafe)]
void HandleDfGetJoinStatus(DFGetJoinStatus packet)
{
if (!GetPlayer().isUsingLfg())
return;
ObjectGuid guid = GetPlayer().GetGUID();
LfgUpdateData updateData = Global.LFGMgr.GetLfgStatus(guid);
if (GetPlayer().GetGroup())
{
SendLfgUpdateStatus(updateData, true);
updateData.dungeons.Clear();
SendLfgUpdateStatus(updateData, false);
}
else
{
SendLfgUpdateStatus(updateData, false);
updateData.dungeons.Clear();
SendLfgUpdateStatus(updateData, true);
}
}
public void SendLfgPlayerLockInfo()
{
// Get Random dungeons that can be done at a certain level and expansion
uint level = GetPlayer().getLevel();
List<uint> randomDungeons = Global.LFGMgr.GetRandomAndSeasonalDungeons(level, (uint)GetExpansion());
LfgPlayerInfo lfgPlayerInfo = new LfgPlayerInfo();
// Get player locked Dungeons
foreach (var locked in Global.LFGMgr.GetLockedDungeons(_player.GetGUID()))
lfgPlayerInfo.BlackList.Slot.Add(new LFGBlackListSlot(locked.Key, (uint)locked.Value.lockStatus, locked.Value.requiredItemLevel, (int)locked.Value.currentItemLevel));
foreach (var slot in randomDungeons)
{
var playerDungeonInfo = new LfgPlayerDungeonInfo();
playerDungeonInfo.Slot = slot;
playerDungeonInfo.CompletionQuantity = 1;
playerDungeonInfo.CompletionLimit = 1;
playerDungeonInfo.CompletionCurrencyID = 0;
playerDungeonInfo.SpecificQuantity = 0;
playerDungeonInfo.SpecificLimit = 1;
playerDungeonInfo.OverallQuantity = 0;
playerDungeonInfo.OverallLimit = 1;
playerDungeonInfo.PurseWeeklyQuantity = 0;
playerDungeonInfo.PurseWeeklyLimit = 0;
playerDungeonInfo.PurseQuantity = 0;
playerDungeonInfo.PurseLimit = 0;
playerDungeonInfo.Quantity = 1;
playerDungeonInfo.CompletedMask = 0;
playerDungeonInfo.EncounterMask = 0;
LfgReward reward = Global.LFGMgr.GetRandomDungeonReward(slot, level);
if (reward != null)
{
Quest quest = Global.ObjectMgr.GetQuestTemplate(reward.firstQuest);
if (quest != null)
{
playerDungeonInfo.FirstReward = !GetPlayer().CanRewardQuest(quest, false);
if (!playerDungeonInfo.FirstReward)
quest = Global.ObjectMgr.GetQuestTemplate(reward.otherQuest);
if (quest != null)
{
playerDungeonInfo.Rewards.RewardMoney = _player.GetQuestMoneyReward(quest);
playerDungeonInfo.Rewards.RewardXP = _player.GetQuestXPReward(quest);
for (byte i = 0; i < SharedConst.QuestRewardItemCount; ++i)
{
uint itemId = quest.RewardItemId[i];
if (itemId != 0)
playerDungeonInfo.Rewards.Item.Add(new LfgPlayerQuestRewardItem(itemId, quest.RewardItemCount[i]));
}
for (byte i = 0; i < SharedConst.QuestRewardCurrencyCount; ++i)
{
uint curencyId = quest.RewardCurrencyId[i];
if (curencyId != 0)
playerDungeonInfo.Rewards.Currency.Add(new LfgPlayerQuestRewardCurrency(curencyId, quest.RewardCurrencyCount[i]));
}
}
}
}
lfgPlayerInfo.Dungeons.Add(playerDungeonInfo);
}
SendPacket(lfgPlayerInfo);
}
public void SendLfgPartyLockInfo()
{
ObjectGuid guid = GetPlayer().GetGUID();
Group group = GetPlayer().GetGroup();
if (!group)
return;
LfgPartyInfo lfgPartyInfo = new LfgPartyInfo();
// Get the Locked dungeons of the other party members
for (GroupReference refe = group.GetFirstMember(); refe != null; refe = refe.next())
{
Player plrg = refe.GetSource();
if (!plrg)
continue;
ObjectGuid pguid = plrg.GetGUID();
if (pguid == guid)
continue;
LFGBlackList lfgBlackList = new LFGBlackList();
lfgBlackList.PlayerGuid.Set(pguid);
foreach (var locked in Global.LFGMgr.GetLockedDungeons(pguid))
lfgBlackList.Slot.Add(new LFGBlackListSlot(locked.Key, (uint)locked.Value.lockStatus, locked.Value.requiredItemLevel, (int)locked.Value.currentItemLevel));
lfgPartyInfo.Player.Add(lfgBlackList);
}
Log.outDebug(LogFilter.Lfg, "SMSG_LFG_PARTY_INFO {0}", GetPlayerInfo());
SendPacket(lfgPartyInfo);
}
public void SendLfgUpdateStatus(LfgUpdateData updateData, bool party)
{
bool join = false;
bool queued = false;
switch (updateData.updateType)
{
case LfgUpdateType.JoinQueueInitial: // Joined queue outside the dungeon
join = true;
break;
case LfgUpdateType.JoinQueue:
case LfgUpdateType.AddedToQueue: // Rolecheck Success
join = true;
queued = true;
break;
case LfgUpdateType.ProposalBegin:
join = true;
break;
case LfgUpdateType.UpdateStatus:
join = updateData.state != LfgState.Rolecheck && updateData.state != LfgState.None;
queued = updateData.state == LfgState.Queued;
break;
default:
break;
}
LFGUpdateStatus lfgUpdateStatus = new LFGUpdateStatus();
RideTicket ticket = Global.LFGMgr.GetTicket(_player.GetGUID());
if (ticket != null)
lfgUpdateStatus.Ticket = ticket;
lfgUpdateStatus.SubType = (byte)LfgQueueType.Dungeon; // other types not implemented
lfgUpdateStatus.Reason = (byte)updateData.updateType;
foreach (var dungeonId in updateData.dungeons)
lfgUpdateStatus.Slots.Add(Global.LFGMgr.GetLFGDungeonEntry(dungeonId));
lfgUpdateStatus.RequestedRoles = (uint)Global.LFGMgr.GetRoles(_player.GetGUID());
//lfgUpdateStatus.SuspendedPlayers;
lfgUpdateStatus.IsParty = party;
lfgUpdateStatus.NotifyUI = true;
lfgUpdateStatus.Joined = join;
lfgUpdateStatus.LfgJoined = updateData.updateType != LfgUpdateType.RemovedFromQueue;
lfgUpdateStatus.Queued = queued;
SendPacket(lfgUpdateStatus);
}
public void SendLfgRoleChosen(ObjectGuid guid, LfgRoles roles)
{
RoleChosen roleChosen = new RoleChosen();
roleChosen.Player = guid;
roleChosen.RoleMask = roles;
roleChosen.Accepted = roles > 0;
SendPacket(roleChosen);
}
public void SendLfgRoleCheckUpdate(LfgRoleCheck roleCheck)
{
List<uint> dungeons = new List<uint>();
if (roleCheck.rDungeonId != 0)
dungeons.Add(roleCheck.rDungeonId);
else
dungeons = roleCheck.dungeons;
Log.outDebug(LogFilter.Lfg, "SMSG_LFG_ROLE_CHECK_UPDATE {0}", GetPlayerInfo());
LFGRoleCheckUpdate lfgRoleCheckUpdate = new LFGRoleCheckUpdate();
lfgRoleCheckUpdate.PartyIndex = 127;
lfgRoleCheckUpdate.RoleCheckStatus = (byte)roleCheck.state;
lfgRoleCheckUpdate.IsBeginning = roleCheck.state == LfgRoleCheckState.Initialiting;
foreach (var dungeonId in dungeons)
lfgRoleCheckUpdate.JoinSlots.Add(Global.LFGMgr.GetLFGDungeonEntry(dungeonId));
lfgRoleCheckUpdate.BgQueueID = 0;
lfgRoleCheckUpdate.GroupFinderActivityID = 0;
if (!roleCheck.roles.Empty())
{
// Leader info MUST be sent 1st :S
byte roles = (byte)roleCheck.roles.Find(roleCheck.leader).Value;
lfgRoleCheckUpdate.Members.Add(new LFGRoleCheckUpdateMember(roleCheck.leader, roles, Global.WorldMgr.GetCharacterInfo(roleCheck.leader).Level, roles > 0));
foreach (var it in roleCheck.roles)
{
if (it.Key == roleCheck.leader)
continue;
roles = (byte)it.Value;
lfgRoleCheckUpdate.Members.Add(new LFGRoleCheckUpdateMember(it.Key, roles, Global.WorldMgr.GetCharacterInfo(it.Key).Level, roles > 0));
}
}
SendPacket(lfgRoleCheckUpdate);
}
public void SendLfgJoinResult(LfgJoinResultData joinData)
{
LFGJoinResult lfgJoinResult = new LFGJoinResult();
RideTicket ticket = Global.LFGMgr.GetTicket(GetPlayer().GetGUID());
if (ticket != null)
lfgJoinResult.Ticket = ticket;
lfgJoinResult.Result = (byte)joinData.result;
if (joinData.result == LfgJoinResult.RoleCheckFailed)
lfgJoinResult.ResultDetail = (byte)joinData.state;
foreach (var it in joinData.lockmap)
{
var blackList = new LFGJoinBlackList();
blackList.PlayerGuid = it.Key;
foreach (var lockInfo in it.Value)
{
Log.outTrace(LogFilter.Lfg, "SendLfgJoinResult:: {0} DungeonID: {1} Lock status: {2} Required itemLevel: {3} Current itemLevel: {4}",
it.Key.ToString(), (lockInfo.Key & 0x00FFFFFF), lockInfo.Value.lockStatus, lockInfo.Value.requiredItemLevel, lockInfo.Value.currentItemLevel);
blackList.Slots.Add(new LFGJoinBlackListSlot((int)lockInfo.Key, (int)lockInfo.Value.lockStatus, lockInfo.Value.requiredItemLevel, (int)lockInfo.Value.currentItemLevel));
}
}
SendPacket(lfgJoinResult);
}
public void SendLfgQueueStatus(LfgQueueStatusData queueData)
{
Log.outDebug(LogFilter.Lfg, "SMSG_LFG_QUEUE_STATUS {0} state: {1} dungeon: {2}, waitTime: {3}, " +
"avgWaitTime: {4}, waitTimeTanks: {5}, waitTimeHealer: {6}, waitTimeDps: {7}, queuedTime: {8}, tanks: {9}, healers: {10}, dps: {11}",
GetPlayerInfo(), Global.LFGMgr.GetState(GetPlayer().GetGUID()), queueData.dungeonId, queueData.waitTime, queueData.waitTimeAvg,
queueData.waitTimeTank, queueData.waitTimeHealer, queueData.waitTimeDps, queueData.queuedTime, queueData.tanks, queueData.healers, queueData.dps);
LFGQueueStatus lfgQueueStatus = new LFGQueueStatus();
RideTicket ticket = Global.LFGMgr.GetTicket(GetPlayer().GetGUID());
if (ticket != null)
lfgQueueStatus.Ticket = ticket;
lfgQueueStatus.Slot = queueData.queueId;
lfgQueueStatus.AvgWaitTimeMe = (uint)queueData.waitTime;
lfgQueueStatus.AvgWaitTime = (uint)queueData.waitTimeAvg;
lfgQueueStatus.AvgWaitTimeByRole[0] = (uint)queueData.waitTimeTank;
lfgQueueStatus.AvgWaitTimeByRole[1] = (uint)queueData.waitTimeHealer;
lfgQueueStatus.AvgWaitTimeByRole[2] = (uint)queueData.waitTimeDps;
lfgQueueStatus.LastNeeded[0] = queueData.tanks;
lfgQueueStatus.LastNeeded[1] = queueData.healers;
lfgQueueStatus.LastNeeded[2] = queueData.dps;
lfgQueueStatus.QueuedTime = queueData.queuedTime;
SendPacket(lfgQueueStatus);
}
public void SendLfgPlayerReward(LfgPlayerRewardData rewardData)
{
if (rewardData.rdungeonEntry == 0 || rewardData.sdungeonEntry == 0 || rewardData.quest == null)
return;
Log.outDebug(LogFilter.Lfg, "SMSG_LFG_PLAYER_REWARD {0} rdungeonEntry: {1}, sdungeonEntry: {2}, done: {3}",
GetPlayerInfo(), rewardData.rdungeonEntry, rewardData.sdungeonEntry, rewardData.done);
LFGPlayerReward lfgPlayerReward = new LFGPlayerReward();
lfgPlayerReward.QueuedSlot = rewardData.rdungeonEntry;
lfgPlayerReward.ActualSlot = rewardData.sdungeonEntry;
lfgPlayerReward.RewardMoney = GetPlayer().GetQuestMoneyReward(rewardData.quest);
lfgPlayerReward.AddedXP = GetPlayer().GetQuestXPReward(rewardData.quest);
for (byte i = 0; i < SharedConst.QuestRewardItemCount; ++i)
{
uint itemId = rewardData.quest.RewardItemId[i];
if (itemId != 0)
lfgPlayerReward.Rewards.Add(new LFGPlayerRewards(itemId, rewardData.quest.RewardItemCount[i], 0, false));
}
for (byte i = 0; i < SharedConst.QuestRewardCurrencyCount; ++i)
{
uint currencyId = rewardData.quest.RewardCurrencyId[i];
if (currencyId != 0)
lfgPlayerReward.Rewards.Add(new LFGPlayerRewards(currencyId, rewardData.quest.RewardCurrencyCount[i], 0, true));
}
SendPacket(lfgPlayerReward);
}
public void SendLfgBootProposalUpdate(LfgPlayerBoot boot)
{
LfgAnswer playerVote = boot.votes.LookupByKey(GetPlayer().GetGUID());
byte votesNum = 0;
byte agreeNum = 0;
uint secsleft = (uint)((boot.cancelTime - Time.UnixTime) / 1000);
foreach (var it in boot.votes)
{
if (it.Value != LfgAnswer.Pending)
{
++votesNum;
if (it.Value == LfgAnswer.Agree)
++agreeNum;
}
}
Log.outDebug(LogFilter.Lfg, "SMSG_LFG_BOOT_PROPOSAL_UPDATE {0} inProgress: {1} - didVote: {2} - agree: {3} - victim: {4} votes: {5} - agrees: {6} - left: {7} - needed: {8} - reason {9}",
GetPlayerInfo(), boot.inProgress, playerVote != LfgAnswer.Pending, playerVote == LfgAnswer.Agree, boot.victim.ToString(), votesNum, agreeNum, secsleft, SharedConst.LFGKickVotesNeeded, boot.reason);
LfgBootPlayer lfgBootPlayer = new LfgBootPlayer();
lfgBootPlayer.Info.VoteInProgress = boot.inProgress; // Vote in progress
lfgBootPlayer.Info.VotePassed = agreeNum >= SharedConst.LFGKickVotesNeeded; // Did succeed
lfgBootPlayer.Info.MyVoteCompleted = playerVote != LfgAnswer.Pending; // Did Vote
lfgBootPlayer.Info.MyVote = playerVote == LfgAnswer.Agree; // Agree
lfgBootPlayer.Info.Target = boot.victim; // Victim GUID
lfgBootPlayer.Info.TotalVotes = votesNum; // Total Votes
lfgBootPlayer.Info.BootVotes = agreeNum; // Agree Count
lfgBootPlayer.Info.TimeLeft = secsleft; // Time Left
lfgBootPlayer.Info.VotesNeeded = SharedConst.LFGKickVotesNeeded; // Needed Votes
lfgBootPlayer.Info.Reason = boot.reason; // Kick reason
SendPacket(lfgBootPlayer);
}
public void SendLfgProposalUpdate(LfgProposal proposal)
{
ObjectGuid playerGuid = GetPlayer().GetGUID();
ObjectGuid guildGuid = proposal.players.LookupByKey(playerGuid).group;
bool silent = !proposal.isNew && guildGuid == proposal.group;
uint dungeonEntry = proposal.dungeonId;
Log.outDebug(LogFilter.Lfg, "SMSG_LFG_PROPOSAL_UPDATE {0} state: {1}", GetPlayerInfo(), proposal.state);
// show random dungeon if player selected random dungeon and it's not lfg group
if (!silent)
{
List<uint> playerDungeons = Global.LFGMgr.GetSelectedDungeons(playerGuid);
if (!playerDungeons.Contains(proposal.dungeonId))
dungeonEntry = playerDungeons.First();
}
LFGProposalUpdate lfgProposalUpdate = new LFGProposalUpdate();
RideTicket ticket = Global.LFGMgr.GetTicket(GetPlayer().GetGUID());
if (ticket != null)
lfgProposalUpdate.Ticket = ticket;
lfgProposalUpdate.InstanceID = 0;
lfgProposalUpdate.ProposalID = proposal.id;
lfgProposalUpdate.Slot = Global.LFGMgr.GetLFGDungeonEntry(dungeonEntry);
lfgProposalUpdate.State = (byte)proposal.state;
lfgProposalUpdate.CompletedMask = proposal.encounters;
lfgProposalUpdate.ValidCompletedMask = true;
lfgProposalUpdate.ProposalSilent = silent;
lfgProposalUpdate.IsRequeue = !proposal.isNew;
foreach (var pair in proposal.players)
{
var proposalPlayer = new LFGProposalUpdatePlayer();
proposalPlayer.Roles = (uint)pair.Value.role;
proposalPlayer.Me = (pair.Key == playerGuid);
proposalPlayer.MyParty = !pair.Value.group.IsEmpty() && pair.Value.group == proposal.group;
proposalPlayer.SameParty = !pair.Value.group.IsEmpty() && pair.Value.group == guildGuid;
proposalPlayer.Responded = (pair.Value.accept != LfgAnswer.Pending);
proposalPlayer.Accepted = (pair.Value.accept == LfgAnswer.Agree);
lfgProposalUpdate.Players.Add(proposalPlayer);
}
SendPacket(lfgProposalUpdate);
}
public void SendLfgDisabled()
{
SendPacket(new LfgDisabled());
}
public void SendLfgOfferContinue(uint dungeonEntry)
{
Log.outDebug(LogFilter.Lfg, "SMSG_LFG_OFFER_CONTINUE {0} dungeon entry: {1}", GetPlayerInfo(), dungeonEntry);
SendPacket(new LfgOfferContinue(Global.LFGMgr.GetLFGDungeonEntry(dungeonEntry)));
}
public void SendLfgTeleportError(LfgTeleportResult err)
{
Log.outDebug(LogFilter.Lfg, "SMSG_LFG_TELEPORT_DENIED {0} reason: {1}", GetPlayerInfo(), err);
SendPacket(new LfgTeleportDenied(err));
}
}
}
+102
View File
@@ -0,0 +1,102 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.Entities;
using Game.Network;
using Game.Network.Packets;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.LogoutRequest)]
void HandleLogoutRequest(LogoutRequest packet)
{
Player pl = GetPlayer();
if (!GetPlayer().GetLootGUID().IsEmpty())
GetPlayer().SendLootReleaseAll();
bool instantLogout = (pl.HasFlag(PlayerFields.Flags, PlayerFlags.Resting) && !pl.IsInCombat() ||
pl.IsInFlight() || HasPermission(RBACPermissions.InstantLogout));
bool canLogoutInCombat = pl.HasFlag(PlayerFields.Flags, PlayerFlags.Resting);
int reason = 0;
if (pl.IsInCombat() && !canLogoutInCombat)
reason = 1;
else if (pl.IsFalling())
reason = 3; // is jumping or falling
else if (pl.duel != null || pl.HasAura(9454)) // is dueling or frozen by GM via freeze command
reason = 2; // FIXME - Need the correct value
LogoutResponse logoutResponse = new LogoutResponse();
logoutResponse.LogoutResult = reason;
logoutResponse.Instant = instantLogout;
SendPacket(logoutResponse);
if (reason != 0)
{
SetLogoutStartTime(0);
return;
}
// instant logout in taverns/cities or on taxi or for admins, gm's, mod's if its enabled in worldserver.conf
if (instantLogout)
{
LogoutPlayer(true);
return;
}
// not set flags if player can't free move to prevent lost state at logout cancel
if (pl.CanFreeMove())
{
if (pl.GetStandState() == UnitStandStateType.Stand)
pl.SetStandState(UnitStandStateType.Sit);
pl.SetRooted(true);
pl.SetFlag(UnitFields.Flags, UnitFlags.Stunned);
}
SetLogoutStartTime(Time.UnixTime);
}
[WorldPacketHandler(ClientOpcodes.LogoutCancel)]
void HandleLogoutCancel(LogoutCancel packet)
{
// Player have already logged out serverside, too late to cancel
if (!GetPlayer())
return;
SetLogoutStartTime(0);
SendPacket(new LogoutCancelAck());
// not remove flags if can't free move - its not set in Logout request code.
if (GetPlayer().CanFreeMove())
{
//!we can move again
GetPlayer().SetRooted(false);
//! Stand Up
GetPlayer().SetStandState(UnitStandStateType.Stand);
//! DISABLE_ROTATE
GetPlayer().RemoveFlag(UnitFields.Flags, UnitFlags.Stunned);
}
}
}
}
+585
View File
@@ -0,0 +1,585 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.DataStorage;
using Game.Entities;
using Game.Groups;
using Game.Guilds;
using Game.Loots;
using Game.Maps;
using Game.Network;
using Game.Network.Packets;
using System;
using System.Collections.Generic;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.LootItem)]
void HandleAutostoreLootItem(LootItemPkt packet)
{
Player player = GetPlayer();
AELootResult aeResult = player.GetAELootView().Count > 1 ? new AELootResult() : null;
/// @todo Implement looting by LootObject guid
foreach (LootRequest req in packet.Loot)
{
Loot loot = null;
ObjectGuid lguid = player.GetLootWorldObjectGUID(req.Object);
if (lguid.IsGameObject())
{
GameObject go = player.GetMap().GetGameObject(lguid);
// not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO
if (!go || ((go.GetOwnerGUID() != player.GetGUID() && go.GetGoType() != GameObjectTypes.FishingHole) && !go.IsWithinDistInMap(player, SharedConst.InteractionDistance)))
{
player.SendLootRelease(lguid);
continue;
}
loot = go.loot;
}
else if (lguid.IsItem())
{
Item pItem = player.GetItemByGuid(lguid);
if (!pItem)
{
player.SendLootRelease(lguid);
continue;
}
loot = pItem.loot;
}
else if (lguid.IsCorpse())
{
Corpse bones = ObjectAccessor.GetCorpse(player, lguid);
if (!bones)
{
player.SendLootRelease(lguid);
continue;
}
loot = bones.loot;
}
else
{
Creature creature = player.GetMap().GetCreature(lguid);
bool lootAllowed = creature && creature.IsAlive() == (player.GetClass() == Class.Rogue && creature.loot.loot_type == LootType.Pickpocketing);
if (!lootAllowed || !creature.IsWithinDistInMap(player, AELootCreatureCheck.LootDistance))
{
player.SendLootError(req.Object, lguid, lootAllowed ? LootError.TooFar : LootError.DidntKill);
continue;
}
loot = creature.loot;
}
player.StoreLootItem((byte)(req.LootListID - 1), loot, aeResult);
// If player is removing the last LootItem, delete the empty container.
if (loot.isLooted() && lguid.IsItem())
player.GetSession().DoLootRelease(lguid);
}
if (aeResult != null)
{
foreach (var resultValue in aeResult.GetByOrder())
{
player.SendNewItem(resultValue.item, resultValue.count, false, false, true);
player.UpdateCriteria(CriteriaTypes.LootItem, resultValue.item.GetEntry(), resultValue.count);
player.UpdateCriteria(CriteriaTypes.LootType, resultValue.item.GetEntry(), resultValue.count, (ulong)resultValue.lootType);
player.UpdateCriteria(CriteriaTypes.LootEpicItem, resultValue.item.GetEntry(), resultValue.count);
}
}
}
[WorldPacketHandler(ClientOpcodes.LootMoney)]
void HandleLootMoney(LootMoney lootMoney)
{
Player player = GetPlayer();
foreach (var lootView in player.GetAELootView())
{
ObjectGuid guid = lootView.Value;
Loot loot = null;
bool shareMoney = true;
switch (guid.GetHigh())
{
case HighGuid.GameObject:
{
GameObject go = player.GetMap().GetGameObject(guid);
// do not check distance for GO if player is the owner of it (ex. fishing bobber)
if (go && ((go.GetOwnerGUID() == player.GetGUID() || go.IsWithinDistInMap(player, SharedConst.InteractionDistance))))
loot = go.loot;
break;
}
case HighGuid.Corpse: // remove insignia ONLY in BG
{
Corpse bones = ObjectAccessor.GetCorpse(player, guid);
if (bones && bones.IsWithinDistInMap(player, SharedConst.InteractionDistance))
{
loot = bones.loot;
shareMoney = false;
}
break;
}
case HighGuid.Item:
{
Item item = player.GetItemByGuid(guid);
if (item)
{
loot = item.loot;
shareMoney = false;
}
break;
}
case HighGuid.Creature:
case HighGuid.Vehicle:
{
Creature creature = player.GetMap().GetCreature(guid);
bool lootAllowed = creature && creature.IsAlive() == (player.GetClass() == Class.Rogue && creature.loot.loot_type == LootType.Pickpocketing);
if (lootAllowed && creature.IsWithinDistInMap(player, AELootCreatureCheck.LootDistance))
{
loot = creature.loot;
if (creature.IsAlive())
shareMoney = false;
}
else
player.SendLootError(lootView.Key, guid, lootAllowed ? LootError.TooFar : LootError.DidntKill);
break;
}
default:
continue; // unlootable type
}
if (loot == null)
continue;
loot.NotifyMoneyRemoved();
if (shareMoney && player.GetGroup() != null) //item, pickpocket and players can be looted only single player
{
Group group = player.GetGroup();
List<Player> playersNear = new List<Player>();
for (GroupReference refe = group.GetFirstMember(); refe != null; refe = refe.next())
{
Player member = refe.GetSource();
if (!member)
continue;
if (player.IsAtGroupRewardDistance(member))
playersNear.Add(member);
}
uint goldPerPlayer = (uint)(loot.gold / playersNear.Count);
foreach (var pl in playersNear)
{
pl.ModifyMoney(goldPerPlayer);
pl.UpdateCriteria(CriteriaTypes.LootMoney, goldPerPlayer);
Guild guild = Global.GuildMgr.GetGuildById(pl.GetGuildId());
if (guild)
{
uint guildGold = MathFunctions.CalculatePct(goldPerPlayer, pl.GetTotalAuraModifier(AuraType.DepositBonusMoneyInGuildBankOnLoot));
if (guildGold != 0)
guild.HandleMemberDepositMoney(this, guildGold, true);
}
LootMoneyNotify packet = new LootMoneyNotify();
packet.Money = goldPerPlayer;
packet.SoleLooter = playersNear.Count <= 1 ? true : false;
pl.SendPacket(packet);
}
}
else
{
player.ModifyMoney(loot.gold);
player.UpdateCriteria(CriteriaTypes.LootMoney, loot.gold);
Guild guild = Global.GuildMgr.GetGuildById(player.GetGuildId());
if (guild)
{
uint guildGold = MathFunctions.CalculatePct(loot.gold, player.GetTotalAuraModifier(AuraType.DepositBonusMoneyInGuildBankOnLoot));
if (guildGold != 0)
guild.HandleMemberDepositMoney(this, guildGold, true);
}
LootMoneyNotify packet = new LootMoneyNotify();
packet.Money = loot.gold;
packet.SoleLooter = true; // "You loot..."
SendPacket(packet);
}
loot.gold = 0;
// Delete the money loot record from the DB
if (!loot.containerID.IsEmpty())
loot.DeleteLootMoneyFromContainerItemDB();
// Delete container if empty
if (loot.isLooted() && guid.IsItem())
player.GetSession().DoLootRelease(guid);
}
}
class AELootCreatureCheck : ICheck<Creature>
{
public static float LootDistance = 30.0f;
public AELootCreatureCheck(Player looter, ObjectGuid mainLootTarget)
{
_looter = looter;
_mainLootTarget = mainLootTarget;
}
public bool Invoke(Creature creature)
{
if (creature.IsAlive())
return false;
if (creature.GetGUID() == _mainLootTarget)
return false;
if (!_looter.IsWithinDist(creature, LootDistance))
return false;
return _looter.isAllowedToLoot(creature);
}
Player _looter;
ObjectGuid _mainLootTarget;
}
[WorldPacketHandler(ClientOpcodes.LootUnit)]
void HandleLoot(LootUnit packet)
{
// Check possible cheat
if (!GetPlayer().IsAlive() || !packet.Unit.IsCreatureOrVehicle())
return;
List<Creature> corpses = new List<Creature>();
AELootCreatureCheck check = new AELootCreatureCheck(_player, packet.Unit);
CreatureListSearcher searcher = new CreatureListSearcher(_player, corpses, check);
Cell.VisitGridObjects(_player, searcher, AELootCreatureCheck.LootDistance);
if (!corpses.Empty())
SendPacket(new AELootTargets((uint)corpses.Count + 1));
GetPlayer().SendLoot(packet.Unit, LootType.Corpse);
if (!corpses.Empty())
{
// main target
SendPacket(new AELootTargetsAck());
foreach (Creature creature in corpses)
{
GetPlayer().SendLoot(creature.GetGUID(), LootType.Corpse, true);
SendPacket(new AELootTargetsAck());
}
}
// interrupt cast
if (GetPlayer().IsNonMeleeSpellCast(false))
GetPlayer().InterruptNonMeleeSpells(false);
}
[WorldPacketHandler(ClientOpcodes.LootRelease)]
void HandleLootRelease(LootRelease packet)
{
// cheaters can modify lguid to prevent correct apply loot release code and re-loot
// use internal stored guid
if (GetPlayer().HasLootWorldObjectGUID(packet.Unit))
DoLootRelease(packet.Unit);
}
public void DoLootRelease(ObjectGuid lguid)
{
Player player = GetPlayer();
Loot loot;
if (player.GetLootGUID() == lguid)
player.SetLootGUID(ObjectGuid.Empty);
player.SendLootRelease(lguid);
player.RemoveFlag(UnitFields.Flags, UnitFlags.Looting);
if (!player.IsInWorld)
return;
if (lguid.IsGameObject())
{
GameObject go = player.GetMap().GetGameObject(lguid);
// not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO
if (!go || ((go.GetOwnerGUID() != player.GetGUID() && go.GetGoType() != GameObjectTypes.FishingHole) && !go.IsWithinDistInMap(player, SharedConst.InteractionDistance)))
return;
loot = go.loot;
if (go.GetGoType() == GameObjectTypes.Door)
{
// locked doors are opened with spelleffect openlock, prevent remove its as looted
go.UseDoorOrButton();
}
else if (loot.isLooted() || go.GetGoType() == GameObjectTypes.FishingNode)
{
if (go.GetGoType() == GameObjectTypes.FishingHole)
{ // The fishing hole used once more
go.AddUse(); // if the max usage is reached, will be despawned in next tick
if (go.GetUseCount() >= go.m_goValue.FishingHole.MaxOpens)
go.SetLootState(LootState.JustDeactivated);
else
go.SetLootState(LootState.Ready);
}
else
go.SetLootState(LootState.JustDeactivated);
loot.clear();
}
else
{
// not fully looted object
go.SetLootState(LootState.Activated, player);
// if the round robin player release, reset it.
if (player.GetGUID() == loot.roundRobinPlayer)
loot.roundRobinPlayer.Clear();
}
}
else if (lguid.IsCorpse()) // ONLY remove insignia at BG
{
Corpse corpse = ObjectAccessor.GetCorpse(player, lguid);
if (!corpse || !corpse.IsWithinDistInMap(player, SharedConst.InteractionDistance))
return;
loot = corpse.loot;
if (loot.isLooted())
{
loot.clear();
corpse.RemoveFlag(CorpseFields.DynamicFlags, 0x0001);
}
}
else if (lguid.IsItem())
{
Item pItem = player.GetItemByGuid(lguid);
if (!pItem)
return;
ItemTemplate proto = pItem.GetTemplate();
// destroy only 5 items from stack in case prospecting and milling
if (proto.GetFlags().HasAnyFlag(ItemFlags.IsProspectable | ItemFlags.IsMillable))
{
pItem.m_lootGenerated = false;
pItem.loot.clear();
uint count = pItem.GetCount();
// >=5 checked in spell code, but will work for cheating cases also with removing from another stacks.
if (count > 5)
count = 5;
player.DestroyItemCount(pItem, ref count, true);
}
else
{
if (pItem.loot.isLooted() || !proto.GetFlags().HasAnyFlag(ItemFlags.HasLoot)) // Only delete item if no loot or money (unlooted loot is saved to db)
player.DestroyItem(pItem.GetBagSlot(), pItem.GetSlot(), true);
}
return; // item can be looted only single player
}
else
{
Creature creature = player.GetMap().GetCreature(lguid);
bool lootAllowed = creature && creature.IsAlive() == (player.GetClass() == Class.Rogue && creature.loot.loot_type == LootType.Pickpocketing);
if (!lootAllowed || !creature.IsWithinDistInMap(player, AELootCreatureCheck.LootDistance))
return;
loot = creature.loot;
if (loot.isLooted())
{
creature.RemoveFlag(ObjectFields.DynamicFlags, UnitDynFlags.Lootable);
// skip pickpocketing loot for speed, skinning timer reduction is no-op in fact
if (!creature.IsAlive())
creature.AllLootRemovedFromCorpse();
loot.clear();
}
else
{
// if the round robin player release, reset it.
if (player.GetGUID() == loot.roundRobinPlayer)
{
loot.roundRobinPlayer.Clear();
Group group = player.GetGroup();
if (group)
{
if (group.GetLootMethod() != LootMethod.MasterLoot)
group.SendLooter(creature, null);
}
// force dynflag update to update looter and lootable info
creature.ForceValuesUpdateAtIndex(ObjectFields.DynamicFlags);
}
}
}
//Player is not looking at loot list, he doesn't need to see updates on the loot list
loot.RemoveLooter(player.GetGUID());
player.RemoveAELootedObject(loot.GetGUID());
}
void DoLootReleaseAll()
{
Dictionary<ObjectGuid, ObjectGuid> lootView = _player.GetAELootView();
foreach (var lootPair in lootView)
DoLootRelease(lootPair.Value);
}
//[WorldPacketHandler(ClientOpcodes.MasterLootItem)]
void HandleLootMasterGive(WorldPacket packet)
{
ObjectGuid lootguid = packet.ReadPackedGuid();
byte slotid = packet.ReadUInt8();
ObjectGuid target_playerguid = packet.ReadPackedGuid();
if (GetPlayer().GetGroup() == null || GetPlayer().GetGroup().GetLooterGuid() != GetPlayer().GetGUID() || GetPlayer().GetGroup().GetLootMethod() != LootMethod.MasterLoot)
{
GetPlayer().SendLootError(lootguid, ObjectGuid.Empty, LootError.DidntKill);
return;
}
Player target = Global.ObjAccessor.FindPlayer(target_playerguid);
if (!target)
{
GetPlayer().SendLootError(lootguid, ObjectGuid.Empty, LootError.PlayerNotFound);
return;
}
Log.outDebug(LogFilter.Network, "HandleLootMasterGive (CMSG_LOOT_MASTER_GIVE, 0x02A3) Target = [{0}].", target.GetName());
if (GetPlayer().GetLootGUID() != lootguid)
{
GetPlayer().SendLootError(lootguid, ObjectGuid.Empty, LootError.DidntKill);
return;
}
if (!GetPlayer().IsInRaidWith(target) || !GetPlayer().IsInMap(target))
{
GetPlayer().SendLootError(lootguid, ObjectGuid.Empty, LootError.MasterOther);
Log.outInfo(LogFilter.Loot, "MasterLootItem: Player {0} tried to give an item to ineligible player {1}!", GetPlayer().GetName(), target.GetName());
return;
}
Loot loot = null;
if (GetPlayer().GetLootGUID().IsCreatureOrVehicle())
{
Creature creature = GetPlayer().GetMap().GetCreature(lootguid);
if (creature == null)
return;
loot = creature.loot;
}
else if (GetPlayer().GetLootGUID().IsGameObject())
{
GameObject pGO = GetPlayer().GetMap().GetGameObject(lootguid);
if (pGO == null)
return;
loot = pGO.loot;
}
if (loot == null)
return;
if (slotid >= loot.items.Count + loot.quest_items.Count)
{
Log.outDebug(LogFilter.Loot, "MasterLootItem: Player {0} might be using a hack! (slot {1}, size {2})",
GetPlayer().GetName(), slotid, loot.items.Count);
return;
}
LootItem item = slotid >= loot.items.Count ? loot.quest_items[slotid - loot.items.Count] : loot.items[slotid];
List<ItemPosCount> dest = new List<ItemPosCount>(); ;
InventoryResult msg = target.CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, item.itemid, item.count);
if (item.follow_loot_rules && !item.AllowedForPlayer(target))
msg = InventoryResult.CantEquipEver;
if (msg != InventoryResult.Ok)
{
if (msg == InventoryResult.ItemMaxCount)
GetPlayer().SendLootError(lootguid, ObjectGuid.Empty, LootError.MasterUniqueItem);
else if (msg == InventoryResult.InvFull)
GetPlayer().SendLootError(lootguid, ObjectGuid.Empty, LootError.MasterInvFull);
else
GetPlayer().SendLootError(lootguid, ObjectGuid.Empty, LootError.MasterOther);
target.SendEquipError(msg, null, null, item.itemid);
return;
}
// not move item from loot to target inventory
Item newitem = target.StoreNewItem(dest, item.itemid, true, item.randomPropertyId, item.GetAllowedLooters(), item.context, item.BonusListIDs);
target.SendNewItem(newitem, item.count, false, false, true);
target.UpdateCriteria(CriteriaTypes.LootItem, item.itemid, item.count);
target.UpdateCriteria(CriteriaTypes.LootType, item.itemid, item.count, (ulong)loot.loot_type);
target.UpdateCriteria(CriteriaTypes.LootEpicItem, item.itemid, item.count);
// mark as looted
item.count = 0;
item.is_looted = true;
loot.NotifyItemRemoved(slotid);
--loot.unlootedCount;
}
[WorldPacketHandler(ClientOpcodes.SetLootSpecialization)]
void HandleSetLootSpecialization(SetLootSpecialization packet)
{
if (packet.SpecID != 0)
{
ChrSpecializationRecord chrSpec = CliDB.ChrSpecializationStorage.LookupByKey(packet.SpecID);
if (chrSpec != null)
{
if (chrSpec.ClassID == (uint)GetPlayer().GetClass())
GetPlayer().SetLootSpecId(packet.SpecID);
}
}
else
GetPlayer().SetLootSpecId(0);
}
}
}
+698
View File
@@ -0,0 +1,698 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Framework.Database;
using Game.DataStorage;
using Game.Entities;
using Game.Guilds;
using Game.Mails;
using Game.Network;
using Game.Network.Packets;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Game
{
public partial class WorldSession
{
bool CanOpenMailBox(ObjectGuid guid)
{
if (guid == GetPlayer().GetGUID())
{
if (!HasPermission(RBACPermissions.CommandMailbox))
{
Log.outWarn(LogFilter.ChatSystem, "{0} attempt open mailbox in cheating way.", GetPlayer().GetName());
return false;
}
}
else if (guid.IsGameObject())
{
if (!GetPlayer().GetGameObjectIfCanInteractWith(guid, GameObjectTypes.Mailbox))
return false;
}
else if (guid.IsAnyTypeCreature())
{
if (!GetPlayer().GetNPCIfCanInteractWith(guid, NPCFlags.Mailbox))
return false;
}
else
return false;
return true;
}
[WorldPacketHandler(ClientOpcodes.SendMail)]
void HandleSendMail(SendMail packet)
{
if (packet.Info.Attachments.Count > SharedConst.MaxMailItems) // client limit
{
GetPlayer().SendMailResult(0, MailResponseType.Send, MailResponseResult.TooManyAttachments);
return;
}
if (!CanOpenMailBox(packet.Info.Mailbox))
return;
if (string.IsNullOrEmpty(packet.Info.Target))
return;
Player player = GetPlayer();
if (player.getLevel() < WorldConfig.GetIntValue(WorldCfg.MailLevelReq))
{
SendNotification(CypherStrings.MailSenderReq, WorldConfig.GetIntValue(WorldCfg.MailLevelReq));
return;
}
ObjectGuid receiverGuid = ObjectGuid.Empty;
if (ObjectManager.NormalizePlayerName(ref packet.Info.Target))
receiverGuid = ObjectManager.GetPlayerGUIDByName(packet.Info.Target);
if (receiverGuid.IsEmpty())
{
Log.outInfo(LogFilter.Network, "Player {0} is sending mail to {1} (GUID: not existed!) with subject {2}" +
"and body {3} includes {4} items, {5} copper and {6} COD copper with StationeryID = {7}",
GetPlayerInfo(), packet.Info.Target, packet.Info.Subject, packet.Info.Body,
packet.Info.Attachments.Count, packet.Info.SendMoney, packet.Info.Cod, packet.Info.StationeryID);
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.RecipientNotFound);
return;
}
if (packet.Info.SendMoney < 0)
{
GetPlayer().SendMailResult(0, MailResponseType.Send, MailResponseResult.InternalError);
Log.outWarn(LogFilter.Server, "Player {0} attempted to send mail to {1} ({2}) with negative money value (SendMoney: {3})",
GetPlayerInfo(), packet.Info.Target, receiverGuid.ToString(), packet.Info.SendMoney);
return;
}
if (packet.Info.Cod < 0)
{
GetPlayer().SendMailResult(0, MailResponseType.Send, MailResponseResult.InternalError);
Log.outWarn(LogFilter.Server, "Player {0} attempted to send mail to {1} ({2}) with negative COD value (Cod: {3})",
GetPlayerInfo(), packet.Info.Target, receiverGuid.ToString(), packet.Info.Cod);
return;
}
Log.outInfo(LogFilter.Network, "Player {0} is sending mail to {1} ({2}) with subject {3} and body {4}" +
"includes {5} items, {6} copper and {7} COD copper with StationeryID = {8}",
GetPlayerInfo(), packet.Info.Target, receiverGuid.ToString(), packet.Info.Subject,
packet.Info.Body, packet.Info.Attachments.Count, packet.Info.SendMoney, packet.Info.Cod, packet.Info.StationeryID);
if (player.GetGUID() == receiverGuid)
{
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.CannotSendToSelf);
return;
}
uint cost = (uint)(!packet.Info.Attachments.Empty() ? 30 * packet.Info.Attachments.Count : 30); // price hardcoded in client
long reqmoney = cost + packet.Info.SendMoney;
// Check for overflow
if (reqmoney < packet.Info.SendMoney)
{
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.NotEnoughMoney);
return;
}
if (!player.HasEnoughMoney(reqmoney) && !player.IsGameMaster())
{
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.NotEnoughMoney);
return;
}
Player receiver = Global.ObjAccessor.FindPlayer(receiverGuid);
Team receiverTeam = 0;
byte mailsCount = 0; //do not allow to send to one player more than 100 mails
byte receiverLevel = 0;
uint receiverAccountId = 0;
if (receiver)
{
receiverTeam = receiver.GetTeam();
mailsCount = (byte)receiver.GetMails().Count;
receiverLevel = (byte)receiver.getLevel();
receiverAccountId = receiver.GetSession().GetAccountId();
}
else
{
receiverTeam = ObjectManager.GetPlayerTeamByGUID(receiverGuid);
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MAIL_COUNT);
stmt.AddValue(0, receiverGuid.GetCounter());
SQLResult result = DB.Characters.Query(stmt);
if (!result.IsEmpty())
mailsCount = (byte)result.Read<ulong>(0);
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_LEVEL);
stmt.AddValue(0, receiverGuid.GetCounter());
result = DB.Characters.Query(stmt);
if (!result.IsEmpty())
receiverLevel = result.Read<byte>(0);
receiverAccountId = ObjectManager.GetPlayerAccountIdByGUID(receiverGuid);
}
// do not allow to have more than 100 mails in mailbox.. mails count is in opcode byte!!! - so max can be 255..
if (mailsCount > 100)
{
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.RecipientCapReached);
return;
}
// test the receiver's Faction... or all items are account bound
bool accountBound = !packet.Info.Attachments.Empty();
foreach (var att in packet.Info.Attachments)
{
Item item = player.GetItemByGuid(att.ItemGUID);
if (item)
{
ItemTemplate itemProto = item.GetTemplate();
if (itemProto == null || !itemProto.GetFlags().HasAnyFlag(ItemFlags.IsBoundToAccount))
{
accountBound = false;
break;
}
}
}
if (!accountBound && player.GetTeam() != receiverTeam && !HasPermission(RBACPermissions.TwoSideInteractionMail))
{
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.NotYourTeam);
return;
}
if (receiverLevel < WorldConfig.GetIntValue(WorldCfg.MailLevelReq))
{
SendNotification(CypherStrings.MailReceiverReq, WorldConfig.GetIntValue(WorldCfg.MailLevelReq));
return;
}
List<Item> items = new List<Item>();
foreach (var att in packet.Info.Attachments)
{
if (att.ItemGUID.IsEmpty())
{
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.MailAttachmentInvalid);
return;
}
Item item = player.GetItemByGuid(att.ItemGUID);
// prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail)
if (!item)
{
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.MailAttachmentInvalid);
return;
}
if (!item.CanBeTraded(true))
{
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.EquipError, InventoryResult.MailBoundItem);
return;
}
if (item.IsBoundAccountWide() && item.IsSoulBound() && player.GetSession().GetAccountId() != receiverAccountId)
{
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.EquipError, InventoryResult.NotSameAccount);
return;
}
if (item.GetTemplate().GetFlags().HasAnyFlag(ItemFlags.Conjured) || item.GetUInt32Value(ItemFields.Duration) != 0)
{
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.EquipError, InventoryResult.MailBoundItem);
return;
}
if (packet.Info.Cod != 0 && item.HasFlag(ItemFields.Flags, ItemFieldFlags.Wrapped))
{
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.CantSendWrappedCod);
return;
}
if (item.IsNotEmptyBag())
{
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.EquipError, InventoryResult.DestroyNonemptyBag);
return;
}
items.Add(item);
}
player.SendMailResult(0, MailResponseType.Send, MailResponseResult.Ok);
player.ModifyMoney(-reqmoney);
player.UpdateCriteria(CriteriaTypes.GoldSpentForMail, cost);
bool needItemDelay = false;
MailDraft draft = new MailDraft(packet.Info.Subject, packet.Info.Body);
SQLTransaction trans = new SQLTransaction();
if (!packet.Info.Attachments.Empty() || packet.Info.SendMoney > 0)
{
bool log = HasPermission(RBACPermissions.LogGmTrade);
if (!packet.Info.Attachments.Empty())
{
foreach (var item in items)
{
if (log)
{
Log.outCommand(GetAccountId(), "GM {0} ({1}) (Account: {2}) mail item: {3} (Entry: {4} Count: {5}) to player: {6} ({7}) (Account: {8})",
GetPlayerName(), GetPlayer().GetGUID().ToString(), GetAccountId(), item.GetTemplate().GetName(), item.GetEntry(), item.GetCount(),
packet.Info.Target, receiverGuid.ToString(), receiverAccountId);
}
item.SetNotRefundable(GetPlayer()); // makes the item no longer refundable
player.MoveItemFromInventory(item.GetBagSlot(), item.GetSlot(), true);
item.DeleteFromInventoryDB(trans); // deletes item from character's inventory
item.SetOwnerGUID(receiverGuid);
item.SetState(ItemUpdateState.Changed);
item.SaveToDB(trans); // recursive and not have transaction guard into self, item not in inventory and can be save standalone
draft.AddItem(item);
}
// if item send to character at another account, then apply item delivery delay
needItemDelay = player.GetSession().GetAccountId() != receiverAccountId;
}
if (log && packet.Info.SendMoney > 0)
{
Log.outCommand(GetAccountId(), "GM {0} ({1}) (Account: {{2}) mail money: {3} to player: {4} ({5}) (Account: {6})",
GetPlayerName(), GetPlayer().GetGUID().ToString(), GetAccountId(), packet.Info.SendMoney, packet.Info.Target, receiverGuid.ToString(), receiverAccountId);
}
}
// If theres is an item, there is a one hour delivery delay if sent to another account's character.
uint deliver_delay = needItemDelay ? WorldConfig.GetUIntValue(WorldCfg.MailDeliveryDelay) : 0;
// Mail sent between guild members arrives instantly
Guild guild = Global.GuildMgr.GetGuildById(player.GetGuildId());
if (guild)
if (guild.IsMember(receiverGuid))
deliver_delay = 0;
// don't ask for COD if there are no items
if (packet.Info.Attachments.Empty())
packet.Info.Cod = 0;
// will delete item or place to receiver mail list
draft.AddMoney((ulong)packet.Info.SendMoney).AddCOD((uint)packet.Info.Cod).SendMailTo(trans, new MailReceiver(receiver, receiverGuid.GetCounter()), new MailSender(player), string.IsNullOrEmpty(packet.Info.Body) ? MailCheckMask.Copied : MailCheckMask.HasBody, deliver_delay);
player.SaveInventoryAndGoldToDB(trans);
DB.Characters.CommitTransaction(trans);
}
//called when mail is read
[WorldPacketHandler(ClientOpcodes.MailMarkAsRead)]
void HandleMailMarkAsRead(MailMarkAsRead packet)
{
if (!CanOpenMailBox(packet.Mailbox))
return;
Player player = GetPlayer();
Mail m = player.GetMail(packet.MailID);
if (m != null && m.state != MailState.Deleted)
{
if (player.unReadMails != 0)
--player.unReadMails;
m.checkMask = m.checkMask | MailCheckMask.Read;
player.m_mailsUpdated = true;
m.state = MailState.Changed;
}
}
//called when client deletes mail
[WorldPacketHandler(ClientOpcodes.MailDelete)]
void HandleMailDelete(MailDelete packet)
{
Mail m = GetPlayer().GetMail(packet.MailID);
Player player = GetPlayer();
player.m_mailsUpdated = true;
if (m != null)
{
// delete shouldn't show up for COD mails
if (m.COD != 0)
{
player.SendMailResult(packet.MailID, MailResponseType.Deleted, MailResponseResult.InternalError);
return;
}
m.state = MailState.Deleted;
}
player.SendMailResult(packet.MailID, MailResponseType.Deleted, MailResponseResult.Ok);
}
[WorldPacketHandler(ClientOpcodes.MailReturnToSender)]
void HandleMailReturnToSender(MailReturnToSender packet)
{
if (!CanOpenMailBox(_player.PlayerTalkClass.GetInteractionData().SourceGuid))
return;
Player player = GetPlayer();
Mail m = player.GetMail(packet.MailID);
if (m == null || m.state == MailState.Deleted || m.deliver_time > Time.UnixTime || m.sender != packet.SenderGUID.GetCounter())
{
player.SendMailResult(packet.MailID, MailResponseType.ReturnedToSender, MailResponseResult.InternalError);
return;
}
//we can return mail now, so firstly delete the old one
SQLTransaction trans = new SQLTransaction();
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_MAIL_BY_ID);
stmt.AddValue(0, packet.MailID);
trans.Append(stmt);
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_MAIL_ITEM_BY_ID);
stmt.AddValue(0, packet.MailID);
trans.Append(stmt);
player.RemoveMail(packet.MailID);
// only return mail if the player exists (and delete if not existing)
if (m.messageType == MailMessageType.Normal && m.sender != 0)
{
MailDraft draft = new MailDraft(m.subject, m.body);
if (m.mailTemplateId != 0)
draft = new MailDraft(m.mailTemplateId, false); // items already included
if (m.HasItems())
{
foreach (var itemInfo in m.items)
{
Item item = player.GetMItem(itemInfo.item_guid);
if (item)
draft.AddItem(item);
player.RemoveMItem(itemInfo.item_guid);
}
}
draft.AddMoney(m.money).SendReturnToSender(GetAccountId(), m.receiver, m.sender, trans);
}
DB.Characters.CommitTransaction(trans);
player.SendMailResult(packet.MailID, MailResponseType.ReturnedToSender, MailResponseResult.Ok);
}
//called when player takes item attached in mail
[WorldPacketHandler(ClientOpcodes.MailTakeItem)]
void HandleMailTakeItem(MailTakeItem packet)
{
uint AttachID = packet.AttachID;
if (!CanOpenMailBox(packet.Mailbox))
return;
Player player = GetPlayer();
Mail m = player.GetMail(packet.MailID);
if (m == null || m.state == MailState.Deleted || m.deliver_time > Time.UnixTime)
{
player.SendMailResult(packet.MailID, MailResponseType.ItemTaken, MailResponseResult.InternalError);
return;
}
// verify that the mail has the item to avoid cheaters taking COD items without paying
if (!m.items.Any(p => p.item_guid == AttachID))
{
player.SendMailResult(packet.MailID, MailResponseType.ItemTaken, MailResponseResult.InternalError);
return;
}
// prevent cheating with skip client money check
if (!player.HasEnoughMoney(m.COD))
{
player.SendMailResult(packet.MailID, MailResponseType.ItemTaken, MailResponseResult.NotEnoughMoney);
return;
}
Item it = player.GetMItem(packet.AttachID);
List<ItemPosCount> dest = new List<ItemPosCount>();
InventoryResult msg = GetPlayer().CanStoreItem(ItemConst.NullBag, ItemConst.NullSlot, dest, it, false);
if (msg == InventoryResult.Ok)
{
SQLTransaction trans = new SQLTransaction();
m.RemoveItem(packet.AttachID);
m.removedItems.Add(packet.AttachID);
if (m.COD > 0) //if there is COD, take COD money from player and send them to sender by mail
{
ObjectGuid sender_guid = ObjectGuid.Create(HighGuid.Player, m.sender);
Player receiver = Global.ObjAccessor.FindPlayer(sender_guid);
uint sender_accId = 0;
if (HasPermission(RBACPermissions.LogGmTrade))
{
string sender_name;
if (receiver)
{
sender_accId = receiver.GetSession().GetAccountId();
sender_name = receiver.GetName();
}
else
{
// can be calculated early
sender_accId = ObjectManager.GetPlayerAccountIdByGUID(sender_guid);
if (!ObjectManager.GetPlayerNameByGUID(sender_guid, out sender_name))
sender_name = Global.ObjectMgr.GetCypherString(CypherStrings.Unknown);
}
Log.outCommand(GetAccountId(), "GM {0} (Account: {1}) receiver mail item: {2} (Entry: {3} Count: {4}) and send COD money: {5} to player: {6} (Account: {7})",
GetPlayerName(), GetAccountId(), it.GetTemplate().GetName(), it.GetEntry(), it.GetCount(), m.COD, sender_name, sender_accId);
}
else if (!receiver)
sender_accId = ObjectManager.GetPlayerAccountIdByGUID(sender_guid);
// check player existence
if (receiver || sender_accId != 0)
{
new MailDraft(m.subject, "")
.AddMoney(m.COD)
.SendMailTo(trans, new MailReceiver(receiver, m.sender), new MailSender( MailMessageType.Normal, m.receiver), MailCheckMask.CodPayment);
}
player.ModifyMoney(-(long)m.COD);
}
m.COD = 0;
m.state = MailState.Changed;
player.m_mailsUpdated = true;
player.RemoveMItem(it.GetGUID().GetCounter());
uint count = it.GetCount(); // save counts before store and possible merge with deleting
it.SetState(ItemUpdateState.Unchanged); // need to set this state, otherwise item cannot be removed later, if neccessary
player.MoveItemToInventory(dest, it, true);
player.SaveInventoryAndGoldToDB(trans);
player._SaveMail(trans);
DB.Characters.CommitTransaction(trans);
player.SendMailResult(packet.MailID, MailResponseType.ItemTaken, MailResponseResult.Ok, 0, packet.AttachID, count);
}
else
player.SendMailResult(packet.MailID, MailResponseType.ItemTaken, MailResponseResult.EquipError, msg);
}
[WorldPacketHandler(ClientOpcodes.MailTakeMoney)]
void HandleMailTakeMoney(MailTakeMoney packet)
{
if (!CanOpenMailBox(packet.Mailbox))
return;
Player player = GetPlayer();
Mail m = player.GetMail(packet.MailID);
if ((m == null || m.state == MailState.Deleted || m.deliver_time > Time.UnixTime) ||
(packet.Money > 0 && m.money != (ulong)packet.Money))
{
player.SendMailResult(packet.MailID, MailResponseType.MoneyTaken, MailResponseResult.InternalError);
return;
}
if (!player.ModifyMoney((long)m.money, false))
{
player.SendMailResult(packet.MailID, MailResponseType.MoneyTaken, MailResponseResult.EquipError, InventoryResult.TooMuchGold);
return;
}
m.money = 0;
m.state = MailState.Changed;
player.m_mailsUpdated = true;
player.SendMailResult(packet.MailID, MailResponseType.MoneyTaken, MailResponseResult.Ok);
// save money and mail to prevent cheating
SQLTransaction trans = new SQLTransaction();
player.SaveGoldToDB(trans);
player._SaveMail(trans);
DB.Characters.CommitTransaction(trans);
}
//called when player lists his received mails
[WorldPacketHandler(ClientOpcodes.MailGetList)]
void HandleGetMailList(MailGetList packet)
{
if (!CanOpenMailBox(packet.Mailbox))
return;
Player player = GetPlayer();
//load players mails, and mailed items
if (!player.m_mailsLoaded)
player._LoadMail();
var mails = player.GetMails();
MailListResult response = new MailListResult();
long curTime = Time.UnixTime;
foreach (Mail m in mails)
{
// skip deleted or not delivered (deliver delay not expired) mails
if (m.state == MailState.Deleted || curTime < m.deliver_time)
continue;
// max. 50 mails can be sent
if (response.Mails.Count < 50)
response.Mails.Add(new MailListEntry(m, player));
}
player.PlayerTalkClass.GetInteractionData().Reset();
player.PlayerTalkClass.GetInteractionData().SourceGuid = packet.Mailbox;
SendPacket(response);
// recalculate m_nextMailDelivereTime and unReadMails
GetPlayer().UpdateNextMailTimeAndUnreads();
}
//used when player copies mail body to his inventory
[WorldPacketHandler(ClientOpcodes.MailCreateTextItem)]
void HandleMailCreateTextItem(MailCreateTextItem packet)
{
if (!CanOpenMailBox(packet.Mailbox))
return;
Player player = GetPlayer();
Mail m = player.GetMail(packet.MailID);
if (m == null || (string.IsNullOrEmpty(m.body) && m.mailTemplateId == 0) || m.state == MailState.Deleted || m.deliver_time > Time.UnixTime)
{
player.SendMailResult(packet.MailID, MailResponseType.MadePermanent, MailResponseResult.InternalError);
return;
}
Item bodyItem = new Item(); // This is not bag and then can be used new Item.
if (!bodyItem.Create(Global.ObjectMgr.GetGenerator(HighGuid.Item).Generate(), 8383, player))
return;
// in mail template case we need create new item text
if (m.mailTemplateId != 0)
{
MailTemplateRecord mailTemplateEntry = CliDB.MailTemplateStorage.LookupByKey(m.mailTemplateId);
if (mailTemplateEntry == null)
{
player.SendMailResult(packet.MailID, MailResponseType.MadePermanent, MailResponseResult.InternalError);
return;
}
bodyItem.SetText(mailTemplateEntry.Body[GetSessionDbcLocale()]);
}
else
bodyItem.SetText(m.body);
if (m.messageType == MailMessageType.Normal)
bodyItem.SetGuidValue(ItemFields.Creator, ObjectGuid.Create(HighGuid.Player, m.sender));
bodyItem.SetFlag(ItemFields.Flags, ItemFieldFlags.Readable);
Log.outInfo(LogFilter.Network, "HandleMailCreateTextItem mailid={0}", packet.MailID);
List<ItemPosCount> dest = new List<ItemPosCount>();
InventoryResult msg = GetPlayer().CanStoreItem(ItemConst.NullBag, ItemConst.NullSlot, dest, bodyItem, false);
if (msg == InventoryResult.Ok)
{
m.checkMask = m.checkMask | MailCheckMask.Copied;
m.state = MailState.Changed;
player.m_mailsUpdated = true;
player.StoreItem(dest, bodyItem, true);
player.SendMailResult(packet.MailID, MailResponseType.MadePermanent, MailResponseResult.Ok);
}
else
player.SendMailResult(packet.MailID, MailResponseType.MadePermanent, MailResponseResult.EquipError, msg);
}
[WorldPacketHandler(ClientOpcodes.QueryNextMailTime)]
void HandleQueryNextMailTime(MailQueryNextMailTime packet)
{
MailQueryNextTimeResult result = new MailQueryNextTimeResult();
if (!GetPlayer().m_mailsLoaded)
GetPlayer()._LoadMail();
if (GetPlayer().unReadMails > 0)
{
result.NextMailTime = 0.0f;
long now = Time.UnixTime;
List<ulong> sentSenders = new List<ulong>();
foreach (Mail mail in GetPlayer().GetMails())
{
if (mail.checkMask.HasAnyFlag(MailCheckMask.Read))
continue;
// and already delivered
if (now < mail.deliver_time)
continue;
// only send each mail sender once
if (sentSenders.Any(p => p == mail.sender))
continue;
result.Next.Add(new MailQueryNextTimeResult.MailNextTimeEntry(mail));
sentSenders.Add(mail.sender);
// do not send more than 2 mails
if (sentSenders.Count > 2)
break;
}
}
else
result.NextMailTime = -Time.Day;
SendPacket(result);
}
public void SendShowMailBox(ObjectGuid guid)
{
ShowMailbox packet = new ShowMailbox();
packet.PostmasterGUID = guid;
SendPacket(packet);
}
}
}
+789
View File
@@ -0,0 +1,789 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Framework.IO;
using Game.BattleGrounds;
using Game.DataStorage;
using Game.Entities;
using Game.Groups;
using Game.Guilds;
using Game.Maps;
using Game.Network;
using Game.Network.Packets;
using Game.PvP;
using System;
using System.Collections.Generic;
using System.Text;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.RequestAccountData, Status = SessionStatus.Authed)]
void HandleRequestAccountData(RequestAccountData request)
{
if (request.DataType > AccountDataTypes.Max)
return;
AccountData adata = GetAccountData(request.DataType);
if (adata.Data == null)
return;
UpdateAccountData data = new UpdateAccountData();
data.Player = GetPlayer() ? GetPlayer().GetGUID() : ObjectGuid.Empty;
data.Time = (uint)adata.Time;
data.Size = (uint)adata.Data.Length;
data.DataType = request.DataType;
data.CompressedData = new ByteBuffer(ZLib.Compress(Encoding.UTF8.GetBytes(adata.Data)));
SendPacket(data);
}
[WorldPacketHandler(ClientOpcodes.UpdateAccountData, Status = SessionStatus.Authed)]
void HandleUpdateAccountData(UserClientUpdateAccountData packet)
{
if (packet.DataType > AccountDataTypes.Max)
return;
if (packet.Size == 0)
{
SetAccountData(packet.DataType, 0, "");
return;
}
if (packet.Size > 0xFFFF)
{
Log.outError(LogFilter.Network, "UpdateAccountData: Account data packet too big, size {0}", packet.Size);
return;
}
byte[] data = ZLib.Decompress(packet.CompressedData.GetData(), packet.Size);
SetAccountData(packet.DataType, packet.Time, Encoding.Default.GetString(data));
}
[WorldPacketHandler(ClientOpcodes.SetSelection)]
void HandleSetSelection(SetSelection packet)
{
GetPlayer().SetSelection(packet.Selection);
}
[WorldPacketHandler(ClientOpcodes.ObjectUpdateFailed)]
void HandleObjectUpdateFailed(ObjectUpdateFailed objectUpdateFailed)
{
Log.outError(LogFilter.Network, "Object update failed for {0} for player {1} ({2})", objectUpdateFailed.ObjectGUID.ToString(), GetPlayerName(), GetPlayer().GetGUID().ToString());
// If create object failed for current player then client will be stuck on loading screen
if (GetPlayer().GetGUID() == objectUpdateFailed.ObjectGUID)
{
LogoutPlayer(true);
return;
}
// Pretend we've never seen this object
GetPlayer().m_clientGUIDs.Remove(objectUpdateFailed.ObjectGUID);
}
[WorldPacketHandler(ClientOpcodes.ObjectUpdateRescued, Processing = PacketProcessing.Inplace)]
void HandleObjectUpdateRescued(ObjectUpdateRescued objectUpdateRescued)
{
Log.outError(LogFilter.Network, "Object update rescued for {0} for player {1} ({2})", objectUpdateRescued.ObjectGUID.ToString(), GetPlayerName(), GetPlayer().GetGUID().ToString());
// Client received values update after destroying object
// re-register object in m_clientGUIDs to send DestroyObject on next visibility update
GetPlayer().m_clientGUIDs.Add(objectUpdateRescued.ObjectGUID);
}
[WorldPacketHandler(ClientOpcodes.SetActionButton)]
void HandleSetActionButton(SetActionButton packet)
{
uint action = packet.GetButtonAction();
uint type = packet.GetButtonType();
if (packet.Action == 0)
GetPlayer().RemoveActionButton(packet.Index);
else
GetPlayer().AddActionButton(packet.Index, action, type);
}
[WorldPacketHandler(ClientOpcodes.SetActionBarToggles)]
void HandleSetActionBarToggles(SetActionBarToggles packet)
{
if (!GetPlayer()) // ignore until not logged (check needed because STATUS_AUTHED)
{
if (packet.Mask != 0)
Log.outError(LogFilter.Network, "WorldSession.HandleSetActionBarToggles in not logged state with value: {0}, ignored", packet.Mask);
return;
}
GetPlayer().SetByteValue(PlayerFields.FieldBytes, PlayerFieldOffsets.FieldBytesOffsetActionBarToggles, packet.Mask);
}
[WorldPacketHandler(ClientOpcodes.CompleteCinematic)]
void HandleCompleteCinematic(CompleteCinematic packet)
{
// If player has sight bound to visual waypoint NPC we should remove it
GetPlayer().GetCinematicMgr().EndCinematic();
}
[WorldPacketHandler(ClientOpcodes.NextCinematicCamera)]
void HandleNextCinematicCamera(NextCinematicCamera packet)
{
// Sent by client when cinematic actually begun. So we begin the server side process
GetPlayer().GetCinematicMgr().BeginCinematic();
}
[WorldPacketHandler(ClientOpcodes.CompleteMovie)]
void HandleCompleteMovie(CompleteMovie packet)
{
uint movie = _player.GetMovie();
if (movie == 0)
return;
_player.SetMovie(0);
Global.ScriptMgr.OnMovieComplete(_player, movie);
}
[WorldPacketHandler(ClientOpcodes.ViolenceLevel, Processing = PacketProcessing.Inplace, Status = SessionStatus.Authed)]
void HandleViolenceLevel(ViolenceLevel violenceLevel)
{
// do something?
}
[WorldPacketHandler(ClientOpcodes.AreaTrigger)]
void HandleAreaTrigger(AreaTriggerPkt packet)
{
Player player = GetPlayer();
if (player.IsInFlight())
{
Log.outDebug(LogFilter.Network, "HandleAreaTriggerOpcode: Player '{0}' (GUID: {1}) in flight, ignore Area Trigger ID:{2}",
player.GetName(), player.GetGUID().ToString(), packet.AreaTriggerID);
return;
}
AreaTriggerRecord atEntry = CliDB.AreaTriggerStorage.LookupByKey(packet.AreaTriggerID);
if (atEntry == null)
{
Log.outDebug(LogFilter.Network, "HandleAreaTriggerOpcode: Player '{0}' (GUID: {1}) send unknown (by DBC) Area Trigger ID:{2}",
player.GetName(), player.GetGUID().ToString(), packet.AreaTriggerID);
return;
}
if (packet.Entered && !player.IsInAreaTriggerRadius(atEntry))
{
Log.outDebug(LogFilter.Network, "HandleAreaTriggerOpcode: Player '{0}' ({1}) too far, ignore Area Trigger ID: {2}",
player.GetName(), player.GetGUID().ToString(), packet.AreaTriggerID);
return;
}
if (player.isDebugAreaTriggers)
player.SendSysMessage(packet.Entered ? CypherStrings.DebugAreatriggerEntered : CypherStrings.DebugAreatriggerLeft, packet.AreaTriggerID);
if (Global.ScriptMgr.OnAreaTrigger(player, atEntry, packet.Entered))
return;
if (player.IsAlive())
{
List<uint> quests = Global.ObjectMgr.GetQuestsForAreaTrigger(packet.AreaTriggerID);
if (quests != null)
{
foreach (uint questId in quests)
{
Quest qInfo = Global.ObjectMgr.GetQuestTemplate(questId);
if (qInfo != null && player.GetQuestStatus(questId) == QuestStatus.Incomplete)
{
foreach (QuestObjective obj in qInfo.Objectives)
{
if (obj.Type == QuestObjectiveType.AreaTrigger && !player.IsQuestObjectiveComplete(obj))
{
player.SetQuestObjectiveData(obj, 1);
player.SendQuestUpdateAddCreditSimple(obj);
break;
}
}
if (player.CanCompleteQuest(questId))
player.CompleteQuest(questId);
}
}
}
}
if (Global.ObjectMgr.IsTavernAreaTrigger(packet.AreaTriggerID))
{
// set resting flag we are in the inn
player.GetRestMgr().SetRestFlag(RestFlag.Tavern, atEntry.Id);
if (Global.WorldMgr.IsFFAPvPRealm())
player.RemoveByteFlag(UnitFields.Bytes2, UnitBytes2Offsets.PvpFlag, UnitBytes2Flags.FFAPvp);
return;
}
Battleground bg = player.GetBattleground();
if (bg)
bg.HandleAreaTrigger(player, packet.AreaTriggerID, packet.Entered);
OutdoorPvP pvp = player.GetOutdoorPvP();
if (pvp != null)
{
if (pvp.HandleAreaTrigger(player, packet.AreaTriggerID, packet.Entered))
return;
}
AreaTriggerStruct at = Global.ObjectMgr.GetAreaTrigger(packet.AreaTriggerID);
if (at == null)
return;
bool teleported = false;
if (player.GetMapId() != at.target_mapId)
{
EnterState denyReason = Global.MapMgr.PlayerCannotEnter(at.target_mapId, player, false);
if (denyReason != 0)
{
bool reviveAtTrigger = false; // should we revive the player if he is trying to enter the correct instance?
switch (denyReason)
{
case EnterState.CannotEnterNoEntry:
Log.outDebug(LogFilter.Maps, "MAP: Player '{0}' attempted to enter map with id {1} which has no entry", player.GetName(), at.target_mapId);
break;
case EnterState.CannotEnterUninstancedDungeon:
Log.outDebug(LogFilter.Maps, "MAP: Player '{0}' attempted to enter dungeon map {1} but no instance template was found", player.GetName(), at.target_mapId);
break;
case EnterState.CannotEnterDifficultyUnavailable:
{
Log.outDebug(LogFilter.Maps, "MAP: Player '{0}' attempted to enter instance map {1} but the requested difficulty was not found", player.GetName(), at.target_mapId);
MapRecord entry = CliDB.MapStorage.LookupByKey(at.target_mapId);
if (entry != null)
player.SendTransferAborted(entry.Id, TransferAbortReason.Difficulty, (byte)player.GetDifficultyID(entry));
}
break;
case EnterState.CannotEnterNotInRaid:
Log.outDebug(LogFilter.Maps, "MAP: Player '{0}' must be in a raid group to enter map {1}", player.GetName(), at.target_mapId);
player.SendRaidGroupOnlyMessage(RaidGroupReason.Only, 0);
reviveAtTrigger = true;
break;
case EnterState.CannotEnterCorpseInDifferentInstance:
player.SendPacket(new AreaTriggerNoCorpse());
Log.outDebug(LogFilter.Maps, "MAP: Player '{0}' does not have a corpse in instance map {1} and cannot enter", player.GetName(), at.target_mapId);
break;
case EnterState.CannotEnterInstanceBindMismatch:
{
MapRecord entry = CliDB.MapStorage.LookupByKey(at.target_mapId);
if (entry != null)
{
string mapName = entry.MapName[player.GetSession().GetSessionDbcLocale()];
Log.outDebug(LogFilter.Maps, "MAP: Player '{0}' cannot enter instance map '{1}' because their permanent bind is incompatible with their group's", player.GetName(), mapName);
// is there a special opcode for this?
// @todo figure out how to get player localized difficulty string (e.g. "10 player", "Heroic" etc)
player.SendSysMessage(CypherStrings.InstanceBindMismatch, mapName);
}
reviveAtTrigger = true;
}
break;
case EnterState.CannotEnterTooManyInstances:
player.SendTransferAborted(at.target_mapId, TransferAbortReason.TooManyInstances);
Log.outDebug(LogFilter.Maps, "MAP: Player '{0}' cannot enter instance map {1} because he has exceeded the maximum number of instances per hour.", player.GetName(), at.target_mapId);
reviveAtTrigger = true;
break;
case EnterState.CannotEnterMaxPlayers:
player.SendTransferAborted(at.target_mapId, TransferAbortReason.MaxPlayers);
reviveAtTrigger = true;
break;
case EnterState.CannotEnterZoneInCombat:
player.SendTransferAborted(at.target_mapId, TransferAbortReason.ZoneInCombat);
reviveAtTrigger = true;
break;
default:
break;
}
if (reviveAtTrigger) // check if the player is touching the areatrigger leading to the map his corpse is on
{
if (!player.IsAlive() && player.HasCorpse())
{
if (player.GetCorpseLocation().GetMapId() == at.target_mapId)
{
player.ResurrectPlayer(0.5f);
player.SpawnCorpseBones();
}
}
}
return;
}
Group group = player.GetGroup();
if (group)
if (group.isLFGGroup() && player.GetMap().IsDungeon())
teleported = player.TeleportToBGEntryPoint();
}
if (!teleported)
{
WorldSafeLocsRecord entranceLocation = null;
InstanceSave instanceSave = player.GetInstanceSave(at.target_mapId);
if (instanceSave != null)
{
// Check if we can contact the instancescript of the instance for an updated entrance location
Map map = Global.MapMgr.FindMap(at.target_mapId, player.GetInstanceSave(at.target_mapId).GetInstanceId());
if (map)
{
InstanceMap instanceMap = map.ToInstanceMap();
if (instanceMap != null)
{
InstanceScript instanceScript = instanceMap.GetInstanceScript();
if (instanceScript != null)
entranceLocation = CliDB.WorldSafeLocsStorage.LookupByKey(instanceScript.GetEntranceLocation());
}
}
// Finally check with the instancesave for an entrance location if we did not get a valid one from the instancescript
if (entranceLocation == null)
entranceLocation = CliDB.WorldSafeLocsStorage.LookupByKey(instanceSave.GetEntranceLocation());
}
if (entranceLocation != null)
player.TeleportTo(entranceLocation.MapID, entranceLocation.Loc.X, entranceLocation.Loc.Y, entranceLocation.Loc.Z, (float)(entranceLocation.Facing * Math.PI / 180), TeleportToOptions.NotLeaveTransport);
else
player.TeleportTo(at.target_mapId, at.target_X, at.target_Y, at.target_Z, at.target_Orientation, TeleportToOptions.NotLeaveTransport);
}
}
[WorldPacketHandler(ClientOpcodes.RequestPlayedTime)]
void HandlePlayedTime(RequestPlayedTime packet)
{
PlayedTime playedTime = new PlayedTime();
playedTime.TotalTime = GetPlayer().GetTotalPlayedTime();
playedTime.LevelTime = GetPlayer().GetLevelPlayedTime();
playedTime.TriggerEvent = packet.TriggerScriptEvent; // 0-1 - will not show in chat frame
SendPacket(playedTime);
}
[WorldPacketHandler(ClientOpcodes.SaveCufProfiles, Processing = PacketProcessing.Inplace)]
void HandleSaveCUFProfiles(SaveCUFProfiles packet)
{
if (packet.CUFProfiles.Count > PlayerConst.MaxCUFProfiles)
{
Log.outError(LogFilter.Player, "HandleSaveCUFProfiles - {0} tried to save more than {1} CUF profiles. Hacking attempt?", GetPlayerName(), PlayerConst.MaxCUFProfiles);
return;
}
for (byte i = 0; i < packet.CUFProfiles.Count; ++i)
GetPlayer().SaveCUFProfile(i, packet.CUFProfiles[i]);
for (byte i = (byte)packet.CUFProfiles.Count; i < PlayerConst.MaxCUFProfiles; ++i)
GetPlayer().SaveCUFProfile(i, null);
}
public void SendLoadCUFProfiles()
{
Player player = GetPlayer();
LoadCUFProfiles loadCUFProfiles = new LoadCUFProfiles();
for (byte i = 0; i < PlayerConst.MaxCUFProfiles; ++i)
{
CUFProfile cufProfile = player.GetCUFProfile(i);
if (cufProfile != null)
loadCUFProfiles.CUFProfiles.Add(cufProfile);
}
SendPacket(loadCUFProfiles);
}
[WorldPacketHandler(ClientOpcodes.SetAdvancedCombatLogging, Processing = PacketProcessing.Inplace)]
void HandleSetAdvancedCombatLogging(SetAdvancedCombatLogging setAdvancedCombatLogging)
{
GetPlayer().SetAdvancedCombatLogging(setAdvancedCombatLogging.Enable);
}
[WorldPacketHandler(ClientOpcodes.MountSpecialAnim)]
void HandleMountSpecialAnim(MountSpecial mountSpecial)
{
SpecialMountAnim specialMountAnim = new SpecialMountAnim();
specialMountAnim.UnitGUID = _player.GetGUID();
GetPlayer().SendMessageToSet(specialMountAnim, false);
}
[WorldPacketHandler(ClientOpcodes.MountSetFavorite)]
void HandleMountSetFavorite(MountSetFavorite mountSetFavorite)
{
_collectionMgr.MountSetFavorite(mountSetFavorite.MountSpellID, mountSetFavorite.IsFavorite);
}
[WorldPacketHandler(ClientOpcodes.PvpPrestigeRankUp)]
void HandlePvpPrestigeRankUp(PvpPrestigeRankUp pvpPrestigeRankUp)
{
if (_player.CanPrestige())
_player.Prestige();
}
[WorldPacketHandler(ClientOpcodes.CloseInteraction)]
void HandleCloseInteraction(CloseInteraction closeInteraction)
{
if (_player.PlayerTalkClass.GetInteractionData().SourceGuid == closeInteraction.SourceGuid)
_player.PlayerTalkClass.GetInteractionData().Reset();
}
[WorldPacketHandler(ClientOpcodes.ChatUnregisterAllAddonPrefixes)]
void HandleUnregisterAllAddonPrefixes(ChatUnregisterAllAddonPrefixes packet)
{
_registeredAddonPrefixes.Clear();
}
[WorldPacketHandler(ClientOpcodes.ChatRegisterAddonPrefixes)]
void HandleAddonRegisteredPrefixes(ChatRegisterAddonPrefixes packet)
{
_registeredAddonPrefixes.AddRange(packet.Prefixes);
if (_registeredAddonPrefixes.Count > 64) // shouldn't happen
{
_filterAddonMessages = false;
return;
}
_filterAddonMessages = true;
}
[WorldPacketHandler(ClientOpcodes.TogglePvp)]
void HandleTogglePvP(TogglePvP packet)
{
Player player = GetPlayer();
bool inPvP = player.HasFlag(PlayerFields.Flags, PlayerFlags.InPVP);
player.ApplyModFlag(PlayerFields.Flags, PlayerFlags.InPVP, !inPvP);
player.ApplyModFlag(PlayerFields.Flags, PlayerFlags.PVPTimer, inPvP);
if (player.HasFlag(PlayerFields.Flags, PlayerFlags.InPVP))
{
if (!player.IsPvP() || player.pvpInfo.EndTimer != 0)
player.UpdatePvP(true, true);
}
else
{
if (!player.pvpInfo.IsHostile && player.IsPvP())
player.pvpInfo.EndTimer = Time.UnixTime; // start toggle-off
}
}
[WorldPacketHandler(ClientOpcodes.SetPvp)]
void HandleSetPvP(SetPvP packet)
{
Player player = GetPlayer();
player.ApplyModFlag(PlayerFields.Flags, PlayerFlags.InPVP, packet.EnablePVP);
player.ApplyModFlag(PlayerFields.Flags, PlayerFlags.PVPTimer, !packet.EnablePVP);
if (player.HasFlag(PlayerFields.Flags, PlayerFlags.InPVP))
{
if (!player.IsPvP() || player.pvpInfo.EndTimer != 0)
player.UpdatePvP(true, true);
}
else
{
if (!player.pvpInfo.IsHostile && player.IsPvP())
player.pvpInfo.EndTimer = Time.UnixTime; // start set-off
}
}
[WorldPacketHandler(ClientOpcodes.FarSight)]
void HandleFarSight(FarSight farSight)
{
if (farSight.Enable)
{
Log.outDebug(LogFilter.Network, "Added FarSight {0} to player {1}", GetPlayer().GetUInt64Value(PlayerFields.Farsight), GetPlayer().GetGUID().ToString());
WorldObject target = GetPlayer().GetViewpoint();
if (target)
GetPlayer().SetSeer(target);
else
Log.outDebug(LogFilter.Network, "Player {0} (GUID: {1}) requests non-existing seer {2}", GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), GetPlayer().GetUInt64Value(PlayerFields.Farsight));
}
else
{
Log.outDebug(LogFilter.Network, "Player {0} set vision to self", GetPlayer().GetGUID().ToString());
GetPlayer().SetSeer(GetPlayer());
}
GetPlayer().UpdateVisibilityForPlayer();
}
[WorldPacketHandler(ClientOpcodes.SetTitle)]
void HandleSetTitle(SetTitle packet)
{
// -1 at none
if (packet.TitleID > 0 && packet.TitleID < PlayerConst.MaxTitleIndex)
{
if (!GetPlayer().HasTitle((uint)packet.TitleID))
return;
}
else
packet.TitleID = 0;
GetPlayer().SetUInt32Value(PlayerFields.ChosenTitle, (uint)packet.TitleID);
}
[WorldPacketHandler(ClientOpcodes.ResetInstances)]
void HandleResetInstances(ResetInstances packet)
{
Group group = GetPlayer().GetGroup();
if (group)
{
if (group.IsLeader(GetPlayer().GetGUID()))
group.ResetInstances(InstanceResetMethod.All, false, false, GetPlayer());
}
else
GetPlayer().ResetInstances(InstanceResetMethod.All, false, false);
}
[WorldPacketHandler(ClientOpcodes.SetDungeonDifficulty)]
void HandleSetDungeonDifficulty(SetDungeonDifficulty setDungeonDifficulty)
{
DifficultyRecord difficultyEntry = CliDB.DifficultyStorage.LookupByKey(setDungeonDifficulty.DifficultyID);
if (difficultyEntry == null)
{
Log.outDebug(LogFilter.Network, "WorldSession.HandleSetDungeonDifficulty: {0} sent an invalid instance mode {1}!",
GetPlayer().GetGUID().ToString(), setDungeonDifficulty.DifficultyID);
return;
}
if (difficultyEntry.InstanceType != MapTypes.Instance)
{
Log.outDebug(LogFilter.Network, "WorldSession.HandleSetDungeonDifficulty: {0} sent an non-dungeon instance mode {1}!",
GetPlayer().GetGUID().ToString(), difficultyEntry.Id);
return;
}
if (!difficultyEntry.Flags.HasAnyFlag(DifficultyFlags.CanSelect))
{
Log.outDebug(LogFilter.Network, "WorldSession.HandleSetDungeonDifficulty: {0} sent unselectable instance mode {1}!",
GetPlayer().GetGUID().ToString(), difficultyEntry.Id);
return;
}
Difficulty difficultyID = (Difficulty)difficultyEntry.Id;
if (difficultyID == GetPlayer().GetDungeonDifficultyID())
return;
// cannot reset while in an instance
Map map = GetPlayer().GetMap();
if (map && map.IsDungeon())
{
Log.outDebug(LogFilter.Network, "WorldSession:HandleSetDungeonDifficulty: player (Name: {0}, {1}) tried to reset the instance while player is inside!",
GetPlayer().GetName(), GetPlayer().GetGUID().ToString());
return;
}
Group group = GetPlayer().GetGroup();
if (group)
{
if (group.IsLeader(GetPlayer().GetGUID()))
{
for (GroupReference refe = group.GetFirstMember(); refe != null; refe = refe.next())
{
Player groupGuy = refe.GetSource();
if (!groupGuy)
continue;
if (!groupGuy.IsInMap(groupGuy))
return;
if (groupGuy.GetMap().IsNonRaidDungeon())
{
Log.outDebug(LogFilter.Network, "WorldSession:HandleSetDungeonDifficulty: {0} tried to reset the instance while group member (Name: {1}, {2}) is inside!",
GetPlayer().GetGUID().ToString(), groupGuy.GetName(), groupGuy.GetGUID().ToString());
return;
}
}
// the difficulty is set even if the instances can't be reset
//_player->SendDungeonDifficulty(true);
group.ResetInstances(InstanceResetMethod.ChangeDifficulty, false, false, GetPlayer());
group.SetDungeonDifficultyID(difficultyID);
}
}
else
{
GetPlayer().ResetInstances(InstanceResetMethod.ChangeDifficulty, false, false);
GetPlayer().SetDungeonDifficultyID(difficultyID);
GetPlayer().SendDungeonDifficulty();
}
}
[WorldPacketHandler(ClientOpcodes.SetRaidDifficulty)]
void HandleSetRaidDifficulty(SetRaidDifficulty setRaidDifficulty)
{
DifficultyRecord difficultyEntry = CliDB.DifficultyStorage.LookupByKey(setRaidDifficulty.DifficultyID);
if (difficultyEntry == null)
{
Log.outDebug(LogFilter.Network, "WorldSession.HandleSetDungeonDifficulty: {0} sent an invalid instance mode {1}!",
GetPlayer().GetGUID().ToString(), setRaidDifficulty.DifficultyID);
return;
}
if (difficultyEntry.InstanceType != MapTypes.Raid)
{
Log.outDebug(LogFilter.Network, "WorldSession.HandleSetDungeonDifficulty: {0} sent an non-dungeon instance mode {1}!",
GetPlayer().GetGUID().ToString(), difficultyEntry.Id);
return;
}
if (!difficultyEntry.Flags.HasAnyFlag(DifficultyFlags.CanSelect))
{
Log.outDebug(LogFilter.Network, "WorldSession.HandleSetDungeonDifficulty: {0} sent unselectable instance mode {1}!",
GetPlayer().GetGUID().ToString(), difficultyEntry.Id);
return;
}
if (((int)(difficultyEntry.Flags & DifficultyFlags.Legacy) >> 5) != setRaidDifficulty.Legacy)
{
Log.outDebug(LogFilter.Network, "WorldSession.HandleSetDungeonDifficulty: {0} sent not matching legacy difficulty {1}!",
GetPlayer().GetGUID().ToString(), difficultyEntry.Id);
return;
}
Difficulty difficultyID = (Difficulty)difficultyEntry.Id;
if (difficultyID == (setRaidDifficulty.Legacy != 0 ? GetPlayer().GetLegacyRaidDifficultyID() : GetPlayer().GetRaidDifficultyID()))
return;
// cannot reset while in an instance
Map map = GetPlayer().GetMap();
if (map && map.IsDungeon())
{
Log.outDebug(LogFilter.Network, "WorldSession:HandleSetRaidDifficulty: player (Name: {0}, {1} tried to reset the instance while inside!",
GetPlayer().GetName(), GetPlayer().GetGUID().ToString());
return;
}
Group group = GetPlayer().GetGroup();
if (group)
{
if (group.IsLeader(GetPlayer().GetGUID()))
{
for (GroupReference refe = group.GetFirstMember(); refe != null; refe = refe.next())
{
Player groupGuy = refe.GetSource();
if (!groupGuy)
continue;
if (!groupGuy.IsInMap(groupGuy))
return;
if (groupGuy.GetMap().IsRaid())
{
Log.outDebug(LogFilter.Network, "WorldSession:HandleSetRaidDifficulty: player {0} tried to reset the instance while inside!", GetPlayer().GetGUID().ToString());
return;
}
}
// the difficulty is set even if the instances can't be reset
group.ResetInstances(InstanceResetMethod.ChangeDifficulty, true, setRaidDifficulty.Legacy != 0, GetPlayer());
if (setRaidDifficulty.Legacy != 0)
group.SetLegacyRaidDifficultyID(difficultyID);
else
group.SetRaidDifficultyID(difficultyID);
}
}
else
{
GetPlayer().ResetInstances(InstanceResetMethod.ChangeDifficulty, true, setRaidDifficulty.Legacy != 0);
if (setRaidDifficulty.Legacy != 0)
GetPlayer().SetLegacyRaidDifficultyID(difficultyID);
else
GetPlayer().SetRaidDifficultyID(difficultyID);
GetPlayer().SendRaidDifficulty(setRaidDifficulty.Legacy != 0);
}
}
[WorldPacketHandler(ClientOpcodes.SetTaxiBenchmarkMode, Processing = PacketProcessing.Inplace)]
void HandleSetTaxiBenchmark(SetTaxiBenchmarkMode packet)
{
_player.ApplyModFlag(PlayerFields.Flags, PlayerFlags.TaxiBenchmark, packet.Enable);
}
public void SendSetPhaseShift(List<uint> phaseIds, List<uint> terrainswaps, List<uint> worldMapAreaSwaps)
{
PhaseShift phaseShift = new PhaseShift();
phaseShift.ClientGUID = GetPlayer().GetGUID();
phaseShift.PersonalGUID = GetPlayer().GetGUID();
phaseShift.PhaseShifts = phaseIds;
phaseShift.VisibleMapIDs = terrainswaps;
phaseShift.UiWorldMapAreaIDSwaps = worldMapAreaSwaps;
SendPacket(phaseShift);
}
[WorldPacketHandler(ClientOpcodes.GuildSetFocusedAchievement)]
void HandleGuildSetFocusedAchievement(GuildSetFocusedAchievement setFocusedAchievement)
{
Guild guild = Global.GuildMgr.GetGuildById(GetPlayer().GetGuildId());
if (guild)
guild.GetAchievementMgr().SendAchievementInfo(GetPlayer(), setFocusedAchievement.AchievementID);
}
[WorldPacketHandler(ClientOpcodes.InstanceLockResponse)]
void HandleInstanceLockResponse(InstanceLockResponse packet)
{
if (!GetPlayer().HasPendingBind())
{
Log.outInfo(LogFilter.Network, "InstanceLockResponse: Player {0} (guid {1}) tried to bind himself/teleport to graveyard without a pending bind!",
GetPlayer().GetName(), GetPlayer().GetGUID().ToString());
return;
}
if (packet.AcceptLock)
GetPlayer().BindToInstance();
else
GetPlayer().RepopAtGraveyard();
GetPlayer().SetPendingBind(0, 0);
}
[WorldPacketHandler(ClientOpcodes.WardenData)]
void HandleWardenDataOpcode(WardenData packet)
{
if (_warden == null || packet.Data.GetSize() == 0)
return;
var unpacked = new ByteBuffer(_warden.DecryptData(packet.Data.GetData()));
WardenOpcodes opcode = (WardenOpcodes)packet.Data.ReadUInt8();
switch (opcode)
{
case WardenOpcodes.CMSG_ModuleMissing:
_warden.SendModuleToClient();
break;
case WardenOpcodes.Cmsg_ModuleOk:
_warden.RequestHash();
break;
case WardenOpcodes.Smsg_CheatChecksRequest:
_warden.HandleData(packet.Data);
break;
case WardenOpcodes.Cmsg_MemChecksResult:
Log.outDebug(LogFilter.Warden, "NYI WARDEN_CMSG_MEM_CHECKS_RESULT received!");
break;
case WardenOpcodes.Cmsg_HashResult:
_warden.HandleHashResult(packet.Data);
_warden.InitializeModule();
break;
case WardenOpcodes.Cmsg_ModuleFailed:
Log.outDebug(LogFilter.Warden, "NYI WARDEN_CMSG_MODULE_FAILED received!");
break;
default:
Log.outDebug(LogFilter.Warden, "Got unknown warden opcode {0} of size {1}.", opcode, packet.Data.GetSize() - 1);
break;
}
}
}
}
+651
View File
@@ -0,0 +1,651 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.BattleGrounds;
using Game.DataStorage;
using Game.Entities;
using Game.Garrisons;
using Game.Maps;
using Game.Movement;
using Game.Network;
using Game.Network.Packets;
using System;
using System.Collections.Generic;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.MoveChangeTransport, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveFallReset, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveFallLand, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveHeartbeat, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveJump, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveSetFacing, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveSetPitch, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveStartAscend, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveStartBackward, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveStartDescend, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveStartForward, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveStartPitchDown, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveStartPitchUp, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveStartStrafeLeft, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveStartStrafeRight, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveStartSwim, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveStartTurnLeft, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveStartTurnRight, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveStop, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveStopAscend, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveStopPitch, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveStopStrafe, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveStopSwim, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveStopTurn, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveDoubleJump, Processing = PacketProcessing.ThreadSafe)]
void HandleMovement(ClientPlayerMovement packet)
{
HandleMovementOpcode(packet.GetOpcode(), packet.Status);
}
void HandleMovementOpcode(ClientOpcodes opcode, MovementInfo movementInfo)
{
Unit mover = GetPlayer().m_unitMovedByMe;
Player plrMover = mover.ToPlayer();
if (plrMover && plrMover.IsBeingTeleported())
return;
GetPlayer().ValidateMovementInfo(movementInfo);
if (movementInfo.Guid != mover.GetGUID())
{
Log.outError(LogFilter.Network, "HandleMovementOpcodes: guid error");
return;
}
if (!movementInfo.Pos.IsPositionValid())
{
Log.outError(LogFilter.Network, "HandleMovementOpcodes: Invalid Position");
return;
}
// stop some emotes at player move
if (plrMover && (plrMover.GetUInt32Value(UnitFields.NpcEmotestate) != 0))
plrMover.SetUInt32Value(UnitFields.NpcEmotestate, (uint)Emote.OneshotNone);
//handle special cases
if (!movementInfo.transport.guid.IsEmpty())
{
if (movementInfo.transport.pos.GetPositionX() > 50 || movementInfo.transport.pos.GetPositionY() > 50 || movementInfo.transport.pos.GetPositionZ() > 50)
return;
if (!GridDefines.IsValidMapCoord(movementInfo.Pos.posX + movementInfo.transport.pos.posX, movementInfo.Pos.posY + movementInfo.transport.pos.posY,
movementInfo.Pos.posZ + movementInfo.transport.pos.posZ, movementInfo.Pos.Orientation + movementInfo.transport.pos.Orientation))
return;
if (plrMover)
{
if (!plrMover.GetTransport())
{
Transport transport = plrMover.GetMap().GetTransport(movementInfo.transport.guid);
if (transport)
transport.AddPassenger(plrMover);
}
else if (plrMover.GetTransport().GetGUID() != movementInfo.transport.guid)
{
plrMover.GetTransport().RemovePassenger(plrMover);
Transport transport = plrMover.GetMap().GetTransport(movementInfo.transport.guid);
if (transport)
transport.AddPassenger(plrMover);
else
movementInfo.ResetTransport();
}
}
if (!mover.GetTransport() && !mover.GetVehicle())
{
GameObject go = mover.GetMap().GetGameObject(movementInfo.transport.guid);
if (!go || go.GetGoType() != GameObjectTypes.Transport)
movementInfo.transport.Reset();
}
}
else if (plrMover && plrMover.GetTransport()) // if we were on a transport, leave
plrMover.GetTransport().RemovePassenger(plrMover);
// fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map).
if (opcode == ClientOpcodes.MoveFallLand && plrMover && !plrMover.IsInFlight())
plrMover.HandleFall(movementInfo);
if (plrMover && movementInfo.HasMovementFlag(MovementFlag.Swimming) != plrMover.IsInWater())
{
// now client not include swimming flag in case jumping under water
plrMover.SetInWater(!plrMover.IsInWater() || plrMover.GetMap().IsUnderWater(movementInfo.Pos.posX, movementInfo.Pos.posY, movementInfo.Pos.posZ));
}
uint mstime = Time.GetMSTime();
if (m_clientTimeDelay == 0)
m_clientTimeDelay = mstime - movementInfo.Time;
movementInfo.Time = movementInfo.Time + m_clientTimeDelay;
movementInfo.Guid = mover.GetGUID();
mover.m_movementInfo = movementInfo;
// Some vehicles allow the passenger to turn by himself
Vehicle vehicle = mover.GetVehicle();
if (vehicle)
{
VehicleSeatRecord seat = vehicle.GetSeatForPassenger(mover);
if (seat != null)
{
if (seat.Flags[0].HasAnyFlag((uint)VehicleSeatFlags.AllowTurning))
{
if (movementInfo.Pos.GetOrientation() != mover.GetOrientation())
{
mover.SetOrientation(movementInfo.Pos.GetOrientation());
mover.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Turning);
}
}
}
return;
}
mover.UpdatePosition(movementInfo.Pos);
MoveUpdate moveUpdate = new MoveUpdate();
moveUpdate.Status = mover.m_movementInfo;
mover.SendMessageToSet(moveUpdate, GetPlayer());
if (plrMover) // nothing is charmed, or player charmed
{
if (plrMover.IsSitState() && movementInfo.HasMovementFlag(MovementFlag.MaskMoving | MovementFlag.MaskTurning))
plrMover.SetStandState(UnitStandStateType.Stand);
plrMover.UpdateFallInformationIfNeed(movementInfo, opcode);
if (movementInfo.Pos.posZ < plrMover.GetMap().GetMinHeight(movementInfo.Pos.GetPositionX(), movementInfo.Pos.GetPositionY()))
{
if (!(plrMover.GetBattleground() && plrMover.GetBattleground().HandlePlayerUnderMap(GetPlayer())))
{
// NOTE: this is actually called many times while falling
// even after the player has been teleported away
/// @todo discard movement packets after the player is rooted
if (plrMover.IsAlive())
{
plrMover.SetFlag(PlayerFields.Flags, PlayerFlags.IsOutOfBounds);
plrMover.EnvironmentalDamage(EnviromentalDamage.FallToVoid, (uint)GetPlayer().GetMaxHealth());
// player can be alive if GM/etc
// change the death state to CORPSE to prevent the death timer from
// starting in the next player update
if (!plrMover.IsAlive())
plrMover.KillPlayer();
}
}
}
else
plrMover.RemoveFlag(PlayerFields.Flags, PlayerFlags.IsOutOfBounds);
}
}
[WorldPacketHandler(ClientOpcodes.WorldPortResponse, Status = SessionStatus.Transfer)]
void HandleMoveWorldportAck(WorldPortResponse packet)
{
HandleMoveWorldportAck();
}
void HandleMoveWorldportAck()
{
// ignore unexpected far teleports
if (!GetPlayer().IsBeingTeleportedFar())
return;
bool seamlessTeleport = GetPlayer().IsBeingTeleportedSeamlessly();
GetPlayer().SetSemaphoreTeleportFar(false);
// get the teleport destination
WorldLocation loc = GetPlayer().GetTeleportDest();
// possible errors in the coordinate validity check
if (!GridDefines.IsValidMapCoord(loc))
{
LogoutPlayer(false);
return;
}
// get the destination map entry, not the current one, this will fix homebind and reset greeting
MapRecord mapEntry = CliDB.MapStorage.LookupByKey(loc.GetMapId());
InstanceTemplate mInstance = Global.ObjectMgr.GetInstanceTemplate(loc.GetMapId());
// reset instance validity, except if going to an instance inside an instance
if (!GetPlayer().m_InstanceValid && mInstance == null)
GetPlayer().m_InstanceValid = true;
Map oldMap = GetPlayer().GetMap();
Map newMap = Global.MapMgr.CreateMap(loc.GetMapId(), GetPlayer());
if (GetPlayer().IsInWorld)
{
Log.outError(LogFilter.Network, "Player (Name {0}) is still in world when teleported from map {1} to new map {2}", GetPlayer().GetName(), oldMap.GetId(), loc.GetMapId());
oldMap.RemovePlayerFromMap(GetPlayer(), false);
}
// relocate the player to the teleport destination
// the CannotEnter checks are done in TeleporTo but conditions may change
// while the player is in transit, for example the map may get full
if (newMap == null || newMap.CannotEnter(GetPlayer()) != 0)
{
Log.outError(LogFilter.Network, "Map {0} could not be created for {1} ({2}), porting player to homebind", loc.GetMapId(), newMap ? newMap.GetMapName() : "Unknown", GetPlayer().GetGUID().ToString());
GetPlayer().TeleportTo(GetPlayer().GetHomebind());
return;
}
float z = loc.GetPositionZ();
if (GetPlayer().HasUnitMovementFlag(MovementFlag.Hover))
z += GetPlayer().GetFloatValue(UnitFields.HoverHeight);
GetPlayer().Relocate(loc.GetPositionX(), loc.GetPositionY(), z, loc.GetOrientation());
GetPlayer().ResetMap();
GetPlayer().SetMap(newMap);
ResumeToken resumeToken = new ResumeToken();
resumeToken.SequenceIndex = _player.m_movementCounter;
resumeToken.Reason = seamlessTeleport ? 2 : 1u;
SendPacket(resumeToken);
if (!seamlessTeleport)
GetPlayer().SendInitialPacketsBeforeAddToMap();
if (!GetPlayer().GetMap().AddPlayerToMap(GetPlayer(), !seamlessTeleport))
{
Log.outError(LogFilter.Network, "WORLD: failed to teleport player {0} ({1}) to map {2} ({3}) because of unknown reason!",
GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), loc.GetMapId(), newMap ? newMap.GetMapName() : "Unknown");
GetPlayer().ResetMap();
GetPlayer().SetMap(oldMap);
GetPlayer().TeleportTo(GetPlayer().GetHomebind());
return;
}
// Battleground state prepare (in case join to BG), at relogin/tele player not invited
// only add to bg group and object, if the player was invited (else he entered through command)
if (GetPlayer().InBattleground())
{
Battleground bg;
// cleanup setting if outdated
if (!mapEntry.IsBattlegroundOrArena())
{
// We're not in BG
GetPlayer().SetBattlegroundId(0, BattlegroundTypeId.None);
// reset destination bg team
GetPlayer().SetBGTeam(0);
}
// join to bg case
else if (bg = GetPlayer().GetBattleground())
{
if (GetPlayer().IsInvitedForBattlegroundInstance(GetPlayer().GetBattlegroundId()))
bg.AddPlayer(GetPlayer());
}
}
if (!seamlessTeleport)
GetPlayer().SendInitialPacketsAfterAddToMap();
else
{
GetPlayer().UpdateVisibilityForPlayer();
Garrison garrison = GetPlayer().GetGarrison();
if (garrison != null)
garrison.SendRemoteInfo();
}
// flight fast teleport case
if (GetPlayer().GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Flight)
{
if (!GetPlayer().InBattleground())
{
if (!seamlessTeleport)
{
// short preparations to continue flight
FlightPathMovementGenerator flight = (FlightPathMovementGenerator)GetPlayer().GetMotionMaster().top();
flight.Initialize(GetPlayer());
}
return;
}
// Battlegroundstate prepare, stop flight
GetPlayer().GetMotionMaster().MovementExpired();
GetPlayer().CleanupAfterTaxiFlight();
}
// resurrect character at enter into instance where his corpse exist after add to map
if (mapEntry.IsDungeon() && !GetPlayer().IsAlive())
{
if (GetPlayer().GetCorpseLocation().GetMapId() == mapEntry.Id)
{
GetPlayer().ResurrectPlayer(0.5f, false);
GetPlayer().SpawnCorpseBones();
}
}
bool allowMount = !mapEntry.IsDungeon() || mapEntry.IsBattlegroundOrArena();
if (mInstance != null)
{
// check if this instance has a reset time and send it to player if so
Difficulty diff = GetPlayer().GetDifficultyID(mapEntry);
MapDifficultyRecord mapDiff = Global.DB2Mgr.GetMapDifficultyData(mapEntry.Id, diff);
if (mapDiff != null)
{
if (mapDiff.GetRaidDuration() != 0)
{
long timeReset = Global.InstanceSaveMgr.GetResetTimeFor(mapEntry.Id, diff);
if (timeReset != 0)
{
uint timeleft = (uint)(timeReset - Time.UnixTime);
GetPlayer().SendInstanceResetWarning(mapEntry.Id, diff, timeleft, true);
}
}
}
// check if instance is valid
if (!GetPlayer().CheckInstanceValidity(false))
GetPlayer().m_InstanceValid = false;
// instance mounting is handled in InstanceTemplate
allowMount = mInstance.AllowMount;
}
// mount allow check
if (!allowMount)
GetPlayer().RemoveAurasByType(AuraType.Mounted);
// update zone immediately, otherwise leave channel will cause crash in mtmap
uint newzone, newarea;
GetPlayer().GetZoneAndAreaId(out newzone, out newarea);
GetPlayer().UpdateZone(newzone, newarea);
// honorless target
if (GetPlayer().pvpInfo.IsHostile)
GetPlayer().CastSpell(GetPlayer(), 2479, true);
// in friendly area
else if (GetPlayer().IsPvP() && !GetPlayer().HasFlag(PlayerFields.Flags, PlayerFlags.InPVP))
GetPlayer().UpdatePvP(false, false);
// resummon pet
GetPlayer().ResummonPetTemporaryUnSummonedIfAny();
//lets process all delayed operations on successful teleport
GetPlayer().ProcessDelayedOperations();
}
[WorldPacketHandler(ClientOpcodes.SuspendTokenResponse, Status = SessionStatus.Transfer)]
void HandleSuspendTokenResponse(SuspendTokenResponse suspendTokenResponse)
{
if (!_player.IsBeingTeleportedFar())
return;
WorldLocation loc = GetPlayer().GetTeleportDest();
if (CliDB.MapStorage.LookupByKey(loc.GetMapId()).IsDungeon())
{
UpdateLastInstance updateLastInstance = new UpdateLastInstance();
updateLastInstance.MapID = loc.GetMapId();
SendPacket(updateLastInstance);
}
NewWorld packet = new NewWorld();
packet.MapID = loc.GetMapId();
packet.Pos = loc;
packet.Reason = (uint)(!_player.IsBeingTeleportedSeamlessly() ? NewWorldReason.Normal : NewWorldReason.Seamless);
SendPacket(packet);
if (_player.IsBeingTeleportedSeamlessly())
HandleMoveWorldportAck();
}
[WorldPacketHandler(ClientOpcodes.MoveTeleportAck, Processing = PacketProcessing.ThreadSafe)]
void HandleMoveTeleportAck(MoveTeleportAck packet)
{
Player plMover = GetPlayer().m_unitMovedByMe.ToPlayer();
if (!plMover || !plMover.IsBeingTeleportedNear())
return;
if (packet.MoverGUID != plMover.GetGUID())
return;
plMover.SetSemaphoreTeleportNear(false);
uint old_zone = plMover.GetZoneId();
WorldLocation dest = plMover.GetTeleportDest();
plMover.UpdatePosition(dest, true);
uint newzone, newarea;
plMover.GetZoneAndAreaId(out newzone, out newarea);
plMover.UpdateZone(newzone, newarea);
// new zone
if (old_zone != newzone)
{
// honorless target
if (plMover.pvpInfo.IsHostile)
plMover.CastSpell(plMover, 2479, true);
// in friendly area
else if (plMover.IsPvP() && !plMover.HasFlag(PlayerFields.Flags, PlayerFlags.InPVP))
plMover.UpdatePvP(false, false);
}
// resummon pet
GetPlayer().ResummonPetTemporaryUnSummonedIfAny();
//lets process all delayed operations on successful teleport
GetPlayer().ProcessDelayedOperations();
}
[WorldPacketHandler(ClientOpcodes.MoveForceFlightBackSpeedChangeAck, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveForceFlightSpeedChangeAck, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveForcePitchRateChangeAck, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveForceRunBackSpeedChangeAck, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveForceRunSpeedChangeAck, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveForceSwimBackSpeedChangeAck, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveForceSwimSpeedChangeAck, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveForceTurnRateChangeAck, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveForceWalkSpeedChangeAck, Processing = PacketProcessing.ThreadSafe)]
void HandleForceSpeedChangeAck(MovementSpeedAck packet)
{
GetPlayer().ValidateMovementInfo(packet.Ack.Status);
// now can skip not our packet
if (GetPlayer().GetGUID() != packet.Ack.Status.Guid)
return;
/*----------------*/
// client ACK send one packet for mounted/run case and need skip all except last from its
// in other cases anti-cheat check can be fail in false case
UnitMoveType move_type;
ClientOpcodes opcode = packet.GetOpcode();
switch (opcode)
{
case ClientOpcodes.MoveForceWalkSpeedChangeAck:
move_type = UnitMoveType.Walk;
break;
case ClientOpcodes.MoveForceRunSpeedChangeAck:
move_type = UnitMoveType.Run;
break;
case ClientOpcodes.MoveForceRunBackSpeedChangeAck:
move_type = UnitMoveType.RunBack;
break;
case ClientOpcodes.MoveForceSwimSpeedChangeAck:
move_type = UnitMoveType.Swim;
break;
case ClientOpcodes.MoveForceSwimBackSpeedChangeAck:
move_type = UnitMoveType.SwimBack;
break;
case ClientOpcodes.MoveForceTurnRateChangeAck:
move_type = UnitMoveType.TurnRate;
break;
case ClientOpcodes.MoveForceFlightSpeedChangeAck:
move_type = UnitMoveType.Flight;
break;
case ClientOpcodes.MoveForceFlightBackSpeedChangeAck:
move_type = UnitMoveType.FlightBack;
break;
case ClientOpcodes.MoveForcePitchRateChangeAck:
move_type = UnitMoveType.PitchRate;
break;
default:
Log.outError(LogFilter.Network, "WorldSession.HandleForceSpeedChangeAck: Unknown move type opcode: {0}", opcode);
return;
}
// skip all forced speed changes except last and unexpected
// in run/mounted case used one ACK and it must be skipped. m_forced_speed_changes[MOVE_RUN] store both.
if (GetPlayer().m_forced_speed_changes[(int)move_type] > 0)
{
--GetPlayer().m_forced_speed_changes[(int)move_type];
if (GetPlayer().m_forced_speed_changes[(int)move_type] > 0)
return;
}
if (!GetPlayer().GetTransport() && Math.Abs(GetPlayer().GetSpeed(move_type) - packet.Speed) > 0.01f)
{
if (GetPlayer().GetSpeed(move_type) > packet.Speed) // must be greater - just correct
{
Log.outError(LogFilter.Network, "{0}SpeedChange player {1} is NOT correct (must be {2} instead {3}), force set to correct value",
move_type, GetPlayer().GetName(), GetPlayer().GetSpeed(move_type), packet.Speed);
GetPlayer().SetSpeedRate(move_type, GetPlayer().GetSpeedRate(move_type));
}
else // must be lesser - cheating
{
Log.outDebug(LogFilter.Server, "Player {0} from account id {1} kicked for incorrect speed (must be {2} instead {3})",
GetPlayer().GetName(), GetPlayer().GetSession().GetAccountId(), GetPlayer().GetSpeed(move_type), packet.Speed);
GetPlayer().GetSession().KickPlayer();
}
}
}
[WorldPacketHandler(ClientOpcodes.SetActiveMover)]
void HandleSetActiveMover(SetActiveMover packet)
{
if (GetPlayer().IsInWorld)
{
if (_player.m_unitMovedByMe.GetGUID() != packet.ActiveMover)
Log.outError(LogFilter.Network, "HandleSetActiveMover: incorrect mover guid: mover is {0} and should be {1},", packet.ActiveMover.ToString(), _player.m_unitMovedByMe.GetGUID().ToString());
}
}
[WorldPacketHandler(ClientOpcodes.MoveKnockBackAck, Processing = PacketProcessing.ThreadSafe)]
void HandleMoveKnockBackAck(MoveKnockBackAck movementAck)
{
GetPlayer().ValidateMovementInfo(movementAck.Ack.Status);
if (GetPlayer().m_unitMovedByMe.GetGUID() != movementAck.Ack.Status.Guid)
return;
GetPlayer().m_movementInfo = movementAck.Ack.Status;
MoveUpdateKnockBack updateKnockBack = new MoveUpdateKnockBack();
updateKnockBack.Status = GetPlayer().m_movementInfo;
GetPlayer().SendMessageToSet(updateKnockBack, false);
}
[WorldPacketHandler(ClientOpcodes.MoveEnableSwimToFlyTransAck, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveFeatherFallAck, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveForceRootAck, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveForceUnrootAck, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveGravityDisableAck, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveGravityEnableAck, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveHoverAck, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveSetCanFlyAck, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveSetCanTurnWhileFallingAck, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveSetIgnoreMovementForcesAck, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveWaterWalkAck, Processing = PacketProcessing.ThreadSafe)]
[WorldPacketHandler(ClientOpcodes.MoveEnableDoubleJumpAck, Processing = PacketProcessing.ThreadSafe)]
void HandleMovementAckMessage(MovementAckMessage movementAck)
{
GetPlayer().ValidateMovementInfo(movementAck.Ack.Status);
}
[WorldPacketHandler(ClientOpcodes.SummonResponse)]
void HandleSummonResponseOpcode(SummonResponse packet)
{
if (!GetPlayer().IsAlive() || GetPlayer().IsInCombat())
return;
GetPlayer().SummonIfPossible(packet.Accept);
}
[WorldPacketHandler(ClientOpcodes.MoveSetCollisionHeightAck, Processing = PacketProcessing.ThreadSafe)]
void HandleSetCollisionHeightAck(MoveSetCollisionHeightAck packet)
{
GetPlayer().ValidateMovementInfo(packet.Data.Status);
}
[WorldPacketHandler(ClientOpcodes.MoveTimeSkipped, Processing = PacketProcessing.Inplace)]
void HandleMoveTimeSkipped(MoveTimeSkipped moveTimeSkipped)
{
}
[WorldPacketHandler(ClientOpcodes.MoveSplineDone, Processing = PacketProcessing.ThreadSafe)]
void HandleMoveSplineDoneOpcode(MoveSplineDone moveSplineDone)
{
MovementInfo movementInfo = moveSplineDone.Status;
_player.ValidateMovementInfo(movementInfo);
// in taxi flight packet received in 2 case:
// 1) end taxi path in far (multi-node) flight
// 2) switch from one map to other in case multim-map taxi path
// we need process only (1)
uint curDest = GetPlayer().m_taxi.GetTaxiDestination();
if (curDest != 0)
{
TaxiNodesRecord curDestNode = CliDB.TaxiNodesStorage.LookupByKey(curDest);
// far teleport case
if (curDestNode != null && curDestNode.MapID != GetPlayer().GetMapId())
{
if (GetPlayer().GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Flight)
{
// short preparations to continue flight
FlightPathMovementGenerator flight = (FlightPathMovementGenerator)GetPlayer().GetMotionMaster().top();
flight.SetCurrentNodeAfterTeleport();
TaxiPathNodeRecord node = flight.GetPath()[(int)flight.GetCurrentNode()];
flight.SkipCurrentNode();
GetPlayer().TeleportTo(curDestNode.MapID, node.Loc.X, node.Loc.Y, node.Loc.Z, GetPlayer().GetOrientation());
}
}
return;
}
// at this point only 1 node is expected (final destination)
if (GetPlayer().m_taxi.GetPath().Count != 1)
return;
GetPlayer().CleanupAfterTaxiFlight();
GetPlayer().SetFallInformation(0, GetPlayer().GetPositionZ());
if (GetPlayer().pvpInfo.IsHostile)
GetPlayer().CastSpell(GetPlayer(), 2479, true);
}
}
}
+577
View File
@@ -0,0 +1,577 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Framework.Database;
using Game.BattleGrounds;
using Game.DataStorage;
using Game.Entities;
using Game.Network;
using Game.Network.Packets;
using System;
using System.Collections.Generic;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.TabardVendorActivate)]
void HandleTabardVendorActivate(Hello packet)
{
Creature unit = GetPlayer().GetNPCIfCanInteractWith(packet.Unit, NPCFlags.TabardDesigner);
if (!unit)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleTabardVendorActivateOpcode - {0} not found or you can not interact with him.", packet.Unit.ToString());
return;
}
// remove fake death
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
SendTabardVendorActivate(packet.Unit);
}
public void SendTabardVendorActivate(ObjectGuid guid)
{
PlayerTabardVendorActivate packet = new PlayerTabardVendorActivate();
packet.Vendor = guid;
SendPacket(packet);
}
[WorldPacketHandler(ClientOpcodes.TrainerList)]
void HandleTrainerList(Hello packet)
{
Creature npc = GetPlayer().GetNPCIfCanInteractWith(packet.Unit, NPCFlags.Trainer);
if (!npc)
{
Log.outDebug(LogFilter.Network, $"WorldSession.SendTrainerList - {packet.Unit.ToString()} not found or you can not interact with him.");
return;
}
uint trainerId = Global.ObjectMgr.GetCreatureDefaultTrainer(npc.GetEntry());
if (trainerId != 0)
SendTrainerList(npc, trainerId);
else
Log.outDebug(LogFilter.Network, $"WorldSession.SendTrainerList - Creature id {npc.GetEntry()} has no trainer data.");
}
public void SendTrainerList(Creature npc, uint trainerId)
{
// remove fake death
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
Trainer trainer = Global.ObjectMgr.GetTrainer(trainerId);
if (trainer == null)
{
Log.outDebug(LogFilter.Network, $"WORLD: SendTrainerList - trainer spells not found for trainer {npc.GetGUID().ToString()} id {trainerId}");
return;
}
_player.PlayerTalkClass.GetInteractionData().Reset();
_player.PlayerTalkClass.GetInteractionData().SourceGuid = npc.GetGUID();
_player.PlayerTalkClass.GetInteractionData().TrainerId = trainerId;
trainer.SendSpells(npc, _player, GetSessionDbLocaleIndex());
}
[WorldPacketHandler(ClientOpcodes.TrainerBuySpell)]
void HandleTrainerBuySpell(TrainerBuySpell packet)
{
Creature npc = _player.GetNPCIfCanInteractWith(packet.TrainerGUID, NPCFlags.Trainer);
if (npc == null)
{
Log.outDebug(LogFilter.Network, $"WORLD: HandleTrainerBuySpell - {packet.TrainerGUID.ToString()} not found or you can not interact with him.");
return;
}
// remove fake death
if (_player.HasUnitState(UnitState.Died))
_player.RemoveAurasByType(AuraType.FeignDeath);
if (_player.PlayerTalkClass.GetInteractionData().SourceGuid != packet.TrainerGUID)
return;
if (_player.PlayerTalkClass.GetInteractionData().TrainerId != packet.TrainerID)
return;
// check present spell in trainer spell list
Trainer trainer = Global.ObjectMgr.GetTrainer(packet.TrainerID);
if (trainer == null)
return;
trainer.TeachSpell(npc, _player, packet.SpellID);
}
void SendTrainerBuyFailed(ObjectGuid trainerGUID, uint spellID, TrainerFailReason trainerFailedReason)
{
TrainerBuyFailed trainerBuyFailed = new TrainerBuyFailed();
trainerBuyFailed.TrainerGUID = trainerGUID;
trainerBuyFailed.SpellID = spellID; // should be same as in packet from client
trainerBuyFailed.TrainerFailedReason = trainerFailedReason; // 1 == "Not enough money for trainer service." 0 == "Trainer service %d unavailable."
SendPacket(trainerBuyFailed);
}
[WorldPacketHandler(ClientOpcodes.TalkToGossip)]
void HandleGossipHello(Hello packet)
{
Creature unit = GetPlayer().GetNPCIfCanInteractWith(packet.Unit, NPCFlags.Gossip);
if (unit == null)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleGossipHello - {0} not found or you can not interact with him.", packet.Unit.ToString());
return;
}
// set faction visible if needed
var factionTemplateEntry = CliDB.FactionTemplateStorage.LookupByKey(unit.getFaction());
if (factionTemplateEntry != null)
GetPlayer().GetReputationMgr().SetVisible(factionTemplateEntry);
GetPlayer().RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Talk);
if (unit.IsArmorer() || unit.IsCivilian() || unit.IsQuestGiver() || unit.IsServiceProvider() || unit.IsGuard())
unit.StopMoving();
// If spiritguide, no need for gossip menu, just put player into resurrect queue
if (unit.IsSpiritGuide())
{
Battleground bg = GetPlayer().GetBattleground();
if (bg)
{
bg.AddPlayerToResurrectQueue(unit.GetGUID(), GetPlayer().GetGUID());
Global.BattlegroundMgr.SendAreaSpiritHealerQuery(GetPlayer(), bg, unit.GetGUID());
return;
}
}
if (!Global.ScriptMgr.OnGossipHello(GetPlayer(), unit))
{
GetPlayer().PrepareGossipMenu(unit, unit.GetCreatureTemplate().GossipMenuId, true);
GetPlayer().SendPreparedGossip(unit);
}
unit.GetAI().sGossipHello(GetPlayer());
}
[WorldPacketHandler(ClientOpcodes.GossipSelectOption)]
void HandleGossipSelectOption(GossipSelectOption packet)
{
if (GetPlayer().PlayerTalkClass.GetGossipMenu().GetItem(packet.GossipIndex) == null)
return;
// Prevent cheating on C# scripted menus
if (GetPlayer().PlayerTalkClass.GetInteractionData().SourceGuid != packet.GossipUnit)
return;
Creature unit = null;
GameObject go = null;
if (packet.GossipUnit.IsCreatureOrVehicle())
{
unit = GetPlayer().GetNPCIfCanInteractWith(packet.GossipUnit, NPCFlags.Gossip);
if (unit == null)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleGossipSelectOption - {0} not found or you can't interact with him.", packet.GossipUnit.ToString());
return;
}
}
else if (packet.GossipUnit.IsGameObject())
{
go = GetPlayer().GetGameObjectIfCanInteractWith(packet.GossipUnit);
if (go == null)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleGossipSelectOption - {0} not found or you can't interact with it.", packet.GossipUnit.ToString());
return;
}
}
else
{
Log.outDebug(LogFilter.Network, "WORLD: HandleGossipSelectOption - unsupported {0}.", packet.GossipUnit.ToString());
return;
}
// remove fake death
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
if ((unit && unit.GetScriptId() != unit.LastUsedScriptID) || (go != null && go.GetScriptId() != go.LastUsedScriptID))
{
Log.outDebug(LogFilter.Network, "WORLD: HandleGossipSelectOption - Script reloaded while in use, ignoring and set new scipt id");
if (unit != null)
unit.LastUsedScriptID = unit.GetScriptId();
if (go != null)
go.LastUsedScriptID = go.GetScriptId();
GetPlayer().PlayerTalkClass.SendCloseGossip();
return;
}
if (!string.IsNullOrEmpty(packet.PromotionCode))
{
if (unit)
{
unit.GetAI().sGossipSelectCode(GetPlayer(), packet.GossipID, packet.GossipIndex, packet.PromotionCode);
if (!Global.ScriptMgr.OnGossipSelectCode(GetPlayer(), unit, GetPlayer().PlayerTalkClass.GetGossipOptionSender(packet.GossipIndex), GetPlayer().PlayerTalkClass.GetGossipOptionAction(packet.GossipIndex), packet.PromotionCode))
GetPlayer().OnGossipSelect(unit, packet.GossipIndex, packet.GossipID);
}
else
{
go.GetAI().GossipSelectCode(GetPlayer(), packet.GossipID, packet.GossipIndex, packet.PromotionCode);
Global.ScriptMgr.OnGossipSelectCode(GetPlayer(), go, GetPlayer().PlayerTalkClass.GetGossipOptionSender(packet.GossipIndex), GetPlayer().PlayerTalkClass.GetGossipOptionAction(packet.GossipIndex), packet.PromotionCode);
}
}
else
{
if (unit != null)
{
unit.GetAI().sGossipSelect(GetPlayer(), packet.GossipID, packet.GossipIndex);
if (!Global.ScriptMgr.OnGossipSelect(GetPlayer(), unit, GetPlayer().PlayerTalkClass.GetGossipOptionSender(packet.GossipIndex), GetPlayer().PlayerTalkClass.GetGossipOptionAction(packet.GossipIndex)))
GetPlayer().OnGossipSelect(unit, packet.GossipIndex, packet.GossipID);
}
else
{
go.GetAI().GossipSelect(GetPlayer(), packet.GossipID, packet.GossipIndex);
if (!Global.ScriptMgr.OnGossipSelect(GetPlayer(), go, GetPlayer().PlayerTalkClass.GetGossipOptionSender(packet.GossipIndex), GetPlayer().PlayerTalkClass.GetGossipOptionAction(packet.GossipIndex)))
GetPlayer().OnGossipSelect(go, packet.GossipIndex, packet.GossipID);
}
}
}
[WorldPacketHandler(ClientOpcodes.SpiritHealerActivate)]
void HandleSpiritHealerActivate(SpiritHealerActivate packet)
{
Creature unit = GetPlayer().GetNPCIfCanInteractWith(packet.Healer, NPCFlags.SpiritHealer);
if (!unit)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleSpiritHealerActivateOpcode - {0} not found or you can not interact with him.", packet.Healer.ToString());
return;
}
// remove fake death
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
SendSpiritResurrect();
}
void SendSpiritResurrect()
{
GetPlayer().ResurrectPlayer(0.5f, true);
GetPlayer().DurabilityLossAll(0.25f, true);
// get corpse nearest graveyard
WorldSafeLocsRecord corpseGrave = null;
WorldLocation corpseLocation = GetPlayer().GetCorpseLocation();
if (GetPlayer().HasCorpse())
{
corpseGrave = Global.ObjectMgr.GetClosestGraveYard(corpseLocation.GetPositionX(), corpseLocation.GetPositionY(),
corpseLocation.GetPositionZ(), corpseLocation.GetMapId(), GetPlayer().GetTeam());
}
// now can spawn bones
GetPlayer().SpawnCorpseBones();
// teleport to nearest from corpse graveyard, if different from nearest to player ghost
if (corpseGrave != null)
{
WorldSafeLocsRecord ghostGrave = Global.ObjectMgr.GetClosestGraveYard(
GetPlayer().GetPositionX(), GetPlayer().GetPositionY(), GetPlayer().GetPositionZ(), GetPlayer().GetMapId(), GetPlayer().GetTeam());
if (corpseGrave != ghostGrave)
GetPlayer().TeleportTo(corpseGrave.MapID, corpseGrave.Loc.X, corpseGrave.Loc.Y, corpseGrave.Loc.Z, GetPlayer().GetOrientation());
// or update at original position
else
GetPlayer().UpdateObjectVisibility();
}
// or update at original position
else
GetPlayer().UpdateObjectVisibility();
}
[WorldPacketHandler(ClientOpcodes.BinderActivate)]
void HandleBinderActivate(Hello packet)
{
if (!GetPlayer().IsInWorld || !GetPlayer().IsAlive())
return;
Creature unit = GetPlayer().GetNPCIfCanInteractWith(packet.Unit, NPCFlags.Innkeeper);
if (!unit)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleBinderActivate - {0} not found or you can not interact with him.", packet.Unit.ToString());
return;
}
// remove fake death
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
SendBindPoint(unit);
}
void SendBindPoint(Creature npc)
{
// prevent set homebind to instances in any case
if (GetPlayer().GetMap().Instanceable())
return;
uint bindspell = 3286;
// send spell for homebinding (3286)
npc.CastSpell(GetPlayer(), bindspell, true);
GetPlayer().PlayerTalkClass.SendCloseGossip();
}
[WorldPacketHandler(ClientOpcodes.RequestStabledPets)]
void HandleRequestStabledPets(RequestStabledPets packet)
{
if (!CheckStableMaster(packet.StableMaster))
return;
// remove fake death
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
// remove mounts this fix bug where getting pet from stable while mounted deletes pet.
if (GetPlayer().IsMounted())
GetPlayer().RemoveAurasByType(AuraType.Mounted);
SendStablePet(packet.StableMaster);
}
public void SendStablePet(ObjectGuid guid)
{
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PET_SLOTS_DETAIL);
stmt.AddValue(0, guid.GetCounter());
stmt.AddValue(1, PetSaveMode.FirstStableSlot);
stmt.AddValue(2, PetSaveMode.LastStableSlot);
_queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(SendStablePetCallback, guid));
}
void SendStablePetCallback(ObjectGuid guid, SQLResult result)
{
if (!GetPlayer())
return;
PetStableList packet = new PetStableList();
packet.StableMaster = guid;
Pet pet = GetPlayer().GetPet();
uint petSlot = 0;
// not let move dead pet in slot
if (pet && pet.IsAlive() && pet.getPetType() == PetType.Hunter)
{
PetStableInfo stableEntry;// = new PetStableInfo();
stableEntry.PetSlot = petSlot;
stableEntry.PetNumber = pet.GetCharmInfo().GetPetNumber();
stableEntry.CreatureID = pet.GetEntry();
stableEntry.DisplayID = pet.GetDisplayId();
stableEntry.ExperienceLevel = pet.getLevel();
stableEntry.PetFlags = PetStableinfo.Active;
stableEntry.PetName = pet.GetName();
++petSlot;
packet.Pets.Add(stableEntry);
}
if (!result.IsEmpty())
{
do
{
PetStableInfo stableEntry;// = new PetStableInfo();
stableEntry.PetSlot = petSlot;
stableEntry.PetNumber = result.Read<uint>(1); // petnumber
stableEntry.CreatureID = result.Read<uint>(2); // creature entry
stableEntry.DisplayID = result.Read<uint>(5); // creature displayid
stableEntry.ExperienceLevel = result.Read<ushort>(3); // level
stableEntry.PetFlags = PetStableinfo.Inactive;
stableEntry.PetName = result.Read<string>(4); // Name
++petSlot;
packet.Pets.Add(stableEntry);
}
while (result.NextRow());
}
SendPacket(packet);
}
void SendPetStableResult(byte res)
{
SendPacket(new PetStableResult(res));
}
[WorldPacketHandler(ClientOpcodes.RepairItem)]
void HandleRepairItem(RepairItem packet)
{
Creature unit = GetPlayer().GetNPCIfCanInteractWith(packet.NpcGUID, NPCFlags.Repair);
if (!unit)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleRepairItemOpcode - {0} not found or you can not interact with him.", packet.NpcGUID.ToString());
return;
}
// remove fake death
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
// reputation discount
float discountMod = GetPlayer().GetReputationPriceDiscount(unit);
if (!packet.ItemGUID.IsEmpty())
{
Log.outDebug(LogFilter.Network, "ITEM: Repair {0}, at {1}", packet.ItemGUID.ToString(), packet.NpcGUID.ToString());
Item item = GetPlayer().GetItemByGuid(packet.ItemGUID);
if (item)
GetPlayer().DurabilityRepair(item.GetPos(), true, discountMod, packet.UseGuildBank);
}
else
{
Log.outDebug(LogFilter.Network, "ITEM: Repair all items at {0}", packet.NpcGUID.ToString());
GetPlayer().DurabilityRepairAll(true, discountMod, packet.UseGuildBank);
}
}
[WorldPacketHandler(ClientOpcodes.ListInventory)]
void HandleListInventory(Hello packet)
{
if (!GetPlayer().IsAlive())
return;
SendListInventory(packet.Unit);
}
public void SendListInventory(ObjectGuid vendorGuid)
{
Creature vendor = GetPlayer().GetNPCIfCanInteractWith(vendorGuid, NPCFlags.Vendor);
if (vendor == null)
{
Log.outDebug(LogFilter.Network, "WORLD: SendListInventory - {0} not found or you can not interact with him.", vendorGuid.ToString());
GetPlayer().SendSellError(SellResult.CantFindVendor, null, ObjectGuid.Empty);
return;
}
// remove fake death
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
// Stop the npc if moving
if (vendor.HasUnitState(UnitState.Moving))
vendor.StopMoving();
VendorItemData vendorItems = vendor.GetVendorItems();
int rawItemCount = vendorItems != null ? vendorItems.GetItemCount() : 0;
VendorInventory packet = new VendorInventory();
packet.Vendor = vendor.GetGUID();
float discountMod = GetPlayer().GetReputationPriceDiscount(vendor);
byte count = 0;
for (uint slot = 0; slot < rawItemCount; ++slot)
{
VendorItem vendorItem = vendorItems.GetItem(slot);
if (vendorItem == null)
continue;
VendorItemPkt item = new VendorItemPkt();
PlayerConditionRecord playerCondition = CliDB.PlayerConditionStorage.LookupByKey(vendorItem.PlayerConditionId);
if (playerCondition != null)
if (!ConditionManager.IsPlayerMeetingCondition(_player, playerCondition))
item.PlayerConditionFailed = (int)playerCondition.Id;
if (vendorItem.Type == ItemVendorType.Item)
{
ItemTemplate itemTemplate = Global.ObjectMgr.GetItemTemplate(vendorItem.item);
if (itemTemplate == null)
continue;
int leftInStock = vendorItem.maxcount == 0 ? -1 : (int)vendor.GetVendorItemCurrentCount(vendorItem);
if (!GetPlayer().IsGameMaster())
{
if (!Convert.ToBoolean(itemTemplate.GetAllowableClass() & GetPlayer().getClassMask()) && itemTemplate.GetBonding() == ItemBondingType.OnAcquire)
continue;
if ((itemTemplate.GetFlags2().HasAnyFlag(ItemFlags2.FactionHorde) && GetPlayer().GetTeam() == Team.Alliance) ||
(itemTemplate.GetFlags2().HasAnyFlag(ItemFlags2.FactionAlliance) && GetPlayer().GetTeam() == Team.Horde))
continue;
if (leftInStock == 0)
continue;
}
if (!Global.ConditionMgr.IsObjectMeetingVendorItemConditions(vendor.GetEntry(), vendorItem.item, _player, vendor))
{
Log.outDebug(LogFilter.Condition, "SendListInventory: conditions not met for creature entry {0} item {1}", vendor.GetEntry(), vendorItem.item);
continue;
}
int price = (int)(vendorItem.IsGoldRequired(itemTemplate) ? Math.Floor(itemTemplate.GetBuyPrice() * discountMod) : 0);
int priceMod = GetPlayer().GetTotalAuraModifier(AuraType.ModVendorItemsPrices);
if (priceMod != 0)
price -= MathFunctions.CalculatePct(price, priceMod);
item.MuID = (int)slot + 1;
item.Durability = (int)itemTemplate.MaxDurability;
item.ExtendedCostID = (int)vendorItem.ExtendedCost;
item.Type = (int)vendorItem.Type;
item.Quantity = leftInStock;
item.StackCount = (int)itemTemplate.GetBuyCount();
item.Price = (ulong)price;
item.DoNotFilterOnVendor = vendorItem.IgnoreFiltering;
item.Item.ItemID = vendorItem.item;
if (!vendorItem.BonusListIDs.Empty())
{
item.Item.ItemBonus.HasValue = true;
item.Item.ItemBonus.Value.BonusListIDs = vendorItem.BonusListIDs;
}
packet.Items.Add(item);
}
else if (vendorItem.Type == ItemVendorType.Currency)
{
CurrencyTypesRecord currencyTemplate = CliDB.CurrencyTypesStorage.LookupByKey(vendorItem.item);
if (currencyTemplate == null)
continue;
if (vendorItem.ExtendedCost == 0)
continue; // there's no price defined for currencies, only extendedcost is used
item.MuID = (int)slot + 1; // client expects counting to start at 1
item.ExtendedCostID = (int)vendorItem.ExtendedCost;
item.Item.ItemID = vendorItem.item;
item.Type = (int)vendorItem.Type;
item.StackCount = (int)vendorItem.maxcount;
item.DoNotFilterOnVendor = vendorItem.IgnoreFiltering;
packet.Items.Add(item);
}
else
continue;
if (++count >= SharedConst.MaxVendorItems)
break;
}
SendPacket(packet);
}
}
}
+726
View File
@@ -0,0 +1,726 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Framework.Database;
using Game.Entities;
using Game.Network;
using Game.Network.Packets;
using Game.Spells;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.DismissCritter)]
void HandleDismissCritter(DismissCritter packet)
{
Unit pet = ObjectAccessor.GetCreatureOrPetOrVehicle(GetPlayer(), packet.CritterGUID);
if (!pet)
{
Log.outDebug(LogFilter.Network, "Vanitypet {0} does not exist - player '{1}' ({2} / account: {3}) attempted to dismiss it (possibly lagged out)",
packet.CritterGUID.ToString(), GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), GetAccountId());
return;
}
if (GetPlayer().GetCritterGUID() == pet.GetGUID())
{
if (pet.IsTypeId(TypeId.Unit) && pet.ToCreature().IsSummon())
pet.ToTempSummon().UnSummon();
}
}
[WorldPacketHandler(ClientOpcodes.RequestPetInfo)]
void HandleRequestPetInfo(RequestPetInfo packet)
{
}
[WorldPacketHandler(ClientOpcodes.PetAction)]
void HandlePetAction(PetAction packet)
{
ObjectGuid guid1 = packet.PetGUID; //pet guid
ObjectGuid guid2 = packet.TargetGUID; //tag guid
uint spellid = UnitActionBarEntry.UNIT_ACTION_BUTTON_ACTION(packet.Action);
ActiveStates flag = (ActiveStates)UnitActionBarEntry.UNIT_ACTION_BUTTON_TYPE(packet.Action); //delete = 0x07 CastSpell = C1
// used also for charmed creature
Unit pet = Global.ObjAccessor.GetUnit(GetPlayer(), guid1);
if (!pet)
{
Log.outError(LogFilter.Network, "HandlePetAction: {0} doesn't exist for {1}", guid1.ToString(), GetPlayer().GetGUID().ToString());
return;
}
if (pet != GetPlayer().GetFirstControlled())
{
Log.outError(LogFilter.Network, "HandlePetAction: {0} does not belong to {1}", guid1.ToString(), GetPlayer().GetGUID().ToString());
return;
}
if (!pet.IsAlive())
{
SpellInfo spell = (flag == ActiveStates.Enabled || flag == ActiveStates.Passive) ? Global.SpellMgr.GetSpellInfo(spellid) : null;
if (spell == null)
return;
if (!spell.HasAttribute(SpellAttr0.CastableWhileDead))
return;
}
/// @todo allow control charmed player?
if (pet.IsTypeId(TypeId.Player) && !(flag == ActiveStates.Command && spellid == (uint)CommandStates.Attack))
return;
if (GetPlayer().m_Controlled.Count == 1)
HandlePetActionHelper(pet, guid1, spellid, flag, guid2, packet.ActionPosition.X, packet.ActionPosition.Y, packet.ActionPosition.Z);
else
{
//If a pet is dismissed, m_Controlled will change
List<Unit> controlled = new List<Unit>();
foreach (var unit in GetPlayer().m_Controlled)
if (unit.GetEntry() == pet.GetEntry() && unit.IsAlive())
controlled.Add(unit);
foreach (var unit in controlled)
HandlePetActionHelper(unit, guid1, spellid, flag, guid2, packet.ActionPosition.X, packet.ActionPosition.Y, packet.ActionPosition.Z);
}
}
[WorldPacketHandler(ClientOpcodes.PetStopAttack)]
void HandlePetStopAttack(PetStopAttack packet)
{
Unit pet = ObjectAccessor.GetCreatureOrPetOrVehicle(GetPlayer(), packet.PetGUID);
if (!pet)
{
Log.outError(LogFilter.Network, "HandlePetStopAttack: {0} does not exist", packet.PetGUID.ToString());
return;
}
if (pet != GetPlayer().GetPet() && pet != GetPlayer().GetCharm())
{
Log.outError(LogFilter.Network, "HandlePetStopAttack: {0} isn't a pet or charmed creature of player {1}", packet.PetGUID.ToString(), GetPlayer().GetName());
return;
}
if (!pet.IsAlive())
return;
pet.AttackStop();
}
void HandlePetActionHelper(Unit pet, ObjectGuid guid1, uint spellid, ActiveStates flag, ObjectGuid guid2, float x, float y, float z)
{
CharmInfo charmInfo = pet.GetCharmInfo();
if (charmInfo == null)
{
Log.outError(LogFilter.Network, "WorldSession.HandlePetAction(petGuid: {0}, tagGuid: {1}, spellId: {2}, flag: {3}): object (GUID: {4} Entry: {5} TypeId: {6}) is considered pet-like but doesn't have a charminfo!",
guid1, guid2, spellid, flag, pet.GetGUID().ToString(), pet.GetEntry(), pet.GetTypeId());
return;
}
switch (flag)
{
case ActiveStates.Command: //0x07
switch ((CommandStates)spellid)
{
case CommandStates.Stay: //flat=1792 //STAY
pet.StopMoving();
pet.GetMotionMaster().Clear(false);
pet.GetMotionMaster().MoveIdle();
charmInfo.SetCommandState(CommandStates.Stay);
charmInfo.SetIsCommandAttack(false);
charmInfo.SetIsAtStay(true);
charmInfo.SetIsCommandFollow(false);
charmInfo.SetIsFollowing(false);
charmInfo.SetIsReturning(false);
charmInfo.SaveStayPosition();
break;
case CommandStates.Follow: //spellid=1792 //FOLLOW
pet.AttackStop();
pet.InterruptNonMeleeSpells(false);
pet.GetMotionMaster().MoveFollow(GetPlayer(), SharedConst.PetFollowDist, pet.GetFollowAngle());
charmInfo.SetCommandState(CommandStates.Follow);
charmInfo.SetIsCommandAttack(false);
charmInfo.SetIsAtStay(false);
charmInfo.SetIsReturning(true);
charmInfo.SetIsCommandFollow(true);
charmInfo.SetIsFollowing(false);
break;
case CommandStates.Attack: //spellid=1792 //ATTACK
{
// Can't attack if owner is pacified
if (GetPlayer().HasAuraType(AuraType.ModPacify))
{
/// @todo Send proper error message to client
return;
}
// only place where pet can be player
Unit TargetUnit = Global.ObjAccessor.GetUnit(GetPlayer(), guid2);
if (!TargetUnit)
return;
Unit owner = pet.GetOwner();
if (owner)
if (!owner.IsValidAttackTarget(TargetUnit))
return;
pet.ClearUnitState(UnitState.Follow);
// This is true if pet has no target or has target but targets differs.
if (pet.GetVictim() != TargetUnit || (pet.GetVictim() == TargetUnit && !pet.GetCharmInfo().IsCommandAttack()))
{
if (pet.GetVictim())
pet.AttackStop();
if (!pet.IsTypeId(TypeId.Player) && pet.ToCreature().IsAIEnabled)
{
charmInfo.SetIsCommandAttack(true);
charmInfo.SetIsAtStay(false);
charmInfo.SetIsFollowing(false);
charmInfo.SetIsCommandFollow(false);
charmInfo.SetIsReturning(false);
pet.ToCreature().GetAI().AttackStart(TargetUnit);
//10% chance to play special pet attack talk, else growl
if (pet.IsPet() && pet.ToPet().getPetType() == PetType.Summon && pet != TargetUnit && RandomHelper.IRand(0, 100) < 10)
pet.SendPetTalk(PetTalk.Attack);
else
{
// 90% chance for pet and 100% chance for charmed creature
pet.SendPetAIReaction(guid1);
}
}
else // charmed player
{
if (pet.GetVictim() && pet.GetVictim() != TargetUnit)
pet.AttackStop();
charmInfo.SetIsCommandAttack(true);
charmInfo.SetIsAtStay(false);
charmInfo.SetIsFollowing(false);
charmInfo.SetIsCommandFollow(false);
charmInfo.SetIsReturning(false);
pet.Attack(TargetUnit, true);
pet.SendPetAIReaction(guid1);
}
}
break;
}
case CommandStates.Abandon: // abandon (hunter pet) or dismiss (summoned pet)
if (pet.GetCharmerGUID() == GetPlayer().GetGUID())
GetPlayer().StopCastingCharm();
else if (pet.GetOwnerGUID() == GetPlayer().GetGUID())
{
Contract.Assert(pet.IsTypeId(TypeId.Unit));
if (pet.IsPet())
{
if (pet.ToPet().getPetType() == PetType.Hunter)
GetPlayer().RemovePet(pet.ToPet(), PetSaveMode.AsDeleted);
else
//dismissing a summoned pet is like killing them (this prevents returning a soulshard...)
pet.setDeathState(DeathState.Corpse);
}
else if (pet.HasUnitTypeMask(UnitTypeMask.Minion))
{
((Minion)pet).UnSummon();
}
}
break;
case CommandStates.MoveTo:
pet.StopMoving();
pet.GetMotionMaster().Clear(false);
pet.GetMotionMaster().MovePoint(0, x, y, z);
charmInfo.SetCommandState(CommandStates.MoveTo);
charmInfo.SetIsCommandAttack(false);
charmInfo.SetIsAtStay(true);
charmInfo.SetIsFollowing(false);
charmInfo.SetIsReturning(false);
charmInfo.SaveStayPosition();
break;
default:
Log.outError(LogFilter.Network, "WORLD: unknown PET flag Action {0} and spellid {1}.", flag, spellid);
break;
}
break;
case ActiveStates.Reaction: // 0x6
switch ((ReactStates)spellid)
{
case ReactStates.Passive: //passive
pet.AttackStop();
goto case ReactStates.Defensive;
case ReactStates.Defensive: //recovery
case ReactStates.Aggressive: //activete
if (pet.IsTypeId(TypeId.Unit))
pet.ToCreature().SetReactState((ReactStates)spellid);
break;
}
break;
case ActiveStates.Disabled: // 0x81 spell (disabled), ignore
case ActiveStates.Passive: // 0x01
case ActiveStates.Enabled: // 0xC1 spell
{
Unit unit_target = null;
if (!guid2.IsEmpty())
unit_target = Global.ObjAccessor.GetUnit(GetPlayer(), guid2);
// do not cast unknown spells
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellid);
if (spellInfo == null)
{
Log.outError(LogFilter.Network, "WORLD: unknown PET spell id {0}", spellid);
return;
}
foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None))
{
if (effect != null && (effect.TargetA.GetTarget() == Targets.UnitSrcAreaEnemy || effect.TargetA.GetTarget() == Targets.UnitDestAreaEnemy || effect.TargetA.GetTarget() == Targets.DestDynobjEnemy))
return;
}
// do not cast not learned spells
if (!pet.HasSpell(spellid) || spellInfo.IsPassive())
return;
// Clear the flags as if owner clicked 'attack'. AI will reset them
// after AttackStart, even if spell failed
if (pet.GetCharmInfo() != null)
{
pet.GetCharmInfo().SetIsAtStay(false);
pet.GetCharmInfo().SetIsCommandAttack(true);
pet.GetCharmInfo().SetIsReturning(false);
pet.GetCharmInfo().SetIsFollowing(false);
}
Spell spell = new Spell(pet, spellInfo, TriggerCastFlags.None);
SpellCastResult result = spell.CheckPetCast(unit_target);
//auto turn to target unless possessed
if (result == SpellCastResult.UnitNotInfront && !pet.isPossessed() && !pet.IsVehicle())
{
Unit unit_target2 = spell.m_targets.GetUnitTarget();
if (unit_target)
{
pet.SetInFront(unit_target);
Player player = unit_target.ToPlayer();
if (player)
pet.SendUpdateToPlayer(player);
}
else if (unit_target2)
{
pet.SetInFront(unit_target2);
Player player = unit_target2.ToPlayer();
if (player)
pet.SendUpdateToPlayer(player);
}
Unit powner = pet.GetCharmerOrOwner();
if (powner)
{
Player player = powner.ToPlayer();
if (player)
pet.SendUpdateToPlayer(player);
}
result = SpellCastResult.SpellCastOk;
}
if (result == SpellCastResult.SpellCastOk)
{
unit_target = spell.m_targets.GetUnitTarget();
//10% chance to play special pet attack talk, else growl
//actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
if (pet.IsPet() && (pet.ToPet().getPetType() == PetType.Summon) && (pet != unit_target) && (RandomHelper.IRand(0, 100) < 10))
pet.SendPetTalk(PetTalk.SpecialSpell);
else
{
pet.SendPetAIReaction(guid1);
}
if (unit_target && !GetPlayer().IsFriendlyTo(unit_target) && !pet.isPossessed() && !pet.IsVehicle())
{
// This is true if pet has no target or has target but targets differs.
if (pet.GetVictim() != unit_target)
{
if (pet.GetVictim())
pet.AttackStop();
pet.GetMotionMaster().Clear();
if (pet.ToCreature().IsAIEnabled)
pet.ToCreature().GetAI().AttackStart(unit_target);
}
}
spell.prepare(spell.m_targets);
}
else
{
if (pet.isPossessed() || pet.IsVehicle()) /// @todo: confirm this check
Spell.SendCastResult(GetPlayer(), spellInfo, spell.m_SpellVisual, spell.m_castId, result);
else
spell.SendPetCastResult(result);
if (!pet.GetSpellHistory().HasCooldown(spellid))
pet.GetSpellHistory().ResetCooldown(spellid, true);
spell.finish(false);
spell.Dispose();
// reset specific flags in case of spell fail. AI will reset other flags
if (pet.GetCharmInfo() != null)
pet.GetCharmInfo().SetIsCommandAttack(false);
}
break;
}
default:
Log.outError(LogFilter.Network, "WORLD: unknown PET flag Action {0} and spellid {1}.", flag, spellid);
break;
}
}
[WorldPacketHandler(ClientOpcodes.QueryPetName)]
void HandleQueryPetName(QueryPetName packet)
{
SendQueryPetNameResponse(packet.UnitGUID);
}
void SendQueryPetNameResponse(ObjectGuid guid)
{
QueryPetNameResponse response = new QueryPetNameResponse();
response.UnitGUID = guid;
Creature unit = ObjectAccessor.GetCreatureOrPetOrVehicle(GetPlayer(), guid);
if (unit)
{
response.Allow = true;
response.Timestamp = unit.GetUInt32Value(UnitFields.PetNameTimestamp);
response.Name = unit.GetName();
Pet pet = unit.ToPet();
if (pet)
{
DeclinedName names = pet.GetDeclinedNames();
if (names != null)
{
response.HasDeclined = true;
response.DeclinedNames = names;
}
}
return;
}
GetPlayer().SendPacket(response);
}
bool CheckStableMaster(ObjectGuid guid)
{
// spell case or GM
if (guid == GetPlayer().GetGUID())
{
if (!GetPlayer().IsGameMaster() && !GetPlayer().HasAuraType(AuraType.OpenStable))
{
Log.outDebug(LogFilter.Network, "{0} attempt open stable in cheating way.", guid.ToString());
return false;
}
}
// stable master case
else
{
if (!GetPlayer().GetNPCIfCanInteractWith(guid, NPCFlags.StableMaster))
{
Log.outDebug(LogFilter.Network, "Stablemaster {0} not found or you can't interact with him.", guid.ToString());
return false;
}
}
return true;
}
[WorldPacketHandler(ClientOpcodes.PetSetAction)]
void HandlePetSetAction(PetSetAction packet)
{
ObjectGuid petguid = packet.PetGUID;
Unit pet = Global.ObjAccessor.GetUnit(GetPlayer(), petguid);
if (!pet || pet != GetPlayer().GetFirstControlled())
{
Log.outError(LogFilter.Network, "HandlePetSetAction: Unknown {0} or pet owner {1}", petguid.ToString(), GetPlayer().GetGUID().ToString());
return;
}
CharmInfo charmInfo = pet.GetCharmInfo();
if (charmInfo == null)
{
Log.outError(LogFilter.Network, "WorldSession.HandlePetSetAction: {0} is considered pet-like but doesn't have a charminfo!", pet.GetGUID().ToString());
return;
}
uint position = packet.Index;
uint actionData = packet.Action;
uint spell_id = UnitActionBarEntry.UNIT_ACTION_BUTTON_ACTION(actionData);
ActiveStates act_state = (ActiveStates)UnitActionBarEntry.UNIT_ACTION_BUTTON_TYPE(actionData);
Log.outDebug(LogFilter.Network, "Player {0} has changed pet spell action. Position: {1}, Spell: {2}, State: {3}", GetPlayer().GetName(), position, spell_id, act_state);
//if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add
if (!((act_state == ActiveStates.Enabled || act_state == ActiveStates.Disabled || act_state == ActiveStates.Passive) && spell_id != 0 && !pet.HasSpell(spell_id)))
{
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell_id);
if (spellInfo != null)
{
//sign for autocast
if (act_state == ActiveStates.Enabled)
{
if (pet.GetTypeId() == TypeId.Unit && pet.IsPet())
((Pet)pet).ToggleAutocast(spellInfo, true);
else
{
foreach (var unit in GetPlayer().m_Controlled)
if (unit.GetEntry() == pet.GetEntry())
unit.GetCharmInfo().ToggleCreatureAutocast(spellInfo, true);
}
}
//sign for no/turn off autocast
else if (act_state == ActiveStates.Disabled)
{
if (pet.GetTypeId() == TypeId.Unit && pet.IsPet())
pet.ToPet().ToggleAutocast(spellInfo, false);
else
{
foreach (var unit in GetPlayer().m_Controlled)
if (unit.GetEntry() == pet.GetEntry())
unit.GetCharmInfo().ToggleCreatureAutocast(spellInfo, false);
}
}
}
charmInfo.SetActionBar((byte)position, spell_id, act_state);
}
}
[WorldPacketHandler(ClientOpcodes.PetRename)]
void HandlePetRename(PetRename packet)
{
ObjectGuid petguid = packet.RenameData.PetGUID;
bool isdeclined = packet.RenameData.HasDeclinedNames;
string name = packet.RenameData.NewName;
Pet pet = ObjectAccessor.GetPet(GetPlayer(), petguid);
// check it!
if (!pet || !pet.IsPet() || pet.ToPet().getPetType() != PetType.Hunter || !pet.HasByteFlag(UnitFields.Bytes2, UnitBytes2Offsets.PetFlags, UnitPetFlags.CanBeRenamed) ||
pet.GetOwnerGUID() != GetPlayer().GetGUID() || pet.GetCharmInfo() == null)
return;
PetNameInvalidReason res = ObjectManager.CheckPetName(name);
if (res != PetNameInvalidReason.Success)
{
SendPetNameInvalid(res, name, null);
return;
}
if (Global.ObjectMgr.IsReservedName(name))
{
SendPetNameInvalid(PetNameInvalidReason.Reserved, name, null);
return;
}
pet.SetName(name);
pet.SetGroupUpdateFlag(GroupUpdatePetFlags.Name);
pet.RemoveByteFlag(UnitFields.Bytes2, UnitBytes2Offsets.PetFlags, UnitPetFlags.CanBeRenamed);
PreparedStatement stmt;
SQLTransaction trans = new SQLTransaction();
if (isdeclined)
{
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHAR_PET_DECLINEDNAME);
stmt.AddValue(0, pet.GetCharmInfo().GetPetNumber());
trans.Append(stmt);
stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_CHAR_PET_DECLINEDNAME);
stmt.AddValue(0, pet.GetCharmInfo().GetPetNumber());
stmt.AddValue(1, GetPlayer().GetGUID().ToString());
for (byte i = 0; i < SharedConst.MaxDeclinedNameCases; i++)
stmt.AddValue(i + 1, packet.RenameData.DeclinedNames.name[i]);
trans.Append(stmt);
}
stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_CHAR_PET_NAME);
stmt.AddValue(0, name);
stmt.AddValue(1, GetPlayer().GetGUID().ToString());
stmt.AddValue(2, pet.GetCharmInfo().GetPetNumber());
trans.Append(stmt);
DB.Characters.CommitTransaction(trans);
pet.SetUInt32Value(UnitFields.PetNameTimestamp, (uint)Time.UnixTime); // cast can't be helped
}
[WorldPacketHandler(ClientOpcodes.PetAbandon)]
void HandlePetAbandon(PetAbandon packet)
{
if (!GetPlayer().IsInWorld)
return;
Creature pet = ObjectAccessor.GetCreatureOrPetOrVehicle(GetPlayer(), packet.Pet);
if (pet)
{
if (pet.IsPet())
GetPlayer().RemovePet(pet.ToPet(), PetSaveMode.AsDeleted);
else if (pet.GetGUID() == GetPlayer().GetCharmGUID())
GetPlayer().StopCastingCharm();
}
}
[WorldPacketHandler(ClientOpcodes.PetSpellAutocast)]
void HandlePetSpellAutocast(PetSpellAutocast packet)
{
Creature pet = ObjectAccessor.GetCreatureOrPetOrVehicle(GetPlayer(), packet.PetGUID);
if (!pet)
{
Log.outError(LogFilter.Network, "WorldSession.HandlePetSpellAutocast: {0} not found.", packet.PetGUID.ToString());
return;
}
if (pet != GetPlayer().GetGuardianPet() && pet != GetPlayer().GetCharm())
{
Log.outError(LogFilter.Network, "WorldSession.HandlePetSpellAutocast: {0} isn't pet of player {1} ({2}).",
packet.PetGUID.ToString(), GetPlayer().GetName(), GetPlayer().GetGUID().ToString());
return;
}
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(packet.SpellID);
if (spellInfo == null)
{
Log.outError(LogFilter.Network, "WorldSession.HandlePetSpellAutocast: Unknown spell id {0} used by {1}.", packet.SpellID, packet.PetGUID.ToString());
return;
}
// do not add not learned spells/ passive spells
if (!pet.HasSpell(packet.SpellID) || !spellInfo.IsAutocastable())
return;
CharmInfo charmInfo = pet.GetCharmInfo();
if (charmInfo == null)
{
Log.outError(LogFilter.Network, "WorldSession.HandlePetSpellAutocastOpcod: object {0} is considered pet-like but doesn't have a charminfo!", pet.GetGUID().ToString());
return;
}
if (pet.IsPet())
pet.ToPet().ToggleAutocast(spellInfo, packet.AutocastEnabled);
else
charmInfo.ToggleCreatureAutocast(spellInfo, packet.AutocastEnabled);
charmInfo.SetSpellAutocast(spellInfo, packet.AutocastEnabled);
}
[WorldPacketHandler(ClientOpcodes.PetCastSpell)]
void HandlePetCastSpell(PetCastSpell petCastSpell)
{
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(petCastSpell.Cast.SpellID);
if (spellInfo == null)
{
Log.outError(LogFilter.Network, "WorldSession.HandlePetCastSpell: unknown spell id {0} tried to cast by {1}", petCastSpell.Cast.SpellID, petCastSpell.PetGUID.ToString());
return;
}
Unit caster = Global.ObjAccessor.GetUnit(GetPlayer(), petCastSpell.PetGUID);
if (!caster)
{
Log.outError(LogFilter.Network, "WorldSession.HandlePetCastSpell: Caster {0} not found.", petCastSpell.PetGUID.ToString());
return;
}
// This opcode is also sent from charmed and possessed units (players and creatures)
if (caster != GetPlayer().GetGuardianPet() && caster != GetPlayer().GetCharm())
{
Log.outError(LogFilter.Network, "WorldSession.HandlePetCastSpell: {0} isn't pet of player {1} ({2}).", petCastSpell.PetGUID.ToString(), GetPlayer().GetName(), GetPlayer().GetGUID().ToString());
return;
}
// do not cast not learned spells
if (!caster.HasSpell(spellInfo.Id) || spellInfo.IsPassive())
return;
SpellCastTargets targets = new SpellCastTargets(caster, petCastSpell.Cast);
caster.ClearUnitState(UnitState.Follow);
Spell spell = new Spell(caster, spellInfo, TriggerCastFlags.None);
spell.m_fromClient = true;
spell.m_misc.Data0 = petCastSpell.Cast.Misc[0];
spell.m_misc.Data1 = petCastSpell.Cast.Misc[1];
spell.m_targets = targets;
SpellCastResult result = spell.CheckPetCast(null);
if (result == SpellCastResult.SpellCastOk)
{
Creature creature = caster.ToCreature();
if (creature)
{
Pet pet = creature.ToPet();
if (pet)
{
// 10% chance to play special pet attack talk, else growl
// actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
if (pet.getPetType() == PetType.Summon && (RandomHelper.IRand(0, 100) < 10))
pet.SendPetTalk(PetTalk.SpecialSpell);
else
pet.SendPetAIReaction(petCastSpell.PetGUID);
}
}
SpellPrepare spellPrepare = new SpellPrepare();
spellPrepare.ClientCastID = petCastSpell.Cast.CastID;
spellPrepare.ServerCastID = spell.m_castId;
SendPacket(spellPrepare);
spell.prepare(targets);
}
else
{
spell.SendPetCastResult(result);
if (!caster.GetSpellHistory().HasCooldown(spellInfo.Id))
caster.GetSpellHistory().ResetCooldown(spellInfo.Id, true);
spell.finish(false);
spell.Dispose();
}
}
void SendPetNameInvalid(PetNameInvalidReason error, string name, DeclinedName declinedName)
{
PetNameInvalid petNameInvalid = new PetNameInvalid();
petNameInvalid.Result = error;
petNameInvalid.RenameData.NewName = name;
for (int i = 0; i < SharedConst.MaxDeclinedNameCases; i++)
petNameInvalid.RenameData.DeclinedNames.name[i] = declinedName.name[i];
SendPacket(petNameInvalid);
}
}
}
+535
View File
@@ -0,0 +1,535 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Framework.Database;
using Game.Entities;
using Game.Guilds;
using Game.Network;
using Game.Network.Packets;
using System.Collections.Generic;
using System.Text;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.PetitionBuy)]
void HandlePetitionBuy(PetitionBuy packet)
{
// prevent cheating
Creature creature = GetPlayer().GetNPCIfCanInteractWith(packet.Unit, NPCFlags.Petitioner);
if (!creature)
{
Log.outDebug(LogFilter.Network, "WORLD: HandlePetitionBuyOpcode - {0} not found or you can't interact with him.", packet.Unit.ToString());
return;
}
// remove fake death
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
uint charterItemID = GuildConst.CharterItemId;
int cost = WorldConfig.GetIntValue(WorldCfg.CharterCostGuild);
// do not let if already in guild.
if (GetPlayer().GetGuildId() != 0)
return;
if (Global.GuildMgr.GetGuildByName(packet.Title))
{
Guild.SendCommandResult(this, GuildCommandType.CreateGuild, GuildCommandError.NameExists_S, packet.Title);
return;
}
if (Global.ObjectMgr.IsReservedName(packet.Title) || !ObjectManager.IsValidCharterName(packet.Title))
{
Guild.SendCommandResult(this, GuildCommandType.CreateGuild, GuildCommandError.NameInvalid, packet.Title);
return;
}
ItemTemplate pProto = Global.ObjectMgr.GetItemTemplate(charterItemID);
if (pProto == null)
{
GetPlayer().SendBuyError(BuyResult.CantFindItem, null, charterItemID);
return;
}
if (!GetPlayer().HasEnoughMoney(cost))
{ //player hasn't got enough money
GetPlayer().SendBuyError(BuyResult.NotEnoughtMoney, creature, charterItemID);
return;
}
List<ItemPosCount> dest = new List<ItemPosCount>();
InventoryResult msg = GetPlayer().CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, charterItemID, pProto.GetBuyCount());
if (msg != InventoryResult.Ok)
{
GetPlayer().SendEquipError(msg, null, null, charterItemID);
return;
}
GetPlayer().ModifyMoney(-cost);
Item charter = GetPlayer().StoreNewItem(dest, charterItemID, true);
if (!charter)
return;
charter.SetUInt32Value(ItemFields.Enchantment, (uint)charter.GetGUID().GetCounter());
// ITEM_FIELD_ENCHANTMENT_1_1 is guild/arenateam id
// ITEM_FIELD_ENCHANTMENT_1_1+1 is current signatures count (showed on item)
charter.SetState(ItemUpdateState.Changed, GetPlayer());
GetPlayer().SendNewItem(charter, 1, true, false);
// a petition is invalid, if both the owner and the type matches
// we checked above, if this player is in an arenateam, so this must be
// datacorruption
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PETITION_BY_OWNER);
stmt.AddValue(0, GetPlayer().GetGUID().GetCounter());
SQLResult result = DB.Characters.Query(stmt);
StringBuilder ssInvalidPetitionGUIDs = new StringBuilder();
if (!result.IsEmpty())
{
do
{
ssInvalidPetitionGUIDs.AppendFormat("'{0}', ", result.Read<uint>(0));
} while (result.NextRow());
}
// delete petitions with the same guid as this one
ssInvalidPetitionGUIDs.AppendFormat("'{0}'", charter.GetGUID().GetCounter());
Log.outDebug(LogFilter.Network, "Invalid petition GUIDs: {0}", ssInvalidPetitionGUIDs.ToString());
SQLTransaction trans = new SQLTransaction();
trans.Append("DELETE FROM petition WHERE petitionguid IN ({0})", ssInvalidPetitionGUIDs.ToString());
trans.Append("DELETE FROM petition_sign WHERE petitionguid IN ({0})", ssInvalidPetitionGUIDs.ToString());
stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_PETITION);
stmt.AddValue(0, GetPlayer().GetGUID().GetCounter());
stmt.AddValue(1, charter.GetGUID().GetCounter());
stmt.AddValue(2, packet.Title);
trans.Append(stmt);
DB.Characters.CommitTransaction(trans);
}
[WorldPacketHandler(ClientOpcodes.PetitionShowSignatures)]
void HandlePetitionShowSignatures(PetitionShowSignatures packet)
{
Log.outDebug(LogFilter.Network, "Received opcode CMSG_PETITION_SHOW_SIGNATURES");
byte signs = 0;
// if has guild => error, return;
if (GetPlayer().GetGuildId() != 0)
return;
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PETITION_SIGNATURE);
stmt.AddValue(0, packet.Item.GetCounter());
SQLResult result = DB.Characters.Query(stmt);
// result == NULL also correct in case no sign yet
if (!result.IsEmpty())
signs = (byte)result.GetRowCount();
ServerPetitionShowSignatures signaturesPacket = new ServerPetitionShowSignatures();
signaturesPacket.Item = packet.Item;
signaturesPacket.Owner = GetPlayer().GetGUID();
signaturesPacket.OwnerAccountID = ObjectGuid.Create(HighGuid.WowAccount, ObjectManager.GetPlayerAccountIdByGUID(GetPlayer().GetGUID()));
signaturesPacket.PetitionID = (int)packet.Item.GetCounter(); // @todo verify that...
for (byte i = 1; i <= signs; ++i)
{
ObjectGuid signerGUID = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(0));
ServerPetitionShowSignatures.PetitionSignature signature = new ServerPetitionShowSignatures.PetitionSignature();
signature.Signer = signerGUID;
signature.Choice = 0;
signaturesPacket.Signatures.Add(signature);
result.NextRow();
}
SendPacket(signaturesPacket);
}
[WorldPacketHandler(ClientOpcodes.QueryPetition)]
void HandleQueryPetition(QueryPetition packet)
{
SendPetitionQuery(packet.ItemGUID);
}
public void SendPetitionQuery(ObjectGuid petitionGUID)
{
ObjectGuid ownerGUID = ObjectGuid.Empty;
string title = "NO_NAME_FOR_GUID";
QueryPetitionResponse responsePacket = new QueryPetitionResponse();
responsePacket.PetitionID = (uint)petitionGUID.GetCounter(); // PetitionID (in Trinity always same as GUID_LOPART(petition guid))
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PETITION);
stmt.AddValue(0, petitionGUID.GetCounter());
SQLResult result = DB.Characters.Query(stmt);
if (!result.IsEmpty())
{
ownerGUID = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(0));
title = result.Read<string>(1);
}
else
{
Log.outDebug(LogFilter.Network, "CMSG_PETITION_Select failed for petition ({0})", petitionGUID.ToString());
return;
}
int reqSignatures = WorldConfig.GetIntValue(WorldCfg.MinPetitionSigns);
PetitionInfo petitionInfo = new PetitionInfo();
petitionInfo.PetitionID = (int)petitionGUID.GetCounter();
petitionInfo.Petitioner = ownerGUID;
petitionInfo.MinSignatures = reqSignatures;
petitionInfo.MaxSignatures = reqSignatures;
petitionInfo.Title = title;
responsePacket.Allow = true;
responsePacket.Info = petitionInfo;
SendPacket(responsePacket);
}
[WorldPacketHandler(ClientOpcodes.PetitionRenameGuild)]
void HandlePetitionRenameGuild(PetitionRenameGuild packet)
{
Item item = GetPlayer().GetItemByGuid(packet.PetitionGuid);
if (!item)
return;
if (Global.GuildMgr.GetGuildByName(packet.NewGuildName))
{
Guild.SendCommandResult(this, GuildCommandType.CreateGuild, GuildCommandError.NameExists_S, packet.NewGuildName);
return;
}
if (Global.ObjectMgr.IsReservedName(packet.NewGuildName) || !ObjectManager.IsValidCharterName(packet.NewGuildName))
{
Guild.SendCommandResult(this, GuildCommandType.CreateGuild, GuildCommandError.NameInvalid, packet.NewGuildName);
return;
}
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_PETITION_NAME);
stmt.AddValue(0, packet.NewGuildName);
stmt.AddValue(1, packet.PetitionGuid.GetCounter());
DB.Characters.Execute(stmt);
PetitionRenameGuildResponse renameResponse = new PetitionRenameGuildResponse();
renameResponse.PetitionGuid = packet.PetitionGuid;
renameResponse.NewGuildName = packet.NewGuildName;
SendPacket(renameResponse);
}
[WorldPacketHandler(ClientOpcodes.SignPetition)]
void HandleSignPetition(SignPetition packet)
{
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PETITION_SIGNATURES);
stmt.AddValue(0, packet.PetitionGUID.GetCounter());
stmt.AddValue(1, packet.PetitionGUID.GetCounter());
SQLResult result = DB.Characters.Query(stmt);
if (result.IsEmpty())
{
Log.outError(LogFilter.Network, "Petition {0} is not found for player {1} {2}", packet.PetitionGUID.ToString(), GetPlayer().GetGUID().ToString(), GetPlayer().GetName());
return;
}
ObjectGuid ownerGuid = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(0));
ulong signs = result.Read<ulong>(1);
if (ownerGuid == GetPlayer().GetGUID())
return;
// not let enemies sign guild charter
if (!WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionGuild) && GetPlayer().GetTeam() != ObjectManager.GetPlayerTeamByGUID(ownerGuid))
{
Guild.SendCommandResult(this, GuildCommandType.CreateGuild, GuildCommandError.NotAllied);
return;
}
if (GetPlayer().GetGuildId() != 0)
{
Guild.SendCommandResult(this, GuildCommandType.InvitePlayer, GuildCommandError.AlreadyInGuild_S, GetPlayer().GetName());
return;
}
if (GetPlayer().GetGuildIdInvited() != 0)
{
Guild.SendCommandResult(this, GuildCommandType.InvitePlayer, GuildCommandError.AlreadyInvitedToGuild_S, GetPlayer().GetName());
return;
}
// Client doesn't allow to sign petition two times by one character, but not check sign by another character from same account
// not allow sign another player from already sign player account
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PETITION_SIG_BY_ACCOUNT);
stmt.AddValue(0, GetAccountId());
stmt.AddValue(1, packet.PetitionGUID.GetCounter());
result = DB.Characters.Query(stmt);
PetitionSignResults signResult = new PetitionSignResults();
signResult.Player = GetPlayer().GetGUID();
signResult.Item = packet.PetitionGUID;
if (!result.IsEmpty())
{
signResult.Error = PetitionSigns.AlreadySigned;
// close at signer side
SendPacket(signResult);
return;
}
stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_PETITION_SIGNATURE);
stmt.AddValue(0, ownerGuid.GetCounter());
stmt.AddValue(1, packet.PetitionGUID.GetCounter());
stmt.AddValue(2, GetPlayer().GetGUID().GetCounter());
stmt.AddValue(3, GetAccountId());
DB.Characters.Execute(stmt);
Log.outDebug(LogFilter.Network, "PETITION SIGN: {0} by player: {1} ({2} Account: {3})", packet.PetitionGUID.ToString(), GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), GetAccountId());
signResult.Error = PetitionSigns.Ok;
// close at signer side
SendPacket(signResult);
// update for owner if online
Player owner = Global.ObjAccessor.FindPlayer(ownerGuid);
if (owner)
owner.SendPacket(signResult);
}
[WorldPacketHandler(ClientOpcodes.DeclinePetition)]
void HandleDeclinePetition(DeclinePetition packet)
{
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PETITION_OWNER_BY_GUID);
stmt.AddValue(0, packet.PetitionGUID.GetCounter());
SQLResult result = DB.Characters.Query(stmt);
if (result.IsEmpty())
return;
ObjectGuid ownerguid = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(0));
Player owner = Global.ObjAccessor.FindPlayer(ownerguid);
if (owner) // petition owner online
{
// Disabled because packet isn't handled by the client in any way
/*
WorldPacket data = new WorldPacket(ServerOpcodes.PetitionDecline);
data.WritePackedGuid(GetPlayer().GetGUID());
owner.SendPacket(data);
*/
}
}
[WorldPacketHandler(ClientOpcodes.OfferPetition)]
void HandleOfferPetition(OfferPetition packet)
{
Player player = Global.ObjAccessor.FindConnectedPlayer(packet.TargetPlayer);
if (!player)
return;
if (!WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionGuild) && GetPlayer().GetTeam() != player.GetTeam())
{
Guild.SendCommandResult(this, GuildCommandType.CreateGuild, GuildCommandError.NotAllied);
return;
}
if (player.GetGuildId() != 0)
{
Guild.SendCommandResult(this, GuildCommandType.InvitePlayer, GuildCommandError.AlreadyInGuild_S, GetPlayer().GetName());
return;
}
if (player.GetGuildIdInvited() != 0)
{
Guild.SendCommandResult(this, GuildCommandType.InvitePlayer, GuildCommandError.AlreadyInvitedToGuild_S, GetPlayer().GetName());
return;
}
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PETITION_SIGNATURE);
stmt.AddValue(0, packet.ItemGUID.GetCounter());
SQLResult result = DB.Characters.Query(stmt);
byte signs = 0;
// result == NULL also correct charter without signs
if (!result.IsEmpty())
signs = (byte)result.GetRowCount();
ServerPetitionShowSignatures signaturesPacket = new ServerPetitionShowSignatures();
signaturesPacket.Item = packet.ItemGUID;
signaturesPacket.Owner = GetPlayer().GetGUID();
signaturesPacket.OwnerAccountID = ObjectGuid.Create(HighGuid.WowAccount, player.GetSession().GetAccountId());
signaturesPacket.PetitionID = (int)packet.ItemGUID.GetCounter(); // @todo verify that...
for (byte i = 1; i <= signs; ++i)
{
ObjectGuid signerGUID = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(0));
ServerPetitionShowSignatures.PetitionSignature signature = new ServerPetitionShowSignatures.PetitionSignature();
signature.Signer = signerGUID;
signature.Choice = 0;
signaturesPacket.Signatures.Add(signature);
result.NextRow();
}
player.SendPacket(signaturesPacket);
}
[WorldPacketHandler(ClientOpcodes.TurnInPetition)]
void HandleTurnInPetition(TurnInPetition packet)
{
// Check if player really has the required petition charter
Item item = GetPlayer().GetItemByGuid(packet.Item);
if (!item)
return;
// Get petition data from db
ObjectGuid ownerguid;
string name;
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PETITION);
stmt.AddValue(0, packet.Item.GetCounter());
SQLResult result = DB.Characters.Query(stmt);
if (!result.IsEmpty())
{
ownerguid = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(0));
name = result.Read<string>(1);
}
else
{
Log.outError(LogFilter.Network, "Player {0} ({1}) tried to turn in petition ({2}) that is not present in the database", GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), packet.Item.ToString());
return;
}
// Only the petition owner can turn in the petition
if (GetPlayer().GetGUID() != ownerguid)
return;
TurnInPetitionResult resultPacket = new TurnInPetitionResult();
// Check if player is already in a guild
if (GetPlayer().GetGuildId() != 0)
{
resultPacket.Result = PetitionTurns.AlreadyInGuild;
GetPlayer().SendPacket(resultPacket);
return;
}
// Check if guild name is already taken
if (Global.GuildMgr.GetGuildByName(name))
{
Guild.SendCommandResult(this, GuildCommandType.CreateGuild, GuildCommandError.NameExists_S, name);
return;
}
// Get petition signatures from db
byte signatures;
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PETITION_SIGNATURE);
stmt.AddValue(0, packet.Item.GetCounter());
result = DB.Characters.Query(stmt);
if (!result.IsEmpty())
signatures = (byte)result.GetRowCount();
else
signatures = 0;
uint requiredSignatures = WorldConfig.GetUIntValue(WorldCfg.MinPetitionSigns);
// Notify player if signatures are missing
if (signatures < requiredSignatures)
{
resultPacket.Result = PetitionTurns.NeedMoreSignatures;
SendPacket(resultPacket);
return;
}
// Proceed with guild/arena team creation
// Delete charter item
GetPlayer().DestroyItem(item.GetBagSlot(), item.GetSlot(), true);
// Create guild
Guild guild = new Guild();
if (!guild.Create(GetPlayer(), name))
return;
// Register guild and add guild master
Global.GuildMgr.AddGuild(guild);
Guild.SendCommandResult(this, GuildCommandType.CreateGuild, GuildCommandError.Success, name);
// Add members from signatures
for (byte i = 0; i < signatures; ++i)
{
guild.AddMember(ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(0)));
result.NextRow();
}
SQLTransaction trans = new SQLTransaction();
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_PETITION_BY_GUID);
stmt.AddValue(0, packet.Item.GetCounter());
trans.Append(stmt);
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_PETITION_SIGNATURE_BY_GUID);
stmt.AddValue(0, packet.Item.GetCounter());
trans.Append(stmt);
DB.Characters.CommitTransaction(trans);
// created
Log.outDebug(LogFilter.Network, "Player {0} ({1}) turning in petition {2}", GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), packet.Item.ToString());
resultPacket.Result = PetitionTurns.Ok;
SendPacket(resultPacket);
}
[WorldPacketHandler(ClientOpcodes.PetitionShowList)]
void HandlePetitionShowList(PetitionShowList packet)
{
SendPetitionShowList(packet.PetitionUnit);
}
public void SendPetitionShowList(ObjectGuid guid)
{
Creature creature = GetPlayer().GetNPCIfCanInteractWith(guid, NPCFlags.Petitioner);
if (!creature)
{
Log.outDebug(LogFilter.Network, "WORLD: HandlePetitionShowListOpcode - {0} not found or you can't interact with him.", guid.ToString());
return;
}
WorldPacket data = new WorldPacket(ServerOpcodes.PetitionShowList);
data.WritePackedGuid(guid); // npc guid
ServerPetitionShowList packet = new ServerPetitionShowList();
packet.Unit = guid;
packet.Price = WorldConfig.GetUIntValue(WorldCfg.CharterCostGuild);
SendPacket(packet);
}
}
}
+447
View File
@@ -0,0 +1,447 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Framework.GameMath;
using Game.DataStorage;
using Game.Entities;
using Game.Maps;
using Game.Misc;
using Game.Network;
using Game.Network.Packets;
using System.Collections.Generic;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.QueryPlayerName)]
void HandleNameQueryRequest(QueryPlayerName queryPlayerName)
{
SendNameQuery(queryPlayerName.Player);
}
public void SendNameQuery(ObjectGuid guid)
{
Player player = Global.ObjAccessor.FindPlayer(guid);
QueryPlayerNameResponse response = new QueryPlayerNameResponse();
response.Player = guid;
if (response.Data.Initialize(guid, player))
response.Result = ResponseCodes.Success;
else
response.Result = ResponseCodes.Failure; // name unknown
SendPacket(response);
}
[WorldPacketHandler(ClientOpcodes.QueryTime)]
void HandleQueryTime(QueryTime packet)
{
SendQueryTimeResponse();
}
void SendQueryTimeResponse()
{
QueryTimeResponse queryTimeResponse = new QueryTimeResponse();
queryTimeResponse.CurrentTime = Time.UnixTime;
SendPacket(queryTimeResponse);
}
[WorldPacketHandler(ClientOpcodes.QueryGameObject, Processing = PacketProcessing.Inplace)]
void HandleGameObjectQuery(QueryGameObject packet)
{
QueryGameObjectResponse response = new QueryGameObjectResponse();
response.GameObjectID = packet.GameObjectID;
GameObjectTemplate gameObjectInfo = Global.ObjectMgr.GetGameObjectTemplate(packet.GameObjectID);
if (gameObjectInfo != null)
{
response.Allow = true;
GameObjectStats stats = new GameObjectStats();
stats.Type = (uint)gameObjectInfo.type;
stats.DisplayID = gameObjectInfo.displayId;
stats.Name[0] = gameObjectInfo.name;
stats.IconName = gameObjectInfo.IconName;
stats.CastBarCaption = gameObjectInfo.castBarCaption;
stats.UnkString = gameObjectInfo.unk1;
LocaleConstant localeConstant = GetSessionDbLocaleIndex();
if (localeConstant != LocaleConstant.enUS)
{
GameObjectLocale gameObjectLocale = Global.ObjectMgr.GetGameObjectLocale(packet.GameObjectID);
if (gameObjectLocale != null)
{
ObjectManager.GetLocaleString(gameObjectLocale.Name, localeConstant, ref stats.Name[0]);
ObjectManager.GetLocaleString(gameObjectLocale.CastBarCaption, localeConstant, ref stats.CastBarCaption);
ObjectManager.GetLocaleString(gameObjectLocale.Unk1, localeConstant, ref stats.UnkString);
}
}
var items = Global.ObjectMgr.GetGameObjectQuestItemList(packet.GameObjectID);
foreach (int item in items)
stats.QuestItems.Add(item);
unsafe
{
fixed (int* ptr = gameObjectInfo.Raw.data)
{
for (int i = 0; i < SharedConst.MaxGOData; i++)
stats.Data[i] = ptr[i];
}
}
stats.RequiredLevel = (uint)gameObjectInfo.RequiredLevel;
response.Stats = stats;
}
SendPacket(response);
}
[WorldPacketHandler(ClientOpcodes.QueryCreature, Processing = PacketProcessing.Inplace)]
void HandleCreatureQuery(QueryCreature packet)
{
QueryCreatureResponse response = new QueryCreatureResponse();
response.CreatureID = packet.CreatureID;
CreatureTemplate creatureInfo = Global.ObjectMgr.GetCreatureTemplate(packet.CreatureID);
if (creatureInfo != null)
{
response.Allow = true;
CreatureStats stats = new CreatureStats();
stats.Leader = creatureInfo.RacialLeader;
string name = creatureInfo.Name;
string nameAlt = creatureInfo.FemaleName;
stats.Flags[0] = (uint)creatureInfo.TypeFlags;
stats.Flags[1] = creatureInfo.TypeFlags2;
stats.CreatureType = (int)creatureInfo.CreatureType;
stats.CreatureFamily = (int)creatureInfo.Family;
stats.Classification = (int)creatureInfo.Rank;
for (uint i = 0; i < SharedConst.MaxCreatureKillCredit; ++i)
stats.ProxyCreatureID[i] = creatureInfo.KillCredit[i];
stats.CreatureDisplayID[0] = creatureInfo.ModelId1;
stats.CreatureDisplayID[1] = creatureInfo.ModelId2;
stats.CreatureDisplayID[2] = creatureInfo.ModelId3;
stats.CreatureDisplayID[3] = creatureInfo.ModelId4;
stats.HpMulti = creatureInfo.ModHealth;
stats.EnergyMulti = creatureInfo.ModMana;
stats.CreatureMovementInfoID = creatureInfo.MovementId;
stats.RequiredExpansion = creatureInfo.RequiredExpansion;
stats.HealthScalingExpansion = creatureInfo.HealthScalingExpansion;
stats.VignetteID = creatureInfo.VignetteID;
stats.Title = creatureInfo.SubName;
//stats.TitleAlt = ;
stats.CursorName = creatureInfo.IconName;
var items = Global.ObjectMgr.GetCreatureQuestItemList(packet.CreatureID);
foreach (uint item in items)
stats.QuestItems.Add(item);
LocaleConstant localeConstant = GetSessionDbLocaleIndex();
if (localeConstant != LocaleConstant.enUS)
{
CreatureLocale creatureLocale = Global.ObjectMgr.GetCreatureLocale(packet.CreatureID);
if (creatureLocale != null)
{
ObjectManager.GetLocaleString(creatureLocale.Name, localeConstant, ref name);
ObjectManager.GetLocaleString(creatureLocale.NameAlt, localeConstant, ref nameAlt);
ObjectManager.GetLocaleString(creatureLocale.Title, localeConstant, ref stats.Title);
ObjectManager.GetLocaleString(creatureLocale.TitleAlt, localeConstant, ref stats.TitleAlt);
}
}
stats.Name[0] = name;
stats.NameAlt[0] = nameAlt;
response.Stats = stats;
}
SendPacket(response);
}
[WorldPacketHandler(ClientOpcodes.QueryNpcText)]
void HandleNpcTextQuery(QueryNPCText packet)
{
NpcText npcText = Global.ObjectMgr.GetNpcText(packet.TextID);
QueryNPCTextResponse response = new QueryNPCTextResponse();
response.TextID = packet.TextID;
if (npcText != null)
{
for (byte i = 0; i < SharedConst.MaxNpcTextOptions; ++i)
{
response.Probabilities[i] = npcText.Data[i].Probability;
response.BroadcastTextID[i] = npcText.Data[i].BroadcastTextID;
if (!response.Allow && npcText.Data[i].BroadcastTextID != 0)
response.Allow = true;
}
}
if (!response.Allow)
Log.outError(LogFilter.Sql, "HandleNpcTextQuery: no BroadcastTextID found for text {0} in `npc_text table`", packet.TextID);
SendPacket(response);
}
[WorldPacketHandler(ClientOpcodes.QueryPageText)]
void HandleQueryPageText(QueryPageText packet)
{
QueryPageTextResponse response = new QueryPageTextResponse();
response.PageTextID = packet.PageTextID;
uint pageID = packet.PageTextID;
while (pageID != 0)
{
PageText pageText = Global.ObjectMgr.GetPageText(pageID);
if (pageText == null)
break;
QueryPageTextResponse.PageTextInfo page;
page.ID = pageID;
page.NextPageID = pageText.NextPageID;
page.Text = pageText.Text;
page.PlayerConditionID = pageText.PlayerConditionID;
page.Flags = pageText.Flags;
LocaleConstant locale = GetSessionDbLocaleIndex();
if (locale != LocaleConstant.enUS)
{
PageTextLocale pageLocale = Global.ObjectMgr.GetPageTextLocale(pageID);
if (pageLocale != null)
ObjectManager.GetLocaleString(pageLocale.Text, locale, ref page.Text);
}
response.Pages.Add(page);
pageID = pageText.NextPageID;
}
response.Allow = !response.Pages.Empty();
SendPacket(response);
}
[WorldPacketHandler(ClientOpcodes.QueryCorpseLocationFromClient)]
void HandleQueryCorpseLocation(QueryCorpseLocationFromClient queryCorpseLocation)
{
CorpseLocation packet = new CorpseLocation();
Player player = Global.ObjAccessor.FindConnectedPlayer(queryCorpseLocation.Player);
if (!player || !player.HasCorpse() || !_player.IsInSameRaidWith(player))
{
packet.Valid = false; // corpse not found
packet.Player = queryCorpseLocation.Player;
SendPacket(packet);
return;
}
WorldLocation corpseLocation = player.GetCorpseLocation();
uint corpseMapID = corpseLocation.GetMapId();
uint mapID = corpseLocation.GetMapId();
float x = corpseLocation.GetPositionX();
float y = corpseLocation.GetPositionY();
float z = corpseLocation.GetPositionZ();
// if corpse at different map
if (mapID != player.GetMapId())
{
// search entrance map for proper show entrance
MapRecord corpseMapEntry = CliDB.MapStorage.LookupByKey(mapID);
if (corpseMapEntry != null)
{
if (corpseMapEntry.IsDungeon() && corpseMapEntry.CorpseMapID >= 0)
{
// if corpse map have entrance
Map entranceMap = Global.MapMgr.CreateBaseMap((uint)corpseMapEntry.CorpseMapID);
if (entranceMap != null)
{
mapID = (uint)corpseMapEntry.CorpseMapID;
x = corpseMapEntry.CorpsePos.X;
y = corpseMapEntry.CorpsePos.Y;
z = entranceMap.GetHeight(player.GetPhases(), x, y, MapConst.MaxHeight);
}
}
}
}
packet.Valid = true;
packet.Player = queryCorpseLocation.Player;
packet.MapID = (int)corpseMapID;
packet.ActualMapID = (int)mapID;
packet.Position = new Vector3(x, y, z);
packet.Transport = ObjectGuid.Empty;
SendPacket(packet);
}
[WorldPacketHandler(ClientOpcodes.QueryCorpseTransport)]
void HandleQueryCorpseTransport(QueryCorpseTransport queryCorpseTransport)
{
CorpseTransportQuery response = new CorpseTransportQuery();
response.Player = queryCorpseTransport.Player;
Player player = Global.ObjAccessor.FindConnectedPlayer(queryCorpseTransport.Player);
if (player)
{
Corpse corpse = player.GetCorpse();
if (_player.IsInSameRaidWith(player) && corpse && !corpse.GetTransGUID().IsEmpty() && corpse.GetTransGUID() == queryCorpseTransport.Transport)
{
response.Position = new Vector3(corpse.GetTransOffsetX(), corpse.GetTransOffsetY(), corpse.GetTransOffsetZ());
response.Facing = corpse.GetTransOffsetO();
}
}
SendPacket(response);
}
[WorldPacketHandler(ClientOpcodes.QueryQuestCompletionNpcs)]
void HandleQueryQuestCompletionNPCs(QueryQuestCompletionNPCs queryQuestCompletionNPCs)
{
QuestCompletionNPCResponse response = new QuestCompletionNPCResponse();
foreach (var questID in queryQuestCompletionNPCs.QuestCompletionNPCs)
{
QuestCompletionNPC questCompletionNPC = new QuestCompletionNPC();
if (Global.ObjectMgr.GetQuestTemplate(questID) == null)
{
Log.outDebug(LogFilter.Network, "WORLD: Unknown quest {0} in CMSG_QUEST_NPC_QUERY by {1}", questID, GetPlayer().GetGUID());
continue;
}
questCompletionNPC.QuestID = questID;
var creatures = Global.ObjectMgr.GetCreatureQuestInvolvedRelationReverseBounds(questID);
foreach (var id in creatures)
questCompletionNPC.NPCs.Add(id);
var gos = Global.ObjectMgr.GetGOQuestInvolvedRelationReverseBounds(questID);
foreach (var id in gos)
questCompletionNPC.NPCs.Add(id | 0x80000000); // GO mask
response.QuestCompletionNPCs.Add(questCompletionNPC);
}
SendPacket(response);
}
[WorldPacketHandler(ClientOpcodes.QuestPoiQuery)]
void HandleQuestPOIQuery(QuestPOIQuery packet)
{
if (packet.MissingQuestCount >= SharedConst.MaxQuestLogSize)
return;
// Read quest ids and add the in a unordered_set so we don't send POIs for the same quest multiple times
HashSet<uint> questIds = new HashSet<uint>();
for (int i = 0; i < packet.MissingQuestCount; ++i)
questIds.Add(packet.MissingQuestPOIs[i]); // QuestID
QuestPOIQueryResponse response = new QuestPOIQueryResponse();
foreach (var QuestID in questIds)
{
bool questOk = false;
ushort questSlot = GetPlayer().FindQuestSlot(QuestID);
if (questSlot != SharedConst.MaxQuestLogSize)
questOk = GetPlayer().GetQuestSlotQuestId(questSlot) == QuestID;
if (questOk)
{
var poiData = Global.ObjectMgr.GetQuestPOIList(QuestID);
if (poiData != null)
{
QuestPOIData questPOIData = new QuestPOIData();
questPOIData.QuestID = QuestID;
foreach (var data in poiData)
{
QuestPOIBlobData questPOIBlobData = new QuestPOIBlobData();
questPOIBlobData.BlobIndex = data.BlobIndex;
questPOIBlobData.ObjectiveIndex = data.ObjectiveIndex;
questPOIBlobData.QuestObjectiveID = data.QuestObjectiveID;
questPOIBlobData.QuestObjectID = data.QuestObjectID;
questPOIBlobData.MapID = data.MapID;
questPOIBlobData.WorldMapAreaID = data.WorldMapAreaID;
questPOIBlobData.Floor = data.Floor;
questPOIBlobData.Priority = data.Priority;
questPOIBlobData.Flags = data.Flags;
questPOIBlobData.WorldEffectID = data.WorldEffectID;
questPOIBlobData.PlayerConditionID = data.PlayerConditionID;
questPOIBlobData.UnkWoD1 = data.UnkWoD1;
foreach (var point in data.points)
questPOIBlobData.QuestPOIBlobPointStats.Add(new QuestPOIBlobPoint(point.X, point.Y));
questPOIData.QuestPOIBlobDataStats.Add(questPOIBlobData);
}
response.QuestPOIDataStats.Add(questPOIData);
}
}
}
SendPacket(response);
}
[WorldPacketHandler(ClientOpcodes.ItemTextQuery)]
void HandleItemTextQuery(ItemTextQuery packet)
{
QueryItemTextResponse queryItemTextResponse = new QueryItemTextResponse();
queryItemTextResponse.Id = packet.Id;
Item item = GetPlayer().GetItemByGuid(packet.Id);
if (item)
{
queryItemTextResponse.Valid = true;
queryItemTextResponse.Text = item.GetText();
}
SendPacket(queryItemTextResponse);
}
[WorldPacketHandler(ClientOpcodes.QueryRealmName)]
void HandleQueryRealmName(QueryRealmName queryRealmName)
{
RealmQueryResponse realmQueryResponse = new RealmQueryResponse();
realmQueryResponse.VirtualRealmAddress = queryRealmName.VirtualRealmAddress;
RealmHandle realmHandle = new RealmHandle(queryRealmName.VirtualRealmAddress);
if (Global.ObjectMgr.GetRealmName(realmHandle.Realm, ref realmQueryResponse.NameInfo.RealmNameActual, ref realmQueryResponse.NameInfo.RealmNameNormalized))
{
realmQueryResponse.LookupState = (byte)ResponseCodes.Success;
realmQueryResponse.NameInfo.IsInternalRealm = false;
realmQueryResponse.NameInfo.IsLocal = queryRealmName.VirtualRealmAddress == Global.WorldMgr.GetRealm().Id.GetAddress();
}
else
realmQueryResponse.LookupState = (byte)ResponseCodes.Failure;
}
}
}
+647
View File
@@ -0,0 +1,647 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.BattleGrounds;
using Game.Entities;
using Game.Groups;
using Game.Network;
using Game.Network.Packets;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.QuestGiverStatusQuery, Processing = PacketProcessing.Inplace)]
void HandleQuestgiverStatusQuery(QuestGiverStatusQuery packet)
{
QuestGiverStatus questStatus = QuestGiverStatus.None;
var questgiver = Global.ObjAccessor.GetObjectByTypeMask(GetPlayer(), packet.QuestGiverGUID, TypeMask.Unit | TypeMask.GameObject);
if (!questgiver)
{
Log.outInfo(LogFilter.Network, "Error in CMSG_QUESTGIVER_STATUS_QUERY, called for non-existing questgiver {0}", packet.QuestGiverGUID.ToString());
return;
}
switch (questgiver.GetTypeId())
{
case TypeId.Unit:
if (!questgiver.ToCreature().IsHostileTo(GetPlayer()))// do not show quest status to enemies
questStatus = GetPlayer().GetQuestDialogStatus(questgiver);
break;
case TypeId.GameObject:
questStatus = GetPlayer().GetQuestDialogStatus(questgiver);
break;
default:
Log.outError(LogFilter.Network, "QuestGiver called for unexpected type {0}", questgiver.GetTypeId());
break;
}
//inform client about status of quest
GetPlayer().PlayerTalkClass.SendQuestGiverStatus(questStatus, packet.QuestGiverGUID);
}
[WorldPacketHandler(ClientOpcodes.QuestGiverHello)]
void HandleQuestgiverHello(QuestGiverHello packet)
{
Creature creature = GetPlayer().GetNPCIfCanInteractWith(packet.QuestGiverGUID, NPCFlags.QuestGiver);
if (creature == null)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleQuestgiverHello - {0} not found or you can't interact with him.", packet.QuestGiverGUID.ToString());
return;
}
// remove fake death
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
// Stop the npc if moving
creature.StopMoving();
if (Global.ScriptMgr.OnGossipHello(GetPlayer(), creature))
return;
GetPlayer().PrepareGossipMenu(creature, creature.GetCreatureTemplate().GossipMenuId, true);
GetPlayer().SendPreparedGossip(creature);
creature.GetAI().sGossipHello(GetPlayer());
}
[WorldPacketHandler(ClientOpcodes.QuestGiverAcceptQuest)]
void HandleQuestgiverAcceptQuest(QuestGiverAcceptQuest packet)
{
WorldObject obj;
if (!packet.QuestGiverGUID.IsPlayer())
obj = Global.ObjAccessor.GetObjectByTypeMask(_player, packet.QuestGiverGUID, TypeMask.Unit | TypeMask.GameObject | TypeMask.Item);
else
obj = Global.ObjAccessor.FindPlayer(packet.QuestGiverGUID);
var CLOSE_GOSSIP_CLEAR_DIVIDER = new System.Action(() =>
{
GetPlayer().PlayerTalkClass.SendCloseGossip();
GetPlayer().SetDivider(ObjectGuid.Empty);
});
// no or incorrect quest giver
if (obj == null)
{
CLOSE_GOSSIP_CLEAR_DIVIDER();
return;
}
Player playerQuestObject = obj.ToPlayer();
if (playerQuestObject)
{
if ((_player.GetDivider().IsEmpty() && _player.GetDivider() != packet.QuestGiverGUID) || !playerQuestObject.CanShareQuest(packet.QuestID))
{
CLOSE_GOSSIP_CLEAR_DIVIDER();
return;
}
if (!_player.IsInSameRaidWith(playerQuestObject))
{
CLOSE_GOSSIP_CLEAR_DIVIDER();
return;
}
}
else
{
if (!obj.hasQuest(packet.QuestID))
{
CLOSE_GOSSIP_CLEAR_DIVIDER();
return;
}
}
// some kind of WPE protection
if (!_player.CanInteractWithQuestGiver(obj))
{
CLOSE_GOSSIP_CLEAR_DIVIDER();
return;
}
Quest quest = Global.ObjectMgr.GetQuestTemplate(packet.QuestID);
if (quest != null)
{
// prevent cheating
if (!GetPlayer().CanTakeQuest(quest, true))
{
CLOSE_GOSSIP_CLEAR_DIVIDER();
return;
}
if (!_player.GetDivider().IsEmpty())
{
Player player = Global.ObjAccessor.FindPlayer(_player.GetDivider());
if (player != null)
{
player.SendPushToPartyResponse(_player, QuestPushReason.Accepted);
_player.SetDivider(ObjectGuid.Empty);
}
}
if (_player.CanAddQuest(quest, true))
{
_player.AddQuestAndCheckCompletion(quest, obj);
if (quest.HasFlag(QuestFlags.PartyAccept))
{
var group = _player.GetGroup();
if (group)
{
for (GroupReference refe = group.GetFirstMember(); refe != null; refe = refe.next())
{
Player player = refe.GetSource();
if (!player || player == _player) // not self
continue;
if (player.CanTakeQuest(quest, true))
{
player.SetDivider(_player.GetGUID());
//need confirmation that any gossip window will close
player.PlayerTalkClass.SendCloseGossip();
_player.SendQuestConfirmAccept(quest, player);
}
}
}
}
_player.PlayerTalkClass.SendCloseGossip();
if (quest.SourceSpellID > 0)
_player.CastSpell(_player, quest.SourceSpellID, true);
return;
}
}
CLOSE_GOSSIP_CLEAR_DIVIDER();
}
[WorldPacketHandler(ClientOpcodes.QuestGiverQueryQuest)]
void HandleQuestgiverQueryQuest(QuestGiverQueryQuest packet)
{
// Verify that the guid is valid and is a questgiver or involved in the requested quest
var obj = Global.ObjAccessor.GetObjectByTypeMask(GetPlayer(), packet.QuestGiverGUID, (TypeMask.Unit | TypeMask.GameObject | TypeMask.Item));
if (!obj || (!obj.hasQuest(packet.QuestID) && !obj.hasInvolvedQuest(packet.QuestID)))
{
GetPlayer().PlayerTalkClass.SendCloseGossip();
return;
}
Quest quest = Global.ObjectMgr.GetQuestTemplate(packet.QuestID);
if (quest != null)
{
if (!GetPlayer().CanTakeQuest(quest, true))
return;
if (quest.IsAutoAccept() && GetPlayer().CanAddQuest(quest, true))
GetPlayer().AddQuestAndCheckCompletion(quest, obj);
if (quest.IsAutoComplete())
GetPlayer().PlayerTalkClass.SendQuestGiverRequestItems(quest, obj.GetGUID(), GetPlayer().CanCompleteQuest(quest.Id), true);
else
GetPlayer().PlayerTalkClass.SendQuestGiverQuestDetails(quest, obj.GetGUID(), true);
}
}
[WorldPacketHandler(ClientOpcodes.QueryQuestInfo)]
void HandleQuestQuery(QueryQuestInfo packet)
{
Quest quest = Global.ObjectMgr.GetQuestTemplate(packet.QuestID);
if (quest != null)
_player.PlayerTalkClass.SendQuestQueryResponse(quest);
else
{
QueryQuestInfoResponse response = new QueryQuestInfoResponse();
response.QuestID = packet.QuestID;
SendPacket(response);
}
}
[WorldPacketHandler(ClientOpcodes.QuestGiverChooseReward)]
void HandleQuestgiverChooseReward(QuestGiverChooseReward packet)
{
Quest quest = Global.ObjectMgr.GetQuestTemplate(packet.QuestID);
if (quest == null)
return;
// This is Real Item Entry, not slot id as pre 5.x
if (packet.ItemChoiceID != 0)
{
ItemTemplate rewardProto = Global.ObjectMgr.GetItemTemplate(packet.ItemChoiceID);
if (rewardProto == null)
{
Log.outError(LogFilter.Network, "Error in CMSG_QUESTGIVER_CHOOSE_REWARD: player {0} ({1}) tried to get invalid reward item (Item Entry: {2}) for quest {3} (possible packet-hacking detected)", GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), packet.ItemChoiceID, packet.QuestID);
return;
}
bool itemValid = false;
for (uint i = 0; i < quest.GetRewChoiceItemsCount(); ++i)
{
if (quest.RewardChoiceItemId[i] != 0 && quest.RewardChoiceItemId[i] == packet.ItemChoiceID)
{
itemValid = true;
break;
}
}
if (!itemValid && quest.PackageID != 0)
{
var questPackageItems = Global.DB2Mgr.GetQuestPackageItems(quest.PackageID);
if (questPackageItems != null)
{
foreach (var questPackageItem in questPackageItems)
{
if (questPackageItem.ItemID != packet.ItemChoiceID)
continue;
if (_player.CanSelectQuestPackageItem(questPackageItem))
{
itemValid = true;
break;
}
}
}
if (!itemValid)
{
var questPackageItems1 = Global.DB2Mgr.GetQuestPackageItemsFallback(quest.PackageID);
if (questPackageItems1 != null)
{
foreach (var questPackageItem in questPackageItems1)
{
if (questPackageItem.ItemID != packet.ItemChoiceID)
continue;
itemValid = true;
break;
}
}
}
}
if (!itemValid)
{
Log.outError(LogFilter.Network, "Error in CMSG_QUESTGIVER_CHOOSE_REWARD: player {0} ({1}) tried to get reward item (Item Entry: {2}) wich is not a reward for quest {3} (possible packet-hacking detected)", GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), packet.ItemChoiceID, packet.QuestID);
return;
}
}
WorldObject obj = GetPlayer();
if (!quest.HasFlag(QuestFlags.AutoComplete))
{
obj = Global.ObjAccessor.GetObjectByTypeMask(GetPlayer(), packet.QuestGiverGUID, TypeMask.Unit | TypeMask.GameObject);
if (!obj || !obj.hasInvolvedQuest(packet.QuestID))
return;
// some kind of WPE protection
if (!GetPlayer().CanInteractWithQuestGiver(obj))
return;
}
if ((!GetPlayer().CanSeeStartQuest(quest) && GetPlayer().GetQuestStatus(packet.QuestID) == QuestStatus.None) ||
(GetPlayer().GetQuestStatus(packet.QuestID) != QuestStatus.Complete && !quest.IsAutoComplete()))
{
Log.outError(LogFilter.Network, "Error in QuestStatus.Complete: player {0} ({1}) tried to complete quest {2}, but is not allowed to do so (possible packet-hacking or high latency)",
GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), packet.QuestID);
return;
}
if (GetPlayer().CanRewardQuest(quest, packet.ItemChoiceID, true))
{
GetPlayer().RewardQuest(quest, packet.ItemChoiceID, obj);
switch (obj.GetTypeId())
{
case TypeId.Unit:
case TypeId.Player:
{
//For AutoSubmition was added plr case there as it almost same exclute AI script cases.
Creature creatureQGiver = obj.ToCreature();
if (!creatureQGiver || !Global.ScriptMgr.OnQuestReward(GetPlayer(), creatureQGiver, quest, packet.ItemChoiceID))
{
// Send next quest
Quest nextQuest = GetPlayer().GetNextQuest(packet.QuestGiverGUID, quest);
if (nextQuest != null)
{
// Only send the quest to the player if the conditions are met
if (GetPlayer().CanTakeQuest(nextQuest, false))
{
if (nextQuest.IsAutoAccept() && GetPlayer().CanAddQuest(nextQuest, true))
GetPlayer().AddQuestAndCheckCompletion(nextQuest, obj);
GetPlayer().PlayerTalkClass.SendQuestGiverQuestDetails(nextQuest, packet.QuestGiverGUID, true);
}
}
if (creatureQGiver)
creatureQGiver.GetAI().sQuestReward(GetPlayer(), quest, packet.ItemChoiceID);
}
break;
}
case TypeId.GameObject:
GameObject questGiver = obj.ToGameObject();
if (!Global.ScriptMgr.OnQuestReward(GetPlayer(), questGiver, quest, packet.ItemChoiceID))
{
// Send next quest
Quest nextQuest = GetPlayer().GetNextQuest(packet.QuestGiverGUID, quest);
if (nextQuest != null)
{
// Only send the quest to the player if the conditions are met
if (GetPlayer().CanTakeQuest(nextQuest, false))
{
if (nextQuest.IsAutoAccept() && GetPlayer().CanAddQuest(nextQuest, true))
GetPlayer().AddQuestAndCheckCompletion(nextQuest, obj);
GetPlayer().PlayerTalkClass.SendQuestGiverQuestDetails(nextQuest, packet.QuestGiverGUID, true);
}
}
questGiver.GetAI().QuestReward(GetPlayer(), quest, packet.ItemChoiceID);
}
break;
default:
break;
}
}
else
GetPlayer().PlayerTalkClass.SendQuestGiverOfferReward(quest, packet.QuestGiverGUID, true);
}
[WorldPacketHandler(ClientOpcodes.QuestGiverRequestReward)]
void HandleQuestgiverRequestReward(QuestGiverRequestReward packet)
{
WorldObject obj = Global.ObjAccessor.GetObjectByTypeMask(GetPlayer(), packet.QuestGiverGUID, TypeMask.Unit | TypeMask.GameObject);
if (obj == null || !obj.hasInvolvedQuest(packet.QuestID))
return;
// some kind of WPE protection
if (!GetPlayer().CanInteractWithQuestGiver(obj))
return;
if (GetPlayer().CanCompleteQuest(packet.QuestID))
GetPlayer().CompleteQuest(packet.QuestID);
if (GetPlayer().GetQuestStatus(packet.QuestID) != QuestStatus.Complete)
return;
Quest quest = Global.ObjectMgr.GetQuestTemplate(packet.QuestID);
if (quest != null)
GetPlayer().PlayerTalkClass.SendQuestGiverOfferReward(quest, packet.QuestGiverGUID, true);
}
[WorldPacketHandler(ClientOpcodes.QuestLogRemoveQuest)]
void HandleQuestLogRemoveQuest(QuestLogRemoveQuest packet)
{
if (packet.Entry < SharedConst.MaxQuestLogSize)
{
uint questId = GetPlayer().GetQuestSlotQuestId(packet.Entry);
if (questId != 0)
{
if (!GetPlayer().TakeQuestSourceItem(questId, true))
return; // can't un-equip some items, reject quest cancel
Quest quest = Global.ObjectMgr.GetQuestTemplate(questId);
if (quest != null)
{
if (quest.HasSpecialFlag(QuestSpecialFlags.Timed))
GetPlayer().RemoveTimedQuest(questId);
if (quest.HasFlag(QuestFlags.Pvp))
{
GetPlayer().pvpInfo.IsHostile = GetPlayer().pvpInfo.IsInHostileArea || GetPlayer().HasPvPForcingQuest();
GetPlayer().UpdatePvPState();
}
}
GetPlayer().TakeQuestSourceItem(questId, true); // remove quest src item from player
GetPlayer().AbandonQuest(questId); // remove all quest items player received before abandoning quest. Note, this does not remove normal drop items that happen to be quest requirements.
GetPlayer().RemoveActiveQuest(questId);
GetPlayer().RemoveCriteriaTimer(CriteriaTimedTypes.Quest, questId);
Log.outInfo(LogFilter.Network, "Player {0} abandoned quest {1}", GetPlayer().GetGUID().ToString(), questId);
Global.ScriptMgr.OnQuestStatusChange(_player, questId);
}
GetPlayer().SetQuestSlot(packet.Entry, 0);
GetPlayer().UpdateCriteria(CriteriaTypes.QuestAbandoned, 1);
}
}
[WorldPacketHandler(ClientOpcodes.QuestConfirmAccept)]
void HandleQuestConfirmAccept(QuestConfirmAccept packet)
{
Quest quest = Global.ObjectMgr.GetQuestTemplate(packet.QuestID);
if (quest != null)
{
if (!quest.HasFlag(QuestFlags.PartyAccept))
return;
Player originalPlayer = Global.ObjAccessor.FindPlayer(GetPlayer().GetDivider());
if (originalPlayer == null)
return;
if (!GetPlayer().IsInSameRaidWith(originalPlayer))
return;
if (!!originalPlayer.IsActiveQuest(packet.QuestID))
return;
if (!GetPlayer().CanTakeQuest(quest, true))
return;
if (GetPlayer().CanAddQuest(quest, true))
{
GetPlayer().AddQuestAndCheckCompletion(quest, null); // NULL, this prevent DB script from duplicate running
if (quest.SourceSpellID > 0)
_player.CastSpell(_player, quest.SourceSpellID, true);
}
}
GetPlayer().SetDivider(ObjectGuid.Empty);
}
[WorldPacketHandler(ClientOpcodes.QuestGiverCompleteQuest)]
void HandleQuestgiverCompleteQuest(QuestGiverCompleteQuest packet)
{
bool autoCompleteMode = packet.FromScript; // 0 - standart complete quest mode with npc, 1 - auto-complete mode
Quest quest = Global.ObjectMgr.GetQuestTemplate(packet.QuestID);
if (quest == null)
return;
if (autoCompleteMode && !quest.HasFlag(QuestFlags.AutoComplete))
return;
WorldObject obj;
if (autoCompleteMode)
obj = GetPlayer();
else
obj = Global.ObjAccessor.GetObjectByTypeMask(GetPlayer(), packet.QuestGiverGUID, TypeMask.Unit | TypeMask.GameObject);
if (!obj)
return;
if (!autoCompleteMode)
{
if (!obj.hasInvolvedQuest(packet.QuestID))
return;
// some kind of WPE protection
if (!GetPlayer().CanInteractWithQuestGiver(obj))
return;
}
else
{
// Do not allow completing quests on other players.
if (packet.QuestGiverGUID != GetPlayer().GetGUID())
return;
}
if (!GetPlayer().CanSeeStartQuest(quest) && GetPlayer().GetQuestStatus(packet.QuestID) == QuestStatus.None)
{
Log.outError(LogFilter.Network, "Possible hacking attempt: Player {0} ({1}) tried to complete quest [entry: {2}] without being in possession of the quest!",
GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), packet.QuestID);
return;
}
Battleground bg = GetPlayer().GetBattleground();
if (bg)
bg.HandleQuestComplete(packet.QuestID, GetPlayer());
if (GetPlayer().GetQuestStatus(packet.QuestID) != QuestStatus.Complete)
{
if (quest.IsRepeatable())
GetPlayer().PlayerTalkClass.SendQuestGiverRequestItems(quest, packet.QuestGiverGUID, GetPlayer().CanCompleteRepeatableQuest(quest), false);
else
GetPlayer().PlayerTalkClass.SendQuestGiverRequestItems(quest, packet.QuestGiverGUID, GetPlayer().CanRewardQuest(quest, false), false);
}
else
{
if (quest.HasSpecialFlag(QuestSpecialFlags.Deliver)) // some items required
GetPlayer().PlayerTalkClass.SendQuestGiverRequestItems(quest, packet.QuestGiverGUID, GetPlayer().CanRewardQuest(quest, false), false);
else // no items required
GetPlayer().PlayerTalkClass.SendQuestGiverOfferReward(quest, packet.QuestGiverGUID, true);
}
}
[WorldPacketHandler(ClientOpcodes.PushQuestToParty)]
void HandlePushQuestToParty(PushQuestToParty packet)
{
if (!GetPlayer().CanShareQuest(packet.QuestID))
return;
Quest quest = Global.ObjectMgr.GetQuestTemplate(packet.QuestID);
if (quest == null)
return;
Player sender = GetPlayer();
Group group = sender.GetGroup();
if (!group)
return;
for (GroupReference refe = group.GetFirstMember(); refe != null; refe = refe.next())
{
Player receiver = refe.GetSource();
if (!receiver || receiver == sender)
continue;
if (!receiver.SatisfyQuestStatus(quest, false))
{
sender.SendPushToPartyResponse(receiver, QuestPushReason.OnQuest);
continue;
}
if (receiver.GetQuestStatus(packet.QuestID) == QuestStatus.Complete)
{
sender.SendPushToPartyResponse(receiver, QuestPushReason.AlreadyDone);
continue;
}
if (!receiver.CanTakeQuest(quest, false))
{
sender.SendPushToPartyResponse(receiver, QuestPushReason.Invalid);
continue;
}
if (!receiver.SatisfyQuestLog(false))
{
sender.SendPushToPartyResponse(receiver, QuestPushReason.LogFull);
continue;
}
if (!receiver.GetDivider().IsEmpty())
{
sender.SendPushToPartyResponse(receiver, QuestPushReason.Busy);
continue;
}
sender.SendPushToPartyResponse(receiver, QuestPushReason.Success);
if (quest.IsAutoAccept() && receiver.CanAddQuest(quest, true) && receiver.CanTakeQuest(quest, true))
receiver.AddQuestAndCheckCompletion(quest, sender);
if ((quest.IsAutoComplete() && quest.IsRepeatable() && !quest.IsDailyOrWeekly()) || quest.HasFlag(QuestFlags.AutoComplete))
receiver.PlayerTalkClass.SendQuestGiverRequestItems(quest, sender.GetGUID(), receiver.CanCompleteRepeatableQuest(quest), true);
else
{
receiver.SetDivider(sender.GetGUID());
receiver.PlayerTalkClass.SendQuestGiverQuestDetails(quest, receiver.GetGUID(), true);
}
}
}
[WorldPacketHandler(ClientOpcodes.QuestPushResult)]
void HandleQuestPushResult(QuestPushResult packet)
{
if (!GetPlayer().GetDivider().IsEmpty())
{
if (_player.GetDivider() == packet.SenderGUID)
{
Player player = Global.ObjAccessor.FindPlayer(_player.GetDivider());
if (player)
player.SendPushToPartyResponse(_player, packet.Result);
}
_player.SetDivider(ObjectGuid.Empty);
}
}
[WorldPacketHandler(ClientOpcodes.QuestGiverStatusMultipleQuery)]
void HandleQuestgiverStatusMultipleQuery(QuestGiverStatusMultipleQuery packet)
{
_player.SendQuestGiverStatusMultiple();
}
[WorldPacketHandler(ClientOpcodes.RequestWorldQuestUpdate)]
void HandleRequestWorldQuestUpdate(RequestWorldQuestUpdate packet)
{
WorldQuestUpdate response = new WorldQuestUpdate();
/// @todo: 7.x Has to be implemented
//response.WorldQuestUpdates.push_back(WorldPackets::Quest::WorldQuestUpdateInfo(lastUpdate, questID, timer, variableID, value));
SendPacket(response);
}
}
}
+86
View File
@@ -0,0 +1,86 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.Entities;
using Game.Network;
using Game.Network.Packets;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.GrantLevel)]
void HandleGrantLevel(GrantLevel grantLevel)
{
Player target = Global.ObjAccessor.GetPlayer(GetPlayer(), grantLevel.Target);
// check cheating
byte levels = GetPlayer().GetGrantableLevels();
ReferAFriendError error = 0;
if (!target)
error = ReferAFriendError.NoTarget;
if (levels == 0)
error = ReferAFriendError.InsufficientGrantableLevels;
else if (GetRecruiterId() != target.GetSession().GetAccountId())
error = ReferAFriendError.NotReferredBy;
else if (target.GetTeamId() != GetPlayer().GetTeamId())
error = ReferAFriendError.DifferentFaction;
else if (target.getLevel() >= GetPlayer().getLevel())
error = ReferAFriendError.TargetTooHigh;
else if (target.getLevel() >= WorldConfig.GetIntValue(WorldCfg.MaxRecruitAFriendBonusPlayerLevel))
error = ReferAFriendError.GrantLevelMaxI;
else if (target.GetGroup() != GetPlayer().GetGroup())
error = ReferAFriendError.NotInGroup;
else if (target.getLevel() >= Global.ObjectMgr.GetMaxLevelForExpansion(target.GetSession().GetExpansion()))
error = ReferAFriendError.InsufExpanLvl;
if (error != 0)
{
ReferAFriendFailure failure = new ReferAFriendFailure();
failure.Reason = error;
if (error == ReferAFriendError.NotInGroup)
failure.Str = target.GetName();
SendPacket(failure);
return;
}
ProposeLevelGrant proposeLevelGrant = new ProposeLevelGrant();
proposeLevelGrant.Sender = GetPlayer().GetGUID();
target.SendPacket(proposeLevelGrant);
}
[WorldPacketHandler(ClientOpcodes.AcceptLevelGrant)]
void HandleAcceptGrantLevel(AcceptLevelGrant acceptLevelGrant)
{
Player other = Global.ObjAccessor.GetPlayer(GetPlayer(), acceptLevelGrant.Granter);
if (!(other && other.GetSession() != null))
return;
if (GetAccountId() != other.GetSession().GetRecruiterId())
return;
if (other.GetGrantableLevels() != 0)
other.SetGrantableLevels(other.GetGrantableLevels() - 1);
else
return;
GetPlayer().GiveLevel(GetPlayer().getLevel() + 1);
}
}
}
+52
View File
@@ -0,0 +1,52 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.Network;
using Game.Network.Packets;
using System.Collections.Generic;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.QueryScenarioPoi)]
void HandleQueryScenarioPOI(QueryScenarioPOI queryScenarioPOI)
{
ScenarioPOIs response = new ScenarioPOIs();
// Read criteria tree ids and add the in a unordered_set so we don't send POIs for the same criteria tree multiple times
List<int> criteriaTreeIds = new List<int>();
for (int i = 0; i < queryScenarioPOI.MissingScenarioPOIs.Count; ++i)
criteriaTreeIds.Add(queryScenarioPOI.MissingScenarioPOIs[i]); // CriteriaTreeID
foreach (int criteriaTreeId in criteriaTreeIds)
{
var poiVector = Global.ScenarioMgr.GetScenarioPOIs((uint)criteriaTreeId);
if (poiVector != null)
{
ScenarioPOIData scenarioPOIData = new ScenarioPOIData();
scenarioPOIData.CriteriaTreeID = criteriaTreeId;
scenarioPOIData.ScenarioPOIs = poiVector;
response.ScenarioPOIDataStats.Add(scenarioPOIData);
}
}
SendPacket(response);
}
}
}
+49
View File
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.Network;
using Game.Network.Packets;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.SceneTriggerEvent)]
void HandleSceneTriggerEvent(SceneTriggerEvent sceneTriggerEvent)
{
Log.outDebug(LogFilter.Scenes, "HandleSceneTriggerEvent: SceneInstanceID: {0} Event: {1}", sceneTriggerEvent.SceneInstanceID, sceneTriggerEvent._Event);
GetPlayer().GetSceneMgr().OnSceneTrigger(sceneTriggerEvent.SceneInstanceID, sceneTriggerEvent._Event);
}
void HandleScenePlaybackComplete(ScenePlaybackComplete scenePlaybackComplete)
{
Log.outDebug(LogFilter.Scenes, "HandleScenePlaybackComplete: SceneInstanceID: {0}", scenePlaybackComplete.SceneInstanceID);
GetPlayer().GetSceneMgr().OnSceneComplete(scenePlaybackComplete.SceneInstanceID);
}
void HandleScenePlaybackCanceled(ScenePlaybackCanceled scenePlaybackCanceled)
{
Log.outDebug(LogFilter.Scenes, "HandleScenePlaybackCanceled: SceneInstanceID: {0}", scenePlaybackCanceled.SceneInstanceID);
GetPlayer().GetSceneMgr().OnSceneCancel(scenePlaybackCanceled.SceneInstanceID);
}
}
}
+101
View File
@@ -0,0 +1,101 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.DataStorage;
using Game.Entities;
using Game.Network;
using Game.Network.Packets;
using System;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.LearnTalents)]
void HandleLearnTalents(LearnTalents packet)
{
LearnTalentsFailed learnTalentsFailed = new LearnTalentsFailed();
bool anythingLearned = false;
foreach (uint talentId in packet.Talents)
{
TalentLearnResult result = _player.LearnTalent(talentId, ref learnTalentsFailed.SpellID);
if (result != 0)
{
if (learnTalentsFailed.Reason == 0)
learnTalentsFailed.Reason = (uint)result;
learnTalentsFailed.Talents.Add((ushort)talentId);
}
else
anythingLearned = true;
}
if (learnTalentsFailed.Reason != 0)
SendPacket(learnTalentsFailed);
if (anythingLearned)
GetPlayer().SendTalentsInfoData();
}
[WorldPacketHandler(ClientOpcodes.ConfirmRespecWipe)]
void HandleConfirmRespecWipe(ConfirmRespecWipe confirmRespecWipe)
{
Creature unit = GetPlayer().GetNPCIfCanInteractWith(confirmRespecWipe.RespecMaster, NPCFlags.Trainer);
if (unit == null)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleTalentWipeConfirm - {0} not found or you can't interact with him.", confirmRespecWipe.RespecMaster.ToString());
return;
}
if (confirmRespecWipe.RespecType != SpecResetType.Talents)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleConfirmRespecWipe - reset type {0} is not implemented.", confirmRespecWipe.RespecType);
return;
}
if (!unit.CanResetTalents(_player))
return;
if (!_player.PlayerTalkClass.GetGossipMenu().HasMenuItemType((uint)GossipOption.Unlearntalents))
return;
// remove fake death
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
if (!GetPlayer().ResetTalents())
{
GetPlayer().SendRespecWipeConfirm(ObjectGuid.Empty, 0);
return;
}
GetPlayer().SendTalentsInfoData();
unit.CastSpell(GetPlayer(), 14867, true); //spell: "Untalent Visual Effect"
}
[WorldPacketHandler(ClientOpcodes.UnlearnSkill)]
void HandleUnlearnSkill(UnlearnSkill packet)
{
SkillRaceClassInfoRecord rcEntry = Global.DB2Mgr.GetSkillRaceClassInfo(packet.SkillLine, GetPlayer().GetRace(), GetPlayer().GetClass());
if (rcEntry == null || !rcEntry.Flags.HasAnyFlag(SkillRaceClassInfoFlags.Unlearnable))
return;
GetPlayer().SetSkill(packet.SkillLine, 0, 0, 0);
}
}
}
+355
View File
@@ -0,0 +1,355 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Framework.Database;
using Game.DataStorage;
using Game.Entities;
using Game.Guilds;
using Game.Network;
using Game.Network.Packets;
using System;
using System.Collections.Generic;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.Who)]
void HandleWho(WhoRequestPkt whoRequest)
{
WhoRequest request = whoRequest.Request;
// zones count, client limit = 10 (2.0.10)
// can't be received from real client or broken packet
if (whoRequest.Areas.Count > 10)
return;
// user entered strings count, client limit=4 (checked on 2.0.10)
// can't be received from real client or broken packet
if (request.Words.Count > 4)
return;
/// @todo: handle following packet values
/// VirtualRealmNames
/// ShowEnemies
/// ShowArenaPlayers
/// ExactName
/// ServerInfo
request.Words.ForEach(p => p = p.ToLower());
request.Name.ToLower();
request.Guild.ToLower();
// client send in case not set max level value 100 but we support 255 max level,
// update it to show GMs with characters after 100 level
if (whoRequest.Request.MaxLevel >= 100)
whoRequest.Request.MaxLevel = 255;
var team = GetPlayer().GetTeam();
uint gmLevelInWhoList = WorldConfig.GetUIntValue(WorldCfg.GmLevelInWhoList);
WhoResponsePkt response = new WhoResponsePkt();
foreach (var target in Global.ObjAccessor.GetPlayers())
{
// player can see member of other team only if CONFIG_ALLOW_TWO_SIDE_WHO_LIST
if (target.GetTeam() != team && !HasPermission(RBACPermissions.TwoSideWhoList))
continue;
// player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST
if (target.GetSession().GetSecurity() > (AccountTypes)gmLevelInWhoList && !HasPermission(RBACPermissions.WhoSeeAllSecLevels))
continue;
// do not process players which are not in world
if (!target.IsInWorld)
continue;
// check if target is globally visible for player
if (!target.IsVisibleGloballyFor(GetPlayer()))
continue;
// check if target's level is in level range
uint lvl = target.getLevel();
if (lvl < request.MinLevel || lvl > request.MaxLevel)
continue;
// check if class matches classmask
int class_ = (byte)target.GetClass();
if (!Convert.ToBoolean(request.ClassFilter & (1 << class_)))
continue;
// check if race matches racemask
int race = (int)target.GetRace();
if (!Convert.ToBoolean(request.RaceFilter & (1 << race)))
continue;
if (!whoRequest.Areas.Empty())
{
if (whoRequest.Areas.Contains((int)target.GetZoneId()))
continue;
}
string wTargetName = target.GetName().ToLower();
if (!string.IsNullOrEmpty(request.Name) && !wTargetName.Equals(request.Name))
continue;
string wTargetGuildName = "";
Guild targetGuild = target.GetGuild();
if (targetGuild)
wTargetGuildName = targetGuild.GetName().ToLower();
if (!string.IsNullOrEmpty(request.Guild) && !wTargetGuildName.Equals(request.Guild))
continue;
if (!request.Words.Empty())
{
string aname = "";
AreaTableRecord areaEntry = CliDB.AreaTableStorage.LookupByKey(target.GetZoneId());
if (areaEntry != null)
aname = areaEntry.AreaName[GetSessionDbcLocale()].ToLower();
bool show = false;
for (int i = 0; i < request.Words.Count; ++i)
{
if (!string.IsNullOrEmpty(request.Words[i]))
{
if (wTargetName.Equals(request.Words[i]) ||
wTargetGuildName.Equals(request.Words[i]) ||
aname.Equals(request.Words[i]))
{
show = true;
break;
}
}
}
if (!show)
continue;
}
WhoEntry whoEntry = new WhoEntry();
if (!whoEntry.PlayerData.Initialize(target.GetGUID(), target))
continue;
if (targetGuild)
{
whoEntry.GuildGUID = targetGuild.GetGUID();
whoEntry.GuildVirtualRealmAddress = Global.WorldMgr.GetVirtualRealmAddress();
whoEntry.GuildName = targetGuild.GetName();
}
whoEntry.AreaID = (int)target.GetZoneId();
whoEntry.IsGM = target.IsGameMaster();
response.Response.Add(whoEntry);
// 50 is maximum player count sent to client
if (response.Response.Count >= 50)
break;
}
SendPacket(response);
}
[WorldPacketHandler(ClientOpcodes.WhoIs)]
void HandleWhoIs(WhoIsRequest packet)
{
if (!HasPermission(RBACPermissions.OpcodeWhois))
{
SendNotification(CypherStrings.YouNotHavePermission);
return;
}
if (!ObjectManager.NormalizePlayerName(ref packet.CharName))
{
SendNotification(CypherStrings.NeedCharacterName);
return;
}
Player player = Global.ObjAccessor.FindPlayerByName(packet.CharName);
if (!player)
{
SendNotification(CypherStrings.PlayerNotExistOrOffline, packet.CharName);
return;
}
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_ACCOUNT_WHOIS);
stmt.AddValue(0, player.GetSession().GetAccountId());
SQLResult result = DB.Login.Query(stmt);
if (result.IsEmpty())
{
SendNotification(CypherStrings.AccountForPlayerNotFound, packet.CharName);
return;
}
string acc = result.Read<string>(0);
if (string.IsNullOrEmpty(acc))
acc = "Unknown";
string email = result.Read<string>(1);
if (string.IsNullOrEmpty(email))
email = "Unknown";
string lastip = result.Read<string>(2);
if (string.IsNullOrEmpty(lastip))
lastip = "Unknown";
WhoIsResponse response = new WhoIsResponse();
response.AccountName = packet.CharName + "'s " + "account is " + acc + ", e-mail: " + email + ", last ip: " + lastip;
SendPacket(response);
}
[WorldPacketHandler(ClientOpcodes.SendContactList)]
void HandleContactList(SendContactList packet)
{
GetPlayer().GetSocial().SendSocialList(GetPlayer(), packet.Flags);
}
[WorldPacketHandler(ClientOpcodes.AddFriend)]
void HandleAddFriend(AddFriend packet)
{
if (!ObjectManager.NormalizePlayerName(ref packet.Name))
return;
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_GUID_RACE_ACC_BY_NAME);
stmt.AddValue(0, packet.Name);
_queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(HandleAddFriendCallBack, packet.Notes));
}
void HandleAddFriendCallBack(string friendNote, SQLResult result)
{
if (!GetPlayer())
return;
ObjectGuid friendGuid = ObjectGuid.Empty;
FriendsResult friendResult = FriendsResult.NotFound;
if (!result.IsEmpty())
{
ulong lowGuid = result.Read<ulong>(0);
if (lowGuid != 0)
{
friendGuid = ObjectGuid.Create(HighGuid.Player, lowGuid);
Team team = Player.TeamForRace((Race)result.Read<byte>(1));
uint friendAccountId = result.Read<uint>(2);
if (HasPermission(RBACPermissions.AllowGmFriend) || Global.AccountMgr.IsPlayerAccount(Global.AccountMgr.GetSecurity(friendAccountId, (int)Global.WorldMgr.GetRealm().Id.Realm)))
{
if (friendGuid == GetPlayer().GetGUID())
friendResult = FriendsResult.Self;
else if (GetPlayer().GetTeam() != team && !HasPermission(RBACPermissions.TwoSideAddFriend))
friendResult = FriendsResult.Enemy;
else if (GetPlayer().GetSocial().HasFriend(friendGuid))
friendResult = FriendsResult.Already;
else
{
Player playerFriend = Global.ObjAccessor.FindPlayer(friendGuid);
if (playerFriend && playerFriend.IsVisibleGloballyFor(GetPlayer()))
friendResult = FriendsResult.AddedOnline;
else
friendResult = FriendsResult.AddedOffline;
if (GetPlayer().GetSocial().AddToSocialList(friendGuid, SocialFlag.Friend))
GetPlayer().GetSocial().SetFriendNote(friendGuid, friendNote);
else
friendResult = FriendsResult.ListFull;
}
}
}
}
Global.SocialMgr.SendFriendStatus(GetPlayer(), friendResult, friendGuid);
}
[WorldPacketHandler(ClientOpcodes.DelFriend)]
void HandleDelFriend(DelFriend packet)
{
/// @todo: handle VirtualRealmAddress
GetPlayer().GetSocial().RemoveFromSocialList(packet.Player.Guid, SocialFlag.Friend);
Global.SocialMgr.SendFriendStatus(GetPlayer(), FriendsResult.Removed, packet.Player.Guid);
}
[WorldPacketHandler(ClientOpcodes.AddIgnore)]
void HandleAddIgnore(AddIgnore packet)
{
if (!ObjectManager.NormalizePlayerName(ref packet.Name))
return;
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_GUID_BY_NAME);
stmt.AddValue(0, packet.Name);
_queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(HandleAddIgnoreCallBack));
}
void HandleAddIgnoreCallBack(SQLResult result)
{
if (!GetPlayer())
return;
ObjectGuid IgnoreGuid = ObjectGuid.Empty;
FriendsResult ignoreResult = FriendsResult.IgnoreNotFound;
if (result.IsEmpty())
{
ulong lowGuid = result.Read<ulong>(0);
if (lowGuid != 0)
{
IgnoreGuid = ObjectGuid.Create(HighGuid.Player, lowGuid);
if (IgnoreGuid == GetPlayer().GetGUID()) //not add yourself
ignoreResult = FriendsResult.IgnoreSelf;
else if (GetPlayer().GetSocial().HasIgnore(IgnoreGuid))
ignoreResult = FriendsResult.IgnoreAlready;
else
{
ignoreResult = FriendsResult.IgnoreAdded;
// ignore list full
if (!GetPlayer().GetSocial().AddToSocialList(IgnoreGuid, SocialFlag.Ignored))
ignoreResult = FriendsResult.IgnoreFull;
}
}
}
Global.SocialMgr.SendFriendStatus(GetPlayer(), ignoreResult, IgnoreGuid);
}
[WorldPacketHandler(ClientOpcodes.DelIgnore)]
void HandleDelIgnore(DelIgnore packet)
{
/// @todo: handle VirtualRealmAddress
Log.outDebug(LogFilter.Network, "WorldSession.HandleDelIgnoreOpcode: {0}", packet.Player.Guid.ToString());
GetPlayer().GetSocial().RemoveFromSocialList(packet.Player.Guid, SocialFlag.Ignored);
Global.SocialMgr.SendFriendStatus(GetPlayer(), FriendsResult.IgnoreRemoved, packet.Player.Guid);
}
[WorldPacketHandler(ClientOpcodes.SetContactNotes)]
void HandleSetContactNotes(SetContactNotes packet)
{
/// @todo: handle VirtualRealmAddress
Log.outDebug(LogFilter.Network, "WorldSession.HandleSetContactNotesOpcode: Contact: {0}, Notes: {1}", packet.Player.Guid.ToString(), packet.Notes);
GetPlayer().GetSocial().SetFriendNote(packet.Player.Guid, packet.Notes);
}
}
}
+616
View File
@@ -0,0 +1,616 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Framework.Database;
using Game.DataStorage;
using Game.Entities;
using Game.Guilds;
using Game.Network;
using Game.Network.Packets;
using Game.Spells;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.UseItem)]
void HandleUseItem(UseItem packet)
{
Player user = GetPlayer();
// ignore for remote control state
if (user.m_unitMovedByMe != user)
return;
Item item = user.GetUseableItemByPos(packet.PackSlot, packet.Slot);
if (item == null)
{
user.SendEquipError(InventoryResult.ItemNotFound);
return;
}
if (item.GetGUID() != packet.CastItem)
{
user.SendEquipError(InventoryResult.ItemNotFound);
return;
}
ItemTemplate proto = item.GetTemplate();
if (proto == null)
{
user.SendEquipError(InventoryResult.ItemNotFound, item);
return;
}
// some item classes can be used only in equipped state
if (proto.GetInventoryType() != InventoryType.NonEquip && !item.IsEquipped())
{
user.SendEquipError(InventoryResult.ItemNotFound, item);
return;
}
InventoryResult msg = user.CanUseItem(item);
if (msg != InventoryResult.Ok)
{
user.SendEquipError(msg, item);
return;
}
// only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB)
if (proto.GetClass() == ItemClass.Consumable && !proto.GetFlags().HasAnyFlag(ItemFlags.IgnoreDefaultArenaRestrictions) && user.InArena())
{
user.SendEquipError(InventoryResult.NotDuringArenaMatch, item);
return;
}
// don't allow items banned in arena
if (proto.GetFlags().HasAnyFlag(ItemFlags.NotUseableInArena) && user.InArena())
{
user.SendEquipError(InventoryResult.NotDuringArenaMatch, item);
return;
}
if (user.IsInCombat())
{
for (int i = 0; i < proto.Effects.Count; ++i)
{
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(proto.Effects[i].SpellID);
if (spellInfo != null)
{
if (!spellInfo.CanBeUsedInCombat())
{
user.SendEquipError(InventoryResult.NotInCombat, item);
return;
}
}
}
}
// check also BIND_WHEN_PICKED_UP and BIND_QUEST_ITEM for .additem or .additemset case by GM (not binded at adding to inventory)
if (item.GetBonding() == ItemBondingType.OnUse || item.GetBonding() == ItemBondingType.OnAcquire || item.GetBonding() == ItemBondingType.Quest)
{
if (!item.IsSoulBound())
{
item.SetState(ItemUpdateState.Changed, user);
item.SetBinding(true);
GetCollectionMgr().AddItemAppearance(item);
}
}
SpellCastTargets targets = new SpellCastTargets(user, packet.Cast);
// Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state.
if (!Global.ScriptMgr.OnItemUse(user, item, targets, packet.Cast.CastID))
{
// no script or script not process request by self
user.CastItemUseSpell(item, targets, packet.Cast.CastID, packet.Cast.Misc);
}
}
[WorldPacketHandler(ClientOpcodes.OpenItem)]
void HandleOpenItem(OpenItem packet)
{
Player player = GetPlayer();
// ignore for remote control state
if (player.m_unitMovedByMe != player)
return;
Item item = player.GetItemByPos(packet.Slot, packet.PackSlot);
if (!item)
{
player.SendEquipError(InventoryResult.ItemNotFound);
return;
}
ItemTemplate proto = item.GetTemplate();
if (proto == null)
{
player.SendEquipError(InventoryResult.ItemNotFound, item);
return;
}
// Verify that the bag is an actual bag or wrapped item that can be used "normally"
if (!proto.GetFlags().HasAnyFlag(ItemFlags.HasLoot) && !item.HasFlag(ItemFields.Flags, ItemFieldFlags.Wrapped))
{
player.SendEquipError(InventoryResult.ClientLockedOut, item);
Log.outError(LogFilter.Network, "Possible hacking attempt: Player {0} [guid: {1}] tried to open item [guid: {2}, entry: {3}] which is not openable!",
player.GetName(), player.GetGUID().ToString(), item.GetGUID().ToString(), proto.GetId());
return;
}
// locked item
uint lockId = proto.GetLockID();
if (lockId != 0)
{
LockRecord lockInfo = CliDB.LockStorage.LookupByKey(lockId);
if (lockInfo == null)
{
player.SendEquipError(InventoryResult.ItemLocked, item);
Log.outError(LogFilter.Network, "WORLD:OpenItem: item [guid = {0}] has an unknown lockId: {1}!", item.GetGUID().ToString(), lockId);
return;
}
// was not unlocked yet
if (item.IsLocked())
{
player.SendEquipError(InventoryResult.ItemLocked, item);
return;
}
}
if (item.HasFlag(ItemFields.Flags, ItemFieldFlags.Wrapped))// wrapped?
{
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHARACTER_GIFT_BY_ITEM);
stmt.AddValue(0, item.GetGUID().GetCounter());
SQLResult result = DB.Characters.Query(stmt);
if (!result.IsEmpty())
{
uint entry = result.Read<uint>(0);
uint flags = result.Read<uint>(1);
item.SetUInt64Value(ItemFields.GiftCreator, 0);
item.SetEntry(entry);
item.SetUInt32Value(ItemFields.Flags, flags);
item.SetState(ItemUpdateState.Changed, player);
}
else
{
Log.outError(LogFilter.Network, "Wrapped item {0} don't have record in character_gifts table and will deleted", item.GetGUID().ToString());
player.DestroyItem(item.GetBagSlot(), item.GetSlot(), true);
return;
}
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_GIFT);
stmt.AddValue(0, item.GetGUID().GetCounter());
DB.Characters.Execute(stmt);
}
else
player.SendLoot(item.GetGUID(), LootType.Corpse);
}
[WorldPacketHandler(ClientOpcodes.GameObjUse)]
void HandleGameObjectUse(GameObjUse packet)
{
GameObject obj = GetPlayer().GetGameObjectIfCanInteractWith(packet.Guid);
if (obj)
{
// ignore for remote control state
if (GetPlayer().m_unitMovedByMe != GetPlayer())
if (!(GetPlayer().IsOnVehicle(GetPlayer().m_unitMovedByMe) || GetPlayer().IsMounted()) && !obj.GetGoInfo().IsUsableMounted())
return;
obj.Use(GetPlayer());
}
}
[WorldPacketHandler(ClientOpcodes.GameObjReportUse)]
void HandleGameobjectReportUse(GameObjReportUse packet)
{
// ignore for remote control state
if (GetPlayer().m_unitMovedByMe != GetPlayer())
return;
GameObject go = GetPlayer().GetGameObjectIfCanInteractWith(packet.Guid);
if (go)
{
if (go.GetAI().GossipHello(GetPlayer(), false))
return;
GetPlayer().UpdateCriteria(CriteriaTypes.UseGameobject, go.GetEntry());
}
}
[WorldPacketHandler(ClientOpcodes.CastSpell, Processing = PacketProcessing.ThreadSafe)]
void HandleCastSpell(CastSpell cast)
{
// ignore for remote control state (for player case)
Unit mover = GetPlayer().m_unitMovedByMe;
if (mover != GetPlayer() && mover.IsTypeId(TypeId.Player))
return;
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(cast.Cast.SpellID);
if (spellInfo == null)
{
Log.outError(LogFilter.Network, "WORLD: unknown spell id {0}", cast.Cast.SpellID);
return;
}
if (spellInfo.IsPassive())
return;
Unit caster = mover;
if (caster.IsTypeId(TypeId.Unit) && !caster.ToCreature().HasSpell(spellInfo.Id))
{
// If the vehicle creature does not have the spell but it allows the passenger to cast own spells
// change caster to player and let him cast
if (!GetPlayer().IsOnVehicle(caster) || spellInfo.CheckVehicle(GetPlayer()) != SpellCastResult.SpellCastOk)
return;
caster = GetPlayer();
}
// check known spell or raid marker spell (which not requires player to know it)
if (caster.IsTypeId(TypeId.Player) && !caster.ToPlayer().HasActiveSpell(spellInfo.Id) && !spellInfo.HasEffect(SpellEffectName.ChangeRaidMarker) && !spellInfo.HasAttribute(SpellAttr8.RaidMarker))
return;
// Check possible spell cast overrides
spellInfo = caster.GetCastSpellInfo(spellInfo);
// Client is resending autoshot cast opcode when other spell is casted during shoot rotation
// Skip it to prevent "interrupt" message
if (spellInfo.IsAutoRepeatRangedSpell() && GetPlayer().GetCurrentSpell(CurrentSpellTypes.AutoRepeat) != null
&& GetPlayer().GetCurrentSpell(CurrentSpellTypes.AutoRepeat).m_spellInfo == spellInfo)
return;
// can't use our own spells when we're in possession of another unit,
if (GetPlayer().isPossessing())
return;
// client provided targets
SpellCastTargets targets = new SpellCastTargets(caster, cast.Cast);
// auto-selection buff level base at target level (in spellInfo)
if (targets.GetUnitTarget() != null)
{
SpellInfo actualSpellInfo = spellInfo.GetAuraRankForLevel(targets.GetUnitTarget().GetLevelForTarget(caster));
// if rank not found then function return NULL but in explicit cast case original spell can be casted and later failed with appropriate error message
if (actualSpellInfo != null)
spellInfo = actualSpellInfo;
}
if (cast.Cast.MoveUpdate.HasValue)
HandleMovementOpcode(ClientOpcodes.MoveStop, cast.Cast.MoveUpdate.Value);
Spell spell = new Spell(caster, spellInfo, TriggerCastFlags.None, ObjectGuid.Empty, false);
SpellPrepare spellPrepare = new SpellPrepare();
spellPrepare.ClientCastID = cast.Cast.CastID;
spellPrepare.ServerCastID = spell.m_castId;
SendPacket(spellPrepare);
spell.m_fromClient = true;
spell.m_misc.Data0 = cast.Cast.Misc[0];
spell.m_misc.Data1 = cast.Cast.Misc[1];
spell.prepare(targets);
}
[WorldPacketHandler(ClientOpcodes.CancelCast, Processing = PacketProcessing.ThreadSafe)]
void HandleCancelCast(CancelCast packet)
{
if (GetPlayer().IsNonMeleeSpellCast(false))
GetPlayer().InterruptNonMeleeSpells(false, packet.SpellID, false);
}
[WorldPacketHandler(ClientOpcodes.CancelAura)]
void HandleCancelAura(CancelAura cancelAura)
{
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(cancelAura.SpellID);
if (spellInfo == null)
return;
// not allow remove spells with attr SPELL_ATTR0_CANT_CANCEL
if (spellInfo.HasAttribute(SpellAttr0.CantCancel))
return;
// channeled spell case (it currently casted then)
if (spellInfo.IsChanneled())
{
Spell curSpell = GetPlayer().GetCurrentSpell(CurrentSpellTypes.Channeled);
if (curSpell != null)
if (curSpell.GetSpellInfo().Id == cancelAura.SpellID)
GetPlayer().InterruptSpell(CurrentSpellTypes.Channeled);
return;
}
// non channeled case:
// don't allow remove non positive spells
// don't allow cancelling passive auras (some of them are visible)
if (!spellInfo.IsPositive() || spellInfo.IsPassive())
return;
GetPlayer().RemoveOwnedAura(cancelAura.SpellID, cancelAura.CasterGUID, 0, AuraRemoveMode.Cancel);
}
[WorldPacketHandler(ClientOpcodes.CancelGrowthAura)]
void HandleCancelGrowthAura(CancelGrowthAura cancelGrowthAura)
{
GetPlayer().RemoveAurasByType(AuraType.ModScale, aurApp =>
{
SpellInfo spellInfo = aurApp.GetBase().GetSpellInfo();
return !spellInfo.HasAttribute(SpellAttr0.CantCancel) && spellInfo.IsPositive() && !spellInfo.IsPassive();
});
}
[WorldPacketHandler(ClientOpcodes.CancelMountAura)]
void HandleCancelMountAura(CancelMountAura packet)
{
GetPlayer().RemoveAurasByType(AuraType.Mounted, aurApp =>
{
SpellInfo spellInfo = aurApp.GetBase().GetSpellInfo();
return !spellInfo.HasAttribute(SpellAttr0.CantCancel) && spellInfo.IsPositive() && !spellInfo.IsPassive();
});
}
[WorldPacketHandler(ClientOpcodes.PetCancelAura)]
void HandlePetCancelAura(PetCancelAura packet)
{
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(packet.SpellID);
if (spellInfo == null)
{
Log.outError(LogFilter.Network, "WORLD: unknown PET spell id {0}", packet.SpellID);
return;
}
Creature pet= ObjectAccessor.GetCreatureOrPetOrVehicle(_player, packet.PetGUID);
if (pet == null)
{
Log.outError(LogFilter.Network, "HandlePetCancelAura: Attempt to cancel an aura for non-existant {0} by player '{1}'", packet.PetGUID.ToString(), GetPlayer().GetName());
return;
}
if (pet != GetPlayer().GetGuardianPet() && pet != GetPlayer().GetCharm())
{
Log.outError(LogFilter.Network, "HandlePetCancelAura: {0} is not a pet of player '{1}'", packet.PetGUID.ToString(), GetPlayer().GetName());
return;
}
if (!pet.IsAlive())
{
pet.SendPetActionFeedback(packet.SpellID, ActionFeedback.PetDead);
return;
}
pet.RemoveOwnedAura(packet.SpellID, ObjectGuid.Empty, 0, AuraRemoveMode.Cancel);
}
[WorldPacketHandler(ClientOpcodes.CancelAutoRepeatSpell)]
void HandleCancelAutoRepeatSpell(CancelAutoRepeatSpell packet)
{
//may be better send SMSG_CANCEL_AUTO_REPEAT?
//cancel and prepare for deleting
_player.InterruptSpell(CurrentSpellTypes.AutoRepeat);
}
[WorldPacketHandler(ClientOpcodes.CancelChannelling)]
void HandleCancelChanneling(CancelChannelling cancelChanneling)
{
// ignore for remote control state (for player case)
Unit mover = _player.m_unitMovedByMe;
if (mover != _player && mover.IsTypeId(TypeId.Player))
return;
mover.InterruptSpell(CurrentSpellTypes.Channeled);
}
[WorldPacketHandler(ClientOpcodes.TotemDestroyed)]
void HandleTotemDestroyed(TotemDestroyed totemDestroyed)
{
// ignore for remote control state
if (GetPlayer().m_unitMovedByMe != GetPlayer())
return;
byte slotId = totemDestroyed.Slot;
slotId += (int)SummonSlot.Totem;
if (slotId >= SharedConst.MaxTotemSlot)
return;
if (GetPlayer().m_SummonSlot[slotId].IsEmpty())
return;
Creature totem = ObjectAccessor.GetCreature(GetPlayer(), _player.m_SummonSlot[slotId]);
if (totem != null && totem.IsTotem())// && totem.GetGUID() == packet.TotemGUID) Unknown why blizz doesnt send the guid when you right click it.
totem.ToTotem().UnSummon();
}
[WorldPacketHandler(ClientOpcodes.SelfRes)]
void HandleSelfRes(SelfRes packet)
{
if (_player.HasAuraType(AuraType.PreventResurrection))
return; // silent return, client should display error by itself and not send this opcode
if (_player.GetUInt32Value(PlayerFields.SelfResSpell) != 0)
{
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(_player.GetUInt32Value(PlayerFields.SelfResSpell));
if (spellInfo != null)
_player.CastSpell(_player, spellInfo, false, null);
_player.SetUInt32Value(PlayerFields.SelfResSpell, 0);
}
}
[WorldPacketHandler(ClientOpcodes.SpellClick)]
void HandleSpellClick(SpellClick packet)
{
// this will get something not in world. crash
Creature unit = ObjectAccessor.GetCreatureOrPetOrVehicle(GetPlayer(), packet.SpellClickUnitGuid);
if (unit == null)
return;
/// @todo Unit.SetCharmedBy: 28782 is not in world but 0 is trying to charm it! . crash
if (!unit.IsInWorld)
return;
unit.HandleSpellClick(GetPlayer());
}
[WorldPacketHandler(ClientOpcodes.GetMirrorImageData)]
void HandleMirrorImageDataRequest(GetMirrorImageData packet)
{
ObjectGuid guid = packet.UnitGUID;
// Get unit for which data is needed by client
Unit unit = Global.ObjAccessor.GetUnit(GetPlayer(), guid);
if (!unit)
return;
if (!unit.HasAuraType(AuraType.CloneCaster))
return;
// Get creator of the unit (SPELL_AURA_CLONE_CASTER does not stack)
Unit creator = unit.GetAuraEffectsByType(AuraType.CloneCaster).FirstOrDefault().GetCaster();
if (!creator)
return;
Player player = creator.ToPlayer();
if (player)
{
MirrorImageComponentedData data = new MirrorImageComponentedData();
data.UnitGUID = guid;
data.DisplayID = (int)creator.GetDisplayId();
data.RaceID = (byte)creator.GetRace();
data.Gender = (byte)creator.GetGender();
data.ClassID = (byte)creator.GetClass();
Guild guild = player.GetGuild();
data.SkinColor = player.GetByteValue(PlayerFields.Bytes, PlayerFieldOffsets.BytesOffsetSkinId);
data.FaceVariation = player.GetByteValue(PlayerFields.Bytes, PlayerFieldOffsets.BytesOffsetFaceId);
data.HairVariation = player.GetByteValue(PlayerFields.Bytes, PlayerFieldOffsets.BytesOffsetHairStyleId);
data.HairColor = player.GetByteValue(PlayerFields.Bytes, PlayerFieldOffsets.BytesOffsetHairColorId);
data.BeardVariation = player.GetByteValue(PlayerFields.Bytes2, PlayerFieldOffsets.Bytes2OffsetFacialStyle);
for (int i = 0; i < PlayerConst.CustomDisplaySize; ++i)
data.CustomDisplay[i] = player.GetByteValue(PlayerFields.Bytes2, (byte)(PlayerFieldOffsets.Bytes2OffsetCustomDisplayOption + i));
data.GuildGUID = (guild ? guild.GetGUID() : ObjectGuid.Empty);
byte[] itemSlots =
{
EquipmentSlot.Head,
EquipmentSlot.Shoulders,
EquipmentSlot.Shirt,
EquipmentSlot.Chest,
EquipmentSlot.Waist ,
EquipmentSlot.Legs ,
EquipmentSlot.Feet,
EquipmentSlot.Wrist,
EquipmentSlot.Hands,
EquipmentSlot.Tabard,
EquipmentSlot.Cloak
};
// Display items in visible slots
foreach (var slot in itemSlots)
{
uint itemDisplayId;
Item item = player.GetItemByPos(InventorySlots.Bag0, slot);
if ((slot == EquipmentSlot.Head && player.HasFlag(PlayerFields.Flags, PlayerFlags.HideHelm)) ||
(slot == EquipmentSlot.Cloak && player.HasFlag(PlayerFields.Flags, PlayerFlags.HideCloak)))
itemDisplayId = 0;
else if (item)
itemDisplayId = item.GetDisplayId(player);
else
itemDisplayId = 0;
data.ItemDisplayID.Add((int)itemDisplayId);
}
SendPacket(data);
}
else
{
MirrorImageCreatureData data = new MirrorImageCreatureData();
data.UnitGUID = guid;
data.DisplayID = (int)creator.GetDisplayId();
SendPacket(data);
}
}
[WorldPacketHandler(ClientOpcodes.MissileTrajectoryCollision)]
void HandleMissileTrajectoryCollision(MissileTrajectoryCollision packet)
{
Unit caster = Global.ObjAccessor.GetUnit(_player, packet.Target);
if (caster == null)
return;
Spell spell = caster.FindCurrentSpellBySpellId(packet.SpellID);
if (spell == null || !spell.m_targets.HasDst())
return;
Position pos = spell.m_targets.GetDstPos();
pos.Relocate(packet.CollisionPos);
spell.m_targets.ModDst(pos);
NotifyMissileTrajectoryCollision data = new NotifyMissileTrajectoryCollision();
data.Caster = packet.Target;
data.CastID = packet.CastID;
data.CollisionPos = packet.CollisionPos;
caster.SendMessageToSet(data, true);
}
[WorldPacketHandler(ClientOpcodes.UpdateMissileTrajectory)]
void HandleUpdateMissileTrajectory(UpdateMissileTrajectory packet)
{
Unit caster = Global.ObjAccessor.GetUnit(GetPlayer(), packet.Guid);
Spell spell = caster ? caster.GetCurrentSpell(CurrentSpellTypes.Generic) : null;
if (!spell || spell.m_spellInfo.Id != packet.SpellID || !spell.m_targets.HasDst() || !spell.m_targets.HasSrc())
return;
Position pos = spell.m_targets.GetSrcPos();
pos.Relocate(packet.FirePos);
spell.m_targets.ModSrc(pos);
pos = spell.m_targets.GetDstPos();
pos.Relocate(packet.ImpactPos);
spell.m_targets.ModDst(pos);
spell.m_targets.SetPitch(packet.Pitch);
spell.m_targets.SetSpeed(packet.Speed);
if (packet.Status.HasValue)
{
GetPlayer().ValidateMovementInfo(packet.Status.Value);
/*public uint opcode;
recvPacket >> opcode;
recvPacket.SetOpcode(CMSG_MOVE_STOP); // always set to CMSG_MOVE_STOP in client SetOpcode
//HandleMovementOpcodes(recvPacket);*/
}
}
[WorldPacketHandler(ClientOpcodes.RequestCategoryCooldowns, Processing = PacketProcessing.Inplace)]
void HandleRequestCategoryCooldowns(RequestCategoryCooldowns requestCategoryCooldowns)
{
GetPlayer().SendSpellCategoryCooldowns();
}
}
}
+238
View File
@@ -0,0 +1,238 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.DataStorage;
using Game.Entities;
using Game.Movement;
using Game.Network;
using Game.Network.Packets;
using System.Collections.Generic;
using System.Linq;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.EnableTaxiNode, Processing = PacketProcessing.ThreadSafe)]
void HandleEnableTaxiNodeOpcode(EnableTaxiNode enableTaxiNode)
{
Creature unit = GetPlayer().GetNPCIfCanInteractWith(enableTaxiNode.Unit, NPCFlags.FlightMaster);
if (unit)
SendLearnNewTaxiNode(unit);
}
[WorldPacketHandler(ClientOpcodes.TaxiNodeStatusQuery, Processing = PacketProcessing.ThreadSafe)]
void HandleTaxiNodeStatusQuery(TaxiNodeStatusQuery taxiNodeStatusQuery)
{
SendTaxiStatus(taxiNodeStatusQuery.UnitGUID);
}
public void SendTaxiStatus(ObjectGuid guid)
{
// cheating checks
Creature unit = ObjectAccessor.GetCreature(GetPlayer(), guid);
if (unit == null)
{
Log.outDebug(LogFilter.Network, "WorldSession.SendTaxiStatus - {0} not found.", guid.ToString());
return;
}
uint curloc = Global.ObjectMgr.GetNearestTaxiNode(unit.GetPositionX(), unit.GetPositionY(), unit.GetPositionZ(), unit.GetMapId(), GetPlayer().GetTeam());
TaxiNodeStatusPkt data = new TaxiNodeStatusPkt();
data.Unit = guid;
if (curloc == 0)
data.Status = TaxiNodeStatus.None;
else if (unit.GetReactionTo(GetPlayer()) >= ReputationRank.Neutral)
data.Status = GetPlayer().m_taxi.IsTaximaskNodeKnown(curloc) ? TaxiNodeStatus.Learned : TaxiNodeStatus.Unlearned;
else
data.Status = TaxiNodeStatus.NotEligible;
SendPacket(data);
}
[WorldPacketHandler(ClientOpcodes.TaxiQueryAvailableNodes, Processing = PacketProcessing.ThreadSafe)]
void HandleTaxiQueryAvailableNodes(TaxiQueryAvailableNodes taxiQueryAvailableNodes)
{
// cheating checks
Creature unit = GetPlayer().GetNPCIfCanInteractWith(taxiQueryAvailableNodes.Unit, NPCFlags.FlightMaster);
if (unit == null)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleTaxiQueryAvailableNodes - {0} not found or you can't interact with him.", taxiQueryAvailableNodes.Unit.ToString());
return;
}
// remove fake death
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
// unknown taxi node case
if (SendLearnNewTaxiNode(unit))
return;
// known taxi node case
SendTaxiMenu(unit);
}
public void SendTaxiMenu(Creature unit)
{
// find current node
uint curloc = Global.ObjectMgr.GetNearestTaxiNode(unit.GetPositionX(), unit.GetPositionY(), unit.GetPositionZ(), unit.GetMapId(), GetPlayer().GetTeam());
if (curloc == 0)
return;
bool lastTaxiCheaterState = GetPlayer().isTaxiCheater();
if (unit.GetEntry() == 29480)
GetPlayer().SetTaxiCheater(true); // Grimwing in Ebon Hold, special case. NOTE: Not perfect, Zul'Aman should not be included according to WoWhead, and I think taxicheat includes it.
ShowTaxiNodes data = new ShowTaxiNodes();
data.WindowInfo.HasValue = true;
data.WindowInfo.Value.UnitGUID = unit.GetGUID();
data.WindowInfo.Value.CurrentNode = (int)curloc;
GetPlayer().m_taxi.AppendTaximaskTo(data, lastTaxiCheaterState);
SendPacket(data);
GetPlayer().SetTaxiCheater(lastTaxiCheaterState);
}
public void SendDoFlight(uint mountDisplayId, uint path, uint pathNode = 0)
{
// remove fake death
if (GetPlayer().HasUnitState(UnitState.Died))
GetPlayer().RemoveAurasByType(AuraType.FeignDeath);
while (GetPlayer().GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Flight)
GetPlayer().GetMotionMaster().MovementExpired(false);
if (mountDisplayId != 0)
GetPlayer().Mount(mountDisplayId);
GetPlayer().GetMotionMaster().MoveTaxiFlight(path, pathNode);
}
public bool SendLearnNewTaxiNode(Creature unit)
{
// find current node
uint curloc = Global.ObjectMgr.GetNearestTaxiNode(unit.GetPositionX(), unit.GetPositionY(), unit.GetPositionZ(), unit.GetMapId(), GetPlayer().GetTeam());
if (curloc == 0)
return true;
if (GetPlayer().m_taxi.SetTaximaskNode(curloc))
{
SendPacket(new NewTaxiPath());
TaxiNodeStatusPkt data = new TaxiNodeStatusPkt();
data.Unit = unit.GetGUID();
data.Status = TaxiNodeStatus.Learned;
SendPacket(data);
return true;
}
else
return false;
}
public void SendDiscoverNewTaxiNode(uint nodeid)
{
if (GetPlayer().m_taxi.SetTaximaskNode(nodeid))
SendPacket(new NewTaxiPath());
}
[WorldPacketHandler(ClientOpcodes.ActivateTaxi, Processing = PacketProcessing.ThreadSafe)]
void HandleActivateTaxi(ActivateTaxi activateTaxi)
{
Creature unit = GetPlayer().GetNPCIfCanInteractWith(activateTaxi.Vendor, NPCFlags.FlightMaster);
if (unit == null)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleActivateTaxiOpcode - {0} not found or you can't interact with it.", activateTaxi.Vendor.ToString());
return;
}
uint curloc = Global.ObjectMgr.GetNearestTaxiNode(unit.GetPositionX(), unit.GetPositionY(), unit.GetPositionZ(), unit.GetMapId(), GetPlayer().GetTeam());
if (curloc == 0)
return;
TaxiNodesRecord from = CliDB.TaxiNodesStorage.LookupByKey(curloc);
TaxiNodesRecord to = CliDB.TaxiNodesStorage.LookupByKey(activateTaxi.Node);
if (to == null)
return;
if (!GetPlayer().isTaxiCheater())
{
if (!GetPlayer().m_taxi.IsTaximaskNodeKnown(curloc) || !GetPlayer().m_taxi.IsTaximaskNodeKnown(activateTaxi.Node))
{
SendActivateTaxiReply(ActivateTaxiReply.NotVisited);
return;
}
}
uint preferredMountDisplay = 0;
MountRecord mount = CliDB.MountStorage.LookupByKey(activateTaxi.FlyingMountID);
if (mount != null)
{
if (GetPlayer().HasSpell(mount.SpellId))
{
var mountDisplays = Global.DB2Mgr.GetMountDisplays(mount.Id);
if (mountDisplays != null)
{
List<MountXDisplayRecord> usableDisplays = mountDisplays.Where(mountDisplay =>
{
PlayerConditionRecord playerCondition = CliDB.PlayerConditionStorage.LookupByKey(mountDisplay.PlayerConditionID);
if (playerCondition != null)
return ConditionManager.IsPlayerMeetingCondition(GetPlayer(), playerCondition);
return true;
}).ToList();
if (!usableDisplays.Empty())
preferredMountDisplay = usableDisplays.SelectRandom().DisplayID;
}
}
}
List<uint> nodes = new List<uint>();
Global.TaxiPathGraph.GetCompleteNodeRoute(from, to, GetPlayer(), nodes);
GetPlayer().ActivateTaxiPathTo(nodes, unit, 0, preferredMountDisplay);
}
public void SendActivateTaxiReply(ActivateTaxiReply reply = ActivateTaxiReply.Ok)
{
ActivateTaxiReplyPkt data = new ActivateTaxiReplyPkt();
data.Reply = reply;
SendPacket(data);
}
[WorldPacketHandler(ClientOpcodes.TaxiRequestEarlyLanding, Processing = PacketProcessing.ThreadSafe)]
void HandleTaxiRequestEarlyLanding(TaxiRequestEarlyLanding taxiRequestEarlyLanding)
{
if (GetPlayer().GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Flight)
{
if (GetPlayer().m_taxi.RequestEarlyLanding())
{
FlightPathMovementGenerator flight = (FlightPathMovementGenerator)GetPlayer().GetMotionMaster().top();
flight.LoadPath(GetPlayer(), flight.GetPath()[(int)flight.GetCurrentNode()].NodeIndex);
flight.Reset(GetPlayer());
}
}
}
}
}
+115
View File
@@ -0,0 +1,115 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Framework.Database;
using Game.Network;
using Game.Network.Packets;
using Game.SupportSystem;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.GmTicketGetCaseStatus, Processing = PacketProcessing.Inplace)]
void HandleGMTicketGetCaseStatus(GMTicketGetCaseStatus packet)
{
//TODO: Implement GmCase and handle this packet correctly
GMTicketCaseStatus status = new GMTicketCaseStatus();
SendPacket(status);
}
[WorldPacketHandler(ClientOpcodes.GmTicketGetSystemStatus, Processing = PacketProcessing.Inplace)]
void HandleGMTicketSystemStatusOpcode(GMTicketGetSystemStatus packet)
{
// Note: This only disables the ticket UI at client side and is not fully reliable
// 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.
GMTicketSystemStatusPkt response = new GMTicketSystemStatusPkt();
response.Status = Global.SupportMgr.GetSupportSystemStatus() ? 1 : 0;
SendPacket(response);
}
[WorldPacketHandler(ClientOpcodes.SupportTicketSubmitBug)]
void HandleSupportTicketSubmitBug(SupportTicketSubmitBug packet)
{
if (!Global.SupportMgr.GetBugSystemStatus())
return;
BugTicket ticket = new BugTicket(GetPlayer());
ticket.SetPosition(packet.Header.MapID, packet.Header.Position);
ticket.SetFacing(packet.Header.Facing);
ticket.SetNote(packet.Note);
Global.SupportMgr.AddTicket(ticket);
}
[WorldPacketHandler(ClientOpcodes.SupportTicketSubmitSuggestion)]
void HandleSupportTicketSubmitSuggestion(SupportTicketSubmitSuggestion packet)
{
if (!Global.SupportMgr.GetSuggestionSystemStatus())
return;
SuggestionTicket ticket = new SuggestionTicket(GetPlayer());
ticket.SetPosition(packet.Header.MapID, packet.Header.Position);
ticket.SetFacing(packet.Header.Facing);
ticket.SetNote(packet.Note);
Global.SupportMgr.AddTicket(ticket);
}
[WorldPacketHandler(ClientOpcodes.SupportTicketSubmitComplaint)]
void HandleSupportTicketSubmitComplaint(SupportTicketSubmitComplaint packet)
{
if (!Global.SupportMgr.GetComplaintSystemStatus())
return;
ComplaintTicket comp = new ComplaintTicket(GetPlayer());
comp.SetPosition(packet.Header.MapID, packet.Header.Position);
comp.SetFacing(packet.Header.Facing);
comp.SetChatLog(packet.ChatLog);
comp.SetTargetCharacterGuid(packet.TargetCharacterGUID);
comp.SetComplaintType((GMSupportComplaintType)packet.ComplaintType);
comp.SetNote(packet.Note);
Global.SupportMgr.AddTicket(comp);
}
[WorldPacketHandler(ClientOpcodes.BugReport)]
void HandleBugReport(BugReport bugReport)
{
// Note: There is no way to trigger this with standard UI except /script ReportBug("text")
if (!Global.SupportMgr.GetBugSystemStatus())
return;
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_BUG_REPORT);
stmt.AddValue(0, bugReport.Text);
stmt.AddValue(1, bugReport.DiagInfo);
DB.Characters.Execute(stmt);
}
[WorldPacketHandler(ClientOpcodes.Complaint)]
void HandleComplaint(Complaint packet)
{ // NOTE: all chat messages from this spammer are automatically ignored by the spam reporter until logout in case of chat spam.
// if it's mail spam - ALL mails from this spammer are automatically removed by client
ComplaintResult result = new ComplaintResult();
result.ComplaintType = packet.ComplaintType;
result.Result = 0;
SendPacket(result);
}
}
}
+54
View File
@@ -0,0 +1,54 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.Network;
using Game.Network.Packets;
using System.Linq;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.UiTimeRequest, Status = SessionStatus.Authed, Processing = PacketProcessing.Inplace)]
void HandleUITimeRequest(UITimeRequest packet)
{
UITime response = new UITime();
response.Time = (uint)Time.UnixTime;
SendPacket(response);
}
[WorldPacketHandler(ClientOpcodes.TimeSyncResponse, Processing = PacketProcessing.Inplace)]
void HandleTimeSyncResponse(TimeSyncResponse packet)
{
Log.outDebug(LogFilter.Network, "CMSG_TIME_SYNC_RESP");
if (packet.SequenceIndex != _player.m_timeSyncQueue.FirstOrDefault())
Log.outError(LogFilter.Network, "Wrong time sync counter from player {0} (cheater?)", _player.GetName());
Log.outDebug(LogFilter.Network, "Time sync received: counter {0}, client ticks {1}, time since last sync {2}", packet.SequenceIndex, packet.ClientTime, packet.ClientTime - _player.m_timeSyncClient);
uint ourTicks = packet.ClientTime + (Time.GetMSTime() - _player.m_timeSyncServer);
// diff should be small
Log.outDebug(LogFilter.Network, "Our ticks: {0}, diff {1}, latency {2}", ourTicks, ourTicks - packet.ClientTime, GetLatency());
_player.m_timeSyncClient = packet.ClientTime;
_player.m_timeSyncQueue.Pop();
}
}
}
+52
View File
@@ -0,0 +1,52 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.Network;
using Game.Network.Packets;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.UpdateWowTokenAuctionableList)]
void HandleUpdateListedAuctionableTokens(UpdateListedAuctionableTokens updateListedAuctionableTokens)
{
UpdateListedAuctionableTokensResponse response = new UpdateListedAuctionableTokensResponse();
/// @todo: fix 6.x implementation
response.UnkInt = updateListedAuctionableTokens.UnkInt;
response.Result = TokenResult.Success;
SendPacket(response);
}
[WorldPacketHandler(ClientOpcodes.RequestWowTokenMarketPrice)]
void HandleRequestWowTokenMarketPrice(RequestWowTokenMarketPrice requestWowTokenMarketPrice)
{
WowTokenMarketPriceResponse response = new WowTokenMarketPriceResponse();
/// @todo: 6.x fix implementation
response.CurrentMarketPrice = 300000000;
response.UnkInt = requestWowTokenMarketPrice.UnkInt;
response.Result = TokenResult.Success;
//packet.ReadUInt32("UnkInt32");
SendPacket(response);
}
}
}
+96
View File
@@ -0,0 +1,96 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.Entities;
using Game.Network;
using Game.Network.Packets;
using Game.Spells;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.AddToy)]
void HandleAddToy(AddToy packet)
{
if (packet.Guid.IsEmpty())
return;
Item item = _player.GetItemByGuid(packet.Guid);
if (!item)
{
_player.SendEquipError(InventoryResult.ItemNotFound);
return;
}
if (!Global.DB2Mgr.IsToyItem(item.GetEntry()))
return;
InventoryResult msg = _player.CanUseItem(item);
if (msg != InventoryResult.Ok)
{
_player.SendEquipError(msg, item);
return;
}
if (_collectionMgr.AddToy(item.GetEntry(), false))
_player.DestroyItem(item.GetBagSlot(), item.GetSlot(), true);
}
[WorldPacketHandler(ClientOpcodes.UseToy)]
void HandleUseToy(UseToy packet)
{
ItemTemplate item = Global.ObjectMgr.GetItemTemplate(packet.ItemID);
if (item == null)
return;
if (!_collectionMgr.HasToy(packet.ItemID))
return;
var effect = item.Effects.Find(eff => { return packet.Cast.SpellID == eff.SpellID; });
if (effect == null)
return;
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(packet.Cast.SpellID);
if (spellInfo == null)
{
Log.outError(LogFilter.Network, "HandleUseToy: unknown spell id: {0} used by Toy Item entry {1}", packet.Cast.SpellID, packet.ItemID);
return;
}
if (_player.isPossessing())
return;
SpellCastTargets targets = new SpellCastTargets(_player, packet.Cast);
Spell spell = new Spell(_player, spellInfo, TriggerCastFlags.None, ObjectGuid.Empty, false);
SpellPrepare spellPrepare = new SpellPrepare();
spellPrepare.ClientCastID = packet.Cast.CastID;
spellPrepare.ServerCastID = spell.m_castId;
SendPacket(spellPrepare);
spell.m_fromClient = true;
spell.m_castItemEntry = packet.ItemID;
spell.m_misc.Data0 = packet.Cast.Misc[0];
spell.m_misc.Data1 = packet.Cast.Misc[1];
spell.m_castFlagsEx |= SpellCastFlagsEx.UseToySpell;
spell.prepare(targets);
}
}
}
+765
View File
@@ -0,0 +1,765 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Framework.Database;
using Game.Entities;
using Game.Network;
using Game.Network.Packets;
using Game.Spells;
using System.Collections.Generic;
namespace Game
{
public partial class WorldSession
{
public void SendTradeStatus(TradeStatusPkt info)
{
info.Clear(); // reuse packet
Player trader = GetPlayer().GetTrader();
info.PartnerIsSameBnetAccount = trader && trader.GetSession().GetBattlenetAccountId() == GetBattlenetAccountId();
SendPacket(info);
}
[WorldPacketHandler(ClientOpcodes.IgnoreTrade)]
void HandleIgnoreTradeOpcode(IgnoreTrade packet) { }
[WorldPacketHandler(ClientOpcodes.BusyTrade)]
void HandleBusyTradeOpcode(BusyTrade packet) { }
public void SendUpdateTrade(bool trader_data = true)
{
TradeData view_trade = trader_data ? GetPlayer().GetTradeData().GetTraderData() : GetPlayer().GetTradeData();
TradeUpdated tradeUpdated = new TradeUpdated();
tradeUpdated.WhichPlayer = (byte)(trader_data ? 1 : 0);
tradeUpdated.ClientStateIndex = view_trade.GetClientStateIndex();
tradeUpdated.CurrentStateIndex = view_trade.GetServerStateIndex();
tradeUpdated.Gold = view_trade.GetMoney();
tradeUpdated.ProposedEnchantment = (int)view_trade.GetSpell();
for (byte i = 0; i < (byte)TradeSlots.Count; ++i)
{
Item item = view_trade.GetItem((TradeSlots)i);
if (item)
{
TradeUpdated.TradeItem tradeItem = new TradeUpdated.TradeItem();
tradeItem.Slot = i;
tradeItem.Item = new ItemInstance(item);
tradeItem.StackCount = (int)item.GetCount();
tradeItem.GiftCreator = item.GetGuidValue(ItemFields.GiftCreator);
if (!item.HasFlag(ItemFields.Flags, ItemFieldFlags.Wrapped))
{
tradeItem.Unwrapped.HasValue = true;
TradeUpdated.UnwrappedTradeItem unwrappedItem = tradeItem.Unwrapped.Value;
unwrappedItem.EnchantID = (int)item.GetEnchantmentId(EnchantmentSlot.Perm);
unwrappedItem.OnUseEnchantmentID = (int)item.GetEnchantmentId(EnchantmentSlot.Use);
unwrappedItem.Creator = item.GetGuidValue(ItemFields.Creator);
unwrappedItem.Charges = item.GetSpellCharges();
unwrappedItem.Lock = item.GetTemplate().GetLockID() != 0 && !item.HasFlag(ItemFields.Flags, ItemFieldFlags.Unlocked);
unwrappedItem.MaxDurability = item.GetUInt32Value(ItemFields.MaxDurability);
unwrappedItem.Durability = item.GetUInt32Value(ItemFields.Durability);
byte g = 0;
foreach (ItemDynamicFieldGems gemData in item.GetGems())
{
if (gemData.ItemId != 0)
{
ItemGemData gem = new ItemGemData();
gem.Slot = g;
gem.Item = new ItemInstance(gemData);
tradeItem.Unwrapped.Value.Gems.Add(gem);
}
++g;
}
}
tradeUpdated.Items.Add(tradeItem);
}
}
SendPacket(tradeUpdated);
}
void moveItems(Item[] myItems, Item[] hisItems)
{
Player trader = GetPlayer().GetTrader();
if (!trader)
return;
for (byte i = 0; i < (int)TradeSlots.TradedCount; ++i)
{
List<ItemPosCount> traderDst = new List<ItemPosCount>();
List<ItemPosCount> playerDst = new List<ItemPosCount>();
bool traderCanTrade = (myItems[i] == null || trader.CanStoreItem(ItemConst.NullBag, ItemConst.NullSlot, traderDst, myItems[i], false) == InventoryResult.Ok);
bool playerCanTrade = (hisItems[i] == null || GetPlayer().CanStoreItem(ItemConst.NullBag, ItemConst.NullSlot, playerDst, hisItems[i], false) == InventoryResult.Ok);
if (traderCanTrade && playerCanTrade)
{
// Ok, if trade item exists and can be stored
// If we trade in both directions we had to check, if the trade will work before we actually do it
// A roll back is not possible after we stored it
if (myItems[i])
{
// logging
Log.outDebug(LogFilter.Network, "partner storing: {0}", myItems[i].GetGUID().ToString());
if (HasPermission(RBACPermissions.LogGmTrade))
{
Log.outCommand(_player.GetSession().GetAccountId(), "GM {0} (Account: {1}) trade: {2} (Entry: {3} Count: {4}) to player: {5} (Account: {6})",
GetPlayer().GetName(), GetPlayer().GetSession().GetAccountId(), myItems[i].GetTemplate().GetName(), myItems[i].GetEntry(), myItems[i].GetCount(),
trader.GetName(), trader.GetSession().GetAccountId());
}
// adjust time (depends on /played)
if (myItems[i].HasFlag(ItemFields.Flags, ItemFieldFlags.BopTradeable))
myItems[i].SetUInt32Value(ItemFields.CreatePlayedTime, trader.GetTotalPlayedTime() - (GetPlayer().GetTotalPlayedTime() - myItems[i].GetUInt32Value(ItemFields.CreatePlayedTime)));
// store
trader.MoveItemToInventory(traderDst, myItems[i], true, true);
}
if (hisItems[i])
{
// logging
Log.outDebug(LogFilter.Network, "player storing: {0}", hisItems[i].GetGUID().ToString());
if (HasPermission(RBACPermissions.LogGmTrade))
{
Log.outCommand(trader.GetSession().GetAccountId(), "GM {0} (Account: {1}) trade: {2} (Entry: {3} Count: {4}) to player: {5} (Account: {6})",
trader.GetName(), trader.GetSession().GetAccountId(), hisItems[i].GetTemplate().GetName(), hisItems[i].GetEntry(), hisItems[i].GetCount(),
GetPlayer().GetName(), GetPlayer().GetSession().GetAccountId());
}
// adjust time (depends on /played)
if (hisItems[i].HasFlag(ItemFields.Flags, ItemFieldFlags.BopTradeable))
hisItems[i].SetUInt32Value(ItemFields.CreatePlayedTime, GetPlayer().GetTotalPlayedTime() - (trader.GetTotalPlayedTime() - hisItems[i].GetUInt32Value(ItemFields.CreatePlayedTime)));
// store
GetPlayer().MoveItemToInventory(playerDst, hisItems[i], true, true);
}
}
else
{
// in case of fatal error log error message
// return the already removed items to the original owner
if (myItems[i])
{
if (!traderCanTrade)
Log.outError(LogFilter.Network, "trader can't store item: {0}", myItems[i].GetGUID().ToString());
if (GetPlayer().CanStoreItem(ItemConst.NullBag, ItemConst.NullSlot, playerDst, myItems[i], false) == InventoryResult.Ok)
GetPlayer().MoveItemToInventory(playerDst, myItems[i], true, true);
else
Log.outError(LogFilter.Network, "player can't take item back: {0}", myItems[i].GetGUID().ToString());
}
// return the already removed items to the original owner
if (hisItems[i])
{
if (!playerCanTrade)
Log.outError(LogFilter.Network, "player can't store item: {0}", hisItems[i].GetGUID().ToString());
if (trader.CanStoreItem(ItemConst.NullBag, ItemConst.NullSlot, traderDst, hisItems[i], false) == InventoryResult.Ok)
trader.MoveItemToInventory(traderDst, hisItems[i], true, true);
else
Log.outError(LogFilter.Network, "trader can't take item back: {0}", hisItems[i].GetGUID().ToString());
}
}
}
}
static void setAcceptTradeMode(TradeData myTrade, TradeData hisTrade, Item[] myItems, Item[] hisItems)
{
myTrade.SetInAcceptProcess(true);
hisTrade.SetInAcceptProcess(true);
// store items in local list and set 'in-trade' flag
for (byte i = 0; i < (int)TradeSlots.Count; ++i)
{
Item item = myTrade.GetItem((TradeSlots)i);
if (item)
{
Log.outDebug(LogFilter.Network, "player trade item {0} bag: {1} slot: {2}", item.GetGUID().ToString(), item.GetBagSlot(), item.GetSlot());
//Can return null
myItems[i] = item;
myItems[i].SetInTrade();
}
item = hisTrade.GetItem((TradeSlots)i);
if (item)
{
Log.outDebug(LogFilter.Network, "partner trade item {0} bag: {1} slot: {2}", item.GetGUID().ToString(), item.GetBagSlot(), item.GetSlot());
hisItems[i] = item;
hisItems[i].SetInTrade();
}
}
}
static void clearAcceptTradeMode(TradeData myTrade, TradeData hisTrade)
{
myTrade.SetInAcceptProcess(false);
hisTrade.SetInAcceptProcess(false);
}
static void clearAcceptTradeMode(Item[] myItems, Item[] hisItems)
{
// clear 'in-trade' flag
for (byte i = 0; i < (int)TradeSlots.Count; ++i)
{
if (myItems[i])
myItems[i].SetInTrade(false);
if (hisItems[i])
hisItems[i].SetInTrade(false);
}
}
[WorldPacketHandler(ClientOpcodes.AcceptTrade)]
void HandleAcceptTrade(AcceptTrade acceptTrade)
{
TradeData my_trade = GetPlayer().GetTradeData();
if (my_trade == null)
return;
Player trader = my_trade.GetTrader();
TradeData his_trade = trader.GetTradeData();
if (his_trade == null)
return;
Item[] myItems = new Item[(int)TradeSlots.Count];
Item[] hisItems = new Item[(int)TradeSlots.Count];
// set before checks for propertly undo at problems (it already set in to client)
my_trade.SetAccepted(true);
TradeStatusPkt info = new TradeStatusPkt();
if (his_trade.GetServerStateIndex() != acceptTrade.StateIndex)
{
info.Status = TradeStatus.StateChanged;
SendTradeStatus(info);
my_trade.SetAccepted(false);
return;
}
if (!GetPlayer().IsWithinDistInMap(trader, 11.11f, false))
{
info.Status = TradeStatus.TooFarAway;
SendTradeStatus(info);
my_trade.SetAccepted(false);
return;
}
// not accept case incorrect money amount
if (!GetPlayer().HasEnoughMoney(my_trade.GetMoney()))
{
info.Status = TradeStatus.Failed;
info.BagResult = InventoryResult.NotEnoughMoney;
SendTradeStatus(info);
my_trade.SetAccepted(false, true);
return;
}
// not accept case incorrect money amount
if (!trader.HasEnoughMoney(his_trade.GetMoney()))
{
info.Status = TradeStatus.Failed;
info.BagResult = InventoryResult.NotEnoughMoney;
trader.GetSession().SendTradeStatus(info);
his_trade.SetAccepted(false, true);
return;
}
if (GetPlayer().GetMoney() >= PlayerConst.MaxMoneyAmount - his_trade.GetMoney())
{
info.Status = TradeStatus.Failed;
info.BagResult = InventoryResult.TooMuchGold;
SendTradeStatus(info);
my_trade.SetAccepted(false, true);
return;
}
if (trader.GetMoney() >= PlayerConst.MaxMoneyAmount - my_trade.GetMoney())
{
info.Status = TradeStatus.Failed;
info.BagResult = InventoryResult.TooMuchGold;
trader.GetSession().SendTradeStatus(info);
his_trade.SetAccepted(false, true);
return;
}
// not accept if some items now can't be trade (cheating)
for (byte i = 0; i < (byte)TradeSlots.Count; ++i)
{
Item item = my_trade.GetItem((TradeSlots)i);
if (item)
{
if (!item.CanBeTraded(false, true))
{
info.Status = TradeStatus.Cancelled;
SendTradeStatus(info);
return;
}
if (item.IsBindedNotWith(trader))
{
info.Status = TradeStatus.Failed;
info.BagResult = InventoryResult.TradeBoundItem;
SendTradeStatus(info);
return;
}
}
item = his_trade.GetItem((TradeSlots)i);
if (item)
{
if (!item.CanBeTraded(false, true))
{
info.Status = TradeStatus.Cancelled;
SendTradeStatus(info);
return;
}
}
}
if (his_trade.IsAccepted())
{
setAcceptTradeMode(my_trade, his_trade, myItems, hisItems);
Spell my_spell = null;
SpellCastTargets my_targets = new SpellCastTargets();
Spell his_spell = null;
SpellCastTargets his_targets = new SpellCastTargets();
// not accept if spell can't be casted now (cheating)
uint my_spell_id = my_trade.GetSpell();
if (my_spell_id != 0)
{
SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(my_spell_id);
Item castItem = my_trade.GetSpellCastItem();
if (spellEntry == null || !his_trade.GetItem(TradeSlots.NonTraded) ||
(my_trade.HasSpellCastItem() && !castItem))
{
clearAcceptTradeMode(my_trade, his_trade);
clearAcceptTradeMode(myItems, hisItems);
my_trade.SetSpell(0);
return;
}
my_spell = new Spell(GetPlayer(), spellEntry, TriggerCastFlags.FullMask);
my_spell.m_CastItem = castItem;
my_targets.SetTradeItemTarget(GetPlayer());
my_spell.m_targets = my_targets;
SpellCastResult res = my_spell.CheckCast(true);
if (res != SpellCastResult.SpellCastOk)
{
my_spell.SendCastResult(res);
clearAcceptTradeMode(my_trade, his_trade);
clearAcceptTradeMode(myItems, hisItems);
my_spell.Dispose();
my_trade.SetSpell(0);
return;
}
}
// not accept if spell can't be casted now (cheating)
uint his_spell_id = his_trade.GetSpell();
if (his_spell_id != 0)
{
SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(his_spell_id);
Item castItem = his_trade.GetSpellCastItem();
if (spellEntry == null || !my_trade.GetItem(TradeSlots.NonTraded) || (his_trade.HasSpellCastItem() && !castItem))
{
his_trade.SetSpell(0);
clearAcceptTradeMode(my_trade, his_trade);
clearAcceptTradeMode(myItems, hisItems);
return;
}
his_spell = new Spell(trader, spellEntry, TriggerCastFlags.FullMask);
his_spell.m_CastItem = castItem;
his_targets.SetTradeItemTarget(trader);
his_spell.m_targets = his_targets;
SpellCastResult res = his_spell.CheckCast(true);
if (res != SpellCastResult.SpellCastOk)
{
his_spell.SendCastResult(res);
clearAcceptTradeMode(my_trade, his_trade);
clearAcceptTradeMode(myItems, hisItems);
my_spell.Dispose();
his_spell.Dispose();
his_trade.SetSpell(0);
return;
}
}
// inform partner client
info.Status = TradeStatus.Accepted;
trader.GetSession().SendTradeStatus(info);
// test if item will fit in each inventory
TradeStatusPkt myCanCompleteInfo = new TradeStatusPkt();
TradeStatusPkt hisCanCompleteInfo = new TradeStatusPkt();
hisCanCompleteInfo.BagResult = trader.CanStoreItems(myItems, (int)TradeSlots.TradedCount, ref hisCanCompleteInfo.ItemID);
myCanCompleteInfo.BagResult = GetPlayer().CanStoreItems(hisItems, (int)TradeSlots.TradedCount, ref myCanCompleteInfo.ItemID);
clearAcceptTradeMode(myItems, hisItems);
// in case of missing space report error
if (myCanCompleteInfo.BagResult != InventoryResult.Ok)
{
clearAcceptTradeMode(my_trade, his_trade);
myCanCompleteInfo.Status = TradeStatus.Failed;
trader.GetSession().SendTradeStatus(myCanCompleteInfo);
myCanCompleteInfo.FailureForYou = true;
SendTradeStatus(myCanCompleteInfo);
my_trade.SetAccepted(false);
his_trade.SetAccepted(false);
return;
}
else if (hisCanCompleteInfo.BagResult != InventoryResult.Ok)
{
clearAcceptTradeMode(my_trade, his_trade);
hisCanCompleteInfo.Status = TradeStatus.Failed;
SendTradeStatus(hisCanCompleteInfo);
hisCanCompleteInfo.FailureForYou = true;
trader.GetSession().SendTradeStatus(hisCanCompleteInfo);
my_trade.SetAccepted(false);
his_trade.SetAccepted(false);
return;
}
// execute trade: 1. remove
for (byte i = 0; i < (int)TradeSlots.TradedCount; ++i)
{
if (myItems[i])
{
myItems[i].SetGuidValue(ItemFields.GiftCreator, GetPlayer().GetGUID());
GetPlayer().MoveItemFromInventory(myItems[i].GetBagSlot(), myItems[i].GetSlot(), true);
}
if (hisItems[i])
{
hisItems[i].SetGuidValue(ItemFields.GiftCreator, trader.GetGUID());
trader.MoveItemFromInventory(hisItems[i].GetBagSlot(), hisItems[i].GetSlot(), true);
}
}
// execute trade: 2. store
moveItems(myItems, hisItems);
// logging money
if (HasPermission(RBACPermissions.LogGmTrade))
{
if (my_trade.GetMoney() > 0)
{
Log.outCommand(GetPlayer().GetSession().GetAccountId(), "GM {0} (Account: {1}) give money (Amount: {2}) to player: {3} (Account: {4})",
GetPlayer().GetName(), GetPlayer().GetSession().GetAccountId(), my_trade.GetMoney(), trader.GetName(), trader.GetSession().GetAccountId());
}
if (his_trade.GetMoney() > 0)
{
Log.outCommand(GetPlayer().GetSession().GetAccountId(), "GM {0} (Account: {1}) give money (Amount: {2}) to player: {3} (Account: {4})",
trader.GetName(), trader.GetSession().GetAccountId(), his_trade.GetMoney(), GetPlayer().GetName(), GetPlayer().GetSession().GetAccountId());
}
}
// update money
GetPlayer().ModifyMoney(-(long)my_trade.GetMoney());
GetPlayer().ModifyMoney((long)his_trade.GetMoney());
trader.ModifyMoney(-(long)his_trade.GetMoney());
trader.ModifyMoney((long)my_trade.GetMoney());
if (my_spell)
my_spell.prepare(my_targets);
if (his_spell)
his_spell.prepare(his_targets);
// cleanup
clearAcceptTradeMode(my_trade, his_trade);
GetPlayer().SetTradeData(null);
trader.SetTradeData(null);
// desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards)
SQLTransaction trans = new SQLTransaction();
GetPlayer().SaveInventoryAndGoldToDB(trans);
trader.SaveInventoryAndGoldToDB(trans);
DB.Characters.CommitTransaction(trans);
info.Status = TradeStatus.Complete;
trader.GetSession().SendTradeStatus(info);
SendTradeStatus(info);
}
else
{
info.Status = TradeStatus.Accepted;
trader.GetSession().SendTradeStatus(info);
}
}
[WorldPacketHandler(ClientOpcodes.UnacceptTrade)]
void HandleUnacceptTrade(UnacceptTrade packet)
{
TradeData my_trade = GetPlayer().GetTradeData();
if (my_trade == null)
return;
my_trade.SetAccepted(false, true);
}
[WorldPacketHandler(ClientOpcodes.BeginTrade)]
void HandleBeginTrade(BeginTrade packet)
{
TradeData my_trade = GetPlayer().GetTradeData();
if (my_trade == null)
return;
TradeStatusPkt info = new TradeStatusPkt();
my_trade.GetTrader().GetSession().SendTradeStatus(info);
SendTradeStatus(info);
}
public void SendCancelTrade()
{
if (PlayerRecentlyLoggedOut() || PlayerLogout())
return;
TradeStatusPkt info = new TradeStatusPkt();
info.Status = TradeStatus.Cancelled;
SendTradeStatus(info);
}
[WorldPacketHandler(ClientOpcodes.CancelTrade, Status = SessionStatus.LoggedinOrRecentlyLogout)]
void HandleCancelTrade(CancelTrade cancelTrade)
{
// sent also after LOGOUT COMPLETE
if (GetPlayer()) // needed because STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT
GetPlayer().TradeCancel(true);
}
[WorldPacketHandler(ClientOpcodes.InitiateTrade)]
void HandleInitiateTrade(InitiateTrade initiateTrade)
{
if (GetPlayer().GetTradeData() != null)
return;
TradeStatusPkt info = new TradeStatusPkt();
if (!GetPlayer().IsAlive())
{
info.Status = TradeStatus.Dead;
SendTradeStatus(info);
return;
}
if (GetPlayer().HasUnitState(UnitState.Stunned))
{
info.Status = TradeStatus.Stunned;
SendTradeStatus(info);
return;
}
if (isLogingOut())
{
info.Status = TradeStatus.LoggingOut;
SendTradeStatus(info);
return;
}
if (GetPlayer().IsInFlight())
{
info.Status = TradeStatus.TooFarAway;
SendTradeStatus(info);
return;
}
if (GetPlayer().getLevel() < WorldConfig.GetIntValue(WorldCfg.TradeLevelReq))
{
SendNotification(Global.ObjectMgr.GetCypherString(CypherStrings.TradeReq), WorldConfig.GetIntValue(WorldCfg.TradeLevelReq));
return;
}
Player pOther = Global.ObjAccessor.FindPlayer(initiateTrade.Guid);
if (!pOther)
{
info.Status = TradeStatus.NoTarget;
SendTradeStatus(info);
return;
}
if (pOther == GetPlayer() || pOther.GetTradeData() != null)
{
info.Status = TradeStatus.PlayerBusy;
SendTradeStatus(info);
return;
}
if (!pOther.IsAlive())
{
info.Status = TradeStatus.TargetDead;
SendTradeStatus(info);
return;
}
if (pOther.IsInFlight())
{
info.Status = TradeStatus.TooFarAway;
SendTradeStatus(info);
return;
}
if (pOther.HasUnitState(UnitState.Stunned))
{
info.Status = TradeStatus.TargetStunned;
SendTradeStatus(info);
return;
}
if (pOther.GetSession().isLogingOut())
{
info.Status = TradeStatus.TargetLoggingOut;
SendTradeStatus(info);
return;
}
if (pOther.GetSocial().HasIgnore(GetPlayer().GetGUID()))
{
info.Status = TradeStatus.PlayerIgnored;
SendTradeStatus(info);
return;
}
if ((pOther.GetTeam() != GetPlayer().GetTeam() ||
pOther.HasFlag(PlayerFields.FlagsEx, PlayerFlagsEx.MercenaryMode) ||
GetPlayer().HasFlag(PlayerFields.FlagsEx, PlayerFlagsEx.MercenaryMode)) &&
(!WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideTrade) &&
!HasPermission(RBACPermissions.AllowTwoSideTrade)))
{
info.Status = TradeStatus.WrongFaction;
SendTradeStatus(info);
return;
}
if (!pOther.IsWithinDistInMap(GetPlayer(), 11.11f, false))
{
info.Status = TradeStatus.TooFarAway;
SendTradeStatus(info);
return;
}
if (pOther.getLevel() < WorldConfig.GetIntValue(WorldCfg.TradeLevelReq))
{
SendNotification(Global.ObjectMgr.GetCypherString(CypherStrings.TradeOtherReq), WorldConfig.GetIntValue(WorldCfg.TradeLevelReq));
return;
}
// OK start trade
GetPlayer().SetTradeData(new TradeData(GetPlayer(), pOther));
pOther.SetTradeData(new TradeData(pOther, GetPlayer()));
info.Status = TradeStatus.Proposed;
info.Partner = GetPlayer().GetGUID();
pOther.GetSession().SendTradeStatus(info);
}
[WorldPacketHandler(ClientOpcodes.SetTradeGold)]
void HandleSetTradeGold(SetTradeGold setTradeGold)
{
TradeData my_trade = GetPlayer().GetTradeData();
if (my_trade == null)
return;
my_trade.UpdateClientStateIndex();
my_trade.SetMoney(setTradeGold.Coinage);
}
[WorldPacketHandler(ClientOpcodes.SetTradeItem)]
void HandleSetTradeItem(SetTradeItem setTradeItem)
{
TradeData my_trade = GetPlayer().GetTradeData();
if (my_trade == null)
return;
TradeStatusPkt info = new TradeStatusPkt();
// invalid slot number
if (setTradeItem.TradeSlot >= (byte)TradeSlots.Count)
{
info.Status = TradeStatus.Cancelled;
SendTradeStatus(info);
return;
}
// check cheating, can't fail with correct client operations
Item item = GetPlayer().GetItemByPos(setTradeItem.PackSlot, setTradeItem.ItemSlotInPack);
if (!item || (setTradeItem.TradeSlot != (byte)TradeSlots.NonTraded && !item.CanBeTraded(false, true)))
{
info.Status = TradeStatus.Cancelled;
SendTradeStatus(info);
return;
}
ObjectGuid iGUID = item.GetGUID();
// prevent place single item into many trade slots using cheating and client bugs
if (my_trade.HasItem(iGUID))
{
// cheating attempt
info.Status = TradeStatus.Cancelled;
SendTradeStatus(info);
return;
}
my_trade.UpdateClientStateIndex();
if (setTradeItem.TradeSlot != (byte)TradeSlots.NonTraded && item.IsBindedNotWith(my_trade.GetTrader()))
{
info.Status = TradeStatus.NotOnTaplist;
info.TradeSlot = setTradeItem.TradeSlot;
SendTradeStatus(info);
return;
}
my_trade.SetItem((TradeSlots)setTradeItem.TradeSlot, item);
}
[WorldPacketHandler(ClientOpcodes.ClearTradeItem)]
void HandleClearTradeItem(ClearTradeItem clearTradeItem)
{
TradeData my_trade = GetPlayer().GetTradeData();
if (my_trade == null)
return;
my_trade.UpdateClientStateIndex();
// invalid slot number
if (clearTradeItem.TradeSlot >= (byte)TradeSlots.Count)
return;
my_trade.SetItem((TradeSlots)clearTradeItem.TradeSlot, null);
}
[WorldPacketHandler(ClientOpcodes.SetTradeCurrency)]
void HandleSetTradeCurrency(SetTradeCurrency setTradeCurrency)
{
}
}
}
@@ -0,0 +1,295 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.DataStorage;
using Game.Entities;
using Game.Network;
using Game.Network.Packets;
using System;
using System.Collections.Generic;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.TransmogrifyItems)]
void HandleTransmogrifyItems(TransmogrifyItems transmogrifyItems)
{
Player player = GetPlayer();
// Validate
if (!player.GetNPCIfCanInteractWith(transmogrifyItems.Npc, NPCFlags.Transmogrifier))
{
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - Unit (GUID: {0}) not found or player can't interact with it.", transmogrifyItems.ToString());
return;
}
long cost = 0;
Dictionary<Item, uint> transmogItems = new Dictionary<Item, uint>();
Dictionary<Item, uint> illusionItems = new Dictionary<Item, uint>();
List<Item> resetAppearanceItems = new List<Item>();
List<Item> resetIllusionItems = new List<Item>();
List<uint> bindAppearances = new List<uint>();
foreach (TransmogrifyItem transmogItem in transmogrifyItems.Items)
{
// slot of the transmogrified item
if (transmogItem.Slot >= EquipmentSlot.End)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - Player ({0}, name: {1}) tried to transmogrify wrong slot {2} when transmogrifying items.", player.GetGUID().ToString(), player.GetName(), transmogItem.Slot);
return;
}
// transmogrified item
Item itemTransmogrified = player.GetItemByPos(InventorySlots.Bag0, (byte)transmogItem.Slot);
if (!itemTransmogrified)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - Player (GUID: {0}, name: {1}) tried to transmogrify an invalid item in a valid slot (slot: {2}).", player.GetGUID().ToString(), player.GetName(), transmogItem.Slot);
return;
}
if (transmogItem.ItemModifiedAppearanceID != 0)
{
ItemModifiedAppearanceRecord itemModifiedAppearance = CliDB.ItemModifiedAppearanceStorage.LookupByKey(transmogItem.ItemModifiedAppearanceID);
if (itemModifiedAppearance == null)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - {0}, Name: {1} tried to transmogrify using invalid appearance ({2}).", player.GetGUID().ToString(), player.GetName(), transmogItem.ItemModifiedAppearanceID);
return;
}
var pairValue = GetCollectionMgr().HasItemAppearance((uint)transmogItem.ItemModifiedAppearanceID);
if (!pairValue.Item1)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - {0}, Name: {1} tried to transmogrify using appearance he has not collected ({2}).", player.GetGUID().ToString(), player.GetName(), transmogItem.ItemModifiedAppearanceID);
return;
}
ItemTemplate itemTemplate = Global.ObjectMgr.GetItemTemplate(itemModifiedAppearance.ItemID);
if (player.CanUseItem(itemTemplate) != InventoryResult.Ok)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - {0}, Name: {1} tried to transmogrify using appearance he can never use ({2}).", player.GetGUID().ToString(), player.GetName(), transmogItem.ItemModifiedAppearanceID);
return;
}
// validity of the transmogrification items
if (!Item.CanTransmogrifyItemWithItem(itemTransmogrified, itemModifiedAppearance))
{
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - {0}, Name: {1} failed CanTransmogrifyItemWithItem ({2} with appearance {3}).", player.GetGUID().ToString(), player.GetName(), itemTransmogrified.GetEntry(), transmogItem.ItemModifiedAppearanceID);
return;
}
transmogItems[itemTransmogrified] = (uint)transmogItem.ItemModifiedAppearanceID;
if (pairValue.Item2)
bindAppearances.Add((uint)transmogItem.ItemModifiedAppearanceID);
// add cost
cost += itemTransmogrified.GetSpecialPrice();
}
else
resetAppearanceItems.Add(itemTransmogrified);
if (transmogItem.SpellItemEnchantmentID != 0)
{
if (transmogItem.Slot != EquipmentSlot.MainHand && transmogItem.Slot != EquipmentSlot.OffHand)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - {0}, Name: {1} tried to transmogrify illusion into non-weapon slot ({2}).", player.GetGUID().ToString(), player.GetName(), transmogItem.Slot);
return;
}
SpellItemEnchantmentRecord illusion = CliDB.SpellItemEnchantmentStorage.LookupByKey(transmogItem.SpellItemEnchantmentID);
if (illusion == null)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - {0}, Name: {1} tried to transmogrify illusion using invalid enchant ({2}).", player.GetGUID().ToString(), player.GetName(), transmogItem.SpellItemEnchantmentID);
return;
}
if (illusion.ItemVisual == 0 || !illusion.Flags.HasAnyFlag(EnchantmentSlotMask.Collectable))
{
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - {0}, Name: {1} tried to transmogrify illusion using not allowed enchant ({2}).", player.GetGUID().ToString(), player.GetName(), transmogItem.SpellItemEnchantmentID);
return;
}
PlayerConditionRecord condition = CliDB.PlayerConditionStorage.LookupByKey(illusion.PlayerConditionID);
if (condition != null)
{
if (!ConditionManager.IsPlayerMeetingCondition(player, condition))
{
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - {0}, Name: {1} tried to transmogrify illusion using not collected enchant ({2}).", player.GetGUID().ToString(), player.GetName(), transmogItem.SpellItemEnchantmentID);
return;
}
}
if (illusion.ScalingClassRestricted > 0 && illusion.ScalingClassRestricted != (byte)player.GetClass())
{
Log.outDebug(LogFilter.Network, "WORLD: HandleTransmogrifyItems - {0}, Name: {1} tried to transmogrify illusion using not allowed class enchant ({2}).", player.GetGUID().ToString(), player.GetName(), transmogItem.SpellItemEnchantmentID);
return;
}
illusionItems[itemTransmogrified] = (uint)transmogItem.SpellItemEnchantmentID;
cost += illusion.TransmogCost;
}
else
resetIllusionItems.Add(itemTransmogrified);
}
if (cost != 0) // 0 cost if reverting look
{
if (!player.HasEnoughMoney(cost))
return;
player.ModifyMoney(-cost);
}
// Everything is fine, proceed
foreach (var transmogPair in transmogItems)
{
Item transmogrified = transmogPair.Key;
if (!transmogrifyItems.CurrentSpecOnly)
{
transmogrified.SetModifier(ItemModifier.TransmogAppearanceAllSpecs, transmogPair.Value);
transmogrified.SetModifier(ItemModifier.TransmogAppearanceSpec1, 0);
transmogrified.SetModifier(ItemModifier.TransmogAppearanceSpec2, 0);
transmogrified.SetModifier(ItemModifier.TransmogAppearanceSpec3, 0);
transmogrified.SetModifier(ItemModifier.TransmogAppearanceSpec4, 0);
}
else
{
if (transmogrified.GetModifier(ItemModifier.TransmogAppearanceSpec1) == 0)
transmogrified.SetModifier(ItemModifier.TransmogAppearanceSpec1, transmogrified.GetModifier(ItemModifier.TransmogAppearanceAllSpecs));
if (transmogrified.GetModifier(ItemModifier.TransmogAppearanceSpec2) == 0)
transmogrified.SetModifier(ItemModifier.TransmogAppearanceSpec2, transmogrified.GetModifier(ItemModifier.TransmogAppearanceAllSpecs));
if (transmogrified.GetModifier(ItemModifier.TransmogAppearanceSpec3) == 0)
transmogrified.SetModifier(ItemModifier.TransmogAppearanceSpec3, transmogrified.GetModifier(ItemModifier.TransmogAppearanceAllSpecs));
if (transmogrified.GetModifier(ItemModifier.TransmogAppearanceSpec4) == 0)
transmogrified.SetModifier(ItemModifier.TransmogAppearanceSpec4, transmogrified.GetModifier(ItemModifier.TransmogAppearanceAllSpecs));
transmogrified.SetModifier(ItemConst.AppearanceModifierSlotBySpec[player.GetActiveTalentGroup()], transmogPair.Value);
}
player.SetVisibleItemSlot(transmogrified.GetSlot(), transmogrified);
transmogrified.SetNotRefundable(player);
transmogrified.ClearSoulboundTradeable(player);
transmogrified.SetState(ItemUpdateState.Changed, player);
}
foreach (var illusionPair in illusionItems)
{
Item transmogrified = illusionPair.Key;
if (!transmogrifyItems.CurrentSpecOnly)
{
transmogrified.SetModifier(ItemModifier.EnchantIllusionAllSpecs, illusionPair.Value);
transmogrified.SetModifier(ItemModifier.EnchantIllusionSpec1, 0);
transmogrified.SetModifier(ItemModifier.EnchantIllusionSpec2, 0);
transmogrified.SetModifier(ItemModifier.EnchantIllusionSpec3, 0);
transmogrified.SetModifier(ItemModifier.EnchantIllusionSpec4, 0);
}
else
{
if (transmogrified.GetModifier(ItemModifier.EnchantIllusionSpec1) == 0)
transmogrified.SetModifier(ItemModifier.EnchantIllusionSpec1, transmogrified.GetModifier(ItemModifier.EnchantIllusionAllSpecs));
if (transmogrified.GetModifier(ItemModifier.EnchantIllusionSpec2) == 0)
transmogrified.SetModifier(ItemModifier.EnchantIllusionSpec2, transmogrified.GetModifier(ItemModifier.EnchantIllusionAllSpecs));
if (transmogrified.GetModifier(ItemModifier.EnchantIllusionSpec3) == 0)
transmogrified.SetModifier(ItemModifier.EnchantIllusionSpec3, transmogrified.GetModifier(ItemModifier.EnchantIllusionAllSpecs));
if (transmogrified.GetModifier(ItemModifier.EnchantIllusionSpec4) == 0)
transmogrified.SetModifier(ItemModifier.EnchantIllusionSpec4, transmogrified.GetModifier(ItemModifier.EnchantIllusionAllSpecs));
transmogrified.SetModifier(ItemConst.IllusionModifierSlotBySpec[player.GetActiveTalentGroup()], illusionPair.Value);
}
player.SetVisibleItemSlot(transmogrified.GetSlot(), transmogrified);
transmogrified.SetNotRefundable(player);
transmogrified.ClearSoulboundTradeable(player);
transmogrified.SetState(ItemUpdateState.Changed, player);
}
foreach (Item item in resetAppearanceItems)
{
if (!transmogrifyItems.CurrentSpecOnly)
{
item.SetModifier(ItemModifier.TransmogAppearanceAllSpecs, 0);
item.SetModifier(ItemModifier.TransmogAppearanceSpec1, 0);
item.SetModifier(ItemModifier.TransmogAppearanceSpec2, 0);
item.SetModifier(ItemModifier.TransmogAppearanceSpec3, 0);
item.SetModifier(ItemModifier.TransmogAppearanceSpec4, 0);
}
else
{
if (item.GetModifier(ItemModifier.TransmogAppearanceSpec1) == 0)
item.SetModifier(ItemModifier.TransmogAppearanceSpec1, item.GetModifier(ItemModifier.TransmogAppearanceAllSpecs));
if (item.GetModifier(ItemModifier.TransmogAppearanceSpec2) == 0)
item.SetModifier(ItemModifier.TransmogAppearanceSpec2, item.GetModifier(ItemModifier.TransmogAppearanceAllSpecs));
if (item.GetModifier(ItemModifier.TransmogAppearanceSpec2) == 0)
item.SetModifier(ItemModifier.TransmogAppearanceSpec3, item.GetModifier(ItemModifier.TransmogAppearanceAllSpecs));
if (item.GetModifier(ItemModifier.TransmogAppearanceSpec4) == 0)
item.SetModifier(ItemModifier.TransmogAppearanceSpec4, item.GetModifier(ItemModifier.TransmogAppearanceAllSpecs));
item.SetModifier(ItemConst.AppearanceModifierSlotBySpec[player.GetActiveTalentGroup()], 0);
item.SetModifier(ItemModifier.EnchantIllusionAllSpecs, 0);
}
item.SetState(ItemUpdateState.Changed, player);
player.SetVisibleItemSlot(item.GetSlot(), item);
}
foreach (Item item in resetIllusionItems)
{
if (!transmogrifyItems.CurrentSpecOnly)
{
item.SetModifier(ItemModifier.EnchantIllusionAllSpecs, 0);
item.SetModifier(ItemModifier.EnchantIllusionSpec1, 0);
item.SetModifier(ItemModifier.EnchantIllusionSpec2, 0);
item.SetModifier(ItemModifier.EnchantIllusionSpec3, 0);
item.SetModifier(ItemModifier.EnchantIllusionSpec4, 0);
}
else
{
if (item.GetModifier(ItemModifier.EnchantIllusionSpec1) == 0)
item.SetModifier(ItemModifier.EnchantIllusionSpec1, item.GetModifier(ItemModifier.EnchantIllusionAllSpecs));
if (item.GetModifier(ItemModifier.EnchantIllusionSpec2) == 0)
item.SetModifier(ItemModifier.EnchantIllusionSpec2, item.GetModifier(ItemModifier.EnchantIllusionAllSpecs));
if (item.GetModifier(ItemModifier.EnchantIllusionSpec3) == 0)
item.SetModifier(ItemModifier.EnchantIllusionSpec3, item.GetModifier(ItemModifier.EnchantIllusionAllSpecs));
if (item.GetModifier(ItemModifier.EnchantIllusionSpec4) == 0)
item.SetModifier(ItemModifier.EnchantIllusionSpec4, item.GetModifier(ItemModifier.EnchantIllusionAllSpecs));
item.SetModifier(ItemConst.IllusionModifierSlotBySpec[player.GetActiveTalentGroup()], 0);
item.SetModifier(ItemModifier.TransmogAppearanceAllSpecs, 0);
}
item.SetState(ItemUpdateState.Changed, player);
player.SetVisibleItemSlot(item.GetSlot(), item);
}
foreach (uint itemModifedAppearanceId in bindAppearances)
{
var itemsProvidingAppearance = GetCollectionMgr().GetItemsProvidingTemporaryAppearance(itemModifedAppearanceId);
foreach (ObjectGuid itemGuid in itemsProvidingAppearance)
{
Item item = player.GetItemByGuid(itemGuid);
if (item)
{
item.SetNotRefundable(player);
item.ClearSoulboundTradeable(player);
GetCollectionMgr().AddItemAppearance(item);
}
}
}
}
}
}
+216
View File
@@ -0,0 +1,216 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.DataStorage;
using Game.Entities;
using Game.Network;
using Game.Network.Packets;
using System.Diagnostics.Contracts;
namespace Game
{
public partial class WorldSession
{
[WorldPacketHandler(ClientOpcodes.MoveDismissVehicle)]
void HandleMoveDismissVehicle(MoveDismissVehicle packet)
{
ObjectGuid vehicleGUID = GetPlayer().GetCharmGUID();
if (vehicleGUID.IsEmpty()) // something wrong here...
return;
GetPlayer().ValidateMovementInfo(packet.Status);
GetPlayer().m_movementInfo = packet.Status;
GetPlayer().ExitVehicle();
}
[WorldPacketHandler(ClientOpcodes.RequestVehiclePrevSeat)]
void HandleRequestVehiclePrevSeat(RequestVehiclePrevSeat packet)
{
Unit vehicle_base = GetPlayer().GetVehicleBase();
if (!vehicle_base)
return;
VehicleSeatRecord seat = GetPlayer().GetVehicle().GetSeatForPassenger(GetPlayer());
if (!seat.CanSwitchFromSeat())
{
Log.outError(LogFilter.Network, "HandleRequestVehiclePrevSeat: {0} tried to switch seats but current seatflags {1} don't permit that.",
GetPlayer().GetGUID().ToString(), seat.Flags[0]);
return;
}
GetPlayer().ChangeSeat(-1, false);
}
[WorldPacketHandler(ClientOpcodes.RequestVehicleNextSeat)]
void HandleRequestVehicleNextSeat(RequestVehicleNextSeat packet)
{
Unit vehicle_base = GetPlayer().GetVehicleBase();
if (!vehicle_base)
return;
VehicleSeatRecord seat = GetPlayer().GetVehicle().GetSeatForPassenger(GetPlayer());
if (!seat.CanSwitchFromSeat())
{
Log.outError(LogFilter.Network, "HandleRequestVehicleNextSeat: {0} tried to switch seats but current seatflags {1} don't permit that.",
GetPlayer().GetGUID().ToString(), seat.Flags[0]);
return;
}
GetPlayer().ChangeSeat(-1, true);
}
[WorldPacketHandler(ClientOpcodes.MoveChangeVehicleSeats)]
void HandleMoveChangeVehicleSeats(MoveChangeVehicleSeats packet)
{
Unit vehicle_base = GetPlayer().GetVehicleBase();
if (!vehicle_base)
return;
VehicleSeatRecord seat = GetPlayer().GetVehicle().GetSeatForPassenger(GetPlayer());
if (!seat.CanSwitchFromSeat())
{
Log.outError(LogFilter.Network, "HandleMoveChangeVehicleSeats, {0} tried to switch seats but current seatflags {1} don't permit that.",
GetPlayer().GetGUID().ToString(), seat.Flags[0]);
return;
}
GetPlayer().ValidateMovementInfo(packet.Status);
if (vehicle_base.GetGUID() != packet.Status.Guid)
return;
vehicle_base.m_movementInfo = packet.Status;
Unit vehUnit;
if (packet.DstVehicle.IsEmpty())
GetPlayer().ChangeSeat(-1, packet.DstSeatIndex != 255);
else if (vehUnit = Global.ObjAccessor.GetUnit(GetPlayer(), packet.DstVehicle))
{
Vehicle vehicle = vehUnit.GetVehicleKit();
if (vehicle)
if (vehicle.HasEmptySeat((sbyte)packet.DstSeatIndex))
vehUnit.HandleSpellClick(GetPlayer(), (sbyte)packet.DstSeatIndex);
}
}
[WorldPacketHandler(ClientOpcodes.RequestVehicleSwitchSeat)]
void HandleRequestVehicleSwitchSeat(RequestVehicleSwitchSeat packet)
{
Unit vehicle_base = GetPlayer().GetVehicleBase();
if (!vehicle_base)
return;
VehicleSeatRecord seat = GetPlayer().GetVehicle().GetSeatForPassenger(GetPlayer());
if (!seat.CanSwitchFromSeat())
{
Log.outError(LogFilter.Network, "HandleRequestVehicleSwitchSeat: {0} tried to switch seats but current seatflags {1} don't permit that.",
GetPlayer().GetGUID().ToString(), seat.Flags[0]);
return;
}
Unit vehUnit;
if (vehicle_base.GetGUID() == packet.Vehicle)
GetPlayer().ChangeSeat((sbyte)packet.SeatIndex);
else if (vehUnit = Global.ObjAccessor.GetUnit(GetPlayer(), packet.Vehicle))
{
Vehicle vehicle = vehUnit.GetVehicleKit();
if (vehicle)
if (vehicle.HasEmptySeat((sbyte)packet.SeatIndex))
vehUnit.HandleSpellClick(GetPlayer(), (sbyte)packet.SeatIndex);
}
}
[WorldPacketHandler(ClientOpcodes.RideVehicleInteract)]
void HandleRideVehicleInteract(RideVehicleInteract packet)
{
Player player = Global.ObjAccessor.FindPlayer(packet.Vehicle);
if (player)
{
if (!player.GetVehicleKit())
return;
if (!player.IsInRaidWith(GetPlayer()))
return;
if (!player.IsWithinDistInMap(GetPlayer(), SharedConst.InteractionDistance))
return;
GetPlayer().EnterVehicle(player);
}
}
[WorldPacketHandler(ClientOpcodes.EjectPassenger)]
void HandleEjectPassenger(EjectPassenger packet)
{
Vehicle vehicle = GetPlayer().GetVehicleKit();
if (!vehicle)
{
Log.outError(LogFilter.Network, "HandleEjectPassenger: {0} is not in a vehicle!", GetPlayer().GetGUID().ToString());
return;
}
if (packet.Passenger.IsUnit())
{
Unit unit = Global.ObjAccessor.GetUnit(GetPlayer(), packet.Passenger);
if (!unit)
{
Log.outError(LogFilter.Network, "{0} tried to eject {1} from vehicle, but the latter was not found in world!", GetPlayer().GetGUID().ToString(), packet.Passenger.ToString());
return;
}
if (!unit.IsOnVehicle(vehicle.GetBase()))
{
Log.outError(LogFilter.Network, "{0} tried to eject {1}, but they are not in the same vehicle", GetPlayer().GetGUID().ToString(), packet.Passenger.ToString());
return;
}
VehicleSeatRecord seat = vehicle.GetSeatForPassenger(unit);
Contract.Assert(seat != null);
if (seat.IsEjectable())
unit.ExitVehicle();
else
Log.outError(LogFilter.Network, "{0} attempted to eject {1} from non-ejectable seat.", GetPlayer().GetGUID().ToString(), packet.Passenger.ToString());
}
else
Log.outError(LogFilter.Network, "HandleEjectPassenger: {0} tried to eject invalid {1}", GetPlayer().GetGUID().ToString(), packet.Passenger.ToString());
}
[WorldPacketHandler(ClientOpcodes.RequestVehicleExit)]
void HandleRequestVehicleExit(RequestVehicleExit packet)
{
Vehicle vehicle = GetPlayer().GetVehicle();
if (vehicle)
{
VehicleSeatRecord seat = vehicle.GetSeatForPassenger(GetPlayer());
if (seat != null)
{
if (seat.CanEnterOrExit())
GetPlayer().ExitVehicle();
else
Log.outError(LogFilter.Network, "{0} tried to exit vehicle, but seatflags {1} (ID: {2}) don't permit that.",
GetPlayer().GetGUID().ToString(), seat.Id, seat.Flags[0]);
}
}
}
[WorldPacketHandler(ClientOpcodes.MoveSetVehicleRecIdAck)]
void HandleMoveSetVehicleRecAck(MoveSetVehicleRecIdAck setVehicleRecIdAck)
{
GetPlayer().ValidateMovementInfo(setVehicleRecIdAck.Data.Status);
}
}
}
+266
View File
@@ -0,0 +1,266 @@
/*
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
*
* 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 3 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/>.
*/
using Framework.Constants;
using Game.Entities;
using Game.Network;
using Game.Network.Packets;
using System.Collections.Generic;
namespace Game
{
public partial class WorldSession
{
public void SendVoidStorageTransferResult(VoidTransferError result)
{
SendPacket(new VoidTransferResult(result));
}
[WorldPacketHandler(ClientOpcodes.UnlockVoidStorage)]
void HandleVoidStorageUnlock(UnlockVoidStorage unlockVoidStorage)
{
Creature unit = GetPlayer().GetNPCIfCanInteractWith(unlockVoidStorage.Npc, NPCFlags.VaultKeeper);
if (!unit)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidStorageUnlock - {0} not found or player can't interact with it.", unlockVoidStorage.Npc.ToString());
return;
}
if (GetPlayer().IsVoidStorageUnlocked())
{
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidStorageUnlock - Player({0}, name: {1}) tried to unlock void storage a 2nd time.", GetPlayer().GetGUID().ToString(), GetPlayer().GetName());
return;
}
GetPlayer().ModifyMoney(-SharedConst.VoidStorageUnlockCost);
GetPlayer().UnlockVoidStorage();
}
[WorldPacketHandler(ClientOpcodes.QueryVoidStorage)]
void HandleVoidStorageQuery(QueryVoidStorage queryVoidStorage)
{
Player player = GetPlayer();
Creature unit = player.GetNPCIfCanInteractWith(queryVoidStorage.Npc, NPCFlags.Transmogrifier | NPCFlags.VaultKeeper);
if (!unit)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidStorageQuery - {0} not found or player can't interact with it.", queryVoidStorage.Npc.ToString());
SendPacket(new VoidStorageFailed());
return;
}
if (!GetPlayer().IsVoidStorageUnlocked())
{
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidStorageQuery - {0} name: {1} queried void storage without unlocking it.", player.GetGUID().ToString(), player.GetName());
SendPacket(new VoidStorageFailed());
return;
}
byte count = 0;
for (byte i = 0; i < SharedConst.VoidStorageMaxSlot; ++i)
if (player.GetVoidStorageItem(i) != null)
++count;
VoidStorageContents voidStorageContents = new VoidStorageContents();
for (byte i = 0; i < SharedConst.VoidStorageMaxSlot; ++i)
{
VoidStorageItem item = player.GetVoidStorageItem(i);
if (item == null)
continue;
VoidItem voidItem = new VoidItem();
voidItem.Guid = ObjectGuid.Create(HighGuid.Item, item.ItemId);
voidItem.Creator = item.CreatorGuid;
voidItem.Slot = i;
voidItem.Item = new ItemInstance(item);
voidStorageContents.Items.Add(voidItem);
}
SendPacket(voidStorageContents);
}
[WorldPacketHandler(ClientOpcodes.VoidStorageTransfer)]
void HandleVoidStorageTransfer(VoidStorageTransfer voidStorageTransfer)
{
Player player = GetPlayer();
Creature unit = player.GetNPCIfCanInteractWith(voidStorageTransfer.Npc, NPCFlags.VaultKeeper);
if (!unit)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidStorageTransfer - {0} not found or player can't interact with it.", voidStorageTransfer.Npc.ToString());
return;
}
if (!player.IsVoidStorageUnlocked())
{
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidStorageTransfer - Player ({0}, name: {1}) queried void storage without unlocking it.", player.GetGUID().ToString(), player.GetName());
return;
}
if (voidStorageTransfer.Deposits.Length > player.GetNumOfVoidStorageFreeSlots())
{
SendVoidStorageTransferResult(VoidTransferError.Full);
return;
}
uint freeBagSlots = 0;
if (!voidStorageTransfer.Withdrawals.Empty())
{
// make this a Player function
for (byte i = InventorySlots.BagStart; i < InventorySlots.BagEnd; i++)
{
Bag bag = player.GetBagByPos(i);
if (bag)
freeBagSlots += bag.GetFreeSlots();
}
for (byte i = InventorySlots.ItemStart; i < InventorySlots.ItemEnd; i++)
{
if (!player.GetItemByPos(InventorySlots.Bag0, i))
++freeBagSlots;
}
}
if (voidStorageTransfer.Withdrawals.Length > freeBagSlots)
{
SendVoidStorageTransferResult(VoidTransferError.InventoryFull);
return;
}
if (!player.HasEnoughMoney((voidStorageTransfer.Deposits.Length * SharedConst.VoidStorageStoreItemCost)))
{
SendVoidStorageTransferResult(VoidTransferError.NotEnoughMoney);
return;
}
VoidStorageTransferChanges voidStorageTransferChanges = new VoidStorageTransferChanges();
byte depositCount = 0;
for (int i = 0; i < voidStorageTransfer.Deposits.Length; ++i)
{
Item item = player.GetItemByGuid(voidStorageTransfer.Deposits[i]);
if (!item)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidStorageTransfer - {0} {1} wants to deposit an invalid item ({2}).", player.GetGUID().ToString(), player.GetName(), voidStorageTransfer.Deposits[i].ToString());
continue;
}
VoidStorageItem itemVS = new VoidStorageItem(Global.ObjectMgr.GenerateVoidStorageItemId(), item.GetEntry(), item.GetGuidValue(ItemFields.Creator),
item.GetItemRandomEnchantmentId(), item.GetItemSuffixFactor(), item.GetModifier(ItemModifier.UpgradeId),
item.GetModifier(ItemModifier.ScalingStatDistributionFixedLevel), item.GetModifier(ItemModifier.ArtifactKnowledgeLevel),
(byte)item.GetUInt32Value(ItemFields.Context), item.GetDynamicValues(ItemDynamicFields.BonusListIds));
VoidItem voidItem;
voidItem.Guid = ObjectGuid.Create(HighGuid.Item, itemVS.ItemId);
voidItem.Creator = item.GetGuidValue(ItemFields.Creator);
voidItem.Item = new ItemInstance(itemVS);
voidItem.Slot = _player.AddVoidStorageItem(itemVS);
voidStorageTransferChanges.AddedItems.Add(voidItem);
player.DestroyItem(item.GetBagSlot(), item.GetSlot(), true);
++depositCount;
}
long cost = depositCount * SharedConst.VoidStorageStoreItemCost;
player.ModifyMoney(-cost);
for (int i = 0; i < voidStorageTransfer.Withdrawals.Length; ++i)
{
byte slot;
VoidStorageItem itemVS = player.GetVoidStorageItem(voidStorageTransfer.Withdrawals[i].GetCounter(), out slot);
if (itemVS == null)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidStorageTransfer - {0} {1} tried to withdraw an invalid item ({2})", player.GetGUID().ToString(), player.GetName(), voidStorageTransfer.Withdrawals[i].ToString());
continue;
}
List<ItemPosCount> dest = new List<ItemPosCount>();
InventoryResult msg = player.CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, itemVS.ItemEntry, 1);
if (msg != InventoryResult.Ok)
{
SendVoidStorageTransferResult(VoidTransferError.InventoryFull);
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidStorageTransfer - {0} {1} couldn't withdraw {2} because inventory was full.", player.GetGUID().ToString(), player.GetName(), voidStorageTransfer.Withdrawals[i].ToString());
return;
}
Item item = player.StoreNewItem(dest, itemVS.ItemEntry, true, itemVS.ItemRandomPropertyId, null, itemVS.Context, itemVS.BonusListIDs);
item.SetUInt32Value(ItemFields.PropertySeed, itemVS.ItemSuffixFactor);
item.SetGuidValue(ItemFields.Creator, itemVS.CreatorGuid);
item.SetModifier(ItemModifier.UpgradeId, itemVS.ItemUpgradeId);
item.SetBinding(true);
GetCollectionMgr().AddItemAppearance(item);
voidStorageTransferChanges.RemovedItems.Add(ObjectGuid.Create(HighGuid.Item, itemVS.ItemId));
player.DeleteVoidStorageItem(slot);
}
SendPacket(voidStorageTransferChanges);
SendVoidStorageTransferResult(VoidTransferError.Ok);
}
[WorldPacketHandler(ClientOpcodes.SwapVoidItem)]
void HandleVoidSwapItem(SwapVoidItem swapVoidItem)
{
Player player = GetPlayer();
Creature unit = player.GetNPCIfCanInteractWith(swapVoidItem.Npc, NPCFlags.VaultKeeper);
if (!unit)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidSwapItem - {0} not found or player can't interact with it.", swapVoidItem.Npc.ToString());
return;
}
if (!player.IsVoidStorageUnlocked())
{
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidSwapItem - Player ({0}, name: {1}) queried void storage without unlocking it.", player.GetGUID().ToString(), player.GetName());
return;
}
byte oldSlot;
if (player.GetVoidStorageItem(swapVoidItem.VoidItemGuid.GetCounter(), out oldSlot) == null)
{
Log.outDebug(LogFilter.Network, "WORLD: HandleVoidSwapItem - Player (GUID: {0}, name: {1}) requested swapping an invalid item (slot: {2}, itemid: {3}).", player.GetGUID().ToString(), player.GetName(), swapVoidItem.DstSlot, swapVoidItem.VoidItemGuid.ToString());
return;
}
bool usedDestSlot = player.GetVoidStorageItem((byte)swapVoidItem.DstSlot) != null;
ObjectGuid itemIdDest = ObjectGuid.Empty;
if (usedDestSlot)
itemIdDest = ObjectGuid.Create(HighGuid.Item, player.GetVoidStorageItem((byte)swapVoidItem.DstSlot).ItemId);
if (!player.SwapVoidStorageItem(oldSlot, (byte)swapVoidItem.DstSlot))
{
SendVoidStorageTransferResult(VoidTransferError.InternalError1);
return;
}
VoidItemSwapResponse voidItemSwapResponse = new VoidItemSwapResponse();
voidItemSwapResponse.VoidItemA = swapVoidItem.VoidItemGuid;
voidItemSwapResponse.VoidItemSlotA = swapVoidItem.DstSlot;
if (usedDestSlot)
{
voidItemSwapResponse.VoidItemB = itemIdDest;
voidItemSwapResponse.VoidItemSlotB = oldSlot;
}
SendPacket(voidItemSwapResponse);
}
}
}