diff options
29 files changed, 2205 insertions, 1697 deletions
diff --git a/sql/updates/world/2012_10_18_00_world_trinity_string.sql b/sql/updates/world/2012_10_18_00_world_trinity_string.sql new file mode 100644 index 00000000000..8d62174d868 --- /dev/null +++ b/sql/updates/world/2012_10_18_00_world_trinity_string.sql @@ -0,0 +1,16 @@ +REPLACE INTO `trinity_string` (`entry`, `content_default`, `content_loc1`, `content_loc2`, `content_loc3`, `content_loc4`, `content_loc5`, `content_loc6`, `content_loc7`, `content_loc8`) +VALUES + (11015, 'Error', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + (11014, 'None', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + (11013, 'Leader', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + (11012, 'Dps', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + (11011, 'Healer', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + (11010, 'Tank', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + (11009, 'Raid browser', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + (11008, 'Finished dungeon', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + (11007, 'In dungeon', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + (11006, 'Vote kick', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + (11005, 'Proposal', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + (11004, 'Queued', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + (11003, 'Role check', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + (11002, 'None', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index 8a647bacfea..584b070def2 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -140,7 +140,7 @@ DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore(ItemRandomProp DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore(ItemRandomSuffixfmt); DBCStorage <ItemSetEntry> sItemSetStore(ItemSetEntryfmt); -DBCStorage <LFGDungeonEntry> sLFGDungeonStore(LFGDungeonEntryfmt); +DBCStorage <LFGDungeonEntryDbc> sLFGDungeonStore(LFGDungeonEntryfmt); DBCStorage <LiquidTypeEntry> sLiquidTypeStore(LiquidTypefmt); DBCStorage <LockEntry> sLockStore(LockEntryfmt); diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index c4e012c62c1..288ecbf6a0e 100755 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -152,7 +152,7 @@ extern DBCStorage <ItemLimitCategoryEntry> sItemLimitCategoryStore; extern DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore; extern DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore; extern DBCStorage <ItemSetEntry> sItemSetStore; -extern DBCStorage <LFGDungeonEntry> sLFGDungeonStore; +extern DBCStorage <LFGDungeonEntryDbc> sLFGDungeonStore; extern DBCStorage <LiquidTypeEntry> sLiquidTypeStore; extern DBCStorage <LockEntry> sLockStore; extern DBCStorage <MailTemplateEntry> sMailTemplateStore; diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index a1a0931dc5a..c4b0a760862 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -1347,10 +1347,10 @@ struct ItemSetEntry uint32 required_skill_value; // 36 m_requiredSkillRank }; -struct LFGDungeonEntry +struct LFGDungeonEntryDbc { uint32 ID; // 0 - //char* name; // 1 + char* name; // 1 uint32 minlevel; // 2 uint32 maxlevel; // 3 uint32 reclevel; // 4 diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index f9339f7515a..c1430c7bef0 100755 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -22,152 +22,152 @@ // x - skip<uint32>, X - skip<uint8>, s - char*, f - float, i - uint32, b - uint8, d - index (not included) // n - index (included), l - bool, p - field present in sql dbc, a - field absent in sql dbc -const char Achievementfmt[]="niixsxiixixxii"; +char const Achievementfmt[]="niixsxiixixxii"; //const std::string CustomAchievementfmt="pppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaapapaaaaaaaaaaaaaaaaaapp"; //const std::string CustomAchievementIndex = "ID"; -const char AchievementCriteriafmt[]="niiiiiiiisiiiiixxiiiiii"; -const char AreaTableEntryfmt[]="iiinixxxxxisiiiiifxxxxxxxx"; -const char AreaGroupEntryfmt[]="niiiiiii"; -const char AreaPOIEntryfmt[]="niiiiiiiiiiiffixixxixx"; -const char AreaTriggerEntryfmt[]="nifffxxxfffff"; -const char ArmorLocationfmt[]="nfffff"; -const char AuctionHouseEntryfmt[]="niiix"; -const char BankBagSlotPricesEntryfmt[]="ni"; -const char BarberShopStyleEntryfmt[]="nixxxiii"; -const char BattlemasterListEntryfmt[]="niiiiiiiiixsiiiixxxx"; -const char CharStartOutfitEntryfmt[]="diiiiiiiiiiiiiiiiiiiiiiiiixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; -const char CharTitlesEntryfmt[]="nxsxix"; -const char ChatChannelsEntryfmt[]="nixsx"; +char const AchievementCriteriafmt[]="niiiiiiiisiiiiixxiiiiii"; +char const AreaTableEntryfmt[]="iiinixxxxxisiiiiifxxxxxxxx"; +char const AreaGroupEntryfmt[]="niiiiiii"; +char const AreaPOIEntryfmt[]="niiiiiiiiiiiffixixxixx"; +char const AreaTriggerEntryfmt[]="nifffxxxfffff"; +char const ArmorLocationfmt[]="nfffff"; +char const AuctionHouseEntryfmt[]="niiix"; +char const BankBagSlotPricesEntryfmt[]="ni"; +char const BarberShopStyleEntryfmt[]="nixxxiii"; +char const BattlemasterListEntryfmt[]="niiiiiiiiixsiiiixxxx"; +char const CharStartOutfitEntryfmt[]="diiiiiiiiiiiiiiiiiiiiiiiiixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; +char const CharTitlesEntryfmt[]="nxsxix"; +char const ChatChannelsEntryfmt[]="nixsx"; -const char ChrClassesEntryfmt[]="nixsxxxixiiiii"; -const char ChrRacesEntryfmt[]="nxixiixixxxxixsxxxxxixxx"; -const char ChrClassesXPowerTypesfmt[]="nii"; +char const ChrClassesEntryfmt[]="nixsxxxixiiiii"; +char const ChrRacesEntryfmt[]="nxixiixixxxxixsxxxxxixxx"; +char const ChrClassesXPowerTypesfmt[]="nii"; -const char CinematicSequencesEntryfmt[]="nxxxxxxxxx"; -const char CreatureDisplayInfofmt[]="nixxfxxxxxxxxxxxx"; -const char CreatureModelDatafmt[]="nxxxxxxxxxxxxxffxxxxxxxxxxxxxxx"; -const char CreatureFamilyfmt[]="nfifiiiiixsx"; -const char CreatureSpellDatafmt[]="niiiixxxx"; -const char CreatureTypefmt[]="nxx"; -const char CurrencyTypesfmt[]="nxxxxxiiiix"; +char const CinematicSequencesEntryfmt[]="nxxxxxxxxx"; +char const CreatureDisplayInfofmt[]="nixxfxxxxxxxxxxxx"; +char const CreatureModelDatafmt[]="nxxxxxxxxxxxxxffxxxxxxxxxxxxxxx"; +char const CreatureFamilyfmt[]="nfifiiiiixsx"; +char const CreatureSpellDatafmt[]="niiiixxxx"; +char const CreatureTypefmt[]="nxx"; +char const CurrencyTypesfmt[]="nxxxxxiiiix"; -const char DestructibleModelDatafmt[]="ixxixxxixxxixxxixxxxxxxx"; -const char DungeonEncounterfmt[]="iiixisxx"; -const char DurabilityCostsfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiii"; -const char DurabilityQualityfmt[]="nf"; -const char EmotesEntryfmt[]="nxxiiixx"; -const char EmotesTextEntryfmt[]="nxixxxxxxxxxxxxxxxx"; -const char FactionEntryfmt[]="niiiiiiiiiiiiiiiiiiffixsxx"; -const char FactionTemplateEntryfmt[]="niiiiiiiiiiiii"; -const char GameObjectDisplayInfofmt[]="nsxxxxxxxxxxffffffxxx"; +char const DestructibleModelDatafmt[]="ixxixxxixxxixxxixxxxxxxx"; +char const DungeonEncounterfmt[]="iiixisxx"; +char const DurabilityCostsfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiii"; +char const DurabilityQualityfmt[]="nf"; +char const EmotesEntryfmt[]="nxxiiixx"; +char const EmotesTextEntryfmt[]="nxixxxxxxxxxxxxxxxx"; +char const FactionEntryfmt[]="niiiiiiiiiiiiiiiiiiffixsxx"; +char const FactionTemplateEntryfmt[]="niiiiiiiiiiiii"; +char const GameObjectDisplayInfofmt[]="nsxxxxxxxxxxffffffxxx"; -const char GemPropertiesEntryfmt[]="nixxix"; -const char GlyphPropertiesfmt[]="niii"; -const char GlyphSlotfmt[]="nii"; +char const GemPropertiesEntryfmt[]="nixxix"; +char const GlyphPropertiesfmt[]="niii"; +char const GlyphSlotfmt[]="nii"; -const char GtBarberShopCostBasefmt[]="xf"; -const char GtCombatRatingsfmt[]="xf"; -const char GtOCTHpPerStaminafmt[]="df"; -const char GtChanceToMeleeCritBasefmt[]="xf"; -const char GtChanceToMeleeCritfmt[]="xf"; -const char GtChanceToSpellCritBasefmt[]="xf"; -const char GtChanceToSpellCritfmt[]="xf"; -const char GtOCTClassCombatRatingScalarfmt[]="df"; -const char GtOCTRegenHPfmt[]="f"; -//const char GtOCTRegenMPfmt[]="f"; -const char GtRegenMPPerSptfmt[]="xf"; -const char GtSpellScalingfmt[]="df"; -const char GtOCTBaseHPByClassfmt[]="df"; -const char GtOCTBaseMPByClassfmt[]="df"; -const char GuildPerkSpellsfmt[]="dii"; -const char Holidaysfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiixxsiix"; -const char ImportPriceArmorfmt[]="nffff"; -const char ImportPriceQualityfmt[]="nf"; -const char ImportPriceShieldfmt[]="nf"; -const char ImportPriceWeaponfmt[]="nf"; -const char ItemPriceBasefmt[]="diff"; -const char ItemReforgefmt[]="nifif"; -const char ItemBagFamilyfmt[]="nx"; -const char ItemArmorQualityfmt[]="nfffffffi"; -const char ItemArmorShieldfmt[]="nifffffff"; -const char ItemArmorTotalfmt[]="niffff"; -const char ItemClassfmt[]="dixxfx"; -const char ItemDamagefmt[]="nfffffffi"; -const char ItemDisenchantLootfmt[]="niiiiii"; -//const char ItemDisplayTemplateEntryfmt[]="nxxxxxxxxxxixxxxxxxxxxx"; -const char ItemLimitCategoryEntryfmt[]="nxii"; -const char ItemRandomPropertiesfmt[]="nxiiixxs"; -const char ItemRandomSuffixfmt[]="nsxiiiiiiiiii"; -const char ItemSetEntryfmt[]="dsiiiiiiiiiixxxxxxxiiiiiiiiiiiiiiiiii"; -const char LFGDungeonEntryfmt[]="nxiiiiiiiiixxixixxxxx"; -const char LiquidTypefmt[]="nxxixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; -const char LockEntryfmt[]="niiiiiiiiiiiiiiiiiiiiiiiixxxxxxxx"; -const char PhaseEntryfmt[]="nsi"; -const char MailTemplateEntryfmt[]="nxs"; -const char MapEntryfmt[]="nxixxxsixxixiffxiixi"; -const char MapDifficultyEntryfmt[]="diisiix"; -const char MovieEntryfmt[]="nxxx"; -const char MountCapabilityfmt[]="niiiiiii"; -const char MountTypefmt[]="niiiiiiiiiiiiiiiiiiiiiiii"; -const char NameGenfmt[] = "dsii"; -const char NumTalentsAtLevelfmt[]="df"; -const char OverrideSpellDatafmt[]="niiiiiiiiiixx"; -const char QuestSortEntryfmt[]="nx"; -const char QuestXPfmt[]="niiiiiiiiii"; -const char QuestFactionRewardfmt[]="niiiiiiiiii"; -const char PvPDifficultyfmt[]="diiiii"; -const char RandomPropertiesPointsfmt[]="niiiiiiiiiiiiiii"; -const char ScalingStatDistributionfmt[]="niiiiiiiiiiiiiiiiiiiixi"; -const char ScalingStatValuesfmt[]="iniiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"; -const char SkillLinefmt[]="nisxixi"; -const char SkillLineAbilityfmt[]="niiiixxiiiiixx"; -const char SoundEntriesfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; -const char SpellCastTimefmt[]="nixx"; -const char SpellCategoriesEntryfmt[]="diiiiii"; -const char SpellDifficultyfmt[]="niiii"; +char const GtBarberShopCostBasefmt[]="xf"; +char const GtCombatRatingsfmt[]="xf"; +char const GtOCTHpPerStaminafmt[]="df"; +char const GtChanceToMeleeCritBasefmt[]="xf"; +char const GtChanceToMeleeCritfmt[]="xf"; +char const GtChanceToSpellCritBasefmt[]="xf"; +char const GtChanceToSpellCritfmt[]="xf"; +char const GtOCTClassCombatRatingScalarfmt[]="df"; +char const GtOCTRegenHPfmt[]="f"; +//char const GtOCTRegenMPfmt[]="f"; +char const GtRegenMPPerSptfmt[]="xf"; +char const GtSpellScalingfmt[]="df"; +char const GtOCTBaseHPByClassfmt[]="df"; +char const GtOCTBaseMPByClassfmt[]="df"; +char const GuildPerkSpellsfmt[]="dii"; +char const Holidaysfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiixxsiix"; +char const ImportPriceArmorfmt[]="nffff"; +char const ImportPriceQualityfmt[]="nf"; +char const ImportPriceShieldfmt[]="nf"; +char const ImportPriceWeaponfmt[]="nf"; +char const ItemPriceBasefmt[]="diff"; +char const ItemReforgefmt[]="nifif"; +char const ItemBagFamilyfmt[]="nx"; +char const ItemArmorQualityfmt[]="nfffffffi"; +char const ItemArmorShieldfmt[]="nifffffff"; +char const ItemArmorTotalfmt[]="niffff"; +char const ItemClassfmt[]="dixxfx"; +char const ItemDamagefmt[]="nfffffffi"; +char const ItemDisenchantLootfmt[]="niiiiii"; +//char const ItemDisplayTemplateEntryfmt[]="nxxxxxxxxxxixxxxxxxxxxx"; +char const ItemLimitCategoryEntryfmt[]="nxii"; +char const ItemRandomPropertiesfmt[]="nxiiixxs"; +char const ItemRandomSuffixfmt[]="nsxiiiiiiiiii"; +char const ItemSetEntryfmt[]="dsiiiiiiiiiixxxxxxxiiiiiiiiiiiiiiiiii"; +char const LFGDungeonEntryfmt[]="nsiiiiiiiiixxixixxxxx"; +char const LiquidTypefmt[]="nxxixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; +char const LockEntryfmt[]="niiiiiiiiiiiiiiiiiiiiiiiixxxxxxxx"; +char const PhaseEntryfmt[]="nsi"; +char const MailTemplateEntryfmt[]="nxs"; +char const MapEntryfmt[]="nxixxxsixxixiffxiixi"; +char const MapDifficultyEntryfmt[]="diisiix"; +char const MovieEntryfmt[]="nxxx"; +char const MountCapabilityfmt[]="niiiiiii"; +char const MountTypefmt[]="niiiiiiiiiiiiiiiiiiiiiiii"; +char const NameGenfmt[] = "dsii"; +char const NumTalentsAtLevelfmt[]="df"; +char const OverrideSpellDatafmt[]="niiiiiiiiiixx"; +char const QuestSortEntryfmt[]="nx"; +char const QuestXPfmt[]="niiiiiiiiii"; +char const QuestFactionRewardfmt[]="niiiiiiiiii"; +char const PvPDifficultyfmt[]="diiiii"; +char const RandomPropertiesPointsfmt[]="niiiiiiiiiiiiiii"; +char const ScalingStatDistributionfmt[]="niiiiiiiiiiiiiiiiiiiixi"; +char const ScalingStatValuesfmt[]="iniiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"; +char const SkillLinefmt[]="nisxixi"; +char const SkillLineAbilityfmt[]="niiiixxiiiiixx"; +char const SoundEntriesfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; +char const SpellCastTimefmt[]="nixx"; +char const SpellCategoriesEntryfmt[]="diiiiii"; +char const SpellDifficultyfmt[]="niiii"; const std::string CustomSpellDifficultyfmt="ppppp"; const std::string CustomSpellDifficultyIndex="id"; -const char SpellDurationfmt[]="niii"; -const char SpellEffectEntryfmt[]="nifiiiffiiiiiifiifiiiiiiiix"; -const char SpellEntryfmt[]="niiiiiiiiiiiiiiifiiiissxxiixxixiiiiiiixiiiiiiiix"; +char const SpellDurationfmt[]="niii"; +char const SpellEffectEntryfmt[]="nifiiiffiiiiiifiifiiiiiiiix"; +char const SpellEntryfmt[]="niiiiiiiiiiiiiiifiiiissxxiixxixiiiiiiixiiiiiiiix"; const std::string CustomSpellEntryfmt="papppppppppppapapaaaaaaaaaaapaaapapppppppaaaaapaapaaaaaaaaaaaaaaaaaappppppppppppppppppppppppppppppppppppaaaaaapppppppppaaapppppppppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaappppppppapppaaaaappaaaaaaa"; const std::string CustomSpellEntryIndex = "Id"; -const char SpellFocusObjectfmt[]="nx"; -const char SpellItemEnchantmentfmt[]="nxiiiiiixxxiiisiiiiiiix"; -const char SpellItemEnchantmentConditionfmt[]="nbbbbbxxxxxbbbbbbbbbbiiiiiXXXXX"; -const char SpellRadiusfmt[]="nfxf"; -const char SpellRangefmt[]="nffffixx"; -const char SpellReagentsEntryfmt[]="diiiiiiiiiiiiiiii"; -const char SpellScalingEntryfmt[]="diiiiffffffffffi"; -const char SpellTotemsEntryfmt[]="niiii"; -const char SpellTargetRestrictionsEntryfmt[]="nxiiii"; -const char SpellPowerEntryfmt[]="diiiixxx"; -const char SpellInterruptsEntryfmt[]="dixixi"; -const char SpellEquippedItemsEntryfmt[]="diii"; -const char SpellAuraOptionsEntryfmt[]="niiii"; -const char SpellAuraRestrictionsEntryfmt[]="diiiiiiii"; -const char SpellCastingRequirementsEntryfmt[]="dixxixi"; -const char SpellClassOptionsEntryfmt[]="dxiiiix"; -const char SpellCooldownsEntryfmt[]="diii"; -const char SpellLevelsEntryfmt[]="diii"; -const char SpellRuneCostfmt[]="niiii"; -const char SpellShapeshiftEntryfmt[]="nixixx"; -const char SpellShapeshiftFormfmt[]="nxxiixiiixxiiiiiiiixx"; -const char StableSlotPricesfmt[] = "ni"; -const char SummonPropertiesfmt[] = "niiiii"; -const char TalentEntryfmt[]="niiiiiiiiixxixxxxxx"; -const char TalentTabEntryfmt[]="nxxiiixxxxx"; -const char TalentTreePrimarySpellsfmt[]="diix"; -const char TaxiNodesEntryfmt[]="nifffsiixxx"; -const char TaxiPathEntryfmt[]="niii"; -const char TaxiPathNodeEntryfmt[]="diiifffiiii"; -const char TeamContributionPointsfmt[]="df"; -const char TotemCategoryEntryfmt[]="nxii"; -const char VehicleEntryfmt[]="niffffiiiiiiiifffffffffffffffssssfifiixx"; -const char VehicleSeatEntryfmt[]="niiffffffffffiiiiiifffffffiiifffiiiiiiiffiiiiixxxxxxxxxxxxxxxxxxxx"; -const char WMOAreaTableEntryfmt[]="niiixxxxxiixxxx"; -const char WorldMapAreaEntryfmt[]="xinxffffixxxxx"; -const char WorldMapOverlayEntryfmt[]="nxiiiixxxxxxxxx"; -const char WorldSafeLocsEntryfmt[]="nifffx"; +char const SpellFocusObjectfmt[]="nx"; +char const SpellItemEnchantmentfmt[]="nxiiiiiixxxiiisiiiiiiix"; +char const SpellItemEnchantmentConditionfmt[]="nbbbbbxxxxxbbbbbbbbbbiiiiiXXXXX"; +char const SpellRadiusfmt[]="nfxf"; +char const SpellRangefmt[]="nffffixx"; +char const SpellReagentsEntryfmt[]="diiiiiiiiiiiiiiii"; +char const SpellScalingEntryfmt[]="diiiiffffffffffi"; +char const SpellTotemsEntryfmt[]="niiii"; +char const SpellTargetRestrictionsEntryfmt[]="nxiiii"; +char const SpellPowerEntryfmt[]="diiiixxx"; +char const SpellInterruptsEntryfmt[]="dixixi"; +char const SpellEquippedItemsEntryfmt[]="diii"; +char const SpellAuraOptionsEntryfmt[]="niiii"; +char const SpellAuraRestrictionsEntryfmt[]="diiiiiiii"; +char const SpellCastingRequirementsEntryfmt[]="dixxixi"; +char const SpellClassOptionsEntryfmt[]="dxiiiix"; +char const SpellCooldownsEntryfmt[]="diii"; +char const SpellLevelsEntryfmt[]="diii"; +char const SpellRuneCostfmt[]="niiii"; +char const SpellShapeshiftEntryfmt[]="nixixx"; +char const SpellShapeshiftFormfmt[]="nxxiixiiixxiiiiiiiixx"; +char const StableSlotPricesfmt[] = "ni"; +char const SummonPropertiesfmt[] = "niiiii"; +char const TalentEntryfmt[]="niiiiiiiiixxixxxxxx"; +char const TalentTabEntryfmt[]="nxxiiixxxxx"; +char const TalentTreePrimarySpellsfmt[]="diix"; +char const TaxiNodesEntryfmt[]="nifffsiixxx"; +char const TaxiPathEntryfmt[]="niii"; +char const TaxiPathNodeEntryfmt[]="diiifffiiii"; +char const TeamContributionPointsfmt[]="df"; +char const TotemCategoryEntryfmt[]="nxii"; +char const VehicleEntryfmt[]="niffffiiiiiiiifffffffffffffffssssfifiixx"; +char const VehicleSeatEntryfmt[]="niiffffffffffiiiiiifffffffiiifffiiiiiiiffiiiiixxxxxxxxxxxxxxxxxxxx"; +char const WMOAreaTableEntryfmt[]="niiixxxxxiixxxx"; +char const WorldMapAreaEntryfmt[]="xinxffffixxxxx"; +char const WorldMapOverlayEntryfmt[]="nxiiiixxxxxxxxx"; +char const WorldSafeLocsEntryfmt[]="nifffx"; #endif diff --git a/src/server/game/DungeonFinding/LFG.h b/src/server/game/DungeonFinding/LFG.h index 28498749af8..abdb0ffa511 100755 --- a/src/server/game/DungeonFinding/LFG.h +++ b/src/server/game/DungeonFinding/LFG.h @@ -20,19 +20,26 @@ #include "Common.h" +enum LFGEnum +{ + LFG_TANKS_NEEDED = 1, + LFG_HEALERS_NEEDED = 1, + LFG_DPS_NEEDED = 3 +}; + enum LfgRoles { - ROLE_NONE = 0x00, - ROLE_LEADER = 0x01, - ROLE_TANK = 0x02, - ROLE_HEALER = 0x04, - ROLE_DAMAGE = 0x08 + PLAYER_ROLE_NONE = 0x00, + PLAYER_ROLE_LEADER = 0x01, + PLAYER_ROLE_TANK = 0x02, + PLAYER_ROLE_HEALER = 0x04, + PLAYER_ROLE_DAMAGE = 0x08 }; enum LfgUpdateType { LFG_UPDATETYPE_DEFAULT = 0, // Internal Use - LFG_UPDATETYPE_LEADER = 1, + LFG_UPDATETYPE_LEADER_UNK1 = 1, // FIXME: At group leave LFG_UPDATETYPE_ROLECHECK_ABORTED = 4, LFG_UPDATETYPE_JOIN_PROPOSAL = 5, LFG_UPDATETYPE_ROLECHECK_FAILED = 6, @@ -44,7 +51,7 @@ enum LfgUpdateType LFG_UPDATETYPE_PROPOSAL_BEGIN = 13, LFG_UPDATETYPE_CLEAR_LOCK_LIST = 14, LFG_UPDATETYPE_GROUP_MEMBER_OFFLINE = 15, - LFG_UPDATETYPE_GROUP_DISBAND = 16 + LFG_UPDATETYPE_GROUP_DISBAND_UNK16 = 16, // FIXME: Sometimes at group disband }; enum LfgState @@ -62,7 +69,6 @@ enum LfgState /// Instance lock types enum LfgLockStatusType { - LFG_LOCKSTATUS_OK = 0, // Internal use only LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION = 1, LFG_LOCKSTATUS_TOO_LOW_LEVEL = 2, LFG_LOCKSTATUS_TOO_HIGH_LEVEL = 3, @@ -73,18 +79,24 @@ enum LfgLockStatusType LFG_LOCKSTATUS_ATTUNEMENT_TOO_HIGH_LEVEL = 1002, LFG_LOCKSTATUS_QUEST_NOT_COMPLETED = 1022, LFG_LOCKSTATUS_MISSING_ITEM = 1025, - LFG_LOCKSTATUS_NOT_IN_SEASON = 1031 + LFG_LOCKSTATUS_NOT_IN_SEASON = 1031, + LFG_LOCKSTATUS_MISSING_ACHIEVEMENT = 1034 }; -/// Dungeon and reason why player can't join -struct LfgLockStatus +/// Answer state (Also used to check compatibilites) +enum LfgAnswer { - uint32 dungeon; ///< Dungeon Id - LfgLockStatusType lockstatus; ///< Lock type + LFG_ANSWER_PENDING = -1, + LFG_ANSWER_DENY = 0, + LFG_ANSWER_AGREE = 1 }; typedef std::set<uint32> LfgDungeonSet; -typedef std::map<uint32, LfgLockStatusType> LfgLockMap; +typedef std::map<uint32, uint32> LfgLockMap; typedef std::map<uint64, LfgLockMap> LfgLockPartyMap; +typedef std::set<uint64> LfgGuidSet; +typedef std::list<uint64> LfgGuidList; +typedef std::map<uint64, uint8> LfgRolesMap; +typedef std::map<uint64, uint64> LfgGroupsMap; #endif diff --git a/src/server/game/DungeonFinding/LFGGroupData.cpp b/src/server/game/DungeonFinding/LFGGroupData.cpp index 607389c5dbf..712ae5132b0 100644 --- a/src/server/game/DungeonFinding/LFGGroupData.cpp +++ b/src/server/game/DungeonFinding/LFGGroupData.cpp @@ -18,25 +18,27 @@ #include "LFG.h" #include "LFGGroupData.h" -LfgGroupData::LfgGroupData(): -m_State(LFG_STATE_NONE), m_OldState(LFG_STATE_NONE), m_Dungeon(0), -m_VotesNeeded(LFG_GROUP_KICK_VOTES_NEEDED), m_KicksLeft(LFG_GROUP_MAX_KICKS) -{ -} +LfgGroupData::LfgGroupData(): m_State(LFG_STATE_NONE), m_OldState(LFG_STATE_NONE), + m_Leader(0), m_Dungeon(0), m_KicksLeft(LFG_GROUP_MAX_KICKS) +{ } LfgGroupData::~LfgGroupData() +{ } + +bool LfgGroupData::IsLfgGroup() { + return m_OldState != LFG_STATE_NONE; } void LfgGroupData::SetState(LfgState state) { switch (state) { + case LFG_STATE_FINISHED_DUNGEON: case LFG_STATE_NONE: case LFG_STATE_DUNGEON: - case LFG_STATE_FINISHED_DUNGEON: m_OldState = state; - // No break on purpose + // No break on purpose default: m_State = state; } @@ -47,6 +49,29 @@ void LfgGroupData::RestoreState() m_State = m_OldState; } +void LfgGroupData::AddPlayer(uint64 guid) +{ + m_Players.insert(guid); +} + +uint8 LfgGroupData::RemovePlayer(uint64 guid) +{ + LfgGuidSet::iterator it = m_Players.find(guid); + if (it != m_Players.end()) + m_Players.erase(it); + return uint8(m_Players.size()); +} + +void LfgGroupData::RemoveAllPlayers() +{ + m_Players.clear(); +} + +void LfgGroupData::SetLeader(uint64 guid) +{ + m_Leader = guid; +} + void LfgGroupData::SetDungeon(uint32 dungeon) { m_Dungeon = dungeon; @@ -63,6 +88,21 @@ LfgState LfgGroupData::GetState() const return m_State; } +LfgState LfgGroupData::GetOldState() const +{ + return m_OldState; +} + +const LfgGuidSet &LfgGroupData::GetPlayers() const +{ + return m_Players; +} + +uint64 LfgGroupData::GetLeader() const +{ + return m_Leader; +} + uint32 LfgGroupData::GetDungeon(bool asId /* = true */) const { if (asId) @@ -71,11 +111,6 @@ uint32 LfgGroupData::GetDungeon(bool asId /* = true */) const return m_Dungeon; } -uint8 LfgGroupData::GetVotesNeeded() const -{ - return m_VotesNeeded; -} - uint8 LfgGroupData::GetKicksLeft() const { return m_KicksLeft; diff --git a/src/server/game/DungeonFinding/LFGGroupData.h b/src/server/game/DungeonFinding/LFGGroupData.h index 74570817698..43cd64f97c3 100644 --- a/src/server/game/DungeonFinding/LFGGroupData.h +++ b/src/server/game/DungeonFinding/LFGGroupData.h @@ -23,7 +23,6 @@ enum LfgGroupEnum { LFG_GROUP_MAX_KICKS = 3, - LFG_GROUP_KICK_VOTES_NEEDED = 3 }; /** @@ -35,31 +34,43 @@ class LfgGroupData LfgGroupData(); ~LfgGroupData(); + bool IsLfgGroup(); + // General void SetState(LfgState state); void RestoreState(); + void AddPlayer(uint64 guid); + uint8 RemovePlayer(uint64 guid); + void RemoveAllPlayers(); + void SetLeader(uint64 guid); + // Dungeon void SetDungeon(uint32 dungeon); + // VoteKick - void SetVotesNeeded(uint8 votes); void DecreaseKicksLeft(); // General LfgState GetState() const; + LfgState GetOldState() const; + LfgGuidSet const& GetPlayers() const; + uint64 GetLeader() const; + // Dungeon uint32 GetDungeon(bool asId = true) const; + // VoteKick - uint8 GetVotesNeeded() const; uint8 GetKicksLeft() const; private: // General LfgState m_State; ///< State if group in LFG LfgState m_OldState; ///< Old State + uint64 m_Leader; ///< Leader GUID + LfgGuidSet m_Players; ///< Players in group // Dungeon uint32 m_Dungeon; ///< Dungeon entry // Vote Kick - uint8 m_VotesNeeded; ///< Votes need to kick success uint8 m_KicksLeft; ///< Number of kicks left }; diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index 2b425dffff0..16fda8952ac 100755 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -18,60 +18,30 @@ #include "Common.h" #include "SharedDefines.h" #include "DBCStores.h" -#include "Containers.h" #include "DisableMgr.h" #include "ObjectMgr.h" #include "SocialMgr.h" #include "LFGMgr.h" -#include "GroupMgr.h" -#include "GameEventMgr.h" #include "LFGScripts.h" #include "LFGGroupData.h" #include "LFGPlayerData.h" - +#include "LFGQueue.h" #include "Group.h" #include "Player.h" +#include "GroupMgr.h" +#include "GameEventMgr.h" -LFGMgr::LFGMgr(): m_update(true), m_QueueTimer(0), m_lfgProposalId(1), -m_WaitTimeAvg(-1), m_WaitTimeTank(-1), m_WaitTimeHealer(-1), m_WaitTimeDps(-1), -m_NumWaitTimeAvg(0), m_NumWaitTimeTank(0), m_NumWaitTimeHealer(0), m_NumWaitTimeDps(0) -{ - m_update = sWorld->getBoolConfig(CONFIG_DUNGEON_FINDER_ENABLE); - if (m_update) - { - new LFGPlayerScript(); - new LFGGroupScript(); - - // Initialize dungeon cache - for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i) - { - LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(i); - if (dungeon && dungeon->type != LFG_TYPE_ZONE) - { - if (dungeon->type != LFG_TYPE_RANDOM) - m_CachedDungeonMap[dungeon->grouptype].insert(dungeon->ID); - m_CachedDungeonMap[0].insert(dungeon->ID); - } - } - } -} +LFGMgr::LFGMgr(): m_QueueTimer(0), m_lfgProposalId(1), + m_options(sWorld->getBoolConfig(CONFIG_DUNGEON_FINDER_ENABLE)), + m_lfgPlayerScript(new LFGPlayerScript()), m_lfgGroupScript(new LFGGroupScript()) +{ } LFGMgr::~LFGMgr() { for (LfgRewardMap::iterator itr = m_RewardMap.begin(); itr != m_RewardMap.end(); ++itr) delete itr->second; - - for (LfgQueueInfoMap::iterator it = m_QueueInfoMap.begin(); it != m_QueueInfoMap.end(); ++it) - delete it->second; - - for (LfgProposalMap::iterator it = m_Proposals.begin(); it != m_Proposals.end(); ++it) - delete it->second; - - for (LfgPlayerBootMap::iterator it = m_Boots.begin(); it != m_Boots.end(); ++it) - delete it->second; - - for (LfgRoleCheckMap::iterator it = m_RoleChecks.begin(); it != m_RoleChecks.end(); ++it) - delete it->second; + delete m_lfgPlayerScript; + delete m_lfgGroupScript; } void LFGMgr::_LoadFromDB(Field* fields, uint64 guid) @@ -122,6 +92,89 @@ void LFGMgr::_SaveToDB(uint64 guid, uint32 db_guid) CharacterDatabase.Execute(stmt); } +std::string LFGMgr::ConcatenateDungeons(LfgDungeonSet const& dungeons) +{ + std::string dungeonstr = ""; + if (!dungeons.empty()) + { + std::ostringstream o; + LfgDungeonSet::const_iterator it = dungeons.begin(); + o << (*it); + for (++it; it != dungeons.end(); ++it) + o << ", " << uint32(*it); + dungeonstr = o.str(); + } + return dungeonstr; +} + +std::string LFGMgr::GetRolesString(uint8 roles) +{ + std::string rolesstr = ""; + + if (roles & PLAYER_ROLE_TANK) + rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_TANK)); + + if (roles & PLAYER_ROLE_HEALER) + { + if (!rolesstr.empty()) + rolesstr.append(", "); + rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_HEALER)); + } + + if (roles & PLAYER_ROLE_DAMAGE) + { + if (!rolesstr.empty()) + rolesstr.append(", "); + rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_DAMAGE)); + } + + if (roles & PLAYER_ROLE_LEADER) + { + if (!rolesstr.empty()) + rolesstr.append(", "); + rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_LEADER)); + } + + if (rolesstr.empty()) + rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_NONE)); + + return rolesstr; +} + +char const * LFGMgr::GetStateString(LfgState state) +{ + int32 entry = LANG_LFG_ERROR; + switch (state) + { + case LFG_STATE_NONE: + entry = LANG_LFG_STATE_NONE; + break; + case LFG_STATE_ROLECHECK: + entry = LANG_LFG_STATE_ROLECHECK; + break; + case LFG_STATE_QUEUED: + entry = LANG_LFG_STATE_QUEUED; + break; + case LFG_STATE_PROPOSAL: + entry = LANG_LFG_STATE_PROPOSAL; + break; + case LFG_STATE_DUNGEON: + entry = LANG_LFG_STATE_DUNGEON; + break; + case LFG_STATE_BOOT: + entry = LANG_LFG_STATE_BOOT; + break; + case LFG_STATE_FINISHED_DUNGEON: + entry = LANG_LFG_STATE_FINISHED_DUNGEON; + break; + case LFG_STATE_RAIDBROWSER: + entry = LANG_LFG_STATE_RAIDBROWSER; + break; + } + char const * const str = sObjectMgr->GetTrinityStringForDBCLocale(entry); + return str; +} + /// Load rewards for completing dungeons void LFGMgr::LoadRewards() { @@ -155,7 +208,7 @@ void LFGMgr::LoadRewards() uint32 otherMoneyVar = fields[6].GetUInt32(); uint32 otherXPVar = fields[7].GetUInt32(); - if (!sLFGDungeonStore.LookupEntry(dungeonId)) + if (!GetLFGDungeon(dungeonId)) { sLog->outError(LOG_FILTER_SQL, "Dungeon %u specified in table `lfg_dungeon_rewards` does not exist!", dungeonId); continue; @@ -186,16 +239,50 @@ void LFGMgr::LoadRewards() sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u lfg dungeon rewards in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } -void LFGMgr::LoadEntrancePositions() +LFGDungeonEntry const* LFGMgr::GetLFGDungeon(uint32 id) +{ + LFGDungeonMap::const_iterator itr = m_LfgDungeonMap.find(id); + if (itr != m_LfgDungeonMap.end()) + return &(itr->second); + + return NULL; +} + +LFGDungeonMap & LFGMgr::GetLFGDungeonMap() +{ + return m_LfgDungeonMap; +} + +void LFGMgr::LoadLFGDungeons(bool reload /* = false */) { uint32 oldMSTime = getMSTime(); - m_entrancePositions.clear(); + m_LfgDungeonMap.clear(); + + // Initialize Dungeon map with data from dbcs + for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i) + { + LFGDungeonEntryDbc const* dungeon = sLFGDungeonStore.LookupEntry(i); + if (!dungeon) + continue; + + switch (dungeon->type) + { + case LFG_TYPE_DUNGEON: + case LFG_TYPE_HEROIC: + case LFG_TYPE_RAID: + case LFG_TYPE_RANDOM: + m_LfgDungeonMap[dungeon->ID] = LFGDungeonEntry(dungeon); + break; + } + } + + // Fill teleport locations from DB QueryResult result = WorldDatabase.Query("SELECT dungeonId, position_x, position_y, position_z, orientation FROM lfg_entrances"); if (!result) { - sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 lfg entrance positions. DB table `lfg_entrances` is empty!"); + sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 lfg entrance positions. DB table `lfg_entrances` is empty!"); return; } @@ -205,49 +292,85 @@ void LFGMgr::LoadEntrancePositions() { Field* fields = result->Fetch(); uint32 dungeonId = fields[0].GetUInt32(); - Position pos; - pos.m_positionX = fields[1].GetFloat(); - pos.m_positionY = fields[2].GetFloat(); - pos.m_positionZ = fields[3].GetFloat(); - pos.m_orientation = fields[4].GetFloat(); - m_entrancePositions[dungeonId] = pos; + LFGDungeonMap::iterator dungeonItr = m_LfgDungeonMap.find(dungeonId); + if (dungeonItr == m_LfgDungeonMap.end()) + { + sLog->outError(LOG_FILTER_SQL, "table `lfg_entrances` contains coordinates for wrong dungeon %u", dungeonId); + continue; + } + + LFGDungeonEntry& data = dungeonItr->second; + data.x = fields[1].GetFloat(); + data.y = fields[2].GetFloat(); + data.z = fields[3].GetFloat(); + data.o = fields[4].GetFloat(); + ++count; } while (result->NextRow()); sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u lfg entrance positions in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + + // Fill all other teleport coords from areatriggers + for (LFGDungeonMap::iterator itr = m_LfgDungeonMap.begin(); itr != m_LfgDungeonMap.end(); ++itr) + { + LFGDungeonEntry& dungeon = itr->second; + // No teleport coords in database, load from areatriggers + if (dungeon.x == 0.0f && dungeon.y == 0.0f && dungeon.z == 0.0f) + { + AreaTrigger const* at = sObjectMgr->GetMapEntranceTrigger(dungeon.map); + if (!at) + { + sLog->outError(LOG_FILTER_LFG, "LFGMgr::LoadLFGDungeons: Failed to load dungeon %s, cant find areatrigger for map %u", dungeon.name.c_str(), dungeon.map); + continue; + } + + dungeon.map = at->target_mapId; + dungeon.x = at->target_X; + dungeon.y = at->target_Y; + dungeon.z = at->target_Z; + dungeon.o = at->target_Orientation; + } + + if (dungeon.type != LFG_TYPE_RANDOM) + m_CachedDungeonMap[dungeon.group].insert(dungeon.id); + m_CachedDungeonMap[0].insert(dungeon.id); + } + + if (reload) + { + m_CachedDungeonMap.clear(); + // Recalculate locked dungeons + for (LfgPlayerDataMap::const_iterator it = m_Players.begin(); it != m_Players.end(); ++it) + if (Player* player = ObjectAccessor::FindPlayer(it->first)) + InitializeLockedDungeons(player); + } } void LFGMgr::Update(uint32 diff) { - if (!m_update) + if (!m_options) return; - m_update = false; time_t currTime = time(NULL); // Remove obsolete role checks for (LfgRoleCheckMap::iterator it = m_RoleChecks.begin(); it != m_RoleChecks.end();) { LfgRoleCheckMap::iterator itRoleCheck = it++; - LfgRoleCheck* roleCheck = itRoleCheck->second; - if (currTime < roleCheck->cancelTime) + LfgRoleCheck& roleCheck = itRoleCheck->second; + if (currTime < roleCheck.cancelTime) continue; - roleCheck->state = LFG_ROLECHECK_MISSING_ROLE; + roleCheck.state = LFG_ROLECHECK_MISSING_ROLE; - for (LfgRolesMap::const_iterator itRoles = roleCheck->roles.begin(); itRoles != roleCheck->roles.end(); ++itRoles) + for (LfgRolesMap::const_iterator itRoles = roleCheck.roles.begin(); itRoles != roleCheck.roles.end(); ++itRoles) { uint64 guid = itRoles->first; - ClearState(guid); - if (Player* player = ObjectAccessor::FindPlayer(guid)) - { - player->GetSession()->SendLfgRoleCheckUpdate(roleCheck); - - if (itRoles->first == roleCheck->leader) - player->GetSession()->SendLfgJoinResult(LfgJoinResultData(LFG_JOIN_FAILED, LFG_ROLECHECK_MISSING_ROLE)); - } + ClearState(guid, "Remove Obsolete RoleCheck"); + SendLfgRoleCheckUpdate(guid, roleCheck); + if (guid == roleCheck.leader) + SendLfgJoinResult(guid, LfgJoinResultData(LFG_JOIN_FAILED, LFG_ROLECHECK_MISSING_ROLE)); } - delete roleCheck; m_RoleChecks.erase(itRoleCheck); } @@ -255,7 +378,7 @@ void LFGMgr::Update(uint32 diff) for (LfgProposalMap::iterator it = m_Proposals.begin(); it != m_Proposals.end();) { LfgProposalMap::iterator itRemove = it++; - if (itRemove->second->cancelTime < currTime) + if (itRemove->second.cancelTime < currTime) RemoveProposal(itRemove, LFG_UPDATETYPE_PROPOSAL_FAILED); } @@ -263,71 +386,51 @@ void LFGMgr::Update(uint32 diff) for (LfgPlayerBootMap::iterator it = m_Boots.begin(); it != m_Boots.end();) { LfgPlayerBootMap::iterator itBoot = it++; - LfgPlayerBoot* pBoot = itBoot->second; - if (pBoot->cancelTime < currTime) + LfgPlayerBoot& boot = itBoot->second; + if (boot.cancelTime < currTime) { - pBoot->inProgress = false; - for (LfgAnswerMap::const_iterator itVotes = pBoot->votes.begin(); itVotes != pBoot->votes.end(); ++itVotes) - if (Player* plrg = ObjectAccessor::FindPlayer(itVotes->first)) - if (plrg->GetGUID() != pBoot->victim) - plrg->GetSession()->SendLfgBootPlayer(pBoot); - delete pBoot; + boot.inProgress = false; + for (LfgAnswerMap::const_iterator itVotes = boot.votes.begin(); itVotes != boot.votes.end(); ++itVotes) + { + uint64 pguid = itVotes->first; + if (pguid != boot.victim) + SendLfgBootProposalUpdate(pguid, boot); + } m_Boots.erase(itBoot); } } + uint32 lastProposalId = m_lfgProposalId; // Check if a proposal can be formed with the new groups being added - for (LfgGuidListMap::iterator it = m_newToQueue.begin(); it != m_newToQueue.end(); ++it) + for (LfgQueueMap::iterator it = m_Queues.begin(); it != m_Queues.end(); ++it) + if (uint8 newProposals = it->second.FindGroups()) + sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::Update: Found %u new groups in queue %u", newProposals, it->first); + + if (lastProposalId != m_lfgProposalId) { - uint8 queueId = it->first; - LfgGuidList& newToQueue = it->second; - LfgGuidList& currentQueue = m_currentQueue[queueId]; - LfgGuidList firstNew; - while (!newToQueue.empty()) + // FIXME lastProposalId ? lastProposalId +1 ? + for (LfgProposalMap::const_iterator itProposal = m_Proposals.find(m_lfgProposalId); itProposal != m_Proposals.end(); ++itProposal) { - uint64 frontguid = newToQueue.front(); - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::Update: QueueId %u: checking [" UI64FMTD "] newToQueue(%u), currentQueue(%u)", queueId, frontguid, uint32(newToQueue.size()), uint32(currentQueue.size())); - firstNew.push_back(frontguid); - newToQueue.pop_front(); + uint32 proposalId = itProposal->first; + LfgProposal& proposal = m_Proposals[proposalId]; - LfgGuidList temporalList = currentQueue; - if (LfgProposal* pProposal = FindNewGroups(firstNew, temporalList)) // Group found! + uint64 guid = 0; + for (LfgProposalPlayerMap::const_iterator itPlayers = proposal.players.begin(); itPlayers != proposal.players.end(); ++itPlayers) { - // Remove groups in the proposal from new and current queues (not from queue map) - for (LfgGuidList::const_iterator itQueue = pProposal->queues.begin(); itQueue != pProposal->queues.end(); ++itQueue) - { - currentQueue.remove(*itQueue); - newToQueue.remove(*itQueue); - } - m_Proposals[++m_lfgProposalId] = pProposal; - - uint64 guid = 0; - for (LfgProposalPlayerMap::const_iterator itPlayers = pProposal->players.begin(); itPlayers != pProposal->players.end(); ++itPlayers) + guid = itPlayers->first; + SetState(guid, LFG_STATE_PROPOSAL); + if (uint64 gguid = GetGroup(guid)) { - guid = itPlayers->first; - SetState(guid, LFG_STATE_PROPOSAL); - if (Player* player = ObjectAccessor::FindPlayer(itPlayers->first)) - { - Group* grp = player->GetGroup(); - if (grp) - { - uint64 gguid = grp->GetGUID(); - SetState(gguid, LFG_STATE_PROPOSAL); - player->GetSession()->SendLfgUpdateParty(LfgUpdateData(LFG_UPDATETYPE_PROPOSAL_BEGIN, GetSelectedDungeons(guid), GetComment(guid))); - } - else - player->GetSession()->SendLfgUpdatePlayer(LfgUpdateData(LFG_UPDATETYPE_PROPOSAL_BEGIN, GetSelectedDungeons(guid), GetComment(guid))); - player->GetSession()->SendLfgUpdateProposal(m_lfgProposalId, pProposal); - } + SetState(gguid, LFG_STATE_PROPOSAL); + SendLfgUpdateParty(guid, LfgUpdateData(LFG_UPDATETYPE_PROPOSAL_BEGIN, GetSelectedDungeons(guid), GetComment(guid))); } - - if (pProposal->state == LFG_PROPOSAL_SUCCESS) - UpdateProposal(m_lfgProposalId, guid, true); + else + SendLfgUpdatePlayer(guid, LfgUpdateData(LFG_UPDATETYPE_PROPOSAL_BEGIN, GetSelectedDungeons(guid), GetComment(guid))); + SendLfgUpdateProposal(guid, m_lfgProposalId, proposal); } - else - if (std::find(currentQueue.begin(), currentQueue.end(), frontguid) == currentQueue.end()) //already in queue? - currentQueue.push_back(frontguid); // Lfg group not found, add this group to the queue. - firstNew.clear(); + + if (proposal.state == LFG_PROPOSAL_SUCCESS) + UpdateProposal(proposalId, guid, true); } } @@ -335,105 +438,12 @@ void LFGMgr::Update(uint32 diff) if (m_QueueTimer > LFG_QUEUEUPDATE_INTERVAL) { m_QueueTimer = 0; - currTime = time(NULL); - for (LfgQueueInfoMap::const_iterator itQueue = m_QueueInfoMap.begin(); itQueue != m_QueueInfoMap.end(); ++itQueue) - { - LfgQueueInfo* queue = itQueue->second; - if (!queue) - { - sLog->outError(LOG_FILTER_LFG, "LFGMgr::Update: [" UI64FMTD "] queued with null queue info!", itQueue->first); - continue; - } - uint32 dungeonId = (*queue->dungeons.begin()); - uint32 queuedTime = uint32(currTime - queue->joinTime); - uint8 role = ROLE_NONE; - for (LfgRolesMap::const_iterator itPlayer = queue->roles.begin(); itPlayer != queue->roles.end(); ++itPlayer) - role |= itPlayer->second; - role &= ~ROLE_LEADER; - - int32 waitTime = -1; - switch (role) - { - case ROLE_NONE: // Should not happen - just in case - waitTime = -1; - break; - case ROLE_TANK: - waitTime = m_WaitTimeTank; - break; - case ROLE_HEALER: - waitTime = m_WaitTimeHealer; - break; - case ROLE_DAMAGE: - waitTime = m_WaitTimeDps; - break; - default: - waitTime = m_WaitTimeAvg; - break; - } - - for (LfgRolesMap::const_iterator itPlayer = queue->roles.begin(); itPlayer != queue->roles.end(); ++itPlayer) - if (Player* player = ObjectAccessor::FindPlayer(itPlayer->first)) - player->GetSession()->SendLfgQueueStatus(dungeonId, waitTime, m_WaitTimeAvg, m_WaitTimeTank, m_WaitTimeHealer, m_WaitTimeDps, queuedTime, queue->tanks, queue->healers, queue->dps); - } + time_t currTime = time(NULL); + for (LfgQueueMap::iterator it = m_Queues.begin(); it != m_Queues.end(); ++it) + it->second.UpdateQueueTimers(currTime); } else m_QueueTimer += diff; - m_update = true; -} - -/** - Add a guid to the queue of guids to be added to main queue. It guid its already - in queue does nothing. If this function is called guid is not in the main queue - (No need to check it here) - - @param[in] guid Player or group guid to add to queue - @param[in] queueId Queue Id to add player/group to -*/ -void LFGMgr::AddToQueue(uint64 guid, uint8 queueId) -{ - if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP)) - queueId = 0; - - LfgGuidList& list = m_newToQueue[queueId]; - if (std::find(list.begin(), list.end(), guid) != list.end()) - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::AddToQueue: [" UI64FMTD "] already in new queue. ignoring", guid); - else - { - list.push_back(guid); - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::AddToQueue: [" UI64FMTD "] added to m_newToQueue (size: %u)", guid, uint32(list.size())); - } -} - -/** - Removes a guid from the main and new queues. - - @param[in] guid Player or group guid to add to queue - @return true if guid was found in main queue. -*/ -bool LFGMgr::RemoveFromQueue(uint64 guid) -{ - for (LfgGuidListMap::iterator it = m_currentQueue.begin(); it != m_currentQueue.end(); ++it) - it->second.remove(guid); - - for (LfgGuidListMap::iterator it = m_newToQueue.begin(); it != m_newToQueue.end(); ++it) - it->second.remove(guid); - - RemoveFromCompatibles(guid); - - LfgQueueInfoMap::iterator it = m_QueueInfoMap.find(guid); - if (it != m_QueueInfoMap.end()) - { - delete it->second; - m_QueueInfoMap.erase(it); - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::RemoveFromQueue: [" UI64FMTD "] removed", guid); - return true; - } - else - { - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::RemoveFromQueue: [" UI64FMTD "] not in queue", guid); - return false; - } - } /** @@ -441,68 +451,61 @@ bool LFGMgr::RemoveFromQueue(uint64 guid) @param[in] player Player we need to initialize the lock status map */ -void LFGMgr::InitializeLockedDungeons(Player* player) +void LFGMgr::InitializeLockedDungeons(Player* player, uint8 level /* = 0 */) { uint64 guid = player->GetGUID(); - uint8 level = player->getLevel(); + if (!level) + level = player->getLevel(); uint8 expansion = player->GetSession()->Expansion(); - LfgDungeonSet dungeons = GetDungeonsByRandom(0); + LfgDungeonSet const& dungeons = GetDungeonsByRandom(0); LfgLockMap lock; for (LfgDungeonSet::const_iterator it = dungeons.begin(); it != dungeons.end(); ++it) { - LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(*it); + LFGDungeonEntry const* dungeon = GetLFGDungeon(*it); if (!dungeon) // should never happen - We provide a list from sLFGDungeonStore continue; - AccessRequirement const* ar = sObjectMgr->GetAccessRequirement(dungeon->map, Difficulty(dungeon->difficulty)); - - LfgLockStatusType locktype = LFG_LOCKSTATUS_OK; + uint32 lockData = 0; if (dungeon->expansion > expansion) - locktype = LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION; + lockData = LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION; else if (DisableMgr::IsDisabledFor(DISABLE_TYPE_MAP, dungeon->map, player)) - locktype = LFG_LOCKSTATUS_RAID_LOCKED; + lockData = LFG_LOCKSTATUS_RAID_LOCKED; else if (dungeon->difficulty > DUNGEON_DIFFICULTY_NORMAL && player->GetBoundInstance(dungeon->map, Difficulty(dungeon->difficulty))) - { - //if (!player->GetGroup() || !player->GetGroup()->isLFGGroup() || GetDungeon(player->GetGroup()->GetGUID(), true) != dungeon->ID || GetState(player->GetGroup()->GetGUID()) != LFG_STATE_DUNGEON) - locktype = LFG_LOCKSTATUS_RAID_LOCKED; - } + lockData = LFG_LOCKSTATUS_RAID_LOCKED; else if (dungeon->minlevel > level) - locktype = LFG_LOCKSTATUS_TOO_LOW_LEVEL; + lockData = LFG_LOCKSTATUS_TOO_LOW_LEVEL; else if (dungeon->maxlevel < level) - locktype = LFG_LOCKSTATUS_TOO_HIGH_LEVEL; - else if (dungeon->flags & LFG_FLAG_SEASONAL) - { - if (HolidayIds holiday = sLFGMgr->GetDungeonSeason(dungeon->ID)) - if (!IsHolidayActive(holiday)) - locktype = LFG_LOCKSTATUS_NOT_IN_SEASON; - } - else if (locktype == LFG_LOCKSTATUS_OK && ar) + lockData = LFG_LOCKSTATUS_TOO_HIGH_LEVEL; + else if (dungeon->seasonal && !IsSeasonActive(dungeon->id)) + lockData = LFG_LOCKSTATUS_NOT_IN_SEASON; + else if (AccessRequirement const* ar = sObjectMgr->GetAccessRequirement(dungeon->map, Difficulty(dungeon->difficulty))) { if (ar->achievement && !player->HasAchieved(ar->achievement)) - locktype = LFG_LOCKSTATUS_RAID_LOCKED; // FIXME: Check the correct lock value + lockData = LFG_LOCKSTATUS_MISSING_ACHIEVEMENT; else if (player->GetTeam() == ALLIANCE && ar->quest_A && !player->GetQuestRewardStatus(ar->quest_A)) - locktype = LFG_LOCKSTATUS_QUEST_NOT_COMPLETED; + lockData = LFG_LOCKSTATUS_QUEST_NOT_COMPLETED; else if (player->GetTeam() == HORDE && ar->quest_H && !player->GetQuestRewardStatus(ar->quest_H)) - locktype = LFG_LOCKSTATUS_QUEST_NOT_COMPLETED; + lockData = LFG_LOCKSTATUS_QUEST_NOT_COMPLETED; else if (ar->item) { if (!player->HasItemCount(ar->item, 1) && (!ar->item2 || !player->HasItemCount(ar->item2, 1))) - locktype = LFG_LOCKSTATUS_MISSING_ITEM; + lockData = LFG_LOCKSTATUS_MISSING_ITEM; } else if (ar->item2 && !player->HasItemCount(ar->item2, 1)) - locktype = LFG_LOCKSTATUS_MISSING_ITEM; + lockData = LFG_LOCKSTATUS_MISSING_ITEM; } + /* TODO VoA closed if WG is not under team control (LFG_LOCKSTATUS_RAID_LOCKED) - locktype = LFG_LOCKSTATUS_TOO_LOW_GEAR_SCORE; - locktype = LFG_LOCKSTATUS_TOO_HIGH_GEAR_SCORE; - locktype = LFG_LOCKSTATUS_ATTUNEMENT_TOO_LOW_LEVEL; - locktype = LFG_LOCKSTATUS_ATTUNEMENT_TOO_HIGH_LEVEL; + lockData = LFG_LOCKSTATUS_TOO_LOW_GEAR_SCORE; + lockData = LFG_LOCKSTATUS_TOO_HIGH_GEAR_SCORE; + lockData = LFG_LOCKSTATUS_ATTUNEMENT_TOO_LOW_LEVEL; + lockData = LFG_LOCKSTATUS_ATTUNEMENT_TOO_HIGH_LEVEL; */ - if (locktype != LFG_LOCKSTATUS_OK) - lock[dungeon->Entry()] = locktype; + if (lockData) + lock[dungeon->Entry()] = lockData; } SetLockedDungeons(guid, lock); } @@ -517,19 +520,18 @@ void LFGMgr::InitializeLockedDungeons(Player* player) @param[in] dungeons Dungeons the player/group is applying for @param[in] comment Player selected comment */ -void LFGMgr::Join(Player* player, uint8 roles, const LfgDungeonSet& selectedDungeons, const std::string& comment) +void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const std::string& comment) { - if (!player || !player->GetSession() || selectedDungeons.empty()) - return; + if (!player || !player->GetSession() || dungeons.empty()) + return; Group* grp = player->GetGroup(); uint64 guid = player->GetGUID(); uint64 gguid = grp ? grp->GetGUID() : guid; LfgJoinResultData joinData; - PlayerSet players; + LfgGuidSet players; uint32 rDungeonId = 0; bool isContinue = grp && grp->isLFGGroup() && GetState(gguid) != LFG_STATE_FINISHED_DUNGEON; - LfgDungeonSet dungeons = selectedDungeons; // Do not allow to change dungeon in the middle of a current dungeon if (isContinue) @@ -539,10 +541,10 @@ void LFGMgr::Join(Player* player, uint8 roles, const LfgDungeonSet& selectedDung } // Already in queue? - LfgQueueInfoMap::iterator itQueue = m_QueueInfoMap.find(gguid); - if (itQueue != m_QueueInfoMap.end()) + LfgState state = GetState(gguid); + if (state == LFG_STATE_QUEUED) { - LfgDungeonSet playerDungeons = GetSelectedDungeons(guid); + LfgDungeonSet const& playerDungeons = GetSelectedDungeons(guid); if (playerDungeons == dungeons) // Joining the same dungeons -- Send OK { LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, dungeons, comment); @@ -556,7 +558,10 @@ void LFGMgr::Join(Player* player, uint8 roles, const LfgDungeonSet& selectedDung return; } else // Remove from queue and rejoin - RemoveFromQueue(gguid); + { + LfgQueue& queue = GetQueue(gguid); + queue.RemoveFromQueue(gguid); + } } // Check player or group member restrictions @@ -586,15 +591,16 @@ void LFGMgr::Join(Player* player, uint8 roles, const LfgDungeonSet& selectedDung else if (plrg->InBattleground() || plrg->InArena() || plrg->InBattlegroundQueue()) joinData.result = LFG_JOIN_USING_BG_SYSTEM; ++memberCount; - players.insert(plrg); + players.insert(plrg->GetGUID()); } } - if (memberCount != grp->GetMembersCount()) + + if (joinData.result == LFG_JOIN_OK && memberCount != grp->GetMembersCount()) joinData.result = LFG_JOIN_DISCONNECTED; } } else - players.insert(player); + players.insert(player->GetGUID()); // Check if all dungeons are valid bool isRaid = false; @@ -652,25 +658,24 @@ void LFGMgr::Join(Player* player, uint8 roles, const LfgDungeonSet& selectedDung return; } - // FIXME - Raid browser not supported yet + SetComment(guid, comment); + if (isRaid) { sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::Join: [" UI64FMTD "] trying to join raid browser and it's disabled.", guid); return; } - SetComment(guid, comment); - + std::string debugNames = ""; if (grp) // Begin rolecheck { // Create new rolecheck - LfgRoleCheck* roleCheck = new LfgRoleCheck(); - roleCheck->cancelTime = time_t(time(NULL)) + LFG_TIME_ROLECHECK; - roleCheck->state = LFG_ROLECHECK_INITIALITING; - roleCheck->leader = guid; - roleCheck->dungeons = dungeons; - roleCheck->rDungeonId = rDungeonId; - m_RoleChecks[gguid] = roleCheck; + LfgRoleCheck& roleCheck = m_RoleChecks[gguid]; + roleCheck.cancelTime = time_t(time(NULL)) + LFG_TIME_ROLECHECK; + roleCheck.state = LFG_ROLECHECK_INITIALITING; + roleCheck.leader = guid; + roleCheck.dungeons = dungeons; + roleCheck.rDungeonId = rDungeonId; if (rDungeonId) { @@ -690,7 +695,10 @@ void LFGMgr::Join(Player* player, uint8 roles, const LfgDungeonSet& selectedDung SetState(pguid, LFG_STATE_ROLECHECK); if (!isContinue) SetSelectedDungeons(pguid, dungeons); - roleCheck->roles[pguid] = 0; + roleCheck.roles[pguid] = 0; + if (!debugNames.empty()) + debugNames.append(", "); + debugNames.append(plrg->GetName()); } } // Update leader role @@ -698,24 +706,11 @@ void LFGMgr::Join(Player* player, uint8 roles, const LfgDungeonSet& selectedDung } else // Add player to queue { - // Queue player - LfgQueueInfo* pqInfo = new LfgQueueInfo(); - pqInfo->joinTime = time_t(time(NULL)); - pqInfo->roles[player->GetGUID()] = roles; - pqInfo->dungeons = dungeons; - if (roles & ROLE_TANK) - --pqInfo->tanks; - else if (roles & ROLE_HEALER) - --pqInfo->healers; - else - --pqInfo->dps; - m_QueueInfoMap[guid] = pqInfo; + LfgRolesMap rolesMap; + rolesMap[guid] = roles; + LfgQueue& queue = GetQueue(gguid); + queue.AddQueueData(guid, time_t(time(NULL)), dungeons, rolesMap); - // Send update to player - player->GetSession()->SendLfgJoinResult(joinData); - player->GetSession()->SendLfgUpdatePlayer(LfgUpdateData(LFG_UPDATETYPE_JOIN_PROPOSAL, dungeons, comment)); - SetState(gguid, LFG_STATE_QUEUED); - SetRoles(guid, roles); if (!isContinue) { if (rDungeonId) @@ -725,66 +720,75 @@ void LFGMgr::Join(Player* player, uint8 roles, const LfgDungeonSet& selectedDung } SetSelectedDungeons(guid, dungeons); } - AddToQueue(guid, uint8(player->GetTeam())); + // Send update to player + player->GetSession()->SendLfgJoinResult(joinData); + player->GetSession()->SendLfgUpdatePlayer(LfgUpdateData(LFG_UPDATETYPE_JOIN_PROPOSAL, dungeons, comment)); + SetState(gguid, LFG_STATE_QUEUED); + SetRoles(guid, roles); + debugNames.append(player->GetName()); + } + + if (sLog->ShouldLog(LOG_FILTER_LFG, LOG_LEVEL_DEBUG)) + { + std::ostringstream o; + o << "LFGMgr::Join: [" << guid << "] joined (" << (grp ? "group" : "player") << ") Members: " << debugNames.c_str() + << ". Dungeons (" << uint32(dungeons.size()) << "): " << ConcatenateDungeons(dungeons); + sLog->outDebug(LOG_FILTER_LFG, "%s", o.str().c_str()); } - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::Join: [" UI64FMTD "] joined with %u members. dungeons: %u", guid, grp ? grp->GetMembersCount() : 1, uint8(dungeons.size())); } /** Leaves Dungeon System. Player/Group is removed from queue, rolechecks, proposals or votekicks. Player or group needs to be not NULL and using Dungeon System - @param[in] player Player trying to leave (can be NULL) - @param[in] grp Group trying to leave (default NULL) + @param[in] guid Player or group guid */ -void LFGMgr::Leave(Player* player, Group* grp /* = NULL*/) +void LFGMgr::LeaveLfg(uint64 guid) { - if (!player && !grp) - return; - - uint64 guid = grp ? grp->GetGUID() : player->GetGUID(); LfgState state = GetState(guid); + uint64 gguid = IS_GROUP(guid) ? guid : GetGroup(guid); sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::Leave: [" UI64FMTD "]", guid); switch (state) { case LFG_STATE_QUEUED: + if (gguid) { - RemoveFromQueue(guid); - LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); - if (grp) + LfgQueue& queue = GetQueue(gguid); + queue.RemoveFromQueue(gguid); + RestoreState(gguid, "Leave queue"); + const LfgGuidSet& players = GetPlayers(gguid); + for (LfgGuidSet::const_iterator it = players.begin(); it != players.end(); ++it) { - RestoreState(guid); - for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) - if (Player* plrg = itr->getSource()) - { - plrg->GetSession()->SendLfgUpdateParty(updateData); - uint64 pguid = plrg->GetGUID(); - ClearState(pguid); - } - } - else - { - player->GetSession()->SendLfgUpdatePlayer(updateData); - ClearState(guid); + uint64 guid = (*it); + ClearState(guid, "Leave queue"); + SendLfgUpdateParty(guid, LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE)); } } + else + { + LfgQueue& queue = GetQueue(guid); + queue.RemoveFromQueue(guid); + SendLfgUpdatePlayer(guid, LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE)); + ClearState(guid, "Leave queue"); + } break; case LFG_STATE_ROLECHECK: - if (grp) - UpdateRoleCheck(guid); // No player to update role = LFG_ROLECHECK_ABORTED + if (gguid) + UpdateRoleCheck(gguid); // No player to update role = LFG_ROLECHECK_ABORTED break; case LFG_STATE_PROPOSAL: { // Remove from Proposals LfgProposalMap::iterator it = m_Proposals.begin(); + uint64 pguid = gguid == guid ? GetLeader(gguid) : guid; while (it != m_Proposals.end()) { - LfgProposalPlayerMap::iterator itPlayer = it->second->players.find(player ? player->GetGUID() : grp->GetLeaderGUID()); - if (itPlayer != it->second->players.end()) + LfgProposalPlayerMap::iterator itPlayer = it->second.players.find(pguid); + if (itPlayer != it->second.players.end()) { // Mark the player/leader of group who left as didn't accept the proposal - itPlayer->second->accept = LFG_ANSWER_DENY; + itPlayer->second.accept = LFG_ANSWER_DENY; break; } ++it; @@ -801,312 +805,13 @@ void LFGMgr::Leave(Player* player, Group* grp /* = NULL*/) } /** - Sends the leader of a group the offer to continue popup - - @param[in] grp Group to send offer to -*/ -void LFGMgr::OfferContinue(Group* grp) -{ - if (grp) - { - uint64 gguid = grp->GetGUID(); - if (Player* leader = ObjectAccessor::FindPlayer(grp->GetLeaderGUID())) - leader->GetSession()->SendLfgOfferContinue(GetDungeon(gguid, false)); - } -} - -/** - Checks que main queue to try to form a Lfg group. Returns first match found (if any) - - @param[in] check List of guids trying to match with other groups - @param[in] all List of all other guids in main queue to match against - @return Pointer to proposal, if match is found -*/ -LfgProposal* LFGMgr::FindNewGroups(LfgGuidList& check, LfgGuidList& all) -{ - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::FindNewGroup: (%s) - all(%s)", ConcatenateGuids(check).c_str(), ConcatenateGuids(all).c_str()); - - LfgProposal* pProposal = NULL; - if (check.empty() || check.size() > MAXGROUPSIZE || !CheckCompatibility(check, pProposal)) - return NULL; - - // Try to match with queued groups - while (!pProposal && !all.empty()) - { - check.push_back(all.front()); - all.pop_front(); - pProposal = FindNewGroups(check, all); - check.pop_back(); - } - return pProposal; -} - -/** - Check compatibilities between groups - - @param[in] check List of guids to check compatibilities - @param[out] pProposal Proposal found if groups are compatibles and Match - @return true if group are compatibles -*/ -bool LFGMgr::CheckCompatibility(LfgGuidList check, LfgProposal*& pProposal) -{ - if (pProposal) // Do not check anything if we already have a proposal - return false; - - std::string strGuids = ConcatenateGuids(check); - - if (check.size() > MAXGROUPSIZE || check.empty()) - { - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s): Size wrong - Not compatibles", strGuids.c_str()); - return false; - } - - if (check.size() == 1 && IS_PLAYER_GUID(check.front())) // Player joining dungeon... compatible - return true; - - // Previously cached? - LfgAnswer answer = GetCompatibles(strGuids); - if (answer != LFG_ANSWER_PENDING) - { - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) compatibles (cached): %d", strGuids.c_str(), answer); - return bool(answer); - } - - // Check all but new compatiblitity - if (check.size() > 2) - { - uint64 frontGuid = check.front(); - check.pop_front(); - - // Check all-but-new compatibilities (New, A, B, C, D) --> check(A, B, C, D) - if (!CheckCompatibility(check, pProposal)) // Group not compatible - { - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) not compatibles (%s not compatibles)", strGuids.c_str(), ConcatenateGuids(check).c_str()); - SetCompatibles(strGuids, false); - return false; - } - check.push_front(frontGuid); - // all-but-new compatibles, now check with new - } - - uint8 numPlayers = 0; - uint8 numLfgGroups = 0; - uint32 groupLowGuid = 0; - LfgQueueInfoMap pqInfoMap; - for (LfgGuidList::const_iterator it = check.begin(); it != check.end() && numLfgGroups < 2 && numPlayers <= MAXGROUPSIZE; ++it) - { - uint64 guid = (*it); - LfgQueueInfoMap::iterator itQueue = m_QueueInfoMap.find(guid); - if (itQueue == m_QueueInfoMap.end() || GetState(guid) != LFG_STATE_QUEUED) - { - sLog->outError(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: [" UI64FMTD "] is not queued but listed as queued!", (*it)); - RemoveFromQueue(guid); - return false; - } - pqInfoMap[guid] = itQueue->second; - numPlayers += itQueue->second->roles.size(); - - if (IS_GROUP(guid)) - { - uint32 lowGuid = GUID_LOPART(guid); - if (Group* grp = sGroupMgr->GetGroupByGUID(lowGuid)) - if (grp->isLFGGroup()) - { - if (!numLfgGroups) - groupLowGuid = lowGuid; - ++numLfgGroups; - } - } - } - - if (check.size() == 1 && numPlayers != MAXGROUPSIZE) // Single group with less than MAXGROUPSIZE - Compatibles - return true; - - // Do not match - groups already in a lfgDungeon or too much players - if (numLfgGroups > 1 || numPlayers > MAXGROUPSIZE) - { - SetCompatibles(strGuids, false); - if (numLfgGroups > 1) - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) More than one Lfggroup (%u)", strGuids.c_str(), numLfgGroups); - else - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) Too much players (%u)", strGuids.c_str(), numPlayers); - return false; - } - - // ----- Player checks ----- - LfgRolesMap rolesMap; - uint64 leader = 0; - for (LfgQueueInfoMap::const_iterator it = pqInfoMap.begin(); it != pqInfoMap.end(); ++it) - { - for (LfgRolesMap::const_iterator itRoles = it->second->roles.begin(); itRoles != it->second->roles.end(); ++itRoles) - { - // Assign new leader - if (itRoles->second & ROLE_LEADER && (!leader || urand(0, 1))) - leader = itRoles->first; - - rolesMap[itRoles->first] = itRoles->second; - } - } - - if (rolesMap.size() != numPlayers) // Player in multiples queues! - return false; - - PlayerSet players; - for (LfgRolesMap::const_iterator it = rolesMap.begin(); it != rolesMap.end(); ++it) - { - Player* player = ObjectAccessor::FindPlayer(it->first); - if (!player) - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) Warning! [" UI64FMTD "] offline! Marking as not compatibles!", strGuids.c_str(), it->first); - else - { - for (PlayerSet::const_iterator itPlayer = players.begin(); itPlayer != players.end() && player; ++itPlayer) - { - // Do not form a group with ignoring candidates - if (player->GetSocial()->HasIgnore((*itPlayer)->GetGUIDLow()) || (*itPlayer)->GetSocial()->HasIgnore(player->GetGUIDLow())) - { - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) Players [" UI64FMTD "] and [" UI64FMTD "] ignoring", strGuids.c_str(), (*itPlayer)->GetGUID(), player->GetGUID()); - player = NULL; - } - } - if (player) - players.insert(player); - } - } - - // if we dont have the same ammount of players then we have self ignoring candidates or different faction groups - // otherwise check if roles are compatible - if (players.size() != numPlayers || !CheckGroupRoles(rolesMap)) - { - if (players.size() == numPlayers) - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) Roles not compatible", strGuids.c_str()); - SetCompatibles(strGuids, false); - return false; - } - - // ----- Selected Dungeon checks ----- - // Check if there are any compatible dungeon from the selected dungeons - LfgDungeonSet compatibleDungeons; - - LfgQueueInfoMap::const_iterator itFirst = pqInfoMap.begin(); - for (LfgDungeonSet::const_iterator itDungeon = itFirst->second->dungeons.begin(); itDungeon != itFirst->second->dungeons.end(); ++itDungeon) - { - LfgQueueInfoMap::const_iterator itOther = itFirst; - ++itOther; - while (itOther != pqInfoMap.end() && itOther->second->dungeons.find(*itDungeon) != itOther->second->dungeons.end()) - ++itOther; - - if (itOther == pqInfoMap.end()) - compatibleDungeons.insert(*itDungeon); - } - LfgLockPartyMap lockMap; - GetCompatibleDungeons(compatibleDungeons, players, lockMap); - - if (compatibleDungeons.empty()) - { - SetCompatibles(strGuids, false); - return false; - } - SetCompatibles(strGuids, true); - - // ----- Group is compatible, if we have MAXGROUPSIZE members then match is found - if (numPlayers != MAXGROUPSIZE) - { - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) Compatibles but not match. Players(%u)", strGuids.c_str(), numPlayers); - uint8 Tanks_Needed = LFG_TANKS_NEEDED; - uint8 Healers_Needed = LFG_HEALERS_NEEDED; - uint8 Dps_Needed = LFG_DPS_NEEDED; - for (LfgQueueInfoMap::const_iterator itQueue = pqInfoMap.begin(); itQueue != pqInfoMap.end(); ++itQueue) - { - LfgQueueInfo* queue = itQueue->second; - for (LfgRolesMap::const_iterator itPlayer = queue->roles.begin(); itPlayer != queue->roles.end(); ++itPlayer) - { - uint8 roles = itPlayer->second; - if ((roles & ROLE_TANK) && Tanks_Needed > 0) - --Tanks_Needed; - else if ((roles & ROLE_HEALER) && Healers_Needed > 0) - --Healers_Needed; - else if ((roles & ROLE_DAMAGE) && Dps_Needed > 0) - --Dps_Needed; - } - } - for (PlayerSet::const_iterator itPlayers = players.begin(); itPlayers != players.end(); ++itPlayers) - { - for (LfgQueueInfoMap::const_iterator itQueue = pqInfoMap.begin(); itQueue != pqInfoMap.end(); ++itQueue) - { - LfgQueueInfo* queue = itQueue->second; - if (!queue) - continue; - - for (LfgRolesMap::const_iterator itPlayer = queue->roles.begin(); itPlayer != queue->roles.end(); ++itPlayer) - { - if (*itPlayers == ObjectAccessor::FindPlayer(itPlayer->first)) - { - queue->tanks = Tanks_Needed; - queue->healers = Healers_Needed; - queue->dps = Dps_Needed; - } - } - } - } - return true; - } - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::CheckCompatibility: (%s) MATCH! Group formed", strGuids.c_str()); - - // GROUP FORMED! - // TODO - Improve algorithm to select proper group based on Item Level - // Do not match bad tank and bad healer on same group - - // Select a random dungeon from the compatible list - // TODO - Select the dungeon based on group item Level, not just random - // Create a new proposal - pProposal = new LfgProposal(Trinity::Containers::SelectRandomContainerElement(compatibleDungeons)); - pProposal->cancelTime = time_t(time(NULL)) + LFG_TIME_PROPOSAL; - pProposal->state = LFG_PROPOSAL_INITIATING; - pProposal->queues = check; - pProposal->groupLowGuid = groupLowGuid; - - // Assign new roles to players and assign new leader - PlayerSet::const_iterator itPlayers = players.begin(); - if (!leader) - { - uint8 pos = uint8(urand(0, players.size() - 1)); - for (uint8 i = 0; i < pos; ++i) - ++itPlayers; - leader = (*itPlayers)->GetGUID(); - } - pProposal->leader = leader; - - uint8 numAccept = 0; - for (itPlayers = players.begin(); itPlayers != players.end(); ++itPlayers) - { - uint64 guid = (*itPlayers)->GetGUID(); - LfgProposalPlayer* ppPlayer = new LfgProposalPlayer(); - if (Group* grp = (*itPlayers)->GetGroup()) - { - ppPlayer->groupLowGuid = grp->GetLowGUID(); - if (grp->isLFGGroup()) // Player from existing group, autoaccept - { - ppPlayer->accept = LFG_ANSWER_AGREE; - ++numAccept; - } - } - ppPlayer->role = rolesMap[guid]; - pProposal->players[guid] = ppPlayer; - } - if (numAccept == MAXGROUPSIZE) - pProposal->state = LFG_PROPOSAL_SUCCESS; - - return true; -} - -/** Update the Role check info with the player selected role. @param[in] grp Group guid to update rolecheck @param[in] guid Player guid (0 = rolecheck failed) @param[in] roles Player selected roles */ -void LFGMgr::UpdateRoleCheck(uint64 gguid, uint64 guid /* = 0 */, uint8 roles /* = ROLE_NONE */) +void LFGMgr::UpdateRoleCheck(uint64 gguid, uint64 guid /* = 0 */, uint8 roles /* = PLAYER_ROLE_NONE */) { if (!gguid) return; @@ -1116,155 +821,73 @@ void LFGMgr::UpdateRoleCheck(uint64 gguid, uint64 guid /* = 0 */, uint8 roles /* if (itRoleCheck == m_RoleChecks.end()) return; - LfgRoleCheck* roleCheck = itRoleCheck->second; - bool sendRoleChosen = roleCheck->state != LFG_ROLECHECK_DEFAULT && guid; + LfgRoleCheck& roleCheck = itRoleCheck->second; + bool sendRoleChosen = roleCheck.state != LFG_ROLECHECK_DEFAULT && guid; if (!guid) - roleCheck->state = LFG_ROLECHECK_ABORTED; - else if (roles < ROLE_TANK) // Player selected no role. - roleCheck->state = LFG_ROLECHECK_NO_ROLE; + roleCheck.state = LFG_ROLECHECK_ABORTED; + else if (roles < PLAYER_ROLE_TANK) // Player selected no role. + roleCheck.state = LFG_ROLECHECK_NO_ROLE; else { - roleCheck->roles[guid] = roles; + roleCheck.roles[guid] = roles; // Check if all players have selected a role - LfgRolesMap::const_iterator itRoles = roleCheck->roles.begin(); - while (itRoles != roleCheck->roles.end() && itRoles->second != ROLE_NONE) + LfgRolesMap::const_iterator itRoles = roleCheck.roles.begin(); + while (itRoles != roleCheck.roles.end() && itRoles->second != PLAYER_ROLE_NONE) ++itRoles; - if (itRoles == roleCheck->roles.end()) + if (itRoles == roleCheck.roles.end()) { // use temporal var to check roles, CheckGroupRoles modifies the roles - check_roles = roleCheck->roles; - roleCheck->state = CheckGroupRoles(check_roles) ? LFG_ROLECHECK_FINISHED : LFG_ROLECHECK_WRONG_ROLES; + check_roles = roleCheck.roles; + roleCheck.state = CheckGroupRoles(check_roles) ? LFG_ROLECHECK_FINISHED : LFG_ROLECHECK_WRONG_ROLES; } } - uint8 team = 0; LfgDungeonSet dungeons; - if (roleCheck->rDungeonId) - dungeons.insert(roleCheck->rDungeonId); + if (roleCheck.rDungeonId) + dungeons.insert(roleCheck.rDungeonId); else - dungeons = roleCheck->dungeons; + dungeons = roleCheck.dungeons; - LfgJoinResultData joinData = LfgJoinResultData(LFG_JOIN_FAILED, roleCheck->state); - for (LfgRolesMap::const_iterator it = roleCheck->roles.begin(); it != roleCheck->roles.end(); ++it) + LfgJoinResultData joinData = LfgJoinResultData(LFG_JOIN_FAILED, roleCheck.state); + for (LfgRolesMap::const_iterator it = roleCheck.roles.begin(); it != roleCheck.roles.end(); ++it) { uint64 pguid = it->first; - Player* plrg = ObjectAccessor::FindPlayer(pguid); - if (!plrg) - { - if (roleCheck->state == LFG_ROLECHECK_FINISHED) - SetState(pguid, LFG_STATE_QUEUED); - else if (roleCheck->state != LFG_ROLECHECK_INITIALITING) - ClearState(pguid); - continue; - } - team = uint8(plrg->GetTeam()); if (!sendRoleChosen) - plrg->GetSession()->SendLfgRoleChosen(guid, roles); - plrg->GetSession()->SendLfgRoleCheckUpdate(roleCheck); - switch (roleCheck->state) + SendLfgRoleChosen(pguid, guid, roles); + + SendLfgRoleCheckUpdate(pguid, roleCheck); + switch (roleCheck.state) { case LFG_ROLECHECK_INITIALITING: continue; case LFG_ROLECHECK_FINISHED: SetState(pguid, LFG_STATE_QUEUED); - plrg->GetSession()->SendLfgUpdateParty(LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, dungeons, GetComment(pguid))); + SetRoles(pguid, it->second); + SendLfgUpdateParty(pguid, LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, dungeons, GetComment(pguid))); break; default: - if (roleCheck->leader == pguid) - plrg->GetSession()->SendLfgJoinResult(joinData); - plrg->GetSession()->SendLfgUpdateParty(LfgUpdateData(LFG_UPDATETYPE_ROLECHECK_FAILED)); - ClearState(pguid); + if (roleCheck.leader == pguid) + SendLfgJoinResult(pguid, joinData); + SendLfgUpdateParty(pguid, LfgUpdateData(LFG_UPDATETYPE_ROLECHECK_FAILED)); + ClearState(pguid, "Role check Failed"); break; } } - if (roleCheck->state == LFG_ROLECHECK_FINISHED) + if (roleCheck.state == LFG_ROLECHECK_FINISHED) { SetState(gguid, LFG_STATE_QUEUED); - LfgQueueInfo* pqInfo = new LfgQueueInfo(); - pqInfo->joinTime = time_t(time(NULL)); - pqInfo->roles = roleCheck->roles; - pqInfo->dungeons = roleCheck->dungeons; - - // Set queue roles needed - As we are using check_roles will not have more that 1 tank, 1 healer, 3 dps - for (LfgRolesMap::const_iterator it = check_roles.begin(); it != check_roles.end(); ++it) - { - uint8 roles2 = it->second; - if (roles2 & ROLE_TANK) - --pqInfo->tanks; - else if (roles2 & ROLE_HEALER) - --pqInfo->healers; - else - --pqInfo->dps; - } - - m_QueueInfoMap[gguid] = pqInfo; - if (GetState(gguid) != LFG_STATE_NONE) - { - LfgGuidList& currentQueue = m_currentQueue[team]; - currentQueue.push_front(gguid); - } - AddToQueue(gguid, team); + LfgQueue& queue = GetQueue(gguid); + queue.AddQueueData(gguid, time_t(time(NULL)), roleCheck.dungeons, roleCheck.roles); } + else if (roleCheck.state != LFG_ROLECHECK_INITIALITING) + RestoreState(gguid, "Rolecheck Failed"); - if (roleCheck->state != LFG_ROLECHECK_INITIALITING) - { - if (roleCheck->state != LFG_ROLECHECK_FINISHED) - RestoreState(gguid); - delete roleCheck; - m_RoleChecks.erase(itRoleCheck); - } -} - -/** - Remove from cached compatible dungeons any entry that contains the given guid - - @param[in] guid Guid to remove from compatible cache -*/ -void LFGMgr::RemoveFromCompatibles(uint64 guid) -{ - std::stringstream out; - out << guid; - std::string strGuid = out.str(); - - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::RemoveFromCompatibles: Removing [" UI64FMTD "]", guid); - for (LfgCompatibleMap::iterator itNext = m_CompatibleMap.begin(); itNext != m_CompatibleMap.end();) - { - LfgCompatibleMap::iterator it = itNext++; - if (it->first.find(strGuid) != std::string::npos) // Found, remove it - m_CompatibleMap.erase(it); - } -} - -/** - Stores the compatibility of a list of guids - - @param[in] key String concatenation of guids (| used as separator) - @param[in] compatibles Compatibles or not -*/ -void LFGMgr::SetCompatibles(std::string key, bool compatibles) -{ - m_CompatibleMap[key] = LfgAnswer(compatibles); -} - -/** - Get the compatibility of a group of guids - - @param[in] key String concatenation of guids (| used as separator) - @return 1 (Compatibles), 0 (Not compatibles), -1 (Not set) -*/ -LfgAnswer LFGMgr::GetCompatibles(std::string key) -{ - LfgAnswer answer = LFG_ANSWER_PENDING; - LfgCompatibleMap::iterator it = m_CompatibleMap.find(key); - if (it != m_CompatibleMap.end()) - answer = it->second; - - return answer; + m_RoleChecks.erase(itRoleCheck); } /** @@ -1274,13 +897,13 @@ LfgAnswer LFGMgr::GetCompatibles(std::string key) @param[in] players Set of players to check their dungeon restrictions @param[out] lockMap Map of players Lock status info of given dungeons (Empty if dungeons is not empty) */ -void LFGMgr::GetCompatibleDungeons(LfgDungeonSet& dungeons, const PlayerSet& players, LfgLockPartyMap& lockMap) +void LFGMgr::GetCompatibleDungeons(LfgDungeonSet& dungeons, const LfgGuidSet& players, LfgLockPartyMap& lockMap) { lockMap.clear(); - for (PlayerSet::const_iterator it = players.begin(); it != players.end() && !dungeons.empty(); ++it) + for (LfgGuidSet::const_iterator it = players.begin(); it != players.end() && !dungeons.empty(); ++it) { - uint64 guid = (*it)->GetGUID(); - LfgLockMap cachedLockMap = GetLockedDungeons(guid); + uint64 guid = (*it); + LfgLockMap const& cachedLockMap = GetLockedDungeons(guid); for (LfgLockMap::const_iterator it2 = cachedLockMap.begin(); it2 != cachedLockMap.end() && !dungeons.empty(); ++it2) { uint32 dungeonId = (it2->first & 0x00FFFFFF); // Compare dungeon ids @@ -1314,21 +937,21 @@ bool LFGMgr::CheckGroupRoles(LfgRolesMap& groles, bool removeLeaderFlag /*= true if (removeLeaderFlag) for (LfgRolesMap::iterator it = groles.begin(); it != groles.end(); ++it) - it->second &= ~ROLE_LEADER; + it->second &= ~PLAYER_ROLE_LEADER; for (LfgRolesMap::iterator it = groles.begin(); it != groles.end(); ++it) { - if (it->second == ROLE_NONE) + if (it->second == PLAYER_ROLE_NONE) return false; - if (it->second & ROLE_TANK) + if (it->second & PLAYER_ROLE_TANK) { - if (it->second != ROLE_TANK) + if (it->second != PLAYER_ROLE_TANK) { - it->second -= ROLE_TANK; + it->second -= PLAYER_ROLE_TANK; if (CheckGroupRoles(groles, false)) return true; - it->second += ROLE_TANK; + it->second += PLAYER_ROLE_TANK; } else if (tank == LFG_TANKS_NEEDED) return false; @@ -1336,14 +959,14 @@ bool LFGMgr::CheckGroupRoles(LfgRolesMap& groles, bool removeLeaderFlag /*= true tank++; } - if (it->second & ROLE_HEALER) + if (it->second & PLAYER_ROLE_HEALER) { - if (it->second != ROLE_HEALER) + if (it->second != PLAYER_ROLE_HEALER) { - it->second -= ROLE_HEALER; + it->second -= PLAYER_ROLE_HEALER; if (CheckGroupRoles(groles, false)) return true; - it->second += ROLE_HEALER; + it->second += PLAYER_ROLE_HEALER; } else if (healer == LFG_HEALERS_NEEDED) return false; @@ -1351,14 +974,14 @@ bool LFGMgr::CheckGroupRoles(LfgRolesMap& groles, bool removeLeaderFlag /*= true healer++; } - if (it->second & ROLE_DAMAGE) + if (it->second & PLAYER_ROLE_DAMAGE) { - if (it->second != ROLE_DAMAGE) + if (it->second != PLAYER_ROLE_DAMAGE) { - it->second -= ROLE_DAMAGE; + it->second -= PLAYER_ROLE_DAMAGE; if (CheckGroupRoles(groles, false)) return true; - it->second += ROLE_DAMAGE; + it->second += PLAYER_ROLE_DAMAGE; } else if (damage == LFG_DPS_NEEDED) return false; @@ -1370,6 +993,84 @@ bool LFGMgr::CheckGroupRoles(LfgRolesMap& groles, bool removeLeaderFlag /*= true } /** + Makes a new group given a proposal + @param[in] proposal Proposal to get info from +*/ +void LFGMgr::MakeNewGroup(const LfgProposal& proposal) +{ + LfgGuidList players; + LfgGuidList playersToTeleport; + + for (LfgProposalPlayerMap::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it) + { + uint64 guid = it->first; + if (guid == proposal.leader) + players.push_front(guid); + else + players.push_back(guid); + + if (proposal.isNew || GetGroup(guid) != proposal.group) + playersToTeleport.push_back(guid); + } + + // Set the dungeon difficulty + LFGDungeonEntry const* dungeon = GetLFGDungeon(proposal.dungeonId); + ASSERT(dungeon); + + Group* grp = proposal.group ? sGroupMgr->GetGroupByGUID(GUID_LOPART(proposal.group)) : NULL; + for (LfgGuidList::const_iterator it = players.begin(); it != players.end(); ++it) + { + uint64 pguid = (*it); + Player* player = ObjectAccessor::FindPlayer(pguid); + if (!player) + continue; + + Group* group = player->GetGroup(); + if (group && group != grp) + player->RemoveFromGroup(); + + if (!grp) + { + grp = new Group(); + grp->ConvertToLFG(); + grp->Create(player); + uint64 gguid = grp->GetGUID(); + SetState(gguid, LFG_STATE_PROPOSAL); + sGroupMgr->AddGroup(grp); + } + else if (group != grp) + grp->AddMember(player); + + grp->SetLfgRoles(pguid, proposal.players.find(pguid)->second.role); + + // Add the cooldown spell if queued for a random dungeon + if (dungeon->type == LFG_TYPE_RANDOM) + player->CastSpell(player, LFG_SPELL_DUNGEON_COOLDOWN, false); + } + + grp->SetDungeonDifficulty(Difficulty(dungeon->difficulty)); + uint64 gguid = grp->GetGUID(); + SetDungeon(gguid, dungeon->Entry()); + SetState(gguid, LFG_STATE_DUNGEON); + + _SaveToDB(gguid, grp->GetDbStoreId()); + + // Teleport Player + for (LfgGuidList::const_iterator it = playersToTeleport.begin(); it != playersToTeleport.end(); ++it) + if (Player* player = ObjectAccessor::FindPlayer(*it)) + TeleportPlayer(player, false); + + // Update group info + grp->SendUpdate(); +} + +uint32 LFGMgr::AddProposal(LfgProposal const& proposal) +{ + m_Proposals[++m_lfgProposalId] = proposal; + return m_lfgProposalId; +} + +/** Update Proposal info with player answer @param[in] proposalId Proposal id to be updated @@ -1382,15 +1083,17 @@ void LFGMgr::UpdateProposal(uint32 proposalId, uint64 guid, bool accept) LfgProposalMap::iterator itProposal = m_Proposals.find(proposalId); if (itProposal == m_Proposals.end()) return; - LfgProposal* pProposal = itProposal->second; + + LfgProposal& proposal = itProposal->second; // Check if proposal have the current player - LfgProposalPlayerMap::iterator itProposalPlayer = pProposal->players.find(guid); - if (itProposalPlayer == pProposal->players.end()) + LfgProposalPlayerMap::iterator itProposalPlayer = proposal.players.find(guid); + if (itProposalPlayer == proposal.players.end()) return; - LfgProposalPlayer* ppPlayer = itProposalPlayer->second; - ppPlayer->accept = LfgAnswer(accept); + LfgProposalPlayer& player = itProposalPlayer->second; + player.accept = LfgAnswer(accept); + sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::UpdateProposal: Player [" UI64FMTD "] of proposal %u selected: %u", guid, proposalId, accept); if (!accept) { @@ -1398,157 +1101,80 @@ void LFGMgr::UpdateProposal(uint32 proposalId, uint64 guid, bool accept) return; } - LfgPlayerList players; - LfgPlayerList playersToTeleport; - // check if all have answered and reorder players (leader first) bool allAnswered = true; - for (LfgProposalPlayerMap::const_iterator itPlayers = pProposal->players.begin(); itPlayers != pProposal->players.end(); ++itPlayers) - { - if (Player* player = ObjectAccessor::FindPlayer(itPlayers->first)) - { - if (itPlayers->first == pProposal->leader) - players.push_front(player); - else - players.push_back(player); - - // Only teleport new players - Group* grp = player->GetGroup(); - uint64 gguid = grp ? grp->GetGUID() : 0; - if (!gguid || !grp->isLFGGroup() || GetState(gguid) == LFG_STATE_FINISHED_DUNGEON) - playersToTeleport.push_back(player); - } - - if (itPlayers->second->accept != LFG_ANSWER_AGREE) // No answer (-1) or not accepted (0) + for (LfgProposalPlayerMap::const_iterator itPlayers = proposal.players.begin(); itPlayers != proposal.players.end(); ++itPlayers) + if (itPlayers->second.accept != LFG_ANSWER_AGREE) // No answer (-1) or not accepted (0) allAnswered = false; - } if (!allAnswered) { - for (LfgPlayerList::const_iterator it = players.begin(); it != players.end(); ++it) - (*it)->GetSession()->SendLfgUpdateProposal(proposalId, pProposal); - } - else - { - bool sendUpdate = pProposal->state != LFG_PROPOSAL_SUCCESS; - pProposal->state = LFG_PROPOSAL_SUCCESS; - time_t joinTime = time_t(time(NULL)); - std::map<uint64, int32> waitTimesMap; - // Save wait times before redoing groups - for (LfgPlayerList::const_iterator it = players.begin(); it != players.end(); ++it) + for (LfgProposalPlayerMap::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it) { - LfgProposalPlayer* player = pProposal->players[(*it)->GetGUID()]; - uint32 lowgroupguid = (*it)->GetGroup() ? (*it)->GetGroup()->GetLowGUID() : 0; - if (player->groupLowGuid != lowgroupguid) - sLog->outError(LOG_FILTER_LFG, "LFGMgr::UpdateProposal: [" UI64FMTD "] group mismatch: actual (%u) - queued (%u)", (*it)->GetGUID(), lowgroupguid, player->groupLowGuid); - - uint64 guid2 = player->groupLowGuid ? MAKE_NEW_GUID(player->groupLowGuid, 0, HIGHGUID_GROUP) : (*it)->GetGUID(); - LfgQueueInfoMap::iterator itQueue = m_QueueInfoMap.find(guid2); - if (itQueue == m_QueueInfoMap.end()) - { - sLog->outError(LOG_FILTER_LFG, "LFGMgr::UpdateProposal: Queue info for guid [" UI64FMTD "] not found!", guid); - waitTimesMap[(*it)->GetGUID()] = -1; - } - else - waitTimesMap[(*it)->GetGUID()] = int32(joinTime - itQueue->second->joinTime); + uint64 guid = it->first; + SendLfgUpdateProposal(guid, proposalId, proposal); } + return; + } - // Set the dungeon difficulty - LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(pProposal->dungeonId); - ASSERT(dungeon); - - // Create a new group (if needed) - LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_GROUP_FOUND); - Group* grp = pProposal->groupLowGuid ? sGroupMgr->GetGroupByGUID(pProposal->groupLowGuid) : NULL; - for (LfgPlayerList::const_iterator it = players.begin(); it != players.end(); ++it) - { - Player* player = (*it); - uint64 pguid = player->GetGUID(); - Group* group = player->GetGroup(); - if (sendUpdate) - player->GetSession()->SendLfgUpdateProposal(proposalId, pProposal); - - if (group) - { - player->GetSession()->SendLfgUpdateParty(updateData); - if (group != grp) - player->RemoveFromGroup(); - } - else - player->GetSession()->SendLfgUpdatePlayer(updateData); - - if (!grp) - { - grp = new Group(); - grp->Create(player); - grp->ConvertToLFG(); - uint64 gguid = grp->GetGUID(); - SetState(gguid, LFG_STATE_PROPOSAL); - sGroupMgr->AddGroup(grp); - } - else if (group != grp) - grp->AddMember(player); - - // Update timers - uint8 role = GetRoles(pguid); - role &= ~ROLE_LEADER; - switch (role) - { - case ROLE_DAMAGE: - { - uint32 old_number = m_NumWaitTimeDps++; - m_WaitTimeDps = int32((m_WaitTimeDps * old_number + waitTimesMap[player->GetGUID()]) / m_NumWaitTimeDps); - break; - } - case ROLE_HEALER: - { - uint32 old_number = m_NumWaitTimeHealer++; - m_WaitTimeHealer = int32((m_WaitTimeHealer * old_number + waitTimesMap[player->GetGUID()]) / m_NumWaitTimeHealer); - break; - } - case ROLE_TANK: - { - uint32 old_number = m_NumWaitTimeTank++; - m_WaitTimeTank = int32((m_WaitTimeTank * old_number + waitTimesMap[player->GetGUID()]) / m_NumWaitTimeTank); - break; - } - default: - { - uint32 old_number = m_NumWaitTimeAvg++; - m_WaitTimeAvg = int32((m_WaitTimeAvg * old_number + waitTimesMap[player->GetGUID()]) / m_NumWaitTimeAvg); - break; - } - } + bool sendUpdate = proposal.state != LFG_PROPOSAL_SUCCESS; + proposal.state = LFG_PROPOSAL_SUCCESS; + time_t joinTime = time_t(time(NULL)); - m_teleport.push_back(pguid); - grp->SetLfgRoles(pguid, pProposal->players[pguid]->role); - SetState(pguid, LFG_STATE_DUNGEON); + LfgQueue& queue = GetQueue(guid); + LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_GROUP_FOUND); + for (LfgProposalPlayerMap::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it) + { + uint64 pguid = it->first; + uint64 gguid = it->second.group; + uint32 dungeonId = (*GetSelectedDungeons(pguid).begin()); + int32 waitTime = -1; + if (sendUpdate) + SendLfgUpdateProposal(pguid, proposalId, proposal); - // Add the cooldown spell if queued for a random dungeon - if (dungeon->type == LFG_TYPE_RANDOM) - player->CastSpell(player, LFG_SPELL_DUNGEON_COOLDOWN, false); + if (gguid) + { + waitTime = int32((joinTime - queue.GetJoinTime(gguid)) / IN_MILLISECONDS); + SendLfgUpdateParty(pguid, updateData); + } + else + { + waitTime = int32((joinTime - queue.GetJoinTime(pguid)) / IN_MILLISECONDS); + SendLfgUpdatePlayer(pguid, updateData); + } + updateData.updateType = LFG_UPDATETYPE_REMOVED_FROM_QUEUE; + SendLfgUpdatePlayer(pguid, updateData); + SendLfgUpdateParty(pguid, updateData); + + // Update timers + uint8 role = GetRoles(pguid); + role &= ~PLAYER_ROLE_LEADER; + switch (role) + { + case PLAYER_ROLE_DAMAGE: + queue.UpdateWaitTimeDps(waitTime, dungeonId); + break; + case PLAYER_ROLE_HEALER: + queue.UpdateWaitTimeHealer(waitTime, dungeonId); + break; + case PLAYER_ROLE_TANK: + queue.UpdateWaitTimeTank(waitTime, dungeonId); + break; + default: + queue.UpdateWaitTimeAvg(waitTime, dungeonId); + break; } - grp->SetDungeonDifficulty(Difficulty(dungeon->difficulty)); - uint64 gguid = grp->GetGUID(); - SetDungeon(gguid, dungeon->Entry()); - SetState(gguid, LFG_STATE_DUNGEON); - _SaveToDB(gguid, grp->GetDbStoreId()); - - // Remove players/groups from Queue - for (LfgGuidList::const_iterator it = pProposal->queues.begin(); it != pProposal->queues.end(); ++it) - RemoveFromQueue(*it); - - // Teleport Player - for (LfgPlayerList::const_iterator it = playersToTeleport.begin(); it != playersToTeleport.end(); ++it) - TeleportPlayer(*it, false); + m_teleport.push_back(pguid); + SetState(pguid, LFG_STATE_DUNGEON); + } - // Update group info - grp->SendUpdate(); + // Remove players/groups from Queue + for (LfgGuidList::const_iterator it = proposal.queues.begin(); it != proposal.queues.end(); ++it) + queue.RemoveFromQueue(*it); - delete pProposal; - m_Proposals.erase(itProposal); - } + MakeNewGroup(proposal); + m_Proposals.erase(itProposal); } /** @@ -1559,51 +1185,44 @@ void LFGMgr::UpdateProposal(uint32 proposalId, uint64 guid, bool accept) */ void LFGMgr::RemoveProposal(LfgProposalMap::iterator itProposal, LfgUpdateType type) { - LfgProposal* pProposal = itProposal->second; - pProposal->state = LFG_PROPOSAL_FAILED; + LfgProposal& proposal = itProposal->second; + proposal.state = LFG_PROPOSAL_FAILED; sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::RemoveProposal: Proposal %u, state FAILED, UpdateType %u", itProposal->first, type); // Mark all people that didn't answered as no accept if (type == LFG_UPDATETYPE_PROPOSAL_FAILED) - for (LfgProposalPlayerMap::const_iterator it = pProposal->players.begin(); it != pProposal->players.end(); ++it) - if (it->second->accept == LFG_ANSWER_PENDING) - it->second->accept = LFG_ANSWER_DENY; + for (LfgProposalPlayerMap::iterator it = proposal.players.begin(); it != proposal.players.end(); ++it) + if (it->second.accept == LFG_ANSWER_PENDING) + it->second.accept = LFG_ANSWER_DENY; // Mark players/groups to be removed LfgGuidSet toRemove; - for (LfgProposalPlayerMap::const_iterator it = pProposal->players.begin(); it != pProposal->players.end(); ++it) + for (LfgProposalPlayerMap::iterator it = proposal.players.begin(); it != proposal.players.end(); ++it) { - if (it->second->accept == LFG_ANSWER_AGREE) + if (it->second.accept == LFG_ANSWER_AGREE) continue; - uint64 guid = it->second->groupLowGuid ? MAKE_NEW_GUID(it->second->groupLowGuid, 0, HIGHGUID_GROUP) : it->first; + uint64 guid = it->second.group ? it->second.group : it->first; // Player didn't accept or still pending when no secs left - if (it->second->accept == LFG_ANSWER_DENY || type == LFG_UPDATETYPE_PROPOSAL_FAILED) + if (it->second.accept == LFG_ANSWER_DENY || type == LFG_UPDATETYPE_PROPOSAL_FAILED) { - it->second->accept = LFG_ANSWER_DENY; + it->second.accept = LFG_ANSWER_DENY; toRemove.insert(guid); } } - uint8 team = 0; // Notify players - for (LfgProposalPlayerMap::const_iterator it = pProposal->players.begin(); it != pProposal->players.end(); ++it) + for (LfgProposalPlayerMap::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it) { - Player* player = ObjectAccessor::FindPlayer(it->first); - if (!player) - continue; - - team = uint8(player->GetTeam()); - player->GetSession()->SendLfgUpdateProposal(itProposal->first, pProposal); + uint64 guid = it->first; + uint64 gguid = it->second.group ? it->second.group : guid; - Group* grp = player->GetGroup(); - uint64 guid = player->GetGUID(); - uint64 gguid = it->second->groupLowGuid ? MAKE_NEW_GUID(it->second->groupLowGuid, 0, HIGHGUID_GROUP) : guid; + SendLfgUpdateProposal(guid, itProposal->first, proposal); if (toRemove.find(gguid) != toRemove.end()) // Didn't accept or in same group that someone that didn't accept { LfgUpdateData updateData; - if (it->second->accept == LFG_ANSWER_DENY) + if (it->second.accept == LFG_ANSWER_DENY) { updateData.updateType = type; sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::RemoveProposal: [" UI64FMTD "] didn't accept. Removing from queue and compatible cache", guid); @@ -1613,126 +1232,110 @@ void LFGMgr::RemoveProposal(LfgProposalMap::iterator itProposal, LfgUpdateType t updateData.updateType = LFG_UPDATETYPE_REMOVED_FROM_QUEUE; sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::RemoveProposal: [" UI64FMTD "] in same group that someone that didn't accept. Removing from queue and compatible cache", guid); } - ClearState(guid); - if (grp) + ClearState(guid, "Proposal Fail (didn't accepted or in group with someone that didn't accept"); + if (gguid != guid) { - RestoreState(gguid); - player->GetSession()->SendLfgUpdateParty(updateData); + RestoreState(gguid, "Proposal Fail (someone in group didn't accepted)"); + SendLfgUpdateParty(guid, updateData); } else - player->GetSession()->SendLfgUpdatePlayer(updateData); + SendLfgUpdatePlayer(guid, updateData); } else { sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::RemoveProposal: Readding [" UI64FMTD "] to queue.", guid); SetState(guid, LFG_STATE_QUEUED); - if (grp) + if (gguid != guid) { SetState(gguid, LFG_STATE_QUEUED); - player->GetSession()->SendLfgUpdateParty(LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, GetSelectedDungeons(guid), GetComment(guid))); + SendLfgUpdateParty(guid, LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, GetSelectedDungeons(guid), GetComment(guid))); } else - player->GetSession()->SendLfgUpdatePlayer(LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, GetSelectedDungeons(guid), GetComment(guid))); + SendLfgUpdatePlayer(guid, LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, GetSelectedDungeons(guid), GetComment(guid))); } } + LfgQueue& queue = GetQueue(proposal.players.begin()->first); // Remove players/groups from queue for (LfgGuidSet::const_iterator it = toRemove.begin(); it != toRemove.end(); ++it) { uint64 guid = *it; - RemoveFromQueue(guid); - pProposal->queues.remove(guid); + queue.RemoveFromQueue(guid); + proposal.queues.remove(guid); } // Readd to queue - for (LfgGuidList::const_iterator it = pProposal->queues.begin(); it != pProposal->queues.end(); ++it) + for (LfgGuidList::const_iterator it = proposal.queues.begin(); it != proposal.queues.end(); ++it) { uint64 guid = *it; - LfgGuidList& currentQueue = m_currentQueue[team]; - currentQueue.push_front(guid); //Add GUID for high priority - AddToQueue(guid, team); //We have to add each GUID in newQueue to check for a new groups + queue.AddToQueue(guid); } - delete pProposal; m_Proposals.erase(itProposal); } /** Initialize a boot kick vote - @param[in] grp Group the vote kicks belongs to + @param[in] gguid Group the vote kicks belongs to @param[in] kicker Kicker guid @param[in] victim Victim guid @param[in] reason Kick reason */ -void LFGMgr::InitBoot(Group* grp, uint64 kicker, uint64 victim, std::string reason) +void LFGMgr::InitBoot(uint64 gguid, uint64 kicker, uint64 victim, std::string const& reason) { - if (!grp) - return; - - uint64 gguid = grp->GetGUID(); SetState(gguid, LFG_STATE_BOOT); - LfgPlayerBoot* pBoot = new LfgPlayerBoot(); - pBoot->inProgress = true; - pBoot->cancelTime = time_t(time(NULL)) + LFG_TIME_BOOT; - pBoot->reason = reason; - pBoot->victim = victim; - pBoot->votedNeeded = GetVotesNeeded(gguid); + LfgPlayerBoot& boot = m_Boots[gguid]; + boot.inProgress = true; + boot.cancelTime = time_t(time(NULL)) + LFG_TIME_BOOT; + boot.reason = reason; + boot.victim = victim; + + LfgGuidSet const& players = GetPlayers(gguid); // Set votes - for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + for (LfgGuidSet::const_iterator itr = players.begin(); itr != players.end(); ++itr) { - if (Player* plrg = itr->getSource()) - { - uint64 guid = plrg->GetGUID(); - SetState(guid, LFG_STATE_BOOT); - if (guid == victim) - pBoot->votes[victim] = LFG_ANSWER_DENY; // Victim auto vote NO - else if (guid == kicker) - pBoot->votes[kicker] = LFG_ANSWER_AGREE; // Kicker auto vote YES - else - { - pBoot->votes[guid] = LFG_ANSWER_PENDING; // Other members need to vote - plrg->GetSession()->SendLfgBootPlayer(pBoot); - } - } + uint64 guid = (*itr); + SetState(guid, LFG_STATE_BOOT); + boot.votes[guid] = LFG_ANSWER_PENDING; } - m_Boots[grp->GetLowGUID()] = pBoot; + boot.votes[victim] = LFG_ANSWER_DENY; // Victim auto vote NO + boot.votes[kicker] = LFG_ANSWER_AGREE; // Kicker auto vote YES + + // Notify players + for (LfgGuidSet::const_iterator it = players.begin(); it != players.end(); ++it) + SendLfgBootProposalUpdate(*it, boot); } /** Update Boot info with player answer - @param[in] player Player who has answered + @param[in] guid Player who has answered @param[in] accept player answer */ -void LFGMgr::UpdateBoot(Player* player, bool accept) +void LFGMgr::UpdateBoot(uint64 guid, bool accept) { - Group* grp = player ? player->GetGroup() : NULL; - if (!grp) + uint64 gguid = GetGroup(guid); + if (!gguid) return; - uint32 bootId = grp->GetLowGUID(); - uint64 guid = player->GetGUID(); - - LfgPlayerBootMap::iterator itBoot = m_Boots.find(bootId); + LfgPlayerBootMap::iterator itBoot = m_Boots.find(gguid); if (itBoot == m_Boots.end()) return; - LfgPlayerBoot* pBoot = itBoot->second; - if (!pBoot) - return; + LfgPlayerBoot& boot = itBoot->second; - if (pBoot->votes[guid] != LFG_ANSWER_PENDING) // Cheat check: Player can't vote twice + if (boot.votes[guid] != LFG_ANSWER_PENDING) // Cheat check: Player can't vote twice return; - pBoot->votes[guid] = LfgAnswer(accept); + boot.votes[guid] = LfgAnswer(accept); uint8 votesNum = 0; uint8 agreeNum = 0; - for (LfgAnswerMap::const_iterator itVotes = pBoot->votes.begin(); itVotes != pBoot->votes.end(); ++itVotes) + for (LfgAnswerMap::const_iterator itVotes = boot.votes.begin(); itVotes != boot.votes.end(); ++itVotes) { if (itVotes->second != LFG_ANSWER_PENDING) { @@ -1742,39 +1345,30 @@ void LFGMgr::UpdateBoot(Player* player, bool accept) } } - if (agreeNum == pBoot->votedNeeded || // Vote passed - votesNum == pBoot->votes.size() || // All voted but not passed - (pBoot->votes.size() - votesNum + agreeNum) < pBoot->votedNeeded) // Vote didnt passed + // if we don't have enough votes (agree or deny) do nothing + if (agreeNum < LFG_GROUP_KICK_VOTES_NEEDED && (votesNum - agreeNum) < LFG_GROUP_KICK_VOTES_NEEDED) + return; + + // Send update info to all players + boot.inProgress = false; + for (LfgAnswerMap::const_iterator itVotes = boot.votes.begin(); itVotes != boot.votes.end(); ++itVotes) { - // Send update info to all players - pBoot->inProgress = false; - for (LfgAnswerMap::const_iterator itVotes = pBoot->votes.begin(); itVotes != pBoot->votes.end(); ++itVotes) + uint64 pguid = itVotes->first; + if (pguid != boot.victim) { - uint64 pguid = itVotes->first; - if (pguid != pBoot->victim) - { - SetState(pguid, LFG_STATE_DUNGEON); - if (Player* plrg = ObjectAccessor::FindPlayer(pguid)) - plrg->GetSession()->SendLfgBootPlayer(pBoot); - } + SetState(pguid, LFG_STATE_DUNGEON); + SendLfgBootProposalUpdate(pguid, boot); } + } - uint64 gguid = grp->GetGUID(); - SetState(gguid, LFG_STATE_DUNGEON); - if (agreeNum == pBoot->votedNeeded) // Vote passed - Kick player - { - Player::RemoveFromGroup(grp, pBoot->victim); - if (Player* victim = ObjectAccessor::FindPlayer(pBoot->victim)) - { - TeleportPlayer(victim, true, false); - SetState(pBoot->victim, LFG_STATE_NONE); - } - OfferContinue(grp); - DecreaseKicksLeft(gguid); - } - delete pBoot; - m_Boots.erase(itBoot); + SetState(gguid, LFG_STATE_DUNGEON); + if (agreeNum == LFG_GROUP_KICK_VOTES_NEEDED) // Vote passed - Kick player + { + if (Group* group = sGroupMgr->GetGroupByGUID(GUID_LOPART(gguid))) + Player::RemoveFromGroup(group, boot.victim, GROUP_REMOVEMETHOD_KICK_LFG); + DecreaseKicksLeft(gguid); } + m_Boots.erase(itBoot); } /** @@ -1788,8 +1382,20 @@ void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false* { sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::TeleportPlayer: [" UI64FMTD "] is being teleported %s", player->GetGUID(), out ? "out" : "in"); - LfgTeleportError error = LFG_TELEPORTERROR_OK; Group* grp = player->GetGroup(); + uint64 gguid = grp->GetGUID(); + LFGDungeonEntry const* dungeon = GetLFGDungeon(GetDungeon(gguid)); + if (!dungeon || (out && player->GetMapId() != uint32(dungeon->map))) + return; + + if (out) + { + player->RemoveAurasDueToSpell(LFG_SPELL_LUCK_OF_THE_DRAW); + player->TeleportToBGEntryPoint(); + return; + } + + LfgTeleportError error = LFG_TELEPORTERROR_OK; if (!grp || !grp->isLFGGroup()) // should never happen, but just in case... error = LFG_TELEPORTERROR_INVALID_LOCATION; @@ -1799,33 +1405,21 @@ void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false* error = LFG_TELEPORTERROR_FALLING; else if (player->IsMirrorTimerActive(FATIGUE_TIMER)) error = LFG_TELEPORTERROR_FATIGUE; + else if (player->GetVehicle()) + error = LFG_TELEPORTERROR_IN_VEHICLE; + else if (player->GetCharmGUID()) + error = LFG_TELEPORTERROR_CHARMING; else { - LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(GetDungeon(grp->GetGUID())); - - if (out) - { - // Player needs to be inside the LFG dungeon to be able to teleport out - if (dungeon && player->GetMapId() == uint32(dungeon->map)) - { - player->RemoveAurasDueToSpell(LFG_SPELL_LUCK_OF_THE_DRAW); - player->TeleportToBGEntryPoint(); - } - else - player->GetSession()->SendLfgTeleportError(LFG_TELEPORTERROR_DONT_REPORT); // Not sure which error message to send - - return; - } - if (!dungeon) error = LFG_TELEPORTERROR_INVALID_LOCATION; else if (player->GetMapId() != uint32(dungeon->map)) // Do not teleport players in dungeon to the entrance { - uint32 mapid = 0; - float x = 0; - float y = 0; - float z = 0; - float orientation = 0; + uint32 mapid = dungeon->map; + float x = dungeon->x; + float y = dungeon->y; + float z = dungeon->z; + float orientation = dungeon->o; if (!fromOpcode) { @@ -1844,32 +1438,6 @@ void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false* } } - if (!mapid) - { - LfgEntrancePositionMap::const_iterator itr = m_entrancePositions.find(dungeon->ID); - if (itr != m_entrancePositions.end()) - { - mapid = dungeon->map; - x = itr->second.GetPositionX(); - y = itr->second.GetPositionY(); - z = itr->second.GetPositionZ(); - orientation = itr->second.GetOrientation(); - } - else if (AreaTrigger const* at = sObjectMgr->GetMapEntranceTrigger(dungeon->map)) - { - mapid = at->target_mapId; - x = at->target_X; - y = at->target_Y; - z = at->target_Z; - orientation = at->target_Orientation; - } - else - { - sLog->outError(LOG_FILTER_LFG, "LfgMgr::TeleportPlayer: Failed to teleport [" UI64FMTD "]: No areatrigger found for map: %u difficulty: %u", player->GetGUID(), dungeon->map, dungeon->difficulty); - error = LFG_TELEPORTERROR_INVALID_LOCATION; - } - } - if (error == LFG_TELEPORTERROR_OK) { if (!player->GetMap()->IsDungeon()) @@ -1881,10 +1449,7 @@ void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false* player->CleanupAfterTaxiFlight(); } - if (player->TeleportTo(mapid, x, y, z, orientation)) - // FIXME - HACK - this should be done by teleport, when teleporting far - player->RemoveAurasByType(SPELL_AURA_MOUNTED); - else + if (!player->TeleportTo(mapid, x, y, z, orientation)) { error = LFG_TELEPORTERROR_INVALID_LOCATION; sLog->outError(LOG_FILTER_LFG, "LfgMgr::TeleportPlayer: Failed to teleport [" UI64FMTD "] to map %u: ", player->GetGUID(), mapid); @@ -1932,12 +1497,12 @@ void LFGMgr::RewardDungeonDoneFor(const uint32 dungeonId, Player* player) // Clear player related lfg stuff uint32 rDungeonId = (*GetSelectedDungeons(guid).begin()); - ClearState(guid); + ClearState(guid, "Dungeon Finished"); SetState(guid, LFG_STATE_FINISHED_DUNGEON); // Give rewards only if its a random or seasonal dungeon - LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(rDungeonId); - if (!dungeon || (dungeon->type != LFG_TYPE_RANDOM && !(dungeon->flags & LFG_FLAG_SEASONAL))) + LFGDungeonEntry const* dungeon = GetLFGDungeon(rDungeonId); + if (!dungeon || (dungeon->type != LFG_TYPE_RANDOM && !dungeon->seasonal)) { sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::RewardDungeonDoneFor: [" UI64FMTD "] dungeon %u is not random nor seasonal", guid, rDungeonId); return; @@ -1986,9 +1551,9 @@ void LFGMgr::RewardDungeonDoneFor(const uint32 dungeonId, Player* player) */ const LfgDungeonSet& LFGMgr::GetDungeonsByRandom(uint32 randomdungeon) { - LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(randomdungeon); - uint32 groupType = dungeon ? dungeon->grouptype : 0; - return m_CachedDungeonMap[groupType]; + LFGDungeonEntry const* dungeon = GetLFGDungeon(randomdungeon); + uint32 group = dungeon ? dungeon->group : 0; + return m_CachedDungeonMap[group]; } /** @@ -2021,81 +1586,42 @@ LfgReward const* LFGMgr::GetRandomDungeonReward(uint32 dungeon, uint8 level) */ LfgType LFGMgr::GetDungeonType(uint32 dungeonId) { - LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(dungeonId); + LFGDungeonEntry const* dungeon = GetLFGDungeon(dungeonId); if (!dungeon) return LFG_TYPE_NONE; return LfgType(dungeon->type); } -/** - Given a list of guids returns the concatenation using | as delimiter - - @param[in] check list of guids - @returns Concatenated string -*/ -std::string LFGMgr::ConcatenateGuids(LfgGuidList check) -{ - if (check.empty()) - return ""; - - std::ostringstream o; - LfgGuidList::const_iterator it = check.begin(); - o << (*it); - for (++it; it != check.end(); ++it) - o << '|' << (*it); - return o.str(); -} - -HolidayIds LFGMgr::GetDungeonSeason(uint32 dungeonId) -{ - HolidayIds holiday = HOLIDAY_NONE; - - switch (dungeonId) - { - case 285: - holiday = HOLIDAY_HALLOWS_END; - break; - case 286: - holiday = HOLIDAY_FIRE_FESTIVAL; - break; - case 287: - holiday = HOLIDAY_BREWFEST; - break; - case 288: - holiday = HOLIDAY_LOVE_IS_IN_THE_AIR; - break; - default: - break; - } - - return holiday; -} - LfgState LFGMgr::GetState(uint64 guid) { - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetState: [" UI64FMTD "]", guid); + LfgState state; if (IS_GROUP(guid)) - return m_Groups[guid].GetState(); + state = m_Groups[guid].GetState(); else - return m_Players[guid].GetState(); + state = m_Players[guid].GetState(); + + sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetState: [" UI64FMTD "] = %u", guid, state); + return state; } -uint32 LFGMgr::GetDungeon(uint64 guid, bool asId /*= true*/) +uint32 LFGMgr::GetDungeon(uint64 guid, bool asId /*= true */) { - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetDungeon: [" UI64FMTD "] asId: %u", guid, asId); - return m_Groups[guid].GetDungeon(asId); + uint32 dungeon = m_Groups[guid].GetDungeon(asId); + sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetDungeon: [" UI64FMTD "] asId: %u = %u", guid, asId, dungeon); + return dungeon; } uint8 LFGMgr::GetRoles(uint64 guid) { - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetRoles: [" UI64FMTD "]", guid); - return m_Players[guid].GetRoles(); + uint8 roles = m_Players[guid].GetRoles(); + sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetRoles: [" UI64FMTD "] = %u", guid, roles); + return roles; } const std::string& LFGMgr::GetComment(uint64 guid) { - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetComment: [" UI64FMTD "]", guid); + sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetComment: [" UI64FMTD "] = %s", guid, m_Players[guid].GetComment().c_str()); return m_Players[guid].GetComment(); } @@ -2123,35 +1649,49 @@ const LfgLockMap& LFGMgr::GetLockedDungeons(uint64 guid) uint8 LFGMgr::GetKicksLeft(uint64 guid) { - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetKicksLeft: [" UI64FMTD "]", guid); - return m_Groups[guid].GetKicksLeft(); -} - -uint8 LFGMgr::GetVotesNeeded(uint64 guid) -{ - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetVotesNeeded: [" UI64FMTD "]", guid); - return m_Groups[guid].GetVotesNeeded(); + uint8 kicks = m_Groups[guid].GetKicksLeft(); + sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::GetKicksLeft: [" UI64FMTD "] = %u", guid, kicks); + return kicks; } -void LFGMgr::RestoreState(uint64 guid) +void LFGMgr::RestoreState(uint64 guid, char const *debugMsg) { - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::RestoreState: [" UI64FMTD "]", guid); - m_Groups[guid].RestoreState(); + LfgGroupData& data = m_Groups[guid]; + char const * const ps = GetStateString(data.GetState()); + char const * const os = GetStateString(data.GetOldState()); + sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::RestoreState: Group: [" UI64FMTD "] (%s), State: %s, oldState: %s", guid, debugMsg, ps, os); + data.RestoreState(); } -void LFGMgr::ClearState(uint64 guid) +void LFGMgr::ClearState(uint64 guid, char const *debugMsg) { - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::ClearState: [" UI64FMTD "]", guid); - m_Players[guid].ClearState(); + LfgPlayerData& data = m_Players[guid]; + char const * const ps = GetStateString(data.GetState()); + char const * const os = GetStateString(data.GetOldState()); + sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::ClearState: Player: [" UI64FMTD "] (%s) State: %s, oldState: %s", guid, debugMsg, ps, os); + data.ClearState(); } void LFGMgr::SetState(uint64 guid, LfgState state) { - sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::SetState: [" UI64FMTD "] state %u", guid, state); if (IS_GROUP(guid)) - m_Groups[guid].SetState(state); + { + LfgGroupData& data = m_Groups[guid]; + char const * const ns = GetStateString(state); + char const * const ps = GetStateString(data.GetState()); + char const * const os = GetStateString(data.GetOldState()); + sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::SetState: Group: [" UI64FMTD "] newState: %s, previous: %s, oldState: %s", guid, ns, ps, os); + data.SetState(state); + } else - m_Players[guid].SetState(state); + { + LfgPlayerData& data = m_Players[guid]; + char const * const ns = GetStateString(state); + char const * const ps = GetStateString(data.GetState()); + char const * const os = GetStateString(data.GetOldState()); + sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::SetState: Player: [" UI64FMTD "] newState: %s, previous: %s, oldState: %s", guid, ns, ps, os); + data.SetState(state); + } } void LFGMgr::SetDungeon(uint64 guid, uint32 dungeon) @@ -2205,3 +1745,155 @@ void LFGMgr::RemoveGroupData(uint64 guid) if (it != m_Groups.end()) m_Groups.erase(it); } + +uint8 LFGMgr::GetTeam(uint64 guid) +{ + return m_Players[guid].GetTeam(); +} + +uint8 LFGMgr::RemovePlayerFromGroup(uint64 gguid, uint64 guid) +{ + return m_Groups[gguid].RemovePlayer(guid); +} + +void LFGMgr::AddPlayerToGroup(uint64 gguid, uint64 guid) +{ + m_Groups[gguid].AddPlayer(guid); +} + +void LFGMgr::SetLeader(uint64 gguid, uint64 leader) +{ + m_Groups[gguid].SetLeader(leader); +} + +void LFGMgr::SetTeam(uint64 guid, uint8 team) +{ + if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP)) + team = 0; + + m_Players[guid].SetTeam(team); +} + +uint64 LFGMgr::GetGroup(uint64 guid) +{ + return m_Players[guid].GetGroup(); +} + +void LFGMgr::SetGroup(uint64 guid, uint64 group) +{ + m_Players[guid].SetGroup(group); +} + +const LfgGuidSet& LFGMgr::GetPlayers(uint64 guid) +{ + return m_Groups[guid].GetPlayers(); +} + +uint64 LFGMgr::GetLeader(uint64 guid) +{ + return m_Groups[guid].GetLeader(); +} + +bool LFGMgr::HasIgnore(uint64 guid1, uint64 guid2) +{ + Player* plr1 = ObjectAccessor::FindPlayer(guid1); + Player* plr2 = ObjectAccessor::FindPlayer(guid2); + uint32 low1 = GUID_LOPART(guid1); + uint32 low2 = GUID_LOPART(guid2); + return plr1 && plr2 && (plr1->GetSocial()->HasIgnore(low2) || plr2->GetSocial()->HasIgnore(low1)); +} + +void LFGMgr::SendLfgRoleChosen(uint64 guid, uint64 pguid, uint8 roles) +{ + if (Player* player = ObjectAccessor::FindPlayer(guid)) + player->GetSession()->SendLfgRoleChosen(pguid, roles); +} + +void LFGMgr::SendLfgRoleCheckUpdate(uint64 guid, const LfgRoleCheck& roleCheck) +{ + if (Player* player = ObjectAccessor::FindPlayer(guid)) + player->GetSession()->SendLfgRoleCheckUpdate(roleCheck); +} + +void LFGMgr::SendLfgUpdatePlayer(uint64 guid, const LfgUpdateData& data) +{ + if (Player* player = ObjectAccessor::FindPlayer(guid)) + player->GetSession()->SendLfgUpdatePlayer(data); +} + +void LFGMgr::SendLfgUpdateParty(uint64 guid, const LfgUpdateData& data) +{ + if (Player* player = ObjectAccessor::FindPlayer(guid)) + player->GetSession()->SendLfgUpdateParty(data); +} + +void LFGMgr::SendLfgJoinResult(uint64 guid, const LfgJoinResultData& data) +{ + if (Player* player = ObjectAccessor::FindPlayer(guid)) + player->GetSession()->SendLfgJoinResult(data); +} + +void LFGMgr::SendLfgBootProposalUpdate(uint64 guid, const LfgPlayerBoot& boot) +{ + if (Player* player = ObjectAccessor::FindPlayer(guid)) + player->GetSession()->SendLfgBootProposalUpdate(boot); +} + +void LFGMgr::SendLfgUpdateProposal(uint64 guid, uint32 proposalId, const LfgProposal& proposal) +{ + if (Player* player = ObjectAccessor::FindPlayer(guid)) + player->GetSession()->SendLfgUpdateProposal(proposalId, proposal); +} + +void LFGMgr::SendLfgQueueStatus(uint64 guid, const LfgQueueStatusData& data) +{ + if (Player* player = ObjectAccessor::FindPlayer(guid)) + player->GetSession()->SendLfgQueueStatus(data); +} + +bool LFGMgr::IsLfgGroup(uint64 guid) +{ + return guid && IS_GROUP(guid) && m_Groups[guid].IsLfgGroup(); +} + +LfgQueue& LFGMgr::GetQueue(uint64 guid) +{ + uint8 queueId = 0; + if (IS_GROUP(guid)) + { + const LfgGuidSet& players = GetPlayers(guid); + uint64 pguid = players.empty() ? 0 : (*players.begin()); + if (pguid) + queueId = GetTeam(pguid); + } + else + queueId = GetTeam(guid); + return m_Queues[queueId]; +} + +bool LFGMgr::AllQueued(const LfgGuidList& check) +{ + if (check.empty()) + return false; + + for (LfgGuidList::const_iterator it = check.begin(); it != check.end(); ++it) + if (GetState(*it) != LFG_STATE_QUEUED) + return false; + return true; +} + +bool LFGMgr::IsSeasonActive(uint32 dungeonId) +{ + switch (dungeonId) + { + case 285: // The Headless Horseman + return IsHolidayActive(HOLIDAY_HALLOWS_END); + case 286: // The Frost Lord Ahune + return IsHolidayActive(HOLIDAY_FIRE_FESTIVAL); + case 287: // Coren Direbrew + return IsHolidayActive(HOLIDAY_BREWFEST); + case 288: // The Crown Chemical Co. + return IsHolidayActive(HOLIDAY_LOVE_IS_IN_THE_AIR); + } + return false; +} diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h index 9937759741b..4fb03bfe701 100755 --- a/src/server/game/DungeonFinding/LFGMgr.h +++ b/src/server/game/DungeonFinding/LFGMgr.h @@ -21,24 +21,25 @@ #include "Common.h" #include <ace/Singleton.h> #include "LFG.h" +#include "LFGQueue.h" +#include "LFGGroupData.h" +#include "LFGPlayerData.h" -class LfgGroupData; -class LfgPlayerData; +class LFGPlayerScript; +class LFGGroupScript; class Group; class Player; -enum LFGenum +enum LFGMgrEnum { - LFG_TIME_ROLECHECK = 40*IN_MILLISECONDS, - LFG_TIME_BOOT = 2*MINUTE, - LFG_TIME_PROPOSAL = 2*MINUTE, - LFG_TANKS_NEEDED = 1, - LFG_HEALERS_NEEDED = 1, - LFG_DPS_NEEDED = 3, - LFG_QUEUEUPDATE_INTERVAL = 15*IN_MILLISECONDS, + LFG_TIME_ROLECHECK = 40 * IN_MILLISECONDS, + LFG_TIME_BOOT = 120, + LFG_TIME_PROPOSAL = 120, + LFG_QUEUEUPDATE_INTERVAL = 15 * IN_MILLISECONDS, LFG_SPELL_DUNGEON_COOLDOWN = 71328, LFG_SPELL_DUNGEON_DESERTER = 71041, - LFG_SPELL_LUCK_OF_THE_DRAW = 72221 + LFG_SPELL_LUCK_OF_THE_DRAW = 72221, + LFG_GROUP_KICK_VOTES_NEEDED = 3 }; enum LfgFlags @@ -52,11 +53,9 @@ enum LfgFlags /// Determines the type of instance enum LfgType { - LFG_TYPE_NONE = 0, // Internal use only + LFG_TYPE_NONE = 0, LFG_TYPE_DUNGEON = 1, LFG_TYPE_RAID = 2, - LFG_TYPE_QUEST = 3, - LFG_TYPE_ZONE = 4, LFG_TYPE_HEROIC = 5, LFG_TYPE_RANDOM = 6 }; @@ -72,13 +71,14 @@ enum LfgProposalState /// Teleport errors enum LfgTeleportError { - // 3, 7, 8 = "You can't do that right now" | 5 = No client reaction + // 7 = "You can't do that right now" | 5 = No client reaction LFG_TELEPORTERROR_OK = 0, // Internal use LFG_TELEPORTERROR_PLAYER_DEAD = 1, LFG_TELEPORTERROR_FALLING = 2, - LFG_TELEPORTERROR_DONT_REPORT = 3, + LFG_TELEPORTERROR_IN_VEHICLE = 3, LFG_TELEPORTERROR_FATIGUE = 4, - LFG_TELEPORTERROR_INVALID_LOCATION = 6 + LFG_TELEPORTERROR_INVALID_LOCATION = 6, + LFG_TELEPORTERROR_CHARMING = 8 // FIXME - It can be 7 or 8 (Need proper data) }; /// Queue join results @@ -116,42 +116,27 @@ enum LfgRoleCheckState LFG_ROLECHECK_NO_ROLE = 6 // Someone selected no role }; -/// Answer state (Also used to check compatibilites) -enum LfgAnswer -{ - LFG_ANSWER_PENDING = -1, - LFG_ANSWER_DENY = 0, - LFG_ANSWER_AGREE = 1 -}; - // Forward declaration (just to have all typedef together) +struct LFGDungeonEntry; struct LfgReward; -struct LfgLockStatus; struct LfgQueueInfo; struct LfgRoleCheck; struct LfgProposal; struct LfgProposalPlayer; struct LfgPlayerBoot; -typedef std::set<uint64> LfgGuidSet; -typedef std::list<uint64> LfgGuidList; -typedef std::map<uint8, LfgGuidList> LfgGuidListMap; -typedef std::set<Player*> PlayerSet; -typedef std::list<Player*> LfgPlayerList; +typedef std::map<uint8, LfgQueue> LfgQueueMap; typedef std::multimap<uint32, LfgReward const*> LfgRewardMap; typedef std::pair<LfgRewardMap::const_iterator, LfgRewardMap::const_iterator> LfgRewardMapBounds; -typedef std::map<std::string, LfgAnswer> LfgCompatibleMap; -typedef std::map<uint64, LfgDungeonSet> LfgDungeonMap; -typedef std::map<uint64, uint8> LfgRolesMap; +typedef std::map<uint8, LfgDungeonSet> LfgCachedDungeonMap; typedef std::map<uint64, LfgAnswer> LfgAnswerMap; -typedef std::map<uint64, LfgRoleCheck*> LfgRoleCheckMap; -typedef std::map<uint64, LfgQueueInfo*> LfgQueueInfoMap; -typedef std::map<uint32, LfgProposal*> LfgProposalMap; -typedef std::map<uint64, LfgProposalPlayer*> LfgProposalPlayerMap; -typedef std::map<uint32, LfgPlayerBoot*> LfgPlayerBootMap; +typedef std::map<uint64, LfgRoleCheck> LfgRoleCheckMap; +typedef std::map<uint32, LfgProposal> LfgProposalMap; +typedef std::map<uint64, LfgProposalPlayer> LfgProposalPlayerMap; +typedef std::map<uint64, LfgPlayerBoot> LfgPlayerBootMap; typedef std::map<uint64, LfgGroupData> LfgGroupDataMap; typedef std::map<uint64, LfgPlayerData> LfgPlayerDataMap; -typedef std::map<uint32, Position> LfgEntrancePositionMap; +typedef UNORDERED_MAP<uint32, LFGDungeonEntry> LFGDungeonMap; // Data needed by SMSG_LFG_JOIN_RESULT struct LfgJoinResultData @@ -167,7 +152,7 @@ struct LfgJoinResultData struct LfgUpdateData { LfgUpdateData(LfgUpdateType _type = LFG_UPDATETYPE_DEFAULT): updateType(_type), comment("") {} - LfgUpdateData(LfgUpdateType _type, const LfgDungeonSet& _dungeons, std::string _comment): + LfgUpdateData(LfgUpdateType _type, LfgDungeonSet const& _dungeons, std::string _comment): updateType(_type), dungeons(_dungeons), comment(_comment) {} LfgUpdateType updateType; @@ -175,6 +160,26 @@ struct LfgUpdateData std::string comment; }; +// Data needed by SMSG_LFG_QUEUE_STATUS +struct LfgQueueStatusData +{ + LfgQueueStatusData(uint32 _dungeonId = 0, int32 _waitTime = -1, int32 _waitTimeAvg = -1, int32 _waitTimeTank = -1, int32 _waitTimeHealer = -1, + int32 _waitTimeDps = -1, uint32 _queuedTime = 0, uint8 _tanks = 0, uint8 _healers = 0, uint8 _dps = 0) : + dungeonId(_dungeonId), waitTime(_waitTime), waitTimeAvg(_waitTimeAvg), waitTimeTank(_waitTimeTank), waitTimeHealer(_waitTimeHealer), + waitTimeDps(_waitTimeDps), queuedTime(_queuedTime), tanks(_tanks), healers(_healers), dps(_dps) {} + + uint32 dungeonId; + int32 waitTime; + int32 waitTimeAvg; + int32 waitTimeTank; + int32 waitTimeHealer; + int32 waitTimeDps; + uint32 queuedTime; + uint8 tanks; + uint8 healers; + uint8 dps; +}; + /// Reward info struct LfgReward { @@ -198,45 +203,31 @@ struct LfgReward } }; -/// Stores player or group queue info -struct LfgQueueInfo -{ - LfgQueueInfo(): joinTime(0), tanks(LFG_TANKS_NEEDED), healers(LFG_HEALERS_NEEDED), dps(LFG_DPS_NEEDED) {}; - time_t joinTime; ///< Player queue join time (to calculate wait times) - uint8 tanks; ///< Tanks needed - uint8 healers; ///< Healers needed - uint8 dps; ///< Dps needed - LfgDungeonSet dungeons; ///< Selected Player/Group Dungeon/s - LfgRolesMap roles; ///< Selected Player Role/s -}; - /// Stores player data related to proposal to join struct LfgProposalPlayer { - LfgProposalPlayer(): role(0), accept(LFG_ANSWER_PENDING), groupLowGuid(0) {}; + LfgProposalPlayer(): role(0), accept(LFG_ANSWER_PENDING), group(0) { } uint8 role; ///< Proposed role LfgAnswer accept; ///< Accept status (-1 not answer | 0 Not agree | 1 agree) - uint32 groupLowGuid; ///< Original group guid (Low guid) 0 if no original group + uint64 group; ///< Original group guid. 0 if no original group }; /// Stores group data related to proposal to join struct LfgProposal { - LfgProposal(uint32 dungeon = 0): dungeonId(dungeon), state(LFG_PROPOSAL_INITIATING), groupLowGuid(0), leader(0), cancelTime(0) {} + LfgProposal(uint32 dungeon = 0): dungeonId(dungeon), state(LFG_PROPOSAL_INITIATING), + group(0), leader(0), cancelTime(0), encounters(0), isNew(true) + { } - ~LfgProposal() - { - for (LfgProposalPlayerMap::iterator it = players.begin(); it != players.end(); ++it) - delete it->second; - }; uint32 dungeonId; ///< Dungeon to join LfgProposalState state; ///< State of the proposal - uint32 groupLowGuid; ///< Proposal group (0 if new) + uint64 group; ///< Proposal group (0 if new) uint64 leader; ///< Leader guid. time_t cancelTime; ///< Time when we will cancel this proposal + uint32 encounters; ///< Dungeon Encounters + bool isNew; ///< Determines if it's new group or not LfgGuidList queues; ///< Queue Ids to remove/readd LfgProposalPlayerMap players; ///< Players data - }; /// Stores all rolecheck info of a group that wants to join @@ -257,10 +248,36 @@ struct LfgPlayerBoot bool inProgress; ///< Vote in progress LfgAnswerMap votes; ///< Player votes (-1 not answer | 0 Not agree | 1 agree) uint64 victim; ///< Player guid to be kicked (can't vote) - uint8 votedNeeded; ///< Votes needed to kick the player std::string reason; ///< kick reason }; +struct LFGDungeonEntry +{ + LFGDungeonEntry(): id(0), name(""), map(0), type(0), expansion(0), group(0), minlevel(0), + maxlevel(0), difficulty(REGULAR_DIFFICULTY), seasonal(false), x(0.0f), y(0.0f), z(0.0f), o(0.0f) + { } + LFGDungeonEntry(LFGDungeonEntryDbc const* dbc): id(dbc->ID), name(dbc->name), map(dbc->map), + type(dbc->type), expansion(dbc->expansion), group(dbc->grouptype), + minlevel(dbc->minlevel), maxlevel(dbc->maxlevel), difficulty(Difficulty(dbc->difficulty)), + seasonal(dbc->flags & LFG_FLAG_SEASONAL), x(0.0f), y(0.0f), z(0.0f), o(0.0f) + { } + + uint32 id; + std::string name; + uint16 map; + uint8 type; + uint8 expansion; + uint8 group; + uint8 minlevel; + uint8 maxlevel; + Difficulty difficulty; + bool seasonal; + float x, y, z, o; + + // Helpers + uint32 Entry() const { return id + (type << 24); } +}; + class LFGMgr { friend class ACE_Singleton<LFGMgr, ACE_Null_Mutex>; @@ -274,108 +291,124 @@ class LFGMgr // Reward void LoadRewards(); - void RewardDungeonDoneFor(const uint32 dungeonId, Player* player); + void RewardDungeonDoneFor(uint32 const dungeonId, Player* player); LfgReward const* GetRandomDungeonReward(uint32 dungeon, uint8 level); // Queue - void Join(Player* player, uint8 roles, const LfgDungeonSet& dungeons, const std::string& comment); - void Leave(Player* player, Group* grp = NULL); + void JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, std::string const& comment); + void LeaveLfg(uint64 guid); // Role Check - void UpdateRoleCheck(uint64 gguid, uint64 guid = 0, uint8 roles = ROLE_NONE); + void UpdateRoleCheck(uint64 gguid, uint64 guid = 0, uint8 roles = PLAYER_ROLE_NONE); + + // Group Matching + static bool CheckGroupRoles(LfgRolesMap &groles, bool removeLeaderFlag = true); + void GetCompatibleDungeons(LfgDungeonSet& dungeons, LfgGuidSet const& players, LfgLockPartyMap& lockMap); // Proposals + uint32 AddProposal(LfgProposal const& proposal); void UpdateProposal(uint32 proposalId, uint64 guid, bool accept); // Teleportation - void LoadEntrancePositions(); void TeleportPlayer(Player* player, bool out, bool fromOpcode = false); // Vote kick - void InitBoot(Group* grp, uint64 kguid, uint64 vguid, std::string reason); - void UpdateBoot(Player* player, bool accept); - void OfferContinue(Group* grp); + void InitBoot(uint64 gguid, uint64 kguid, uint64 vguid, std::string const& reason); + void UpdateBoot(uint64 guid, bool accept); - HolidayIds GetDungeonSeason(uint32 dungeonId); + void InitializeLockedDungeons(Player* player, uint8 level = 0); - void InitializeLockedDungeons(Player* player); + void SetRoles(uint64 guid, uint8 roles); + void SetComment(uint64 guid, std::string const& comment); + void SetTeam(uint64 guid, uint8 team); + void SetGroup(uint64 guid, uint64 group); + void SetLeader(uint64 gguid, uint64 leader); + void SetState(uint64 guid, LfgState state); + void SetSelectedDungeons(uint64 guid, LfgDungeonSet const& dungeons); void _LoadFromDB(Field* fields, uint64 guid); void _SaveToDB(uint64 guid, uint32 db_guid); - void SetComment(uint64 guid, const std::string& comment); - const LfgLockMap& GetLockedDungeons(uint64 guid); - LfgState GetState(uint64 guid); - const LfgDungeonSet& GetSelectedDungeons(uint64 guid); - uint32 GetDungeon(uint64 guid, bool asId = true); - void SetState(uint64 guid, LfgState state); - void ClearState(uint64 guid); void RemovePlayerData(uint64 guid); void RemoveGroupData(uint64 guid); + uint8 RemovePlayerFromGroup(uint64 gguid, uint64 guid); + void AddPlayerToGroup(uint64 gguid, uint64 guid); + + LfgLockMap const& GetLockedDungeons(uint64 guid); + LfgDungeonSet const& GetSelectedDungeons(uint64 guid); + uint32 GetDungeon(uint64 guid, bool asId = true); + LfgState GetState(uint64 guid); uint8 GetKicksLeft(uint64 gguid); - uint8 GetVotesNeeded(uint64 gguid); - bool IsTeleported(uint64 pguid); - void SetRoles(uint64 guid, uint8 roles); - void SetSelectedDungeons(uint64 guid, const LfgDungeonSet& dungeons); + uint64 GetLeader(uint64 guid); + bool IsLfgGroup(uint64 guid); + uint8 GetRoles(uint64 guid); + std::string const& GetComment(uint64 gguid); + LfgGuidSet const& GetPlayers(uint64 guid); + + bool IsTeleported(uint64 guid); + bool AllQueued(LfgGuidList const& check); + static bool HasIgnore(uint64 guid1, uint64 guid2); + static void SendLfgQueueStatus(uint64 guid, LfgQueueStatusData const& data); + + bool IsSeasonActive(uint32 dungeonId); + + static std::string ConcatenateDungeons(LfgDungeonSet const& dungeons); + static std::string GetRolesString(uint8 roles); + static char const * GetStateString(LfgState state); + + void LoadLFGDungeons(bool reload = false); + LFGDungeonEntry const* GetLFGDungeon(uint32 id); + LFGDungeonMap& GetLFGDungeonMap(); + + void ClearState(uint64 guid, char const *debugMsg); private: - uint8 GetRoles(uint64 guid); - const std::string& GetComment(uint64 gguid); - void RestoreState(uint64 guid); + uint8 GetTeam(uint64 guid); + uint64 GetGroup(uint64 guid); + void RestoreState(uint64 guid, char const *debugMsg); + void SetDungeon(uint64 guid, uint32 dungeon); - void SetLockedDungeons(uint64 guid, const LfgLockMap& lock); + void SetLockedDungeons(uint64 guid, LfgLockMap const& lock); void DecreaseKicksLeft(uint64 guid); - // Queue - void AddToQueue(uint64 guid, uint8 queueId); - bool RemoveFromQueue(uint64 guid); - // Proposals void RemoveProposal(LfgProposalMap::iterator itProposal, LfgUpdateType type); - - // Group Matching - LfgProposal* FindNewGroups(LfgGuidList& check, LfgGuidList& all); - bool CheckGroupRoles(LfgRolesMap &groles, bool removeLeaderFlag = true); - bool CheckCompatibility(LfgGuidList check, LfgProposal*& pProposal); - void GetCompatibleDungeons(LfgDungeonSet& dungeons, const PlayerSet& players, LfgLockPartyMap& lockMap); - void SetCompatibles(std::string concatenatedGuids, bool compatibles); - LfgAnswer GetCompatibles(std::string concatenatedGuids); - void RemoveFromCompatibles(uint64 guid); + void MakeNewGroup(LfgProposal const& proposal); // Generic - const LfgDungeonSet& GetDungeonsByRandom(uint32 randomdungeon); + LfgQueue &GetQueue(uint64 guid); + LfgDungeonSet const& GetDungeonsByRandom(uint32 randomdungeon); LfgType GetDungeonType(uint32 dungeon); - std::string ConcatenateGuids(LfgGuidList check); + + void SendLfgBootProposalUpdate(uint64 guid, LfgPlayerBoot const& boot); + void SendLfgJoinResult(uint64 guid, LfgJoinResultData const& data); + void SendLfgRoleChosen(uint64 guid, uint64 pguid, uint8 roles); + void SendLfgRoleCheckUpdate(uint64 guid, LfgRoleCheck const& roleCheck); + void SendLfgUpdateParty(uint64 guid, LfgUpdateData const& data); + void SendLfgUpdatePlayer(uint64 guid, LfgUpdateData const& data); + void SendLfgUpdateProposal(uint64 guid, uint32 proposalId, LfgProposal const& proposal); // General variables - bool m_update; ///< Doing an update? uint32 m_QueueTimer; ///< used to check interval of update uint32 m_lfgProposalId; ///< used as internal counter for proposals - int32 m_WaitTimeAvg; ///< Average wait time to find a group queuing as multiple roles - int32 m_WaitTimeTank; ///< Average wait time to find a group queuing as tank - int32 m_WaitTimeHealer; ///< Average wait time to find a group queuing as healer - int32 m_WaitTimeDps; ///< Average wait time to find a group queuing as dps - uint32 m_NumWaitTimeAvg; ///< Num of players used to calc avs wait time - uint32 m_NumWaitTimeTank; ///< Num of players used to calc tank wait time - uint32 m_NumWaitTimeHealer; ///< Num of players used to calc healers wait time - uint32 m_NumWaitTimeDps; ///< Num of players used to calc dps wait time - LfgDungeonMap m_CachedDungeonMap; ///< Stores all dungeons by groupType - LfgEntrancePositionMap m_entrancePositions; ///< Stores special entrance positions + uint32 m_options; ///< Stores config options + + LfgQueueMap m_Queues; ///< Queues + LfgCachedDungeonMap m_CachedDungeonMap; ///< Stores all dungeons by groupType // Reward System LfgRewardMap m_RewardMap; ///< Stores rewards for random dungeons - // Queue - LfgQueueInfoMap m_QueueInfoMap; ///< Queued groups - LfgGuidListMap m_currentQueue; ///< Ordered list. Used to find groups - LfgGuidListMap m_newToQueue; ///< New groups to add to queue - LfgCompatibleMap m_CompatibleMap; ///< Compatible dungeons - LfgGuidList m_teleport; ///< Players being teleported + LFGDungeonMap m_LfgDungeonMap; // Rolecheck - Proposal - Vote Kicks LfgRoleCheckMap m_RoleChecks; ///< Current Role checks LfgProposalMap m_Proposals; ///< Current Proposals LfgPlayerBootMap m_Boots; ///< Current player kicks LfgPlayerDataMap m_Players; ///< Player data LfgGroupDataMap m_Groups; ///< Group data + LfgGuidList m_teleport; ///< Players being teleported + + LFGPlayerScript *m_lfgPlayerScript; + LFGGroupScript *m_lfgGroupScript; }; #define sLFGMgr ACE_Singleton<LFGMgr, ACE_Null_Mutex>::instance() diff --git a/src/server/game/DungeonFinding/LFGPlayerData.cpp b/src/server/game/DungeonFinding/LFGPlayerData.cpp index 4a6e86ab966..e5645f0f0aa 100644 --- a/src/server/game/DungeonFinding/LFGPlayerData.cpp +++ b/src/server/game/DungeonFinding/LFGPlayerData.cpp @@ -17,8 +17,8 @@ #include "LFGPlayerData.h" -LfgPlayerData::LfgPlayerData(): -m_State(LFG_STATE_NONE), m_OldState(LFG_STATE_NONE), m_Roles(0), m_Comment("") +LfgPlayerData::LfgPlayerData(): m_State(LFG_STATE_NONE), m_OldState(LFG_STATE_NONE), + m_Team(0), m_Group(0), m_Roles(0), m_Comment("") {} LfgPlayerData::~LfgPlayerData() @@ -30,10 +30,13 @@ void LfgPlayerData::SetState(LfgState state) switch (state) { case LFG_STATE_NONE: - case LFG_STATE_DUNGEON: case LFG_STATE_FINISHED_DUNGEON: + m_Roles = 0; + m_SelectedDungeons.clear(); + // No break on purpose + case LFG_STATE_DUNGEON: m_OldState = state; - // No break on purpose + // No break on purpose default: m_State = state; } @@ -51,6 +54,16 @@ void LfgPlayerData::SetLockedDungeons(const LfgLockMap& lockStatus) m_LockedDungeons = lockStatus; } +void LfgPlayerData::SetTeam(uint8 team) +{ + m_Team = team; +} + +void LfgPlayerData::SetGroup(uint64 group) +{ + m_Group = group; +} + void LfgPlayerData::SetRoles(uint8 roles) { m_Roles = roles; @@ -66,21 +79,31 @@ void LfgPlayerData::SetSelectedDungeons(const LfgDungeonSet& dungeons) m_SelectedDungeons = dungeons; } -void LfgPlayerData::ClearSelectedDungeons() +LfgState LfgPlayerData::GetState() const { - m_SelectedDungeons.clear(); + return m_State; } -LfgState LfgPlayerData::GetState() const +LfgState LfgPlayerData::GetOldState() const { - return m_State; + return m_OldState; } -const LfgLockMap & LfgPlayerData::GetLockedDungeons() const +const LfgLockMap& LfgPlayerData::GetLockedDungeons() const { return m_LockedDungeons; } +uint8 LfgPlayerData::GetTeam() const +{ + return m_Team; +} + +uint64 LfgPlayerData::GetGroup() const +{ + return m_Group; +} + uint8 LfgPlayerData::GetRoles() const { return m_Roles; diff --git a/src/server/game/DungeonFinding/LFGPlayerData.h b/src/server/game/DungeonFinding/LFGPlayerData.h index e8bae1c5a0f..0682ad66698 100644 --- a/src/server/game/DungeonFinding/LFGPlayerData.h +++ b/src/server/game/DungeonFinding/LFGPlayerData.h @@ -18,7 +18,6 @@ #ifndef _LFGPLAYERDATA_H #define _LFGPLAYERDATA_H -#include "Common.h" #include "LFG.h" /** @@ -33,20 +32,26 @@ class LfgPlayerData // General void SetState(LfgState state); void ClearState(); - void SetLockedDungeons(const LfgLockMap& lock); + void SetLockedDungeons(LfgLockMap const& lock); + void SetTeam(uint8 team); + void SetGroup(uint64 group); + // Queue void SetRoles(uint8 roles); - void SetComment(const std::string& comment); + void SetComment(std::string const& comment); void SetSelectedDungeons(const LfgDungeonSet& dungeons); - void ClearSelectedDungeons(); // General LfgState GetState() const; - const LfgLockMap& GetLockedDungeons() const; + LfgState GetOldState() const; + LfgLockMap const& GetLockedDungeons() const; + uint8 GetTeam() const; + uint64 GetGroup() const; + // Queue uint8 GetRoles() const; - const std::string& GetComment() const; - const LfgDungeonSet& GetSelectedDungeons() const; + std::string const& GetComment() const; + LfgDungeonSet const& GetSelectedDungeons() const; private: // General @@ -54,6 +59,9 @@ class LfgPlayerData LfgState m_OldState; ///< Old State // Player LfgLockMap m_LockedDungeons; ///< Dungeons player can't do and reason + uint8 m_Team; ///< Player team - determines the queue to join + uint64 m_Group; ///< Original group of player when joined LFG + // Queue uint8 m_Roles; ///< Roles the player selected when joined LFG std::string m_Comment; ///< Player comment used when joined LFG diff --git a/src/server/game/DungeonFinding/LFGQueue.cpp b/src/server/game/DungeonFinding/LFGQueue.cpp new file mode 100644 index 00000000000..c1d89a16300 --- /dev/null +++ b/src/server/game/DungeonFinding/LFGQueue.cpp @@ -0,0 +1,539 @@ +/* + * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ObjectDefines.h" +#include "Containers.h" +#include "DBCStructure.h" +#include "DBCStores.h" +#include "Group.h" +#include "LFGQueue.h" +#include "LFGMgr.h" +#include "Log.h" +#include "ObjectMgr.h" +#include "World.h" + +/** + Given a list of guids returns the concatenation using | as delimiter + + @param[in] check list of guids + @returns Concatenated string +*/ +std::string ConcatenateGuids(LfgGuidList const& check) +{ + if (check.empty()) + return ""; + + // need the guids in order to avoid duplicates + LfgGuidSet guids(check.begin(), check.end()); + + std::ostringstream o; + + LfgGuidSet::const_iterator it = guids.begin(); + o << (*it); + for (++it; it != guids.end(); ++it) + o << '|' << (*it); + + return o.str(); +} + +char const * GetCompatibleString(LfgCompatibility compatibles) +{ + switch (compatibles) + { + case LFG_COMPATIBILITY_PENDING: + return "Pending"; + case LFG_COMPATIBLES_BAD_STATES: + return "Compatibles (Bad States)"; + case LFG_COMPATIBLES_MATCH: + return "Match"; + case LFG_COMPATIBLES_WITH_LESS_PLAYERS: + return "Compatibles (Not enough players)"; + case LFG_INCOMPATIBLES_HAS_IGNORES: + return "Has ignores"; + case LFG_INCOMPATIBLES_MULTIPLE_LFG_GROUPS: + return "Multiple Lfg Groups"; + case LFG_INCOMPATIBLES_NO_DUNGEONS: + return "Incompatible dungeons"; + case LFG_INCOMPATIBLES_NO_ROLES: + return "Incompatible roles"; + case LFG_INCOMPATIBLES_TOO_MUCH_PLAYERS: + return "Too much players"; + case LFG_INCOMPATIBLES_WRONG_GROUP_SIZE: + return "Wrong group size"; + default: + return "Unknown"; + } +} + +void LfgQueue::AddToQueue(uint64 guid) +{ + LfgQueueDataMap::iterator itQueue = m_QueueDataMap.find(guid); + if (itQueue == m_QueueDataMap.end()) + { + sLog->outError(LOG_FILTER_LFG, "LfgQueue::AddToQueue: Queue data not found for [" UI64FMTD "]", guid); + return; + } + + AddToNewQueue(guid); +} + +void LfgQueue::RemoveFromQueue(uint64 guid) +{ + RemoveFromNewQueue(guid); + RemoveFromCurrentQueue(guid); + RemoveFromCompatibles(guid); + RemoveQueueData(guid); +} + +void LfgQueue::AddToNewQueue(uint64 guid) +{ + m_newToQueue.push_back(guid); +} + +void LfgQueue::RemoveFromNewQueue(uint64 guid) +{ + m_newToQueue.remove(guid); +} + +void LfgQueue::AddToCurrentQueue(uint64 guid) +{ + m_currentQueue.push_back(guid); +} + +void LfgQueue::RemoveFromCurrentQueue(uint64 guid) +{ + m_currentQueue.remove(guid); +} + +void LfgQueue::AddQueueData(uint64 guid, time_t joinTime, const LfgDungeonSet &dungeons, const LfgRolesMap &rolesMap) +{ + m_QueueDataMap[guid] = LfgQueueData(joinTime, dungeons, rolesMap); + AddToQueue(guid); +} + +void LfgQueue::RemoveQueueData(uint64 guid) +{ + LfgQueueDataMap::iterator it = m_QueueDataMap.find(guid); + if (it != m_QueueDataMap.end()) + m_QueueDataMap.erase(it); +} + +void LfgQueue::UpdateWaitTimeAvg(int32 waitTime, uint32 dungeonId) +{ + LfgWaitTime &wt = m_waitTimesAvg[dungeonId]; + uint32 old_number = wt.number++; + wt.time = int32((wt.time * old_number + waitTime) / wt.number); +} + +void LfgQueue::UpdateWaitTimeTank(int32 waitTime, uint32 dungeonId) +{ + LfgWaitTime &wt = m_waitTimesTank[dungeonId]; + uint32 old_number = wt.number++; + wt.time = int32((wt.time * old_number + waitTime) / wt.number); +} + +void LfgQueue::UpdateWaitTimeHealer(int32 waitTime, uint32 dungeonId) +{ + LfgWaitTime &wt = m_waitTimesHealer[dungeonId]; + uint32 old_number = wt.number++; + wt.time = int32((wt.time * old_number + waitTime) / wt.number); +} + +void LfgQueue::UpdateWaitTimeDps(int32 waitTime, uint32 dungeonId) +{ + LfgWaitTime &wt = m_waitTimesDps[dungeonId]; + uint32 old_number = wt.number++; + wt.time = int32((wt.time * old_number + waitTime) / wt.number); +} + +/** + Remove from cached compatible dungeons any entry that contains the given guid + + @param[in] guid Guid to remove from compatible cache +*/ +void LfgQueue::RemoveFromCompatibles(uint64 guid) +{ + std::stringstream out; + out << guid; + std::string strGuid = out.str(); + + sLog->outDebug(LOG_FILTER_LFG, "LfgQueue::RemoveFromCompatibles: Removing [" UI64FMTD "]", guid); + for (LfgCompatibleMap::iterator itNext = m_CompatibleMap.begin(); itNext != m_CompatibleMap.end();) + { + LfgCompatibleMap::iterator it = itNext++; + if (it->first.find(strGuid) != std::string::npos) // Found, remove it + m_CompatibleMap.erase(it); + } +} + + +/** + Stores the compatibility of a list of guids + + @param[in] key String concatenation of guids (| used as separator) + @param[in] compatibles type of compatibility +*/ +void LfgQueue::SetCompatibles(const std::string &key, LfgCompatibility compatibles) +{ + m_CompatibleMap[key] = compatibles; +} + +/** + Get the compatibility of a group of guids + + @param[in] key String concatenation of guids (| used as separator) + @return LfgCompatibility type of compatibility +*/ +LfgCompatibility LfgQueue::GetCompatibles(std::string const& key) +{ + LfgCompatibleMap::iterator it = m_CompatibleMap.find(key); + if (it != m_CompatibleMap.end()) + return it->second; + + return LFG_COMPATIBILITY_PENDING; +} + +uint8 LfgQueue::FindGroups() +{ + uint8 proposals = 0; + LfgGuidList firstNew; + while (!m_newToQueue.empty()) + { + uint64 frontguid = m_newToQueue.front(); + sLog->outDebug(LOG_FILTER_LFG, "LfgQueue::FindGroups: checking [" UI64FMTD "] newToQueue(%u), currentQueue(%u)", frontguid, uint32(m_newToQueue.size()), uint32(m_currentQueue.size())); + firstNew.clear(); + firstNew.push_back(frontguid); + RemoveFromNewQueue(frontguid); + + LfgGuidList temporalList = m_currentQueue; + LfgCompatibility compatibles = FindNewGroups(firstNew, temporalList); + + if (compatibles == LFG_COMPATIBLES_MATCH) + ++proposals; + else + AddToCurrentQueue(frontguid); // Lfg group not found, add this group to the queue. + } + return proposals; +} + +/** + Checks que main queue to try to form a Lfg group. Returns first match found (if any) + + @param[in] check List of guids trying to match with other groups + @param[in] all List of all other guids in main queue to match against + @return LfgCompatibility type of compatibility between groups +*/ +LfgCompatibility LfgQueue::FindNewGroups(LfgGuidList& check, LfgGuidList& all) +{ + std::string strGuids = ConcatenateGuids(check); + LfgCompatibility compatibles = GetCompatibles(strGuids); + + sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::FindNewGroup: (%s): %s - all(%s)", strGuids.c_str(), GetCompatibleString(compatibles), ConcatenateGuids(all).c_str()); + if (compatibles == LFG_COMPATIBILITY_PENDING || compatibles == LFG_COMPATIBLES_BAD_STATES) // Not previously cached, calculate + compatibles = CheckCompatibility(check); + + if (compatibles != LFG_COMPATIBLES_WITH_LESS_PLAYERS) + return compatibles; + + // Try to match with queued groups + while (!all.empty()) + { + check.push_back(all.front()); + all.pop_front(); + LfgCompatibility subcompatibility = FindNewGroups(check, all); + if (subcompatibility == LFG_COMPATIBLES_MATCH) + return LFG_COMPATIBLES_MATCH; + check.pop_back(); + } + return compatibles; +} + +/** + Check compatibilities between groups. If group is Matched proposal will be created + + @param[in] check List of guids to check compatibilities + @return LfgCompatibility type of compatibility +*/ +LfgCompatibility LfgQueue::CheckCompatibility(LfgGuidList check) +{ + std::string strGuids = ConcatenateGuids(check); + LfgProposal proposal; + LfgDungeonSet proposalDungeons; + LfgGroupsMap proposalGroups; + LfgRolesMap proposalRoles; + + // Check for correct size + if (check.size() > MAXGROUPSIZE || check.empty()) + { + sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s): Size wrong - Not compatibles", strGuids.c_str()); + return LFG_INCOMPATIBLES_WRONG_GROUP_SIZE; + } + + // Player joining alone always compatible + if (check.size() == 1 && IS_PLAYER_GUID(check.front())) + return LFG_COMPATIBLES_WITH_LESS_PLAYERS; + + // Check all-but-new compatiblitity + if (check.size() > 2) + { + uint64 frontGuid = check.front(); + check.pop_front(); + + // Check all-but-new compatibilities (New, A, B, C, D) --> check(A, B, C, D) + LfgCompatibility child_compatibles = CheckCompatibility(check); + if (child_compatibles < LFG_COMPATIBLES_WITH_LESS_PLAYERS) // Group not compatible + { + sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s) child %s not compatibles", strGuids.c_str(), ConcatenateGuids(check).c_str()); + SetCompatibles(strGuids, child_compatibles); + return child_compatibles; + } + check.push_front(frontGuid); + } + + // Check if more than one LFG group and number of players joining + uint8 numPlayers = 0; + uint8 numLfgGroups = 0; + for (LfgGuidList::const_iterator it = check.begin(); it != check.end() && numLfgGroups < 2 && numPlayers <= MAXGROUPSIZE; ++it) + { + uint64 guid = (*it); + LfgQueueDataMap::iterator itQueue = m_QueueDataMap.find(guid); + if (itQueue == m_QueueDataMap.end()) + { + sLog->outError(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: [" UI64FMTD "] is not queued but listed as queued!", guid); + RemoveFromQueue(guid); + return LFG_COMPATIBILITY_PENDING; + } + + // Store group so we don't need to call Mgr to get it later (if it's player group will be 0 otherwise would have joined as group) + for (LfgRolesMap::const_iterator it2 = itQueue->second.roles.begin(); it2 != itQueue->second.roles.end(); ++it2) + proposalGroups[it2->first] = IS_GROUP(itQueue->first) ? itQueue->first : 0; + + numPlayers += itQueue->second.roles.size(); + + if (sLFGMgr->IsLfgGroup(guid)) + { + if (!numLfgGroups) + proposal.group = guid; + ++numLfgGroups; + } + } + + // Group with less that MAXGROUPSIZE members always compatible + if (check.size() == 1 && numPlayers != MAXGROUPSIZE) + { + sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s) sigle group. Compatibles", strGuids.c_str()); + return LFG_COMPATIBLES_WITH_LESS_PLAYERS; + } + + if (numLfgGroups > 1) + { + sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s) More than one Lfggroup (%u)", strGuids.c_str(), numLfgGroups); + SetCompatibles(strGuids, LFG_INCOMPATIBLES_MULTIPLE_LFG_GROUPS); + return LFG_INCOMPATIBLES_MULTIPLE_LFG_GROUPS; + } + + if (numPlayers > MAXGROUPSIZE) + { + sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s) Too much players (%u)", strGuids.c_str(), numPlayers); + SetCompatibles(strGuids, LFG_INCOMPATIBLES_TOO_MUCH_PLAYERS); + return LFG_INCOMPATIBLES_TOO_MUCH_PLAYERS; + } + + // If it's single group no need to check for duplicate players, ignores, bad roles or bad dungeons as it's been checked before joining + if (check.size() > 1) + { + for (LfgGuidList::const_iterator it = check.begin(); it != check.end(); ++it) + { + const LfgRolesMap &roles = m_QueueDataMap[(*it)].roles; + for (LfgRolesMap::const_iterator itRoles = roles.begin(); itRoles != roles.end(); ++itRoles) + { + LfgRolesMap::const_iterator itPlayer; + for (itPlayer = proposalRoles.begin(); itPlayer != proposalRoles.end(); ++itPlayer) + { + if (itRoles->first == itPlayer->first) + sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: ERROR! Player multiple times in queue! [" UI64FMTD "]", itRoles->first); + else if (sLFGMgr->HasIgnore(itRoles->first, itPlayer->first)) + break; + } + if (itPlayer == proposalRoles.end()) + proposalRoles[itRoles->first] = itRoles->second; + } + } + + if (uint8 playersize = numPlayers - proposalRoles.size()) + { + sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s) not compatible, %u players are ignoring each other", strGuids.c_str(), playersize); + SetCompatibles(strGuids, LFG_INCOMPATIBLES_HAS_IGNORES); + return LFG_INCOMPATIBLES_HAS_IGNORES; + } + + LfgRolesMap debugRoles = proposalRoles; // DEBUG + if (!LFGMgr::CheckGroupRoles(proposalRoles)) + { + std::ostringstream o; + for (LfgRolesMap::const_iterator it = debugRoles.begin(); it != debugRoles.end(); ++it) + o << ", " << it->first << ": " << sLFGMgr->GetRolesString(it->second); + + sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s) Roles not compatible%s", strGuids.c_str(), o.str().c_str()); + SetCompatibles(strGuids, LFG_INCOMPATIBLES_NO_ROLES); + return LFG_INCOMPATIBLES_NO_ROLES; + } + + LfgGuidList::iterator itguid = check.begin(); + proposalDungeons = m_QueueDataMap[*itguid].dungeons; + std::ostringstream o; + o << ", " << *itguid << ": (" << sLFGMgr->ConcatenateDungeons(proposalDungeons) << ")"; + for (++itguid; itguid != check.end(); ++itguid) + { + LfgDungeonSet temporal; + LfgDungeonSet &dungeons = m_QueueDataMap[*itguid].dungeons; + o << ", " << *itguid << ": (" << sLFGMgr->ConcatenateDungeons(dungeons) << ")"; + std::set_intersection(proposalDungeons.begin(), proposalDungeons.end(), dungeons.begin(), dungeons.end(), std::inserter(temporal, temporal.begin())); + proposalDungeons = temporal; + } + + if (proposalDungeons.empty()) + { + sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s) No compatible dungeons%s", strGuids.c_str(), o.str().c_str()); + SetCompatibles(strGuids, LFG_INCOMPATIBLES_NO_DUNGEONS); + return LFG_INCOMPATIBLES_NO_DUNGEONS; + } + } + else + { + uint64 gguid = *check.begin(); + const LfgQueueData &queue = m_QueueDataMap[gguid]; + proposalDungeons = queue.dungeons; + proposalRoles = queue.roles; + LFGMgr::CheckGroupRoles(proposalRoles); // assing new roles + } + + // Enough players? + if (numPlayers != MAXGROUPSIZE) + { + sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s) Compatibles but not enough players(%u)", strGuids.c_str(), numPlayers); + SetCompatibles(strGuids, LFG_COMPATIBLES_WITH_LESS_PLAYERS); + return LFG_COMPATIBLES_WITH_LESS_PLAYERS; + } + + proposal.queues = check; + if (check.size() == 1) + { + for (LfgGroupsMap::const_iterator it = proposalGroups.begin(); it != proposalGroups.end(); ++it) + if (proposal.group && it->second != proposal.group) + proposal.isNew = false; + } + + if (!sLFGMgr->AllQueued(check)) + { + sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s) Group MATCH but can't create proposal!", strGuids.c_str()); + SetCompatibles(strGuids, LFG_COMPATIBLES_BAD_STATES); + return LFG_COMPATIBLES_BAD_STATES; + } + + // Create a new proposal + proposal.cancelTime = time(NULL) + LFG_TIME_PROPOSAL; + proposal.state = LFG_PROPOSAL_INITIATING; + proposal.leader = 0; + proposal.dungeonId = Trinity::Containers::SelectRandomContainerElement(proposalDungeons); + + bool leader = false; + for (LfgRolesMap::const_iterator itRoles = proposalRoles.begin(); itRoles != proposalRoles.end(); ++itRoles) + { + // Assing new leader + if (itRoles->second & PLAYER_ROLE_LEADER) + { + if (!leader || !proposal.leader || urand(0, 1)) + proposal.leader = itRoles->first; + leader = true; + } + else if (!leader && (!proposal.leader || urand(0, 1))) + proposal.leader = itRoles->first; + + // Assing player data and roles + LfgProposalPlayer &data = proposal.players[itRoles->first]; + data.role = itRoles->second; + data.group = proposalGroups.find(itRoles->first)->second; + if (!proposal.isNew && data.group && data.group == proposal.group) // Player from existing group, autoaccept + data.accept = LFG_ANSWER_AGREE; + } + + // Mark proposal members as not queued (but not remove queue data) + for (LfgGuidList::const_iterator itQueue = proposal.queues.begin(); itQueue != proposal.queues.end(); ++itQueue) + { + uint64 guid = (*itQueue); + RemoveFromNewQueue(guid); + RemoveFromCurrentQueue(guid); + } + + sLFGMgr->AddProposal(proposal); + + sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s) MATCH! Group formed", strGuids.c_str()); + SetCompatibles(strGuids, LFG_COMPATIBLES_MATCH); + return LFG_COMPATIBLES_MATCH; +} + +void LfgQueue::UpdateQueueTimers(time_t currTime) +{ + for (LfgQueueDataMap::const_iterator itQueue = m_QueueDataMap.begin(); itQueue != m_QueueDataMap.end(); ++itQueue) + { + const LfgQueueData &queueinfo = itQueue->second; + uint32 dungeonId = (*queueinfo.dungeons.begin()); + uint32 queuedTime = uint32(currTime - queueinfo.joinTime); + uint8 role = PLAYER_ROLE_NONE; + int32 waitTime = -1; + int32 wtTank = m_waitTimesTank[dungeonId].time; + int32 wtHealer = m_waitTimesHealer[dungeonId].time; + int32 wtDps = m_waitTimesDps[dungeonId].time; + int32 wtAvg = m_waitTimesAvg[dungeonId].time; + + for (LfgRolesMap::const_iterator itPlayer = queueinfo.roles.begin(); itPlayer != queueinfo.roles.end(); ++itPlayer) + role |= itPlayer->second; + role &= ~PLAYER_ROLE_LEADER; + + switch (role) + { + case PLAYER_ROLE_NONE: // Should not happen - just in case + waitTime = -1; + break; + case PLAYER_ROLE_TANK: + waitTime = wtTank; + break; + case PLAYER_ROLE_HEALER: + waitTime = wtHealer; + break; + case PLAYER_ROLE_DAMAGE: + waitTime = wtDps; + break; + default: + waitTime = wtAvg; + break; + } + + LfgQueueStatusData queueData(dungeonId, waitTime, wtAvg, wtTank, wtHealer, wtDps, queuedTime, queueinfo.tanks, queueinfo.healers, queueinfo.dps); + for (LfgRolesMap::const_iterator itPlayer = queueinfo.roles.begin(); itPlayer != queueinfo.roles.end(); ++itPlayer) + { + uint64 pguid = itPlayer->first; + LFGMgr::SendLfgQueueStatus(pguid, queueData); + } + } +} + +time_t LfgQueue::GetJoinTime(uint64 guid) +{ + return m_QueueDataMap[guid].joinTime; +}
\ No newline at end of file diff --git a/src/server/game/DungeonFinding/LFGQueue.h b/src/server/game/DungeonFinding/LFGQueue.h new file mode 100644 index 00000000000..f08199d725a --- /dev/null +++ b/src/server/game/DungeonFinding/LFGQueue.h @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _LFGQUEUE_H +#define _LFGQUEUE_H + +#include "LFG.h" + +enum LfgCompatibility +{ + LFG_COMPATIBILITY_PENDING, + LFG_INCOMPATIBLES_WRONG_GROUP_SIZE, + LFG_INCOMPATIBLES_TOO_MUCH_PLAYERS, + LFG_INCOMPATIBLES_MULTIPLE_LFG_GROUPS, + LFG_INCOMPATIBLES_HAS_IGNORES, + LFG_INCOMPATIBLES_NO_ROLES, + LFG_INCOMPATIBLES_NO_DUNGEONS, + LFG_COMPATIBLES_WITH_LESS_PLAYERS, // Values under this = not compatible (do not modify order) + LFG_COMPATIBLES_BAD_STATES, + LFG_COMPATIBLES_MATCH // Must be the last one +}; + +/// Stores player or group queue info +struct LfgQueueData +{ + LfgQueueData(): joinTime(time_t(time(NULL))), tanks(LFG_TANKS_NEEDED), + healers(LFG_HEALERS_NEEDED), dps(LFG_DPS_NEEDED) + { } + + LfgQueueData(time_t _joinTime, const LfgDungeonSet &_dungeons, const LfgRolesMap &_roles) + { + joinTime = _joinTime; + dungeons = _dungeons; + roles = _roles; + tanks = LFG_TANKS_NEEDED; + healers = LFG_HEALERS_NEEDED; + dps = LFG_DPS_NEEDED; + + for (LfgRolesMap::const_iterator it = roles.begin(); it != roles.end(); ++it) + { + uint8 role = it->second; + if (role & PLAYER_ROLE_TANK) + --tanks; + else if (role & PLAYER_ROLE_HEALER) + --healers; + else + --dps; + } + } + + time_t joinTime; ///< Player queue join time (to calculate wait times) + uint8 tanks; ///< Tanks needed + uint8 healers; ///< Healers needed + uint8 dps; ///< Dps needed + LfgDungeonSet dungeons; ///< Selected Player/Group Dungeon/s + LfgRolesMap roles; ///< Selected Player Role/s +}; + +struct LfgWaitTime +{ + LfgWaitTime(): time(-1), number(0) {} + int32 time; ///< Wait time + uint32 number; ///< Number of people used to get that wait time +}; + +typedef std::map<uint32, LfgWaitTime> LfgWaitTimesMap; +typedef std::map<std::string, LfgCompatibility> LfgCompatibleMap; +typedef std::map<uint64, LfgQueueData> LfgQueueDataMap; + +/** + Stores all data related to queue +*/ +class LfgQueue +{ + public: + + // Add/Remove from queue + void AddToQueue(uint64 guid); + void RemoveFromQueue(uint64 guid); + void AddQueueData(uint64 guid, time_t joinTime, const LfgDungeonSet &dungeons, const LfgRolesMap &rolesMap); + void RemoveQueueData(uint64 guid); + + // Update Timers (when proposal success) + void UpdateWaitTimeAvg(int32 waitTime, uint32 dungeonId); + void UpdateWaitTimeTank(int32 waitTime, uint32 dungeonId); + void UpdateWaitTimeHealer(int32 waitTime, uint32 dungeonId); + void UpdateWaitTimeDps(int32 waitTime, uint32 dungeonId); + + // Update Queue timers + void UpdateQueueTimers(time_t currTime); + time_t GetJoinTime(uint64 guid); + + // Find new group + uint8 FindGroups(); + + // Just for debugging purposes + LfgCompatibleMap const& GetCompatibleMap(); + std::string DumpQueueInfo() const; + std::string DumpCompatibleInfo() const; + private: + void AddToNewQueue(uint64 guid); + void AddToCurrentQueue(uint64 guid); + void RemoveFromNewQueue(uint64 guid); + void RemoveFromCurrentQueue(uint64 guid); + + void SetCompatibles(std::string const& key, LfgCompatibility compatibles); + LfgCompatibility GetCompatibles(std::string const& key); + void RemoveFromCompatibles(uint64 guid); + + LfgCompatibility FindNewGroups(LfgGuidList& check, LfgGuidList& all); + LfgCompatibility CheckCompatibility(LfgGuidList check); + + // Queue + LfgQueueDataMap m_QueueDataMap; ///< Queued groups + LfgCompatibleMap m_CompatibleMap; ///< Compatible dungeons + + LfgWaitTimesMap m_waitTimesAvg; ///< Average wait time to find a group queuing as multiple roles + LfgWaitTimesMap m_waitTimesTank; ///< Average wait time to find a group queuing as tank + LfgWaitTimesMap m_waitTimesHealer; ///< Average wait time to find a group queuing as healer + LfgWaitTimesMap m_waitTimesDps; ///< Average wait time to find a group queuing as dps + LfgGuidList m_currentQueue; ///< Ordered list. Used to find groups + LfgGuidList m_newToQueue; ///< New groups to add to queue +}; + +#endif diff --git a/src/server/game/DungeonFinding/LFGScripts.cpp b/src/server/game/DungeonFinding/LFGScripts.cpp index 36f04b3020b..10ce42da610 100644 --- a/src/server/game/DungeonFinding/LFGScripts.cpp +++ b/src/server/game/DungeonFinding/LFGScripts.cpp @@ -39,12 +39,12 @@ void LFGPlayerScript::OnLevelChanged(Player* player, uint8 /*oldLevel*/) void LFGPlayerScript::OnLogout(Player* player) { - sLFGMgr->Leave(player); + uint64 guid = player->GetGUID(); + sLFGMgr->LeaveLfg(guid); LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE); player->GetSession()->SendLfgUpdateParty(updateData); player->GetSession()->SendLfgUpdatePlayer(updateData); - player->GetSession()->SendLfgUpdateSearch(false); - uint64 guid = player->GetGUID(); + player->GetSession()->SendLfgLfrList(false); // TODO - Do not remove, add timer before deleting sLFGMgr->RemovePlayerData(guid); } @@ -52,6 +52,7 @@ void LFGPlayerScript::OnLogout(Player* player) void LFGPlayerScript::OnLogin(Player* player) { sLFGMgr->InitializeLockedDungeons(player); + sLFGMgr->SetTeam(player->GetGUID(), player->GetTeam()); // TODO - Restore LfgPlayerData and send proper status to player if it was in a group } @@ -69,75 +70,89 @@ LFGGroupScript::LFGGroupScript() : GroupScript("LFGGroupScript") void LFGGroupScript::OnAddMember(Group* group, uint64 guid) { uint64 gguid = group->GetGUID(); - if (!gguid) - return; + uint64 leader = group->GetLeaderGUID(); - sLog->outDebug(LOG_FILTER_LFG, "LFGScripts::OnAddMember [" UI64FMTD "]: added [" UI64FMTD "]", gguid, guid); - LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_CLEAR_LOCK_LIST); - for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) + if (leader == guid) { - if (Player* plrg = itr->getSource()) + sLog->outDebug(LOG_FILTER_LFG, "LFGScripts::OnAddMember [" UI64FMTD "]: added [" UI64FMTD "] leader " UI64FMTD "]", gguid, guid, leader); + sLFGMgr->SetLeader(gguid, guid); + } + else + { + LfgState gstate = sLFGMgr->GetState(gguid); + LfgState state = sLFGMgr->GetState(guid); + sLog->outDebug(LOG_FILTER_LFG, "LFGScripts::OnAddMember [" UI64FMTD "]: added [" UI64FMTD "] leader " UI64FMTD "] gstate: %u, state: %u", gguid, guid, leader, gstate, state); + LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_CLEAR_LOCK_LIST); + for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) { - plrg->GetSession()->SendLfgUpdatePlayer(updateData); - plrg->GetSession()->SendLfgUpdateParty(updateData); + if (Player* plrg = itr->getSource()) + { + plrg->GetSession()->SendLfgUpdatePlayer(updateData); + plrg->GetSession()->SendLfgUpdateParty(updateData); + } } - } - // TODO - if group is queued and new player is added convert to rolecheck without notify the current players queued - if (sLFGMgr->GetState(gguid) == LFG_STATE_QUEUED) - sLFGMgr->Leave(NULL, group); + if (state == LFG_STATE_QUEUED) + sLFGMgr->LeaveLfg(guid); - if (sLFGMgr->GetState(guid) == LFG_STATE_QUEUED) - if (Player* player = ObjectAccessor::FindPlayer(guid)) - sLFGMgr->Leave(player); + // TODO - if group is queued and new player is added convert to rolecheck without notify the current players queued + if (gstate == LFG_STATE_QUEUED) + sLFGMgr->LeaveLfg(gguid); + } + + sLFGMgr->SetGroup(guid, gguid); + sLFGMgr->AddPlayerToGroup(gguid, guid); } void LFGGroupScript::OnRemoveMember(Group* group, uint64 guid, RemoveMethod method, uint64 kicker, char const* reason) { uint64 gguid = group->GetGUID(); - if (!gguid || method == GROUP_REMOVEMETHOD_DEFAULT) - return; - sLog->outDebug(LOG_FILTER_LFG, "LFGScripts::OnRemoveMember [" UI64FMTD "]: remove [" UI64FMTD "] Method: %d Kicker: [" UI64FMTD "] Reason: %s", gguid, guid, method, kicker, (reason ? reason : "")); - if (sLFGMgr->GetState(gguid) == LFG_STATE_QUEUED) - { - // TODO - Do not remove, just remove the one leaving and rejoin queue with all other data - sLFGMgr->Leave(NULL, group); - } - if (!group->isLFGGroup()) - return; + bool isLFG = group->isLFGGroup(); - if (method == GROUP_REMOVEMETHOD_KICK) // Player have been kicked + if (isLFG && method == GROUP_REMOVEMETHOD_KICK) // Player have been kicked { // TODO - Update internal kick cooldown of kicker std::string str_reason = ""; if (reason) str_reason = std::string(reason); - sLFGMgr->InitBoot(group, kicker, guid, str_reason); + sLFGMgr->InitBoot(gguid, kicker, guid, str_reason); return; } - uint32 state = sLFGMgr->GetState(gguid); - sLFGMgr->ClearState(guid); + LfgState state = sLFGMgr->GetState(gguid); + + // If group is being formed after proposal success do nothing more + if (state == LFG_STATE_PROPOSAL && method == GROUP_REMOVEMETHOD_DEFAULT) + { + // LfgData: Remove player from group + sLFGMgr->SetGroup(guid, 0); + sLFGMgr->RemovePlayerFromGroup(gguid, guid); + return; + } + + sLFGMgr->LeaveLfg(guid); sLFGMgr->SetState(guid, LFG_STATE_NONE); + sLFGMgr->SetGroup(guid, 0); + uint8 players = sLFGMgr->RemovePlayerFromGroup(gguid, guid); + if (Player* player = ObjectAccessor::FindPlayer(guid)) { - if (method == GROUP_REMOVEMETHOD_LEAVE && sLFGMgr->GetState(gguid) != LFG_STATE_FINISHED_DUNGEON && sLFGMgr->GetDungeon(gguid, false)) + if (method == GROUP_REMOVEMETHOD_LEAVE && state == LFG_STATE_DUNGEON && + players >= LFG_GROUP_KICK_VOTES_NEEDED) player->CastSpell(player, LFG_SPELL_DUNGEON_DESERTER, true); - /* - else if (group->isLfgKickActive()) + //else if (state == LFG_STATE_BOOT) // Update internal kick cooldown of kicked - */ - LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_LEADER); - player->GetSession()->SendLfgUpdateParty(updateData); - if (player->GetMap()->IsDungeon()) // Teleport player out the dungeon + player->GetSession()->SendLfgUpdateParty(LfgUpdateData(LFG_UPDATETYPE_LEADER_UNK1)); + if (isLFG && player->GetMap()->IsDungeon()) // Teleport player out the dungeon sLFGMgr->TeleportPlayer(player, true); } - if (state != LFG_STATE_FINISHED_DUNGEON)// Need more players to finish the dungeon - sLFGMgr->OfferContinue(group); + if (isLFG && state != LFG_STATE_FINISHED_DUNGEON) // Need more players to finish the dungeon + if (Player* leader = ObjectAccessor::FindPlayer(sLFGMgr->GetLeader(gguid))) + leader->GetSession()->SendLfgOfferContinue(sLFGMgr->GetDungeon(gguid, false)); } void LFGGroupScript::OnDisband(Group* group) @@ -151,30 +166,19 @@ void LFGGroupScript::OnDisband(Group* group) void LFGGroupScript::OnChangeLeader(Group* group, uint64 newLeaderGuid, uint64 oldLeaderGuid) { uint64 gguid = group->GetGUID(); - if (!gguid) - return; sLog->outDebug(LOG_FILTER_LFG, "LFGScripts::OnChangeLeader [" UI64FMTD "]: old [" UI64FMTD "] new [" UI64FMTD "]", gguid, newLeaderGuid, oldLeaderGuid); - Player* player = ObjectAccessor::FindPlayer(newLeaderGuid); - - LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_LEADER); - if (player) - player->GetSession()->SendLfgUpdateParty(updateData); - - player = ObjectAccessor::FindPlayer(oldLeaderGuid); - if (player) - { - updateData.updateType = LFG_UPDATETYPE_GROUP_DISBAND; - player->GetSession()->SendLfgUpdateParty(updateData); - } + sLFGMgr->SetLeader(gguid, newLeaderGuid); } void LFGGroupScript::OnInviteMember(Group* group, uint64 guid) { uint64 gguid = group->GetGUID(); - if (!gguid) - return; - - sLog->outDebug(LOG_FILTER_LFG, "LFGScripts::OnInviteMember [" UI64FMTD "]: invite [" UI64FMTD "] leader [" UI64FMTD "]", gguid, guid, group->GetLeaderGUID()); - sLFGMgr->Leave(NULL, group); + uint64 leader = group->GetLeaderGUID(); + sLog->outDebug(LOG_FILTER_LFG, "LFGScripts::OnInviteMember [" UI64FMTD "]: invite [" UI64FMTD "] leader [" UI64FMTD "]", gguid, guid, leader); + // No gguid == new group being formed + // No leader == after group creation first invite is new leader + // leader and no gguid == first invite after leader is added to new group (this is the real invite) + if (leader && !gguid) + sLFGMgr->LeaveLfg(leader); } diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index d152dc5642f..68d69c2e14a 100755 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1523,14 +1523,18 @@ void GameObject::Use(Unit* user) Player* player = user->ToPlayer(); - if (player->CanUseBattlegroundObject()) + if (player->CanUseBattlegroundObject(this)) { // in battleground check Battleground* bg = player->GetBattleground(); if (!bg) return; + if (player->GetVehicle()) return; + + player->RemoveAurasByType(SPELL_AURA_MOD_STEALTH); + player->RemoveAurasByType(SPELL_AURA_MOD_INVISIBILITY); // BG flag click // AB: // 15001 @@ -1563,14 +1567,18 @@ void GameObject::Use(Unit* user) Player* player = user->ToPlayer(); - if (player->CanUseBattlegroundObject()) + if (player->CanUseBattlegroundObject(this)) { // in battleground check Battleground* bg = player->GetBattleground(); if (!bg) return; + if (player->GetVehicle()) return; + + player->RemoveAurasByType(SPELL_AURA_MOD_STEALTH); + player->RemoveAurasByType(SPELL_AURA_MOD_INVISIBILITY); // BG flag dropped // WS: // 179785 - Silverwing Flag diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 036062393fb..9e62f85e3a1 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -11684,7 +11684,7 @@ InventoryResult Player::CanRollForItemInLFG(ItemTemplate const* proto, WorldObje bool lootedObjectInDungeon = false; Map const* map = lootedObject->GetMap(); if (uint32 dungeonId = sLFGMgr->GetDungeon(GetGroup()->GetGUID(), true)) - if (LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(dungeonId)) + if (LFGDungeonEntry const* dungeon = sLFGMgr->GetLFGDungeon(dungeonId)) if (uint32(dungeon->map) == map->GetId() && dungeon->difficulty == uint32(map->GetDifficulty())) lootedObjectInDungeon = true; @@ -23530,7 +23530,7 @@ PartyResult Player::CanUninviteFromGroup() const if (state == LFG_STATE_BOOT) return ERR_PARTY_LFG_BOOT_IN_PROGRESS; - if (grp->GetMembersCount() <= sLFGMgr->GetVotesNeeded(gguid)) + if (grp->GetMembersCount() <= LFG_GROUP_KICK_VOTES_NEEDED) return ERR_PARTY_LFG_BOOT_TOO_FEW_PLAYERS; if (state == LFG_STATE_FINISHED_DUNGEON) @@ -23563,8 +23563,22 @@ PartyResult Player::CanUninviteFromGroup() const bool Player::isUsingLfg() { - uint64 guid = GetGUID(); - return sLFGMgr->GetState(guid) != LFG_STATE_NONE; + return sLFGMgr->GetState(GetGUID()) != LFG_STATE_NONE; +} + +bool Player::inRandomLfgDungeon() +{ + if (isUsingLfg()) + { + const LfgDungeonSet& dungeons = sLFGMgr->GetSelectedDungeons(GetGUID()); + if (!dungeons.empty()) + { + LFGDungeonEntry const* dungeon = sLFGMgr->GetLFGDungeon(*dungeons.begin()); + if (dungeon && (dungeon->type == LFG_TYPE_RANDOM || dungeon->seasonal)) + return true; + } + } + return false; } void Player::SetBattlegroundOrBattlefieldRaid(Group* group, int8 subgroup) @@ -23757,10 +23771,14 @@ WorldObject* Player::GetViewpoint() const return NULL; } -bool Player::CanUseBattlegroundObject() +bool Player::CanUseBattlegroundObject(GameObject* gameobject) { - // TODO : some spells gives player ForceReaction to one faction (ReputationMgr::ApplyForceReaction) - // maybe gameobject code should handle that ForceReaction usage + FactionTemplateEntry const* playerFaction = getFactionTemplateEntry(); + FactionTemplateEntry const* faction = sFactionTemplateStore.LookupEntry(gameobject->GetUInt32Value(GAMEOBJECT_FACTION)); + + if (playerFaction && faction && !playerFaction->IsFriendlyTo(*faction)) + return false; + // BUG: sometimes when player clicks on flag in AB - client won't send gameobject_use, only gameobject_report_use packet // Note: Mount, stealth and invisibility will be removed when used return (!isTotalImmune() && // Damage immune diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index f1f58231bef..583423a28d5 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2429,7 +2429,7 @@ class Player : public Unit, public GridObject<Player> bool GetBGAccessByLevel(BattlegroundTypeId bgTypeId) const; bool isTotalImmunity(); - bool CanUseBattlegroundObject(); + bool CanUseBattlegroundObject(GameObject* gameobject); bool isTotalImmune(); bool CanCaptureTowerPoint(); @@ -2548,6 +2548,7 @@ class Player : public Unit, public GridObject<Player> void RemoveAtLoginFlag(AtLoginFlags flags, bool persist = false); bool isUsingLfg(); + bool inRandomLfgDungeon(); typedef std::set<uint32> DFQuestsDoneList; DFQuestsDoneList m_DFQuests; diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index d62a4c9b9fb..87f4a0e6dbf 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -47,6 +47,7 @@ #include "PoolMgr.h" #include "DB2Structure.h" #include "DB2Stores.h" +#include "LFGMgr.h" ScriptMapMap sQuestEndScripts; ScriptMapMap sQuestStartScripts; @@ -4978,7 +4979,7 @@ void ObjectMgr::LoadInstanceEncounters() continue; } - if (lastEncounterDungeon && !sLFGDungeonStore.LookupEntry(lastEncounterDungeon)) + if (lastEncounterDungeon && !sLFGMgr->GetLFGDungeon(lastEncounterDungeon)) { sLog->outError(LOG_FILTER_SQL, "Table `instance_encounters` has an encounter %u (%s) marked as final for invalid dungeon id %u, skipped!", entry, dungeonEncounter->encounterName, lastEncounterDungeon); continue; diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 84e5dd58e44..2b35020fd62 100755 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -554,7 +554,7 @@ bool Group::RemoveMember(uint64 guid, const RemoveMethod &method /*= GROUP_REMOV WorldPacket data; - if (method == GROUP_REMOVEMETHOD_KICK) + if (method == GROUP_REMOVEMETHOD_KICK || method == GROUP_REMOVEMETHOD_KICK_LFG) { data.Initialize(SMSG_GROUP_UNINVITE, 0); player->GetSession()->SendPacket(&data); @@ -631,7 +631,7 @@ bool Group::RemoveMember(uint64 guid, const RemoveMethod &method /*= GROUP_REMOV if (isLFGGroup() && GetMembersCount() == 1) { Player* Leader = ObjectAccessor::FindPlayer(GetLeaderGUID()); - LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(sLFGMgr->GetDungeon(GetGUID())); + LFGDungeonEntry const* dungeon = sLFGMgr->GetLFGDungeon(sLFGMgr->GetDungeon(GetGUID())); if ((Leader && dungeon && Leader->isAlive() && Leader->GetMapId() != uint32(dungeon->map)) || !dungeon) { Disband(); diff --git a/src/server/game/Handlers/LFGHandler.cpp b/src/server/game/Handlers/LFGHandler.cpp index c2d8dbb8ee0..02c5b2e1414 100755 --- a/src/server/game/Handlers/LFGHandler.cpp +++ b/src/server/game/Handlers/LFGHandler.cpp @@ -23,8 +23,6 @@ #include "LFGMgr.h" #include "ObjectMgr.h" #include "GroupMgr.h" -#include "GameEventMgr.h" -#include "InstanceScript.h" void BuildPlayerLockDungeonBlock(WorldPacket& data, const LfgLockMap& lock) { @@ -84,18 +82,20 @@ void WorldSession::HandleLfgJoinOpcode(WorldPacket& recvData) std::string comment; recvData >> comment; sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_JOIN [" UI64FMTD "] roles: %u, Dungeons: %u, Comment: %s", GetPlayer()->GetGUID(), roles, uint8(newDungeons.size()), comment.c_str()); - sLFGMgr->Join(GetPlayer(), uint8(roles), newDungeons, comment); + sLFGMgr->JoinLfg(GetPlayer(), uint8(roles), newDungeons, comment); } void WorldSession::HandleLfgLeaveOpcode(WorldPacket& /*recvData*/) { Group* grp = GetPlayer()->GetGroup(); + uint64 guid = GetPlayer()->GetGUID(); + uint64 gguid = grp ? grp->GetGUID() : guid; - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_LEAVE [" UI64FMTD "] in group: %u", GetPlayer()->GetGUID(), grp ? 1 : 0); + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_LEAVE [" UI64FMTD "] in group: %u", guid, grp ? 1 : 0); // Check cheating - only leader can leave the queue if (!grp || grp->GetLeaderGUID() == GetPlayer()->GetGUID()) - sLFGMgr->Leave(GetPlayer(), grp); + sLFGMgr->LeaveLfg(gguid); } void WorldSession::HandleLfgProposalResultOpcode(WorldPacket& recvData) @@ -130,7 +130,7 @@ void WorldSession::HandleLfgSetCommentOpcode(WorldPacket& recvData) std::string comment; recvData >> comment; uint64 guid = GetPlayer()->GetGUID(); - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_SET_LFG_COMMENT [" UI64FMTD "] comment: %s", guid, comment.c_str()); + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_SET_COMMENT [" UI64FMTD "] comment: %s", guid, comment.c_str()); sLFGMgr->SetComment(guid, comment); } @@ -140,8 +140,9 @@ void WorldSession::HandleLfgSetBootVoteOpcode(WorldPacket& recvData) bool agree; // Agree to kick player recvData >> agree; - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_SET_BOOT_VOTE [" UI64FMTD "] agree: %u", GetPlayer()->GetGUID(), agree ? 1 : 0); - sLFGMgr->UpdateBoot(GetPlayer(), agree); + uint64 guid = GetPlayer()->GetGUID(); + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_SET_BOOT_VOTE [" UI64FMTD "] agree: %u", guid, agree ? 1 : 0); + sLFGMgr->UpdateBoot(guid, agree); } void WorldSession::HandleLfgTeleportOpcode(WorldPacket& recvData) @@ -156,32 +157,24 @@ void WorldSession::HandleLfgTeleportOpcode(WorldPacket& recvData) void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& /*recvData*/) { uint64 guid = GetPlayer()->GetGUID(); - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFD_PLAYER_LOCK_INFO_REQUEST [" UI64FMTD "]", guid); + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_PLAYER_LOCK_INFO_REQUEST [" UI64FMTD "]", guid); // Get Random dungeons that can be done at a certain level and expansion LfgDungeonSet randomDungeons; uint8 level = GetPlayer()->getLevel(); uint8 expansion = GetPlayer()->GetSession()->Expansion(); - for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i) - { - LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(i); - if (dungeon && dungeon->expansion <= expansion && dungeon->minlevel <= level && level <= dungeon->maxlevel) - { - if (dungeon->flags & LFG_FLAG_SEASONAL) - { - if (HolidayIds holiday = sLFGMgr->GetDungeonSeason(dungeon->ID)) - if (!IsHolidayActive(holiday)) - continue; - } - else if (dungeon->type != LFG_TYPE_RANDOM) - continue; - randomDungeons.insert(dungeon->Entry()); - } + LFGDungeonMap& LfgDungeons = sLFGMgr->GetLFGDungeonMap(); + for (LFGDungeonMap::const_iterator itr = LfgDungeons.begin(); itr != LfgDungeons.end(); ++itr) + { + LFGDungeonEntry const& dungeon = itr->second; + if ((dungeon.type == LFG_TYPE_RANDOM || (dungeon.seasonal && sLFGMgr->IsSeasonActive(dungeon.id))) + && dungeon.expansion <= expansion && dungeon.minlevel <= level && level <= dungeon.maxlevel) + randomDungeons.insert(dungeon.Entry()); } // Get player locked Dungeons - LfgLockMap lock = sLFGMgr->GetLockedDungeons(guid); + LfgLockMap const& lock = sLFGMgr->GetLockedDungeons(guid); uint32 rsize = uint32(randomDungeons.size()); uint32 lsize = uint32(lock.size()); @@ -193,40 +186,37 @@ void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& /*recvData* { data << uint32(*it); // Dungeon Entry (id + type) LfgReward const* reward = sLFGMgr->GetRandomDungeonReward(*it, level); - Quest const* qRew = NULL; + Quest const* quest = NULL; uint8 done = 0; if (reward) { - qRew = sObjectMgr->GetQuestTemplate(reward->reward[0].questId); - if (qRew) + quest = sObjectMgr->GetQuestTemplate(reward->reward[0].questId); + if (quest) { - done = !GetPlayer()->CanRewardQuest(qRew, false); + done = !GetPlayer()->CanRewardQuest(quest, false); if (done) - qRew = sObjectMgr->GetQuestTemplate(reward->reward[1].questId); + quest = sObjectMgr->GetQuestTemplate(reward->reward[1].questId); } } - if (qRew) + + if (quest) { data << uint8(done); - data << uint32(qRew->GetRewOrReqMoney()); - data << uint32(qRew->XPValue(GetPlayer())); + data << uint32(quest->GetRewOrReqMoney()); + data << uint32(quest->XPValue(GetPlayer())); data << uint32(reward->reward[done].variableMoney); data << uint32(reward->reward[done].variableXP); - data << uint8(qRew->GetRewItemsCount()); - if (qRew->GetRewItemsCount()) + data << uint8(quest->GetRewItemsCount()); + if (quest->GetRewItemsCount()) { - ItemTemplate const* iProto = NULL; for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i) - { - if (!qRew->RewardItemId[i]) - continue; - - iProto = sObjectMgr->GetItemTemplate(qRew->RewardItemId[i]); - - data << uint32(qRew->RewardItemId[i]); - data << uint32(iProto ? iProto->DisplayInfoID : 0); - data << uint32(qRew->RewardItemIdCount[i]); - } + if (uint32 itemId = quest->RewardItemId[i]) + { + ItemTemplate const* item = sObjectMgr->GetItemTemplate(itemId); + data << uint32(itemId); + data << uint32(item ? item->DisplayInfoID : 0); + data << uint32(quest->RewardItemIdCount[i]); + } } } else @@ -246,7 +236,7 @@ void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& /*recvData* void WorldSession::HandleLfgPartyLockInfoRequestOpcode(WorldPacket& /*recvData*/) { uint64 guid = GetPlayer()->GetGUID(); - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFD_PARTY_LOCK_INFO_REQUEST [" UI64FMTD "]", guid); + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_PARTY_LOCK_INFO_REQUEST [" UI64FMTD "]", guid); Group* grp = GetPlayer()->GetGroup(); if (!grp) @@ -277,11 +267,11 @@ void WorldSession::HandleLfgPartyLockInfoRequestOpcode(WorldPacket& /*recvData* SendPacket(&data); } -void WorldSession::HandleLfrSearchOpcode(WorldPacket& recvData) +void WorldSession::HandleLfrJoinOpcode(WorldPacket& recv_data) { uint32 entry; // Raid id to search - recvData >> entry; - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_SEARCH_LFG_JOIN [" UI64FMTD "] dungeon entry: %u", GetPlayer()->GetGUID(), entry); + recv_data >> entry; + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_LFR_JOIN [" UI64FMTD "] dungeon entry: %u", GetPlayer()->GetGUID(), entry); //SendLfrUpdateListOpcode(entry); } @@ -289,7 +279,7 @@ void WorldSession::HandleLfrLeaveOpcode(WorldPacket& recvData) { uint32 dungeonId; // Raid id queue to leave recvData >> dungeonId; - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_SEARCH_LFG_LEAVE [" UI64FMTD "] dungeonId: %u", GetPlayer()->GetGUID(), dungeonId); + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_LFG_LFR_LEAVE [" UI64FMTD "] dungeonId: %u", GetPlayer()->GetGUID(), dungeonId); //sLFGMgr->LeaveLfr(GetPlayer(), dungeonId); } @@ -297,6 +287,8 @@ void WorldSession::SendLfgUpdatePlayer(const LfgUpdateData& updateData) { bool queued = false; bool extrainfo = false; + uint64 guid = GetPlayer()->GetGUID(); + uint8 size = uint8(updateData.dungeons.size()); switch (updateData.updateType) { @@ -313,9 +305,6 @@ void WorldSession::SendLfgUpdatePlayer(const LfgUpdateData& updateData) break; } - uint64 guid = GetPlayer()->GetGUID(); - uint8 size = uint8(updateData.dungeons.size()); - sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_UPDATE_PLAYER [" UI64FMTD "] updatetype: %u", guid, updateData.updateType); WorldPacket data(SMSG_LFG_UPDATE_PLAYER, 1 + 1 + (extrainfo ? 1 : 0) * (1 + 1 + 1 + 1 + size * 4 + updateData.comment.length())); data << uint8(updateData.updateType); // Lfg Update type @@ -340,6 +329,8 @@ void WorldSession::SendLfgUpdateParty(const LfgUpdateData& updateData) bool join = false; bool extrainfo = false; bool queued = false; + uint64 guid = GetPlayer()->GetGUID(); + uint8 size = uint8(updateData.dungeons.size()); switch (updateData.updateType) { @@ -363,9 +354,6 @@ void WorldSession::SendLfgUpdateParty(const LfgUpdateData& updateData) break; } - uint64 guid = GetPlayer()->GetGUID(); - uint8 size = uint8(updateData.dungeons.size()); - sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_UPDATE_PARTY [" UI64FMTD "] updatetype: %u", guid, updateData.updateType); WorldPacket data(SMSG_LFG_UPDATE_PARTY, 1 + 1 + (extrainfo ? 1 : 0) * (1 + 1 + 1 + 1 + 1 + size * 4 + updateData.comment.length())); data << uint8(updateData.updateType); // Lfg Update type @@ -399,45 +387,44 @@ void WorldSession::SendLfgRoleChosen(uint64 guid, uint8 roles) SendPacket(&data); } -void WorldSession::SendLfgRoleCheckUpdate(const LfgRoleCheck* pRoleCheck) +void WorldSession::SendLfgRoleCheckUpdate(const LfgRoleCheck& roleCheck) { - ASSERT(pRoleCheck); LfgDungeonSet dungeons; - if (pRoleCheck->rDungeonId) - dungeons.insert(pRoleCheck->rDungeonId); + if (roleCheck.rDungeonId) + dungeons.insert(roleCheck.rDungeonId); else - dungeons = pRoleCheck->dungeons; + dungeons = roleCheck.dungeons; sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_ROLE_CHECK_UPDATE [" UI64FMTD "]", GetPlayer()->GetGUID()); - WorldPacket data(SMSG_LFG_ROLE_CHECK_UPDATE, 4 + 1 + 1 + dungeons.size() * 4 + 1 + pRoleCheck->roles.size() * (8 + 1 + 4 + 1)); + WorldPacket data(SMSG_LFG_ROLE_CHECK_UPDATE, 4 + 1 + 1 + dungeons.size() * 4 + 1 + roleCheck.roles.size() * (8 + 1 + 4 + 1)); - data << uint32(pRoleCheck->state); // Check result - data << uint8(pRoleCheck->state == LFG_ROLECHECK_INITIALITING); + data << uint32(roleCheck.state); // Check result + data << uint8(roleCheck.state == LFG_ROLECHECK_INITIALITING); data << uint8(dungeons.size()); // Number of dungeons if (!dungeons.empty()) { for (LfgDungeonSet::iterator it = dungeons.begin(); it != dungeons.end(); ++it) { - LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(*it); + LFGDungeonEntry const* dungeon = sLFGMgr->GetLFGDungeon(*it); data << uint32(dungeon ? dungeon->Entry() : 0); // Dungeon } } - data << uint8(pRoleCheck->roles.size()); // Players in group - if (!pRoleCheck->roles.empty()) + data << uint8(roleCheck.roles.size()); // Players in group + if (!roleCheck.roles.empty()) { // Leader info MUST be sent 1st :S - uint64 guid = pRoleCheck->leader; - uint8 roles = pRoleCheck->roles.find(guid)->second; + uint64 guid = roleCheck.leader; + uint8 roles = roleCheck.roles.find(guid)->second; data << uint64(guid); // Guid data << uint8(roles > 0); // Ready data << uint32(roles); // Roles Player* player = ObjectAccessor::FindPlayer(guid); data << uint8(player ? player->getLevel() : 0); // Level - for (LfgRolesMap::const_iterator it = pRoleCheck->roles.begin(); it != pRoleCheck->roles.end(); ++it) + for (LfgRolesMap::const_iterator it = roleCheck.roles.begin(); it != roleCheck.roles.end(); ++it) { - if (it->first == pRoleCheck->leader) + if (it->first == roleCheck.leader) continue; guid = it->first; @@ -467,30 +454,31 @@ void WorldSession::SendLfgJoinResult(const LfgJoinResultData& joinData) SendPacket(&data); } -void WorldSession::SendLfgQueueStatus(uint32 dungeon, int32 waitTime, int32 avgWaitTime, int32 waitTimeTanks, int32 waitTimeHealer, int32 waitTimeDps, uint32 queuedTime, uint8 tanks, uint8 healers, uint8 dps) +void WorldSession::SendLfgQueueStatus(const LfgQueueStatusData& queueData) { - sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_QUEUE_STATUS [" UI64FMTD "] dungeon: %u - waitTime: %d - avgWaitTime: %d - waitTimeTanks: %d - waitTimeHealer: %d - waitTimeDps: %d - queuedTime: %u - tanks: %u - healers: %u - dps: %u", GetPlayer()->GetGUID(), dungeon, waitTime, avgWaitTime, waitTimeTanks, waitTimeHealer, waitTimeDps, queuedTime, tanks, healers, dps); + sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_QUEUE_STATUS [" UI64FMTD "] dungeon: %u - waitTime: %d - avgWaitTime: %d - waitTimeTanks: %d - waitTimeHealer: %d - waitTimeDps: %d - queuedTime: %u - tanks: %u - healers: %u - dps: %u", + GetPlayer()->GetGUID(), queueData.dungeonId, queueData.waitTime, queueData.waitTimeAvg, queueData.waitTimeTank, queueData.waitTimeHealer, queueData.waitTimeDps, queueData.queuedTime, queueData.tanks, queueData.healers, queueData.dps); WorldPacket data(SMSG_LFG_QUEUE_STATUS, 4 + 4 + 4 + 4 + 4 +4 + 1 + 1 + 1 + 4); - data << uint32(dungeon); // Dungeon - data << int32(avgWaitTime); // Average Wait time - data << int32(waitTime); // Wait Time - data << int32(waitTimeTanks); // Wait Tanks - data << int32(waitTimeHealer); // Wait Healers - data << int32(waitTimeDps); // Wait Dps - data << uint8(tanks); // Tanks needed - data << uint8(healers); // Healers needed - data << uint8(dps); // Dps needed - data << uint32(queuedTime); // Player wait time in queue + data << uint32(queueData.dungeonId); // Dungeon + data << int32(queueData.waitTimeAvg); // Average Wait time + data << int32(queueData.waitTime); // Wait Time + data << int32(queueData.waitTimeTank); // Wait Tanks + data << int32(queueData.waitTimeHealer); // Wait Healers + data << int32(queueData.waitTimeDps); // Wait Dps + data << uint8(queueData.tanks); // Tanks needed + data << uint8(queueData.healers); // Healers needed + data << uint8(queueData.dps); // Dps needed + data << uint32(queueData.queuedTime); // Player wait time in queue SendPacket(&data); } -void WorldSession::SendLfgPlayerReward(uint32 rdungeonEntry, uint32 sdungeonEntry, uint8 done, const LfgReward* reward, const Quest* qRew) +void WorldSession::SendLfgPlayerReward(uint32 rdungeonEntry, uint32 sdungeonEntry, uint8 done, const LfgReward* reward, const Quest* quest) { - if (!rdungeonEntry || !sdungeonEntry || !qRew) + if (!rdungeonEntry || !sdungeonEntry || !quest) return; - uint8 itemNum = uint8(qRew ? qRew->GetRewItemsCount() : 0); + uint8 itemNum = uint8(quest ? quest->GetRewItemsCount() : 0); sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_PLAYER_REWARD [" UI64FMTD "] rdungeonEntry: %u - sdungeonEntry: %u - done: %u", GetPlayer()->GetGUID(), rdungeonEntry, sdungeonEntry, done); WorldPacket data(SMSG_LFG_PLAYER_REWARD, 4 + 4 + 1 + 4 + 4 + 4 + 4 + 4 + 1 + itemNum * (4 + 4 + 4)); @@ -498,37 +486,33 @@ void WorldSession::SendLfgPlayerReward(uint32 rdungeonEntry, uint32 sdungeonEntr data << uint32(sdungeonEntry); // Dungeon Finished data << uint8(done); data << uint32(1); - data << uint32(qRew->GetRewOrReqMoney()); - data << uint32(qRew->XPValue(GetPlayer())); + data << uint32(quest->GetRewOrReqMoney()); + data << uint32(quest->XPValue(GetPlayer())); data << uint32(reward->reward[done].variableMoney); data << uint32(reward->reward[done].variableXP); data << uint8(itemNum); if (itemNum) { - ItemTemplate const* iProto = NULL; for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i) - { - if (!qRew->RewardItemId[i]) - continue; - - iProto = sObjectMgr->GetItemTemplate(qRew->RewardItemId[i]); - - data << uint32(qRew->RewardItemId[i]); - data << uint32(iProto ? iProto->DisplayInfoID : 0); - data << uint32(qRew->RewardItemIdCount[i]); - } + if (uint32 itemId = quest->RewardItemId[i]) + { + ItemTemplate const* item = sObjectMgr->GetItemTemplate(itemId); + data << uint32(itemId); + data << uint32(item ? item->DisplayInfoID : 0); + data << uint32(quest->RewardItemIdCount[i]); + } } SendPacket(&data); } -void WorldSession::SendLfgBootPlayer(const LfgPlayerBoot* pBoot) +void WorldSession::SendLfgBootProposalUpdate(const LfgPlayerBoot& boot) { uint64 guid = GetPlayer()->GetGUID(); - LfgAnswer playerVote = pBoot->votes.find(guid)->second; + LfgAnswer playerVote = boot.votes.find(guid)->second; uint8 votesNum = 0; uint8 agreeNum = 0; - uint32 secsleft = uint8((pBoot->cancelTime - time(NULL)) / 1000); - for (LfgAnswerMap::const_iterator it = pBoot->votes.begin(); it != pBoot->votes.end(); ++it) + uint32 secsleft = uint8((boot.cancelTime - time(NULL)) / 1000); + for (LfgAnswerMap::const_iterator it = boot.votes.begin(); it != boot.votes.end(); ++it) { if (it->second != LFG_ANSWER_PENDING) { @@ -538,107 +522,73 @@ void WorldSession::SendLfgBootPlayer(const LfgPlayerBoot* pBoot) } } sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_BOOT_PROPOSAL_UPDATE [" UI64FMTD "] inProgress: %u - didVote: %u - agree: %u - victim: [" UI64FMTD "] votes: %u - agrees: %u - left: %u - needed: %u - reason %s", - guid, uint8(pBoot->inProgress), uint8(playerVote != LFG_ANSWER_PENDING), uint8(playerVote == LFG_ANSWER_AGREE), pBoot->victim, votesNum, agreeNum, secsleft, pBoot->votedNeeded, pBoot->reason.c_str()); - WorldPacket data(SMSG_LFG_BOOT_PROPOSAL_UPDATE, 1 + 1 + 1 + 8 + 4 + 4 + 4 + 4 + pBoot->reason.length()); - data << uint8(pBoot->inProgress); // Vote in progress + guid, uint8(boot.inProgress), uint8(playerVote != LFG_ANSWER_PENDING), uint8(playerVote == LFG_ANSWER_AGREE), boot.victim, votesNum, agreeNum, secsleft, LFG_GROUP_KICK_VOTES_NEEDED, boot.reason.c_str()); + WorldPacket data(SMSG_LFG_BOOT_PROPOSAL_UPDATE, 1 + 1 + 1 + 8 + 4 + 4 + 4 + 4 + boot.reason.length()); + data << uint8(boot.inProgress); // Vote in progress data << uint8(playerVote != LFG_ANSWER_PENDING); // Did Vote data << uint8(playerVote == LFG_ANSWER_AGREE); // Agree data << uint8(0); // Unknown 4.2.2 - data << uint64(pBoot->victim); // Victim GUID + data << uint64(boot.victim); // Victim GUID data << uint32(votesNum); // Total Votes data << uint32(agreeNum); // Agree Count data << uint32(secsleft); // Time Left - data << uint32(pBoot->votedNeeded); // Needed Votes - data << pBoot->reason.c_str(); // Kick reason + data << uint32(LFG_GROUP_KICK_VOTES_NEEDED); // Needed Votes + data << boot.reason.c_str(); // Kick reason SendPacket(&data); } -void WorldSession::SendLfgUpdateProposal(uint32 proposalId, const LfgProposal* pProp) +void WorldSession::SendLfgUpdateProposal(uint32 proposalId, LfgProposal const& proposal) { - if (!pProp) - return; - uint64 guid = GetPlayer()->GetGUID(); - LfgProposalPlayerMap::const_iterator itPlayer = pProp->players.find(guid); - if (itPlayer == pProp->players.end()) // Player MUST be in the proposal - return; + uint64 gguid = proposal.players.find(guid)->second.group; + bool silent = !proposal.isNew && gguid == proposal.group; + uint32 dungeonEntry = proposal.dungeonId; - LfgProposalPlayer* ppPlayer = itPlayer->second; - uint32 pLowGroupGuid = ppPlayer->groupLowGuid; - uint32 dLowGuid = pProp->groupLowGuid; - uint32 dungeonId = pProp->dungeonId; - bool isSameDungeon = false; - bool isContinue = false; - Group* grp = dLowGuid ? sGroupMgr->GetGroupByGUID(dLowGuid) : NULL; - uint32 completedEncounters = 0; - if (grp) - { - uint64 gguid = grp->GetGUID(); - isContinue = grp->isLFGGroup() && sLFGMgr->GetState(gguid) != LFG_STATE_FINISHED_DUNGEON; - isSameDungeon = GetPlayer()->GetGroup() == grp && isContinue; - } - - sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_PROPOSAL_UPDATE [" UI64FMTD "] state: %u", GetPlayer()->GetGUID(), pProp->state); - WorldPacket data(SMSG_LFG_PROPOSAL_UPDATE, 4 + 1 + 4 + 4 + 1 + 1 + pProp->players.size() * (4 + 1 + 1 + 1 + 1 +1)); + sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_PROPOSAL_UPDATE [" UI64FMTD "] state: %u", guid, proposal.state); + WorldPacket data(SMSG_LFG_PROPOSAL_UPDATE, 4 + 1 + 4 + 4 + 1 + 1 + proposal.players.size() * (4 + 1 + 1 + 1 + 1 +1)); - if (!isContinue) // Only show proposal dungeon if it's continue + // show random dungeon if player selected random dungeon and it's not lfg group + if (!silent) { - LfgDungeonSet playerDungeons = sLFGMgr->GetSelectedDungeons(guid); - if (playerDungeons.size() == 1) - dungeonId = (*playerDungeons.begin()); + LfgDungeonSet const& playerDungeons = sLFGMgr->GetSelectedDungeons(guid); + if (playerDungeons.find(proposal.dungeonId) == playerDungeons.end()) + dungeonEntry = (*playerDungeons.begin()); } - if (LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(dungeonId)) - { - dungeonId = dungeon->Entry(); - - // Select a player inside to be get completed encounters from - if (grp) - { - for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* groupMember = itr->getSource(); - if (groupMember && groupMember->GetMapId() == uint32(dungeon->map)) - { - if (InstanceScript* instance = groupMember->GetInstanceScript()) - completedEncounters = instance->GetCompletedEncounterMask(); - break; - } - } - } - } + if (LFGDungeonEntry const* dungeon = sLFGMgr->GetLFGDungeon(dungeonEntry)) + dungeonEntry = dungeon->Entry(); - data << uint32(dungeonId); // Dungeon - data << uint8(pProp->state); // Result state - data << uint32(proposalId); // Internal Proposal ID - data << uint32(completedEncounters); // Bosses killed - data << uint8(isSameDungeon); // Silent (show client window) - data << uint8(pProp->players.size()); // Group size + data << uint32(dungeonEntry); // Dungeon + data << uint8(proposal.state); // Proposal state + data << uint32(proposalId); // Proposal ID + data << uint32(proposal.encounters); // encounters done + data << uint8(silent); // Show proposal window + data << uint8(proposal.players.size()); // Group size - for (itPlayer = pProp->players.begin(); itPlayer != pProp->players.end(); ++itPlayer) + for (LfgProposalPlayerMap::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it) { - ppPlayer = itPlayer->second; - data << uint32(ppPlayer->role); // Role - data << uint8(itPlayer->first == guid); // Self player - if (!ppPlayer->groupLowGuid) // Player not it a group + LfgProposalPlayer const& player = it->second; + data << uint32(player.role); // Role + data << uint8(it->first == guid); // Self player + if (!player.group) // Player not it a group { data << uint8(0); // Not in dungeon data << uint8(0); // Not same group } else { - data << uint8(ppPlayer->groupLowGuid == dLowGuid); // In dungeon (silent) - data << uint8(ppPlayer->groupLowGuid == pLowGroupGuid); // Same Group than player + data << uint8(player.group == proposal.group); // In dungeon (silent) + data << uint8(player.group == gguid); // Same Group than player } - data << uint8(ppPlayer->accept != LFG_ANSWER_PENDING); // Answered - data << uint8(ppPlayer->accept == LFG_ANSWER_AGREE); // Accepted + data << uint8(player.accept != LFG_ANSWER_PENDING); // Answered + data << uint8(player.accept == LFG_ANSWER_AGREE); // Accepted } SendPacket(&data); } -void WorldSession::SendLfgUpdateSearch(bool update) +void WorldSession::SendLfgLfrList(bool update) { - sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_UPDATE_SEARCH [" UI64FMTD "] update: %u", GetPlayer()->GetGUID(), update ? 1 : 0); + sLog->outDebug(LOG_FILTER_NETWORKIO, "SMSG_LFG_LFR_LIST [" UI64FMTD "] update: %u", GetPlayer()->GetGUID(), update ? 1 : 0); WorldPacket data(SMSG_LFG_UPDATE_SEARCH, 1); data << uint8(update); // In Lfg Queue? SendPacket(&data); diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index c0f4bfd1c24..eff6543443a 100755 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -2469,8 +2469,8 @@ bool InstanceMap::AddPlayerToMap(Player* player) if (group && group->isLFGGroup()) if (uint32 dungeonId = sLFGMgr->GetDungeon(group->GetGUID(), true)) - if (LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(dungeonId)) - if (LFGDungeonEntry const* randomDungeon = sLFGDungeonStore.LookupEntry(*(sLFGMgr->GetSelectedDungeons(player->GetGUID()).begin()))) + if (LFGDungeonEntry const* dungeon = sLFGMgr->GetLFGDungeon(dungeonId)) + if (LFGDungeonEntry const* randomDungeon = sLFGMgr->GetLFGDungeon(*(sLFGMgr->GetSelectedDungeons(player->GetGUID()).begin()))) if (uint32(dungeon->map) == GetId() && dungeon->difficulty == uint32(GetDifficulty()) && randomDungeon->type == uint32(LFG_TYPE_RANDOM)) player->CastSpell(player, LFG_SPELL_LUCK_OF_THE_DRAW, true); } diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index c55c57481f4..1de08a21563 100755 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -1084,7 +1084,22 @@ enum TrinityStrings // Use for custom patches 11000-11999 LANG_AUTO_BROADCAST = 11000, - LANG_INVALID_REALMID = 11001 + LANG_INVALID_REALMID = 11001, + + LANG_LFG_STATE_NONE = 11002, + LANG_LFG_STATE_ROLECHECK = 11003, + LANG_LFG_STATE_QUEUED = 11004, + LANG_LFG_STATE_PROPOSAL = 11005, + LANG_LFG_STATE_BOOT = 11006, + LANG_LFG_STATE_DUNGEON = 11007, + LANG_LFG_STATE_FINISHED_DUNGEON = 11008, + LANG_LFG_STATE_RAIDBROWSER = 11009, + LANG_LFG_ROLE_TANK = 11010, + LANG_LFG_ROLE_HEALER = 11011, + LANG_LFG_ROLE_DAMAGE = 11012, + LANG_LFG_ROLE_LEADER = 11013, + LANG_LFG_ROLE_NONE = 11014, + LANG_LFG_ERROR = 11015, // NOT RESERVED IDS 12000-1999999999 // `db_script_string` table index 2000000000-2000009999 (MIN_DB_SCRIPT_STRING_ID-MAX_DB_SCRIPT_STRING_ID) diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 2c0dd0aa1a3..ed7ed2ea05a 100755 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -3697,9 +3697,10 @@ enum XPColorChar enum RemoveMethod { - GROUP_REMOVEMETHOD_DEFAULT = 0, - GROUP_REMOVEMETHOD_KICK = 1, - GROUP_REMOVEMETHOD_LEAVE = 2 + GROUP_REMOVEMETHOD_DEFAULT = 0, + GROUP_REMOVEMETHOD_KICK = 1, + GROUP_REMOVEMETHOD_LEAVE = 2, + GROUP_REMOVEMETHOD_KICK_LFG = 3 }; enum ActivateTaxiReply diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 694b2cf2d7f..022faa11b27 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -1477,7 +1477,7 @@ void OpcodeTable::Initialize() //DEFINE_OPCODE_HANDLER(CMSG_RUN_SCRIPT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); //DEFINE_OPCODE_HANDLER(CMSG_SAVE_DANCE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); //DEFINE_OPCODE_HANDLER(CMSG_SAVE_PLAYER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); - //DEFINE_OPCODE_HANDLER(CMSG_SEARCH_LFG_JOIN, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfrSearchOpcode ); + //DEFINE_OPCODE_HANDLER(CMSG_SEARCH_LFG_JOIN, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfrJoinOpcode ); //DEFINE_OPCODE_HANDLER(CMSG_SEARCH_LFG_LEAVE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLfrLeaveOpcode ); //DEFINE_OPCODE_HANDLER(CMSG_SEND_COMBAT_TRIGGER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); //DEFINE_OPCODE_HANDLER(CMSG_SEND_EVENT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 5c61385f537..fb555b42ea0 100755 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -55,6 +55,7 @@ struct LfgJoinResultData; struct LfgLockStatus; struct LfgPlayerBoot; struct LfgProposal; +struct LfgQueueStatusData; struct LfgReward; struct LfgRoleCheck; struct LfgUpdateData; @@ -844,19 +845,19 @@ class WorldSession void HandleLfgProposalResultOpcode(WorldPacket& recvData); void HandleLfgSetBootVoteOpcode(WorldPacket& recvData); void HandleLfgTeleportOpcode(WorldPacket& recvData); - void HandleLfrSearchOpcode(WorldPacket& recvData); + void HandleLfrJoinOpcode(WorldPacket& recvData); void HandleLfrLeaveOpcode(WorldPacket& recvData); void SendLfgUpdatePlayer(const LfgUpdateData& updateData); void SendLfgUpdateParty(const LfgUpdateData& updateData); void SendLfgRoleChosen(uint64 guid, uint8 roles); - void SendLfgRoleCheckUpdate(const LfgRoleCheck* pRoleCheck); - void SendLfgUpdateSearch(bool update); + void SendLfgRoleCheckUpdate(const LfgRoleCheck& pRoleCheck); + void SendLfgLfrList(bool update); void SendLfgJoinResult(const LfgJoinResultData& joinData); - void SendLfgQueueStatus(uint32 dungeon, int32 waitTime, int32 avgWaitTime, int32 waitTimeTanks, int32 waitTimeHealer, int32 waitTimeDps, uint32 queuedTime, uint8 tanks, uint8 healers, uint8 dps); + void SendLfgQueueStatus(const LfgQueueStatusData& queueData); void SendLfgPlayerReward(uint32 rdungeonEntry, uint32 sdungeonEntry, uint8 done, const LfgReward* reward, const Quest *qRew); - void SendLfgBootPlayer(const LfgPlayerBoot* pBoot); - void SendLfgUpdateProposal(uint32 proposalId, const LfgProposal *pProp); + void SendLfgBootProposalUpdate(const LfgPlayerBoot& boot); + void SendLfgUpdateProposal(uint32 proposalId, const LfgProposal& proposal); void SendLfgDisabled(); void SendLfgOfferContinue(uint32 dungeonEntry); void SendLfgTeleportError(uint8 err); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 04a371ba776..57f3a7d3711 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -5243,7 +5243,7 @@ SpellCastResult Spell::CheckCast(bool strict) if (m_spellInfo->Id != 1842 || (m_targets.GetGOTarget() && m_targets.GetGOTarget()->GetGOInfo()->type != GAMEOBJECT_TYPE_TRAP)) if (m_caster->ToPlayer()->InBattleground() && // In Battleground players can use only flags and banners - !m_caster->ToPlayer()->CanUseBattlegroundObject()) + !m_caster->ToPlayer()->CanUseBattlegroundObject(m_targets.GetGOTarget())) return SPELL_FAILED_TRY_AGAIN; // get the lock entry diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 371668e73d9..43c0f5bd73c 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1467,14 +1467,15 @@ void World::SetInitialWorldSettings() sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Vehicle Accessories..."); sObjectMgr->LoadVehicleAccessories(); // must be after LoadCreatureTemplates() and LoadNPCSpellClickSpells() + sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading LFG entrance positions..."); + sLFGMgr->LoadLFGDungeons(); + sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Dungeon boss data..."); sObjectMgr->LoadInstanceEncounters(); sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading LFG rewards..."); sLFGMgr->LoadRewards(); - sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading LFG entrance positions..."); - sLFGMgr->LoadEntrancePositions(); sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading SpellArea Data..."); // must be after quest load sSpellMgr->LoadSpellAreas(); diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 21402ddcd92..fee77fc5796 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -1581,12 +1581,12 @@ class spell_gen_luck_of_the_draw : public SpellScriptLoader } - LFGDungeonEntry const* randomDungeon = sLFGDungeonStore.LookupEntry(*itr); + LFGDungeonEntry const* randomDungeon = sLFGMgr->GetLFGDungeon(*itr); if (Group* group = owner->GetGroup()) if (Map const* map = owner->GetMap()) if (group->isLFGGroup()) if (uint32 dungeonId = sLFGMgr->GetDungeon(group->GetGUID(), true)) - if (LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(dungeonId)) + if (LFGDungeonEntry const* dungeon = sLFGMgr->GetLFGDungeon(dungeonId)) if (uint32(dungeon->map) == map->GetId() && dungeon->difficulty == uint32(map->GetDifficulty())) if (randomDungeon && randomDungeon->type == LFG_TYPE_RANDOM) return; // in correct dungeon |