From 23e49e96c0aa146855849d32b477955bfcd935ad Mon Sep 17 00:00:00 2001 From: hondacrx Date: Mon, 23 Jan 2023 00:01:10 -0500 Subject: [PATCH] Core/Creatures: Split creature_addon and creature_template_addon's byte columns into seperate ones Port From (https://github.com/TrinityCore/TrinityCore/commit/4119f69b214d6199b7ab508e305b2958eeffb332) --- Source/Framework/Constants/UnitConst.cs | 9 +- Source/Game/Entities/Creature/Creature.cs | 74 +++++------- Source/Game/Entities/Creature/CreatureData.cs | 7 +- Source/Game/Globals/ObjectManager.cs | 114 ++++++++++++------ ...023_01_12_37_world_2023_01_09_00_world.sql | 34 ++++++ 5 files changed, 156 insertions(+), 82 deletions(-) create mode 100644 sql/updates/world/master/2023_01_12_37_world_2023_01_09_00_world.sql diff --git a/Source/Framework/Constants/UnitConst.cs b/Source/Framework/Constants/UnitConst.cs index 52ff54ad2..b0a9f3485 100644 --- a/Source/Framework/Constants/UnitConst.cs +++ b/Source/Framework/Constants/UnitConst.cs @@ -252,7 +252,9 @@ namespace Framework.Constants SitHighChair = 6, Dead = 7, Kneel = 8, - Submerged = 9 + Submerged = 9, + + Max } public enum UnitVisFlags @@ -271,7 +273,9 @@ namespace Framework.Constants Swim = 1, // falls back to ground tier animations, not handled by the client, should never appear in sniffs, will prevent tier change animations from playing correctly if used Hover = 2, // plays flying tier animations or falls back to ground tier animations, automatically enables hover clientside when entering visibility with this value Fly = 3, // plays flying tier animations - Submerged = 4 + Submerged = 4, + + Max } public enum UnitPVPStateFlags @@ -543,6 +547,7 @@ namespace Framework.Constants Unarmed = 0, // non prepared weapon Melee = 1, // prepared melee weapon Ranged = 2, // prepared ranged weapon + Max = 3 } public enum MeleeHitOutcome diff --git a/Source/Game/Entities/Creature/Creature.cs b/Source/Game/Entities/Creature/Creature.cs index 35a9b2335..f197382e5 100644 --- a/Source/Game/Entities/Creature/Creature.cs +++ b/Source/Game/Entities/Creature/Creature.cs @@ -2352,64 +2352,50 @@ namespace Game.Entities public bool LoadCreaturesAddon() { - CreatureAddon cainfo = GetCreatureAddon(); - if (cainfo == null) + CreatureAddon creatureAddon = GetCreatureAddon(); + if (creatureAddon == null) return false; - if (cainfo.mount != 0) - Mount(cainfo.mount); + if (creatureAddon.mount != 0) + Mount(creatureAddon.mount); - if (cainfo.bytes1 != 0) - { - // 0 StandState - // 1 FreeTalentPoints Pet only, so always 0 for default creature - // 2 StandFlags - // 3 StandMiscFlags + SetStandState((UnitStandStateType)creatureAddon.standState); + ReplaceAllVisFlags((UnitVisFlags)creatureAddon.visFlags); + SetAnimTier((AnimTier)creatureAddon.animTier, false); - SetStandState((UnitStandStateType)(cainfo.bytes1 & 0xFF)); - ReplaceAllVisFlags((UnitVisFlags)((cainfo.bytes1 >> 16) & 0xFF)); - SetAnimTier((AnimTier)((cainfo.bytes1 >> 24) & 0xFF), false); + //! Suspected correlation between UNIT_FIELD_BYTES_1, offset 3, value 0x2: + //! If no inhabittype_fly (if no MovementFlag_DisableGravity or MovementFlag_CanFly flag found in sniffs) + //! Check using InhabitType as movement flags are assigned dynamically + //! basing on whether the creature is in air or not + //! Set MovementFlag_Hover. Otherwise do nothing. + if (CanHover()) + AddUnitMovementFlag(MovementFlag.Hover); - //! Suspected correlation between UNIT_FIELD_BYTES_1, offset 3, value 0x2: - //! If no inhabittype_fly (if no MovementFlag_DisableGravity or MovementFlag_CanFly flag found in sniffs) - //! Check using InhabitType as movement flags are assigned dynamically - //! basing on whether the creature is in air or not - //! Set MovementFlag_Hover. Otherwise do nothing. - if (CanHover()) - AddUnitMovementFlag(MovementFlag.Hover); - } + SetSheath((SheathState)creatureAddon.sheathState); + ReplaceAllPvpFlags((UnitPVPStateFlags)creatureAddon.pvpFlags); - if (cainfo.bytes2 != 0) - { - // 0 SheathState - // 1 PvpFlags - // 2 PetFlags Pet only, so always 0 for default creature - // 3 ShapeshiftForm Must be determined/set by shapeshift spell/aura + // These fields must only be handled by core internals and must not be modified via scripts/DB dat + ReplaceAllPetFlags(UnitPetFlags.None); + SetShapeshiftForm(ShapeShiftForm.None); - SetSheath((SheathState)(cainfo.bytes2 & 0xFF)); - ReplaceAllPvpFlags((UnitPVPStateFlags)((cainfo.bytes2 >> 8) & 0xFF)); - ReplaceAllPetFlags(UnitPetFlags.None); - SetShapeshiftForm(ShapeShiftForm.None); - } + if (creatureAddon.emote != 0) + SetEmoteState((Emote)creatureAddon.emote); - if (cainfo.emote != 0) - SetEmoteState((Emote)cainfo.emote); - - SetAIAnimKitId(cainfo.aiAnimKit); - SetMovementAnimKitId(cainfo.movementAnimKit); - SetMeleeAnimKitId(cainfo.meleeAnimKit); + SetAIAnimKitId(creatureAddon.aiAnimKit); + SetMovementAnimKitId(creatureAddon.movementAnimKit); + SetMeleeAnimKitId(creatureAddon.meleeAnimKit); // Check if visibility distance different - if (cainfo.visibilityDistanceType != VisibilityDistanceType.Normal) - SetVisibilityDistanceOverride(cainfo.visibilityDistanceType); + if (creatureAddon.visibilityDistanceType != VisibilityDistanceType.Normal) + SetVisibilityDistanceOverride(creatureAddon.visibilityDistanceType); //Load Path - if (cainfo.path_id != 0) - _waypointPathId = cainfo.path_id; + if (creatureAddon.path_id != 0) + _waypointPathId = creatureAddon.path_id; - if (cainfo.auras != null) + if (creatureAddon.auras != null) { - foreach (var id in cainfo.auras) + foreach (var id in creatureAddon.auras) { SpellInfo AdditionalSpellInfo = Global.SpellMgr.GetSpellInfo(id, GetMap().GetDifficultyID()); if (AdditionalSpellInfo == null) diff --git a/Source/Game/Entities/Creature/CreatureData.cs b/Source/Game/Entities/Creature/CreatureData.cs index 768329d4f..cbb7ddd61 100644 --- a/Source/Game/Entities/Creature/CreatureData.cs +++ b/Source/Game/Entities/Creature/CreatureData.cs @@ -408,8 +408,11 @@ namespace Game.Entities { public uint path_id; public uint mount; - public uint bytes1; - public uint bytes2; + public byte standState; + public byte animTier; + public byte sheathState; + public byte pvpFlags; + public byte visFlags; public uint emote; public ushort aiAnimKit; public ushort movementAnimKit; diff --git a/Source/Game/Globals/ObjectManager.cs b/Source/Game/Globals/ObjectManager.cs index 9795bdd67..34e355738 100644 --- a/Source/Game/Globals/ObjectManager.cs +++ b/Source/Game/Globals/ObjectManager.cs @@ -2097,8 +2097,8 @@ namespace Game public void LoadCreatureTemplateAddons() { var time = Time.GetMSTime(); - // 0 1 2 3 4 5 6 7 8 9 10 - SQLResult result = DB.World.Query("SELECT entry, path_id, mount, bytes1, bytes2, emote, aiAnimKit, movementAnimKit, meleeAnimKit, visibilityDistanceType, auras FROM creature_template_addon"); + // 0 1 2 3 4 5 6 7 8 9 10 11 12 + SQLResult result = DB.World.Query("SELECT entry, path_id, mount, StandState, AnimTier, VisFlags, SheathState, PvPFlags, emote, aiAnimKit, movementAnimKit, meleeAnimKit, visibilityDistanceType, auras FROM creature_template_addon"); if (result.IsEmpty()) { @@ -2112,20 +2112,23 @@ namespace Game uint entry = result.Read(0); if (GetCreatureTemplate(entry) == null) { - Log.outError(LogFilter.Sql, "Creature template (Entry: {0}) does not exist but has a record in `creature_template_addon`", entry); + Log.outError(LogFilter.Sql, $"Creature template (Entry: {entry}) does not exist but has a record in `creature_template_addon`"); continue; } CreatureAddon creatureAddon = new(); creatureAddon.path_id = result.Read(1); creatureAddon.mount = result.Read(2); - creatureAddon.bytes1 = result.Read(3); - creatureAddon.bytes2 = result.Read(4); - creatureAddon.emote = result.Read(5); - creatureAddon.aiAnimKit = result.Read(6); - creatureAddon.movementAnimKit = result.Read(7); - creatureAddon.meleeAnimKit = result.Read(8); - creatureAddon.visibilityDistanceType = (VisibilityDistanceType)result.Read(9); + creatureAddon.standState = result.Read(3); + creatureAddon.animTier = result.Read(4); + creatureAddon.visFlags = result.Read(5); + creatureAddon.sheathState = result.Read(6); + creatureAddon.pvpFlags = result.Read(7); + creatureAddon.emote = result.Read(8); + creatureAddon.aiAnimKit = result.Read(9); + creatureAddon.movementAnimKit = result.Read(10); + creatureAddon.meleeAnimKit = result.Read(11); + creatureAddon.visibilityDistanceType = (VisibilityDistanceType)result.Read(12); var tokens = new StringArray(result.Read(10), ' '); for (var c = 0; c < tokens.Length; ++c) @@ -2137,16 +2140,16 @@ namespace Game SpellInfo AdditionalSpellInfo = Global.SpellMgr.GetSpellInfo(spellId, Difficulty.None); if (AdditionalSpellInfo == null) { - Log.outError(LogFilter.Sql, "Creature (Entry: {0}) has wrong spell {1} defined in `auras` field in `creature_template_addon`.", entry, spellId); + Log.outError(LogFilter.Sql, $"Creature (Entry: {entry}) has wrong spell {spellId} defined in `auras` field in `creature_template_addon`."); continue; } if (AdditionalSpellInfo.HasAura(AuraType.ControlVehicle)) - Log.outError(LogFilter.Sql, "Creature (Entry: {0}) has SPELL_AURA_CONTROL_VEHICLE aura {1} defined in `auras` field in `creature_template_addon`.", entry, spellId); + Log.outError(LogFilter.Sql, $"Creature (Entry: {entry}) has SPELL_AURA_CONTROL_VEHICLE aura {spellId} defined in `auras` field in `creature_template_addon`."); if (creatureAddon.auras.Contains(spellId)) { - Log.outError(LogFilter.Sql, "Creature (Entry: {0}) has duplicate aura (spell {1}) in `auras` field in `creature_template_addon`.", entry, spellId); + Log.outError(LogFilter.Sql, $"Creature (Entry: {entry}) has duplicate aura (spell {spellId}) in `auras` field in `creature_template_addon`."); continue; } @@ -2163,32 +2166,52 @@ namespace Game { if (CliDB.CreatureDisplayInfoStorage.LookupByKey(creatureAddon.mount) == null) { - Log.outError(LogFilter.Sql, "Creature (Entry: {0}) has invalid displayInfoId ({1}) for mount defined in `creature_template_addon`", entry, creatureAddon.mount); + Log.outError(LogFilter.Sql, $"Creature (Entry: {entry}) has invalid displayInfoId ({creatureAddon.mount}) for mount defined in `creature_template_addon`"); creatureAddon.mount = 0; } } + if (creatureAddon.standState >= (int)UnitStandStateType.Max) + { + Log.outError(LogFilter.Sql, $"Creature (Entry: {entry}) has invalid unit stand state ({creatureAddon.standState}) defined in `creature_addon`. Truncated to 0."); + creatureAddon.standState = 0; + } + + if (creatureAddon.animTier >= (int)AnimTier.Max) + { + Log.outError(LogFilter.Sql, $"Creature (Entry: {entry}) has invalid animation tier ({creatureAddon.animTier}) defined in `creature_addon`. Truncated to 0."); + creatureAddon.animTier = 0; + } + + if (creatureAddon.sheathState >= (int)SheathState.Max) + { + Log.outError(LogFilter.Sql, $"Creature (Entry: {entry}) has invalid sheath state ({creatureAddon.sheathState}) defined in `creature_addon`. Truncated to 0."); + creatureAddon.sheathState = 0; + } + + // PvPFlags don't need any checking for the time being since they cover the entire range of a byte + if (!CliDB.EmotesStorage.ContainsKey(creatureAddon.emote)) { - Log.outError(LogFilter.Sql, "Creature (Entry: {0}) has invalid emote ({1}) defined in `creatureaddon`.", entry, creatureAddon.emote); + Log.outError(LogFilter.Sql, $"Creature (Entry: {entry}) has invalid emote ({creatureAddon.emote}) defined in `creatureaddon`."); creatureAddon.emote = 0; } if (creatureAddon.aiAnimKit != 0 && !CliDB.AnimKitStorage.ContainsKey(creatureAddon.aiAnimKit)) { - Log.outError(LogFilter.Sql, "Creature (Entry: {0}) has invalid aiAnimKit ({1}) defined in `creature_template_addon`.", entry, creatureAddon.aiAnimKit); + Log.outError(LogFilter.Sql, $"Creature (Entry: {entry}) has invalid aiAnimKit ({creatureAddon.aiAnimKit}) defined in `creature_template_addon`."); creatureAddon.aiAnimKit = 0; } if (creatureAddon.movementAnimKit != 0 && !CliDB.AnimKitStorage.ContainsKey(creatureAddon.movementAnimKit)) { - Log.outError(LogFilter.Sql, "Creature (Entry: {0}) has invalid movementAnimKit ({1}) defined in `creature_template_addon`.", entry, creatureAddon.movementAnimKit); + Log.outError(LogFilter.Sql, $"Creature (Entry: {entry}) has invalid movementAnimKit ({creatureAddon.movementAnimKit}) defined in `creature_template_addon`."); creatureAddon.movementAnimKit = 0; } if (creatureAddon.meleeAnimKit != 0 && !CliDB.AnimKitStorage.ContainsKey(creatureAddon.meleeAnimKit)) { - Log.outError(LogFilter.Sql, "Creature (Entry: {0}) has invalid meleeAnimKit ({1}) defined in `creature_template_addon`.", entry, creatureAddon.meleeAnimKit); + Log.outError(LogFilter.Sql, $"Creature (Entry: {entry}) has invalid meleeAnimKit ({creatureAddon.meleeAnimKit}) defined in `creature_template_addon`."); creatureAddon.meleeAnimKit = 0; } @@ -2202,13 +2225,13 @@ namespace Game count++; } while (result.NextRow()); - Log.outInfo(LogFilter.ServerLoading, "Loaded {0} creature template addons in {1} ms", count, Time.GetMSTimeDiffToNow(time)); + Log.outInfo(LogFilter.ServerLoading, $"Loaded {count} creature template addons in {Time.GetMSTimeDiffToNow(time)} ms"); } public void LoadCreatureAddons() { var time = Time.GetMSTime(); - // 0 1 2 3 4 5 6 7 8 9 10 - SQLResult result = DB.World.Query("SELECT guid, path_id, mount, bytes1, bytes2, emote, aiAnimKit, movementAnimKit, meleeAnimKit, visibilityDistanceType, auras FROM creature_addon"); + // 0 1 2 3 4 5 6 7 8 9 10 11 12 + SQLResult result = DB.World.Query("SELECT guid, path_id, mount, StandState, AnimTier, VisFlags, SheathState, PvPFlags, emote, aiAnimKit, movementAnimKit, meleeAnimKit, visibilityDistanceType, auras FROM creature_addon"); if (result.IsEmpty()) { @@ -2223,7 +2246,7 @@ namespace Game CreatureData creData = GetCreatureData(guid); if (creData == null) { - Log.outError(LogFilter.Sql, "Creature (GUID: {0}) does not exist but has a record in `creatureaddon`", guid); + Log.outError(LogFilter.Sql, $"Creature (GUID: {guid}) does not exist but has a record in `creatureaddon`"); continue; } @@ -2233,12 +2256,15 @@ namespace Game if (creData.movementType == (byte)MovementGeneratorType.Waypoint && creatureAddon.path_id == 0) { creData.movementType = (byte)MovementGeneratorType.Idle; - Log.outError(LogFilter.Sql, "Creature (GUID {0}) has movement type set to WAYPOINTMOTIONTYPE but no path assigned", guid); + Log.outError(LogFilter.Sql, $"Creature (GUID {guid}) has movement type set to WAYPOINTMOTIONTYPE but no path assigned"); } creatureAddon.mount = result.Read(2); - creatureAddon.bytes1 = result.Read(3); - creatureAddon.bytes2 = result.Read(4); + creatureAddon.standState = result.Read(3); + creatureAddon.animTier = result.Read(4); + creatureAddon.visFlags = result.Read(5); + creatureAddon.sheathState = result.Read(6); + creatureAddon.pvpFlags = result.Read(7); creatureAddon.emote = result.Read(5); creatureAddon.aiAnimKit = result.Read(6); creatureAddon.movementAnimKit = result.Read(7); @@ -2255,16 +2281,16 @@ namespace Game SpellInfo AdditionalSpellInfo = Global.SpellMgr.GetSpellInfo(spellId, Difficulty.None); if (AdditionalSpellInfo == null) { - Log.outError(LogFilter.Sql, "Creature (GUID: {0}) has wrong spell {1} defined in `auras` field in `creatureaddon`.", guid, spellId); + Log.outError(LogFilter.Sql, $"Creature (GUID: {guid}) has wrong spell {spellId} defined in `auras` field in `creatureaddon`."); continue; } if (AdditionalSpellInfo.HasAura(AuraType.ControlVehicle)) - Log.outError(LogFilter.Sql, "Creature (GUID: {0}) has SPELL_AURA_CONTROL_VEHICLE aura {1} defined in `auras` field in `creature_addon`.", guid, spellId); + Log.outError(LogFilter.Sql, $"Creature (GUID: {guid}) has SPELL_AURA_CONTROL_VEHICLE aura {spellId} defined in `auras` field in `creature_addon`."); if (creatureAddon.auras.Contains(spellId)) { - Log.outError(LogFilter.Sql, "Creature (GUID: {0}) has duplicate aura (spell {1}) in `auras` field in `creature_addon`.", guid, spellId); + Log.outError(LogFilter.Sql, $"Creature (GUID: {guid}) has duplicate aura (spell {spellId}) in `auras` field in `creature_addon`."); continue; } @@ -2281,33 +2307,53 @@ namespace Game { if (!CliDB.CreatureDisplayInfoStorage.ContainsKey(creatureAddon.mount)) { - Log.outError(LogFilter.Sql, "Creature (GUID: {0}) has invalid displayInfoId ({1}) for mount defined in `creatureaddon`", guid, creatureAddon.mount); + Log.outError(LogFilter.Sql, $"Creature (GUID: {guid}) has invalid displayInfoId ({creatureAddon.mount}) for mount defined in `creatureaddon`"); creatureAddon.mount = 0; } } + if (creatureAddon.standState >= (int)UnitStandStateType.Max) + { + Log.outError(LogFilter.Sql, $"Creature (GUID: {guid}) has invalid unit stand state ({creatureAddon.standState}) defined in `creature_addon`. Truncated to 0."); + creatureAddon.standState = 0; + } + + if (creatureAddon.animTier >= (int)AnimTier.Max) + { + Log.outError(LogFilter.Sql, $"Creature (GUID: {guid}) has invalid animation tier ({creatureAddon.animTier}) defined in `creature_addon`. Truncated to 0."); + creatureAddon.animTier = 0; + } + + if (creatureAddon.sheathState >= (int)SheathState.Max) + { + Log.outError(LogFilter.Sql, $"Creature (GUID: {guid}) has invalid sheath state ({creatureAddon.sheathState}) defined in `creature_addon`. Truncated to 0."); + creatureAddon.sheathState = 0; + } + + // PvPFlags don't need any checking for the time being since they cover the entire range of a byte + if (!CliDB.EmotesStorage.ContainsKey(creatureAddon.emote)) { - Log.outError(LogFilter.Sql, "Creature (GUID: {0}) has invalid emote ({1}) defined in `creatureaddon`.", guid, creatureAddon.emote); + Log.outError(LogFilter.Sql, $"Creature (GUID: {guid}) has invalid emote ({creatureAddon.emote}) defined in `creatureaddon`."); creatureAddon.emote = 0; } if (creatureAddon.aiAnimKit != 0 && !CliDB.AnimKitStorage.ContainsKey(creatureAddon.aiAnimKit)) { - Log.outError(LogFilter.Sql, "Creature (Guid: {0}) has invalid aiAnimKit ({1}) defined in `creature_addon`.", guid, creatureAddon.aiAnimKit); + Log.outError(LogFilter.Sql, $"Creature (Guid: {guid}) has invalid aiAnimKit ({creatureAddon.aiAnimKit}) defined in `creature_addon`."); creatureAddon.aiAnimKit = 0; } if (creatureAddon.movementAnimKit != 0 && !CliDB.AnimKitStorage.ContainsKey(creatureAddon.movementAnimKit)) { - Log.outError(LogFilter.Sql, "Creature (Guid: {0}) has invalid movementAnimKit ({1}) defined in `creature_addon`.", guid, creatureAddon.movementAnimKit); + Log.outError(LogFilter.Sql, $"Creature (Guid: {guid}) has invalid movementAnimKit ({creatureAddon.movementAnimKit}) defined in `creature_addon`."); creatureAddon.movementAnimKit = 0; } if (creatureAddon.meleeAnimKit != 0 && !CliDB.AnimKitStorage.ContainsKey(creatureAddon.meleeAnimKit)) { - Log.outError(LogFilter.Sql, "Creature (Guid: {0}) has invalid meleeAnimKit ({1}) defined in `creature_addon`.", guid, creatureAddon.meleeAnimKit); + Log.outError(LogFilter.Sql, $"Creature (Guid: {guid}) has invalid meleeAnimKit ({creatureAddon.meleeAnimKit}) defined in `creature_addon`."); creatureAddon.meleeAnimKit = 0; } @@ -2321,7 +2367,7 @@ namespace Game count++; } while (result.NextRow()); - Log.outInfo(LogFilter.ServerLoading, "Loaded {0} creature addons in {1} ms", count, Time.GetMSTimeDiffToNow(time)); + Log.outInfo(LogFilter.ServerLoading, $"Loaded {count} creature addons in {Time.GetMSTimeDiffToNow(time)} ms"); } public void LoadCreatureQuestItems() { diff --git a/sql/updates/world/master/2023_01_12_37_world_2023_01_09_00_world.sql b/sql/updates/world/master/2023_01_12_37_world_2023_01_09_00_world.sql new file mode 100644 index 000000000..c58503cbc --- /dev/null +++ b/sql/updates/world/master/2023_01_12_37_world_2023_01_09_00_world.sql @@ -0,0 +1,34 @@ +ALTER TABLE `creature_template_addon` + ADD COLUMN `StandState` TINYINT UNSIGNED DEFAULT 0 NOT NULL AFTER `MountCreatureID`, + ADD COLUMN `AnimTier` TINYINT UNSIGNED DEFAULT 0 NOT NULL AFTER `StandState`, + ADD COLUMN `VisFlags` TINYINT UNSIGNED DEFAULT 0 NOT NULL AFTER `AnimTier`, + ADD COLUMN `SheathState` TINYINT UNSIGNED DEFAULT 1 NOT NULL AFTER `VisFlags`, + ADD COLUMN `PvPFlags` TINYINT UNSIGNED DEFAULT 0 NOT NULL AFTER `SheathState`; + +UPDATE `creature_template_addon` SET `StandState`=`bytes1` & 0xFF; +UPDATE `creature_template_addon` SET `AnimTier`=(`bytes1` >> 24) & 0xFF; +UPDATE `creature_template_addon` SET `VisFlags`=(`bytes1` >> 16) & 0xFF; +UPDATE `creature_template_addon` SET `SheathState`=`bytes2` & 0xFF; +UPDATE `creature_template_addon` SET `PvPFlags`=(`bytes2` >> 8) & 0xFF; + +ALTER TABLE `creature_addon` + ADD COLUMN `StandState` TINYINT UNSIGNED DEFAULT 0 NOT NULL AFTER `MountCreatureID`, + ADD COLUMN `AnimTier` TINYINT UNSIGNED DEFAULT 0 NOT NULL AFTER `StandState`, + ADD COLUMN `VisFlags` TINYINT UNSIGNED DEFAULT 0 NOT NULL AFTER `AnimTier`, + ADD COLUMN `SheathState` TINYINT UNSIGNED DEFAULT 1 NOT NULL AFTER `VisFlags`, + ADD COLUMN `PvPFlags` TINYINT UNSIGNED DEFAULT 0 NOT NULL AFTER `SheathState`; + +UPDATE `creature_addon` SET `StandState`=`bytes1` & 0xFF; +UPDATE `creature_addon` SET `AnimTier`=(`bytes1` >> 24) & 0xFF; +UPDATE `creature_addon` SET `VisFlags`=(`bytes1` >> 16) & 0xFF; +UPDATE `creature_addon` SET `SheathState`=`bytes2` & 0xFF; +UPDATE `creature_addon` SET `PvPFlags`=(`bytes2` >> 8) & 0xFF; + +-- Conversion done, drop old columns +ALTER TABLE `creature_template_addon` + DROP COLUMN `bytes1`, + DROP COLUMN `bytes2`; + +ALTER TABLE `creature_addon` + DROP COLUMN `bytes1`, + DROP COLUMN `bytes2`;