614 lines
20 KiB
C#
614 lines
20 KiB
C#
/*
|
|
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
using Framework.Constants;
|
|
using Game.Achievements;
|
|
using Game.Chat;
|
|
using Game.DataStorage;
|
|
using Game.Garrisons;
|
|
using Game.Groups;
|
|
using Game.Mails;
|
|
using Game.Maps;
|
|
using Game.Misc;
|
|
using Game.Spells;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
|
|
namespace Game.Entities
|
|
{
|
|
public partial class Player
|
|
{
|
|
public WorldSession GetSession() { return Session; }
|
|
public PlayerSocial GetSocial() { return m_social; }
|
|
|
|
//Gossip
|
|
public PlayerMenu PlayerTalkClass;
|
|
PlayerSocial m_social;
|
|
List<Channel> m_channels = new List<Channel>();
|
|
List<ObjectGuid> WhisperList = new List<ObjectGuid>();
|
|
public string autoReplyMsg;
|
|
|
|
//Inventory
|
|
Dictionary<ulong, EquipmentSetInfo> _equipmentSets = new Dictionary<ulong, EquipmentSetInfo>();
|
|
public List<ItemSetEffect> ItemSetEff = new List<ItemSetEffect>();
|
|
List<EnchantDuration> m_enchantDuration = new List<EnchantDuration>();
|
|
List<Item> m_itemDuration = new List<Item>();
|
|
List<ObjectGuid> m_itemSoulboundTradeable = new List<ObjectGuid>();
|
|
List<ObjectGuid> m_refundableItems = new List<ObjectGuid>();
|
|
public List<Item> ItemUpdateQueue = new List<Item>();
|
|
VoidStorageItem[] _voidStorageItems = new VoidStorageItem[SharedConst.VoidStorageMaxSlot];
|
|
Item[] m_items = new Item[(int)PlayerSlots.Count];
|
|
uint m_WeaponProficiency;
|
|
uint m_ArmorProficiency;
|
|
uint m_currentBuybackSlot;
|
|
TradeData m_trade;
|
|
|
|
//PVP
|
|
BgBattlegroundQueueID_Rec[] m_bgBattlegroundQueueID = new BgBattlegroundQueueID_Rec[SharedConst.MaxPlayerBGQueues];
|
|
BGData m_bgData;
|
|
bool m_IsBGRandomWinner;
|
|
public PvPInfo pvpInfo;
|
|
uint m_ArenaTeamIdInvited;
|
|
long m_lastHonorUpdateTime;
|
|
uint m_contestedPvPTimer;
|
|
|
|
//Groups/Raids
|
|
GroupReference m_group = new GroupReference();
|
|
GroupReference m_originalGroup = new GroupReference();
|
|
Group m_groupInvite;
|
|
GroupUpdateFlags m_groupUpdateMask;
|
|
bool m_bPassOnGroupLoot;
|
|
GroupUpdateCounter[] m_groupUpdateSequences = new GroupUpdateCounter[2];
|
|
|
|
public Dictionary<uint, InstanceBind>[] m_boundInstances = new Dictionary<uint, InstanceBind>[(int)Difficulty.Max];
|
|
Dictionary<uint, long> _instanceResetTimes = new Dictionary<uint, long>();
|
|
uint _pendingBindId;
|
|
uint _pendingBindTimer;
|
|
public bool m_InstanceValid;
|
|
|
|
Difficulty m_dungeonDifficulty;
|
|
Difficulty m_raidDifficulty;
|
|
Difficulty m_legacyRaidDifficulty;
|
|
Difficulty m_prevMapDifficulty;
|
|
|
|
//Movement
|
|
public PlayerTaxi m_taxi = new PlayerTaxi();
|
|
public byte[] m_forced_speed_changes = new byte[(int)UnitMoveType.Max];
|
|
uint m_lastFallTime;
|
|
float m_lastFallZ;
|
|
WorldLocation teleportDest;
|
|
TeleportToOptions m_teleport_options;
|
|
bool mSemaphoreTeleport_Near;
|
|
bool mSemaphoreTeleport_Far;
|
|
PlayerDelayedOperations m_DelayedOperations;
|
|
bool m_bCanDelayTeleport;
|
|
bool m_bHasDelayedTeleport;
|
|
|
|
PlayerUnderwaterState m_MirrorTimerFlags;
|
|
PlayerUnderwaterState m_MirrorTimerFlagsLast;
|
|
bool m_isInWater;
|
|
|
|
//Stats
|
|
uint m_baseSpellPower;
|
|
uint m_baseManaRegen;
|
|
uint m_baseHealthRegen;
|
|
int m_spellPenetrationItemMod;
|
|
uint m_lastPotionId;
|
|
|
|
//Spell
|
|
Dictionary<uint, PlayerSpell> m_spells = new Dictionary<uint, PlayerSpell>();
|
|
Dictionary<uint, SkillStatusData> mSkillStatus = new Dictionary<uint, SkillStatusData>();
|
|
Dictionary<uint, PlayerCurrency> _currencyStorage = new Dictionary<uint, PlayerCurrency>();
|
|
List<SpellModifier>[][] m_spellMods = new List<SpellModifier>[(int)SpellModOp.Max][];
|
|
MultiMap<uint, uint> m_overrideSpells = new MultiMap<uint, uint>();
|
|
public Spell m_spellModTakingSpell;
|
|
uint m_oldpetspell;
|
|
// Rune type / Rune timer
|
|
uint[] m_runeGraceCooldown = new uint[PlayerConst.MaxRunes];
|
|
uint[] m_lastRuneGraceTimers = new uint[PlayerConst.MaxRunes];
|
|
|
|
//Mail
|
|
List<Mail> m_mail = new List<Mail>();
|
|
Dictionary<ulong, Item> mMitems = new Dictionary<ulong, Item>();
|
|
public byte unReadMails;
|
|
long m_nextMailDelivereTime;
|
|
public bool m_mailsLoaded;
|
|
public bool m_mailsUpdated;
|
|
|
|
//Pets
|
|
public uint m_stableSlots;
|
|
uint m_temporaryUnsummonedPetNumber;
|
|
uint m_lastpetnumber;
|
|
|
|
// Player summoning
|
|
long m_summon_expire;
|
|
WorldLocation m_summon_location;
|
|
|
|
RestMgr _restMgr;
|
|
|
|
//Combat
|
|
int[] baseRatingValue = new int[(int)CombatRating.Max];
|
|
public float[][] m_auraBaseMod = new float[(int)BaseModGroup.End][];
|
|
public DuelInfo duel;
|
|
bool m_canParry;
|
|
bool m_canBlock;
|
|
bool m_canTitanGrip;
|
|
uint m_titanGripPenaltySpellId;
|
|
uint m_deathTimer;
|
|
long m_deathExpireTime;
|
|
byte m_swingErrorMsg;
|
|
uint m_combatExitTime;
|
|
uint m_regenTimerCount;
|
|
uint m_weaponChangeTimer;
|
|
|
|
//Quest
|
|
List<uint> m_timedquests = new List<uint>();
|
|
List<uint> m_weeklyquests = new List<uint>();
|
|
List<uint> m_monthlyquests = new List<uint>();
|
|
MultiMap<uint, uint> m_seasonalquests = new MultiMap<uint, uint>();
|
|
Dictionary<uint, QuestStatusData> m_QuestStatus = new Dictionary<uint, QuestStatusData>();
|
|
Dictionary<uint, QuestSaveType> m_QuestStatusSave = new Dictionary<uint, QuestSaveType>();
|
|
List<uint> m_DFQuests = new List<uint>();
|
|
List<uint> m_RewardedQuests = new List<uint>();
|
|
Dictionary<uint, QuestSaveType> m_RewardedQuestsSave = new Dictionary<uint, QuestSaveType>();
|
|
|
|
bool m_DailyQuestChanged;
|
|
bool m_WeeklyQuestChanged;
|
|
bool m_MonthlyQuestChanged;
|
|
bool m_SeasonalQuestChanged;
|
|
long m_lastDailyQuestTime;
|
|
|
|
Garrison _garrison;
|
|
|
|
CinematicManager _cinematicMgr;
|
|
|
|
// variables to save health and mana before duel and restore them after duel
|
|
ulong healthBeforeDuel;
|
|
uint manaBeforeDuel;
|
|
|
|
bool _advancedCombatLoggingEnabled;
|
|
|
|
WorldLocation _corpseLocation;
|
|
|
|
//Core
|
|
WorldSession Session;
|
|
uint m_nextSave;
|
|
byte m_cinematic;
|
|
|
|
uint m_movie;
|
|
|
|
SpecializationInfo _specializationInfo;
|
|
public List<ObjectGuid> m_clientGUIDs = new List<ObjectGuid>();
|
|
public WorldObject seerView;
|
|
// only changed for direct client control (possess, vehicle etc.), not stuff you control using pet commands
|
|
public Unit m_unitMovedByMe;
|
|
Team m_team;
|
|
public Stack<uint> m_timeSyncQueue = new Stack<uint>();
|
|
uint m_timeSyncTimer;
|
|
public uint m_timeSyncClient;
|
|
public uint m_timeSyncServer;
|
|
ReputationMgr reputationMgr;
|
|
QuestObjectiveCriteriaManager m_questObjectiveCriteriaMgr;
|
|
public AtLoginFlags atLoginFlags;
|
|
public bool m_itemUpdateQueueBlocked;
|
|
|
|
PlayerExtraFlags m_ExtraFlags;
|
|
|
|
public bool isDebugAreaTriggers { get; set; }
|
|
uint m_zoneUpdateId;
|
|
uint m_areaUpdateId;
|
|
uint m_zoneUpdateTimer;
|
|
|
|
uint m_ChampioningFaction;
|
|
byte m_grantableLevels;
|
|
byte m_fishingSteps;
|
|
|
|
// Recall position
|
|
WorldLocation m_recall_location;
|
|
WorldLocation homebind;
|
|
uint homebindAreaId;
|
|
uint m_HomebindTimer;
|
|
|
|
ResurrectionData _resurrectionData;
|
|
|
|
PlayerAchievementMgr m_achievementSys;
|
|
|
|
SceneMgr m_sceneMgr;
|
|
|
|
Dictionary<ObjectGuid /*LootObject*/, ObjectGuid /*WorldObject*/> m_AELootView = new Dictionary<ObjectGuid, ObjectGuid>();
|
|
|
|
CUFProfile[] _CUFProfiles = new CUFProfile[PlayerConst.MaxCUFProfiles];
|
|
float[] m_powerFraction = new float[(int)PowerType.MaxPerClass];
|
|
int[] m_MirrorTimer = new int[3];
|
|
|
|
ulong m_GuildIdInvited;
|
|
DeclinedName _declinedname;
|
|
Runes m_runes = new Runes();
|
|
uint m_drunkTimer;
|
|
long m_logintime;
|
|
long m_Last_tick;
|
|
uint m_PlayedTimeTotal;
|
|
uint m_PlayedTimeLevel;
|
|
|
|
Dictionary<byte, ActionButton> m_actionButtons = new Dictionary<byte, ActionButton>();
|
|
ObjectGuid m_divider;
|
|
uint m_ingametime;
|
|
|
|
PlayerCommandStates _activeCheats;
|
|
}
|
|
|
|
public class PlayerInfo
|
|
{
|
|
public uint MapId;
|
|
public uint ZoneId;
|
|
public float PositionX;
|
|
public float PositionY;
|
|
public float PositionZ;
|
|
public float Orientation;
|
|
|
|
public uint DisplayId_m;
|
|
public uint DisplayId_f;
|
|
|
|
public List<PlayerCreateInfoItem> item = new List<PlayerCreateInfoItem>();
|
|
public List<uint> customSpells = new List<uint>();
|
|
public List<uint> castSpells = new List<uint>();
|
|
public List<PlayerCreateInfoAction> action = new List<PlayerCreateInfoAction>();
|
|
public List<SkillRaceClassInfoRecord> skills = new List<SkillRaceClassInfoRecord>();
|
|
|
|
public PlayerLevelInfo[] levelInfo = new PlayerLevelInfo[WorldConfig.GetIntValue(WorldCfg.MaxPlayerLevel)];
|
|
}
|
|
|
|
public class PlayerCreateInfoItem
|
|
{
|
|
public PlayerCreateInfoItem(uint id, uint amount)
|
|
{
|
|
item_id = id;
|
|
item_amount = amount;
|
|
}
|
|
|
|
public uint item_id;
|
|
public uint item_amount;
|
|
}
|
|
|
|
public class PlayerCreateInfoAction
|
|
{
|
|
public PlayerCreateInfoAction() : this(0, 0, 0) { }
|
|
public PlayerCreateInfoAction(byte _button, uint _action, byte _type)
|
|
{
|
|
button = _button;
|
|
type = _type;
|
|
action = _action;
|
|
}
|
|
|
|
public byte button;
|
|
public byte type;
|
|
public uint action;
|
|
}
|
|
|
|
public class PlayerLevelInfo
|
|
{
|
|
public ushort[] stats = new ushort[(int)Stats.Max];
|
|
}
|
|
|
|
public class PlayerCurrency
|
|
{
|
|
public PlayerCurrencyState state;
|
|
public uint Quantity;
|
|
public uint WeeklyQuantity;
|
|
public uint TrackedQuantity;
|
|
public byte Flags;
|
|
}
|
|
|
|
struct PlayerDynamicFieldSpellModByLabel
|
|
{
|
|
public uint Mod { get; set; }
|
|
public float Value { get; set; }
|
|
public uint Label { get; set; }
|
|
}
|
|
|
|
public class SpecializationInfo
|
|
{
|
|
public SpecializationInfo()
|
|
{
|
|
for (byte i = 0; i < PlayerConst.MaxSpecializations; ++i)
|
|
{
|
|
Talents[i] = new Dictionary<uint, PlayerSpellState>();
|
|
Glyphs[i] = new List<uint>();
|
|
}
|
|
}
|
|
|
|
public Dictionary<uint, PlayerSpellState>[] Talents = new Dictionary<uint, PlayerSpellState>[PlayerConst.MaxSpecializations];
|
|
public List<uint>[] Glyphs = new List<uint>[PlayerConst.MaxSpecializations];
|
|
public uint ResetTalentsCost;
|
|
public long ResetTalentsTime;
|
|
public uint PrimarySpecialization;
|
|
public byte ActiveGroup;
|
|
}
|
|
|
|
public class Runes
|
|
{
|
|
public void SetRuneState(byte index, bool set = true)
|
|
{
|
|
var id = CooldownOrder.LookupByIndex(index);
|
|
if (set)
|
|
{
|
|
RuneState |= (byte)(1 << index); // usable
|
|
if (id == 0)
|
|
CooldownOrder.Add(index);
|
|
}
|
|
else
|
|
{
|
|
RuneState &= (byte)~(1 << index); // on cooldown
|
|
if (id != 0)
|
|
CooldownOrder.Remove(id);
|
|
}
|
|
}
|
|
|
|
public List<byte> CooldownOrder = new List<byte>();
|
|
public uint[] Cooldown = new uint[PlayerConst.MaxRunes];
|
|
public byte RuneState; // mask of available runes
|
|
}
|
|
|
|
public class ActionButton
|
|
{
|
|
public ActionButton()
|
|
{
|
|
packedData = 0;
|
|
uState = ActionButtonUpdateState.New;
|
|
}
|
|
|
|
public ActionButtonType GetButtonType() { return (ActionButtonType)((packedData & 0xFFFFFFFF00000000) >> 56); }
|
|
public uint GetAction() { return (uint)(packedData & 0x00000000FFFFFFFF); }
|
|
public void SetActionAndType(ulong action, ActionButtonType type)
|
|
{
|
|
ulong newData = action | ((ulong)type << 56);
|
|
if (newData != packedData || uState == ActionButtonUpdateState.Deleted)
|
|
{
|
|
packedData = newData;
|
|
if (uState != ActionButtonUpdateState.New)
|
|
uState = ActionButtonUpdateState.Changed;
|
|
}
|
|
}
|
|
|
|
public ulong packedData;
|
|
public ActionButtonUpdateState uState;
|
|
}
|
|
|
|
public class ResurrectionData
|
|
{
|
|
public ObjectGuid GUID;
|
|
public WorldLocation Location = new WorldLocation();
|
|
public uint Health;
|
|
public uint Mana;
|
|
public uint Aura;
|
|
}
|
|
|
|
public struct PvPInfo
|
|
{
|
|
public bool IsHostile;
|
|
public bool IsInHostileArea; //> Marks if player is in an area which forces PvP flag
|
|
public bool IsInNoPvPArea; //> Marks if player is in a sanctuary or friendly capital city
|
|
public bool IsInFFAPvPArea; //> Marks if player is in an FFAPvP area (such as Gurubashi Arena)
|
|
public long EndTimer; //> Time when player unflags himself for PvP (flag removed after 5 minutes)
|
|
}
|
|
|
|
public class DuelInfo
|
|
{
|
|
public Player initiator;
|
|
public Player opponent;
|
|
public long startTimer;
|
|
public long startTime;
|
|
public long outOfBound;
|
|
public bool isMounted;
|
|
public bool isCompleted;
|
|
|
|
public bool IsDueling() { return opponent != null; }
|
|
}
|
|
|
|
public class AccessRequirement
|
|
{
|
|
public byte levelMin;
|
|
public byte levelMax;
|
|
public uint item;
|
|
public uint item2;
|
|
public uint quest_A;
|
|
public uint quest_H;
|
|
public uint achievement;
|
|
public string questFailedText;
|
|
}
|
|
|
|
public class EnchantDuration
|
|
{
|
|
public EnchantDuration(Item _item = null, EnchantmentSlot _slot = EnchantmentSlot.Max, uint _leftduration = 0)
|
|
{
|
|
item = _item;
|
|
slot = _slot;
|
|
leftduration = _leftduration;
|
|
}
|
|
|
|
public Item item;
|
|
public EnchantmentSlot slot;
|
|
public uint leftduration;
|
|
}
|
|
|
|
public class VoidStorageItem
|
|
{
|
|
public VoidStorageItem(ulong id, uint entry, ObjectGuid creator, ItemRandomEnchantmentId randomPropertyId, uint suffixFactor, uint upgradeId, uint fixedScalingLevel, uint artifactKnowledgeLevel, byte context, ICollection<uint> bonuses)
|
|
{
|
|
ItemId = id;
|
|
ItemEntry = entry;
|
|
CreatorGuid = creator;
|
|
ItemRandomPropertyId = randomPropertyId;
|
|
ItemSuffixFactor = suffixFactor;
|
|
ItemUpgradeId = upgradeId;
|
|
FixedScalingLevel = fixedScalingLevel;
|
|
ArtifactKnowledgeLevel = artifactKnowledgeLevel;
|
|
Context = context;
|
|
|
|
foreach (var value in bonuses)
|
|
BonusListIDs.Add(value);
|
|
}
|
|
|
|
public ulong ItemId;
|
|
public uint ItemEntry;
|
|
public ObjectGuid CreatorGuid;
|
|
public ItemRandomEnchantmentId ItemRandomPropertyId;
|
|
public uint ItemSuffixFactor;
|
|
public uint ItemUpgradeId;
|
|
public uint FixedScalingLevel;
|
|
public uint ArtifactKnowledgeLevel;
|
|
public byte Context;
|
|
public List<uint> BonusListIDs = new List<uint>();
|
|
}
|
|
|
|
public class EquipmentSetInfo
|
|
{
|
|
public EquipmentSetInfo()
|
|
{
|
|
state = EquipmentSetUpdateState.New;
|
|
Data = new EquipmentSetData();
|
|
}
|
|
|
|
public EquipmentSetUpdateState state;
|
|
public EquipmentSetData Data;
|
|
|
|
// Data sent in EquipmentSet related packets
|
|
public class EquipmentSetData
|
|
{
|
|
public EquipmentSetType Type;
|
|
public ulong Guid; // Set Identifier
|
|
public uint SetID; // Index
|
|
public uint IgnoreMask ; // Mask of EquipmentSlot
|
|
public int AssignedSpecIndex = -1; // Index of character specialization that this set is automatically equipped for
|
|
public string SetName = "";
|
|
public string SetIcon = "";
|
|
public Array<ObjectGuid> Pieces = new Array<ObjectGuid>(EquipmentSlot.End);
|
|
public Array<int> Appearances = new Array<int>(EquipmentSlot.End); // ItemModifiedAppearanceID
|
|
public Array<int> Enchants = new Array<int>(2); // SpellItemEnchantmentID
|
|
}
|
|
|
|
public enum EquipmentSetType
|
|
{
|
|
Equipment = 0,
|
|
Transmog = 1
|
|
}
|
|
}
|
|
|
|
public class BgBattlegroundQueueID_Rec
|
|
{
|
|
public BattlegroundQueueTypeId bgQueueTypeId;
|
|
public uint invitedToInstance;
|
|
public uint joinTime;
|
|
}
|
|
|
|
// Holder for Battlegrounddata
|
|
public class BGData
|
|
{
|
|
public BGData()
|
|
{
|
|
bgTypeID = BattlegroundTypeId.None;
|
|
ClearTaxiPath();
|
|
joinPos = new WorldLocation();
|
|
}
|
|
|
|
public uint bgInstanceID; //< This variable is set to bg.m_InstanceID,
|
|
// when player is teleported to BG - (it is Battleground's GUID)
|
|
public BattlegroundTypeId bgTypeID;
|
|
|
|
public List<ObjectGuid> bgAfkReporter = new List<ObjectGuid>();
|
|
public byte bgAfkReportedCount;
|
|
public long bgAfkReportedTimer;
|
|
|
|
public uint bgTeam; //< What side the player will be added to
|
|
|
|
public uint mountSpell;
|
|
public uint[] taxiPath = new uint[2];
|
|
|
|
public WorldLocation joinPos; //< From where player entered BG
|
|
|
|
public void ClearTaxiPath() { taxiPath[0] = taxiPath[1] = 0; }
|
|
public bool HasTaxiPath() { return taxiPath[0] != 0 && taxiPath[1] != 0; }
|
|
}
|
|
|
|
public class CUFProfile
|
|
{
|
|
public CUFProfile()
|
|
{
|
|
BoolOptions = new BitArray((int)CUFBoolOptions.BoolOptionsCount);
|
|
}
|
|
|
|
public CUFProfile(string name, ushort frameHeight, ushort frameWidth, byte sortBy, byte healthText, uint boolOptions,
|
|
byte topPoint, byte bottomPoint, byte leftPoint, ushort topOffset, ushort bottomOffset, ushort leftOffset)
|
|
{
|
|
ProfileName = name;
|
|
BoolOptions = new BitArray(new int[] { (int)boolOptions });
|
|
|
|
FrameHeight = frameHeight;
|
|
FrameWidth = frameWidth;
|
|
SortBy = sortBy;
|
|
HealthText = healthText;
|
|
TopPoint = topPoint;
|
|
BottomPoint = bottomPoint;
|
|
LeftPoint = leftPoint;
|
|
TopOffset = topOffset;
|
|
BottomOffset = bottomOffset;
|
|
LeftOffset = leftOffset;
|
|
}
|
|
|
|
public void SetOption(CUFBoolOptions opt, byte arg)
|
|
{
|
|
BoolOptions.Set((int)opt, arg != 0);
|
|
}
|
|
public bool GetOption(CUFBoolOptions opt)
|
|
{
|
|
return BoolOptions.Get((int)opt);
|
|
}
|
|
public ulong GetUlongOptionValue()
|
|
{
|
|
int[] array = new int[1];
|
|
BoolOptions.CopyTo(array, 0);
|
|
return (ulong)array[0];
|
|
}
|
|
|
|
public string ProfileName;
|
|
public ushort FrameHeight;
|
|
public ushort FrameWidth;
|
|
public byte SortBy;
|
|
public byte HealthText;
|
|
|
|
// LeftAlign, TopAlight, BottomAlign
|
|
public byte TopPoint;
|
|
public byte BottomPoint;
|
|
public byte LeftPoint;
|
|
|
|
// LeftOffset, TopOffset and BottomOffset
|
|
public ushort TopOffset;
|
|
public ushort BottomOffset;
|
|
public ushort LeftOffset;
|
|
|
|
public BitArray BoolOptions;
|
|
|
|
// More fields can be added to BoolOptions without changing DB schema (up to 32, currently 27)
|
|
}
|
|
|
|
struct GroupUpdateCounter
|
|
{
|
|
public ObjectGuid GroupGuid;
|
|
public int UpdateSequenceNumber;
|
|
}
|
|
}
|