From 406aa5e4450b34b9a18fce7545650ffd5159331d Mon Sep 17 00:00:00 2001 From: Hondacrx Date: Sat, 16 Nov 2024 23:05:45 -0500 Subject: [PATCH] Fix login --- Source/Framework/Constants/Network/Opcodes.cs | 2 - Source/Framework/Database/DatabaseUpdater.cs | 4 +- .../Database/Databases/HotfixDatabase.cs | 3 +- Source/Framework/Realm/ClientBuildInfo.cs | 24 +++++++++- Source/Framework/Realm/RealmId.cs | 2 +- Source/Framework/Realm/RealmManager.cs | 3 +- .../Game/Collision/Management/VMapManager.cs | 12 ++--- Source/Game/Collision/Maps/MapTree.cs | 4 +- .../Game/DataStorage/ClientReader/DBReader.cs | 2 +- Source/Game/DataStorage/DB2Manager.cs | 11 +++-- .../Game/Entities/Object/Update/UpdateData.cs | 7 +-- .../Entities/Object/Update/UpdateFields.cs | 2 +- .../Object/Update/WowCSEntityDefinitions.cs | 18 +++---- Source/Game/Entities/Object/WorldObject.cs | 10 ++-- Source/Game/Entities/Unit/Unit.Movement.cs | 4 +- Source/Game/Entities/Unit/Unit.cs | 3 +- Source/Game/Globals/ObjectManager.cs | 20 ++++---- Source/Game/Handlers/CharacterHandler.cs | 13 ++--- .../Movement/Generators/WaypointMovement.cs | 6 +-- Source/Game/Movement/WaypointManager.cs | 4 +- Source/Game/Networking/Packet.cs | 47 +++++++++++++++++++ .../Networking/Packets/CharacterPackets.cs | 8 ++-- .../Game/Networking/Packets/UpdatePackets.cs | 3 -- Source/Game/Networking/WorldSocket.cs | 4 +- Source/Game/Server/WorldSession.cs | 5 +- Source/WorldServer/Server.cs | 6 +-- 26 files changed, 151 insertions(+), 76 deletions(-) diff --git a/Source/Framework/Constants/Network/Opcodes.cs b/Source/Framework/Constants/Network/Opcodes.cs index 89df67c43..05e8ec15d 100644 --- a/Source/Framework/Constants/Network/Opcodes.cs +++ b/Source/Framework/Constants/Network/Opcodes.cs @@ -883,7 +883,6 @@ namespace Framework.Constants WorldPortResponse = 0x350025, WrapItem = 0x320000, - Max = 0x5040, Unknown = 0xbadd } @@ -2100,7 +2099,6 @@ namespace Framework.Constants CompressedPacket = 0x3E000A, MultiplePackets = 0x3E0009, - Max = 0x5040, Unknown = 0xbadd, None = 0 } diff --git a/Source/Framework/Database/DatabaseUpdater.cs b/Source/Framework/Database/DatabaseUpdater.cs index 3855a4e42..c59c6af5b 100644 --- a/Source/Framework/Database/DatabaseUpdater.cs +++ b/Source/Framework/Database/DatabaseUpdater.cs @@ -37,10 +37,10 @@ namespace Framework.Database fileName = @"/sql/base/characters_database.sql"; break; case "WorldDatabase": - fileName = @"/sql/TDB_full_world_1027.24051_2024_05_11.sql"; + fileName = @"/sql/TDB_full_world_1102.24092_2024_09_23.sql"; break; case "HotfixDatabase": - fileName = @"/sql/TDB_full_hotfixes_1027.24051_2024_05_11.sql"; + fileName = @"/sql/TDB_full_hotfixes_1102.24092_2024_09_23.sql"; break; } diff --git a/Source/Framework/Database/Databases/HotfixDatabase.cs b/Source/Framework/Database/Databases/HotfixDatabase.cs index 534bfc6d7..664e854ac 100644 --- a/Source/Framework/Database/Databases/HotfixDatabase.cs +++ b/Source/Framework/Database/Databases/HotfixDatabase.cs @@ -46,6 +46,7 @@ namespace Framework.Database // AreaTable.db2 PrepareStatement(HotfixStatements.SEL_AREA_TABLE, "SELECT ID, ZoneName, AreaName, ContinentID, ParentAreaID, AreaBit, SoundProviderPref, " + + "SoundProviderPrefUnderwater, AmbienceID, UwAmbience, ZoneMusic, UwZoneMusic, IntroSound, UwIntroSound, FactionGroupMask, AmbientMultiplier, " + "SoundProviderPrefUnderwater, AmbienceID, UwAmbience, ZoneMusic, UwZoneMusic, IntroSound, UwIntroSound, FactionGroupMask, AmbientMultiplier, " + "MountFlags, PvpCombatWorldStateID, WildBattlePetLevelMin, WildBattlePetLevelMax, WindSettingsID, ContentTuningID, Flags1, Flags2, " + "LiquidTypeID1, LiquidTypeID2, LiquidTypeID3, LiquidTypeID4 FROM area_table WHERE (`VerifiedBuild` > 0) = ?"); @@ -782,7 +783,7 @@ namespace Framework.Database // ItemModifiedAppearance.db2 PrepareStatement(HotfixStatements.SEL_ITEM_MODIFIED_APPEARANCE, "SELECT ID, ItemID, ItemAppearanceModifierID, ItemAppearanceID, OrderIndex, " + - "TransmogSourceTypeEnum Flags, FROM item_modified_appearance WHERE (`VerifiedBuild` > 0) = ?"); + "TransmogSourceTypeEnum, Flags FROM item_modified_appearance WHERE (`VerifiedBuild` > 0) = ?"); // ItemModifiedAppearanceExtra.db2 PrepareStatement(HotfixStatements.SEL_ITEM_MODIFIED_APPEARANCE_EXTRA, "SELECT ID, IconFileDataID, UnequippedIconFileDataID, SheatheType, " + diff --git a/Source/Framework/Realm/ClientBuildInfo.cs b/Source/Framework/Realm/ClientBuildInfo.cs index 5bd35cf8c..c9febbde5 100644 --- a/Source/Framework/Realm/ClientBuildInfo.cs +++ b/Source/Framework/Realm/ClientBuildInfo.cs @@ -30,6 +30,8 @@ namespace Framework.ClientBuild build.HotfixVersion = hotfixVersion.ToCharArray(); build.Build = result.Read(4); + + _builds.Add(build); } while (result.NextRow()); } @@ -169,11 +171,31 @@ namespace Framework.ClientBuild } } - public class ClientBuildVariantId + public struct ClientBuildVariantId { public int Platform; public int Arch; public int Type; + + public override int GetHashCode() + { + return Platform.GetHashCode() ^ Arch.GetHashCode() ^ Type.GetHashCode(); + } + + public override bool Equals(object obj) + { + return this == (ClientBuildVariantId)obj; + } + + public static bool operator ==(ClientBuildVariantId left, ClientBuildVariantId right) + { + return left.Platform == right.Platform && left.Arch == right.Arch && left.Type == right.Type; + } + + public static bool operator !=(ClientBuildVariantId left, ClientBuildVariantId right) + { + return !(left == right); + } } public class ClientBuildAuthKey diff --git a/Source/Framework/Realm/RealmId.cs b/Source/Framework/Realm/RealmId.cs index 6b947834a..950f09d18 100644 --- a/Source/Framework/Realm/RealmId.cs +++ b/Source/Framework/Realm/RealmId.cs @@ -52,7 +52,7 @@ namespace Framework.Realm public override int GetHashCode() { - return new { Site, Region, Index }.GetHashCode(); + return new { Index }.GetHashCode(); } } } diff --git a/Source/Framework/Realm/RealmManager.cs b/Source/Framework/Realm/RealmManager.cs index 682a187f3..f86a38f94 100644 --- a/Source/Framework/Realm/RealmManager.cs +++ b/Source/Framework/Realm/RealmManager.cs @@ -83,6 +83,7 @@ public class RealmManager : Singleton } var realm = new Realm(); + realm.Name = name; realm.Addresses.Add(externalAddress); realm.Addresses.Add(localAddress); realm.Port = result.Read(4); @@ -127,7 +128,7 @@ public class RealmManager : Singleton if (_currentRealmId.HasValue) { - var realm = _realms.LookupByKey(_currentRealmId.Value); + var realm = _realms.LookupByKey(_currentRealmId); if (realm != null) _currentRealmId = realm.Id; // fill other fields of realm id } diff --git a/Source/Game/Collision/Management/VMapManager.cs b/Source/Game/Collision/Management/VMapManager.cs index 0536fcc17..b5de80874 100644 --- a/Source/Game/Collision/Management/VMapManager.cs +++ b/Source/Game/Collision/Management/VMapManager.cs @@ -191,8 +191,8 @@ namespace Game.Collision if (iLoadedModelFiles.TryGetValue(filename, out worldmodel)) return worldmodel.Model; - var model = new ManagedModel(filename); - if (!model.Model.ReadFile(VMapPath + filename)) + worldmodel = new ManagedModel(filename); + if (!worldmodel.Model.ReadFile(VMapPath + filename)) { Log.outError(LogFilter.Server, $"VMapManager: could not load '{filename}'"); return null; @@ -200,10 +200,8 @@ namespace Game.Collision Log.outDebug(LogFilter.Maps, $"VMapManager: loading file '{filename}'"); - model = worldmodel; - - iLoadedModelFiles.Add(filename, model); - return model.Model; + iLoadedModelFiles.Add(filename, worldmodel); + return worldmodel.Model; } } @@ -271,7 +269,7 @@ namespace Game.Collision public class ManagedModel { - public WorldModel Model; + public WorldModel Model = new(); string _name; // valid only while model is held in VMapManager2::iLoadedModelFiles public ManagedModel(string name) diff --git a/Source/Game/Collision/Maps/MapTree.cs b/Source/Game/Collision/Maps/MapTree.cs index 19f6f9a60..baf268dc5 100644 --- a/Source/Game/Collision/Maps/MapTree.cs +++ b/Source/Game/Collision/Maps/MapTree.cs @@ -90,7 +90,7 @@ namespace Game.Collision LoadResult result = LoadResult.FileNotFound; TileFileOpenResult fileResult = OpenMapTileFile(VMapManager.VMapPath, iMapID, tileX, tileY, vm); - if (fileResult.TileFile != null) + if (fileResult.TileFile != null && fileResult.SpawnIndicesFile != null) { result = LoadResult.Success; using BinaryReader reader = new(fileResult.TileFile); @@ -127,7 +127,7 @@ namespace Game.Collision continue; } - if (iTreeValues[referencedVal].GetWorldModel() == null) + if (iTreeValues[referencedVal]?.GetWorldModel() == null) iTreeValues[referencedVal] = new ModelInstance(spawn, model); iTreeValues[referencedVal].AddTileReference(); diff --git a/Source/Game/DataStorage/ClientReader/DBReader.cs b/Source/Game/DataStorage/ClientReader/DBReader.cs index 0f8a936fe..0c9994b9c 100644 --- a/Source/Game/DataStorage/ClientReader/DBReader.cs +++ b/Source/Game/DataStorage/ClientReader/DBReader.cs @@ -405,7 +405,7 @@ namespace Game.DataStorage if (fieldIndex >= _fieldMeta.Length) { if (_refId != -1) - f.SetValue(obj, (uint)_refId); + f.SetValue(obj, Convert.ChangeType(_refId, f.FieldType)); continue; } diff --git a/Source/Game/DataStorage/DB2Manager.cs b/Source/Game/DataStorage/DB2Manager.cs index 1148f841b..9c479cb70 100644 --- a/Source/Game/DataStorage/DB2Manager.cs +++ b/Source/Game/DataStorage/DB2Manager.cs @@ -443,7 +443,12 @@ namespace Game.DataStorage foreach (var (_, pathProperty) in CliDB.PathPropertyStorage) if (CliDB.PathStorage.HasRecord(pathProperty.PathID)) + { + if (!_paths.ContainsKey(pathProperty.PathID)) + _paths[pathProperty.PathID] = new(); + _paths[pathProperty.PathID].Properties.Add(pathProperty); + } foreach (var group in PhaseXPhaseGroupStorage.Values) { @@ -594,9 +599,9 @@ namespace Game.DataStorage } } - Dictionary, UiMapLinkRecord> uiMapLinks = new(); + Dictionary, UiMapLinkRecord> uiMapLinks = new(); foreach (UiMapLinkRecord uiMapLink in UiMapLinkStorage.Values) - uiMapLinks[Tuple.Create(uiMapLink.ParentUiMapID, uiMapLink.ChildUiMapID)] = uiMapLink; + uiMapLinks[Tuple.Create(uiMapLink.ParentUiMapID, (uint)uiMapLink.ChildUiMapID)] = uiMapLink; foreach (UiMapRecord uiMap in UiMapStorage.Values) { @@ -2361,7 +2366,7 @@ namespace Game.DataStorage Dictionary[]> _nameGenData = new(); List[] _nameValidators = new List[(int)Locale.Total + 1]; Dictionary _paragonReputations = new(); - Dictionary _paths; + Dictionary _paths = new(); MultiMap _phasesByGroup = new(); Dictionary _powerTypes = new(); Dictionary _pvpItemBonus = new(); diff --git a/Source/Game/Entities/Object/Update/UpdateData.cs b/Source/Game/Entities/Object/Update/UpdateData.cs index ce96d5c38..0e384c14d 100644 --- a/Source/Game/Entities/Object/Update/UpdateData.cs +++ b/Source/Game/Entities/Object/Update/UpdateData.cs @@ -46,10 +46,11 @@ namespace Game.Entities { packet = new UpdateObject(); - packet.NumObjUpdates = BlockCount; - packet.MapID = (ushort)MapId; - WorldPacket buffer = new(); + buffer.WriteUInt16((ushort)MapId); + buffer.WriteUInt32(BlockCount); + buffer.WriteBit(true); // unk + if (buffer.WriteBit(!outOfRangeGUIDs.Empty() || !destroyGUIDs.Empty())) { buffer.WriteUInt16((ushort)destroyGUIDs.Count); diff --git a/Source/Game/Entities/Object/Update/UpdateFields.cs b/Source/Game/Entities/Object/Update/UpdateFields.cs index 08d6cf989..321d6b827 100644 --- a/Source/Game/Entities/Object/Update/UpdateFields.cs +++ b/Source/Game/Entities/Object/Update/UpdateFields.cs @@ -4337,7 +4337,7 @@ namespace Game.Entities public class TraitSubTreeCache { - public List Entries; + public List Entries = new(); public int TraitSubTreeID; public uint Active; diff --git a/Source/Game/Entities/Object/Update/WowCSEntityDefinitions.cs b/Source/Game/Entities/Object/Update/WowCSEntityDefinitions.cs index c4d18a04d..c2bc91994 100644 --- a/Source/Game/Entities/Object/Update/WowCSEntityDefinitions.cs +++ b/Source/Game/Entities/Object/Update/WowCSEntityDefinitions.cs @@ -50,7 +50,6 @@ namespace Game.Entities public const byte CGObjectActiveMask = 0x1; public const byte CGObjectChangedMask = 0x2; public const byte CGObjectUpdateMask = CGObjectActiveMask | CGObjectChangedMask; - } public class EntityFragmentsHolder @@ -75,15 +74,16 @@ namespace Game.Entities (int, bool) insertSorted(ref EntityFragment[] arr, ref byte count, EntityFragment f) { - //auto where = std::ranges::lower_bound(arr.begin(), arr.begin() + count, f); - var where = Array.IndexOf(arr, f); - if (where != -1) - return (where, false); + var whereIndex = Array.IndexOf(arr, f); + if (whereIndex != -1) + return (whereIndex, false); - arr.SetValue(f, where); - arr = arr[^1..^0].Concat(arr[..^1]).ToArray(); + whereIndex = Array.IndexOf(arr, EntityFragment.End); + + arr.SetValue(f, whereIndex); + Array.Sort(arr); ++count; - return (where, true); + return (whereIndex, true); }; if (!insertSorted(ref Ids, ref Count, fragment).Item2) @@ -120,7 +120,7 @@ namespace Game.Entities if (where != -1) { arr.SetValue(EntityFragment.End, where); - arr = arr[^1..^0].Concat(arr[..^1]).ToArray(); + Array.Sort(arr); --count; return (where, true); } diff --git a/Source/Game/Entities/Object/WorldObject.cs b/Source/Game/Entities/Object/WorldObject.cs index 774ebc306..7efd0a89a 100644 --- a/Source/Game/Entities/Object/WorldObject.cs +++ b/Source/Game/Entities/Object/WorldObject.cs @@ -172,11 +172,13 @@ namespace Game.Entities UpdateFieldFlag fieldFlags = GetUpdateFieldFlagsFor(target); WorldPacket tempBuffer = new(); + tempBuffer.WriteUInt8((byte)fieldFlags); + BuildEntityFragments(tempBuffer, m_entityFragments.GetIds()); + tempBuffer.WriteUInt8(1); // IndirectFragmentActive: CGObject BuildValuesCreate(tempBuffer, fieldFlags, target); + + buffer.WriteUInt32(tempBuffer.GetSize()); - buffer.WriteUInt8((byte)fieldFlags); - BuildEntityFragments(buffer, m_entityFragments.GetIds()); - buffer.WriteUInt8(1); // IndirectFragmentActive: CGObject buffer.WriteBytes(tempBuffer); data.AddUpdateBlock(buffer); @@ -3879,7 +3881,7 @@ namespace Game.Entities public TypeMask ObjectTypeMask { get; set; } protected TypeId ObjectTypeId { get; set; } protected CreateObjectBits m_updateFlag; - public EntityFragmentsHolder m_entityFragments; + public EntityFragmentsHolder m_entityFragments = new(); ObjectGuid m_guid; bool _isNewObject; bool _isDestroyedObject; diff --git a/Source/Game/Entities/Unit/Unit.Movement.cs b/Source/Game/Entities/Unit/Unit.Movement.cs index 53a804ddc..f80d307fa 100644 --- a/Source/Game/Entities/Unit/Unit.Movement.cs +++ b/Source/Game/Entities/Unit/Unit.Movement.cs @@ -193,7 +193,7 @@ namespace Game.Entities AdvFlyingRateTypeSingle.SurfaceFriction => (ServerOpcodes.MoveSetAdvFlyingSurfaceFriction, flightCapabilityEntry.SurfaceFriction, AuraType.None), AdvFlyingRateTypeSingle.OverMaxDeceleration => (ServerOpcodes.MoveSetAdvFlyingOverMaxDeceleration, flightCapabilityEntry.OverMaxDeceleration, AuraType.ModAdvFlyingOverMaxDeceleration), AdvFlyingRateTypeSingle.LaunchSpeedCoefficient => (ServerOpcodes.MoveSetAdvFlyingLaunchSpeedCoefficient, flightCapabilityEntry.LaunchSpeedCoefficient, AuraType.None), - _ => (ServerOpcodes.Max, 0, AuraType.None) + _ => (ServerOpcodes.Unknown, 0, AuraType.None) }; if (rateAura != AuraType.None) @@ -239,7 +239,7 @@ namespace Game.Entities AdvFlyingRateTypeRange.PitchingRateDown => (ServerOpcodes.MoveSetAdvFlyingPitchingRateDown, flightCapabilityEntry.PitchingRateDownMin, flightCapabilityEntry.PitchingRateDownMax, AuraType.ModAdvFlyingPitchingRateDown), AdvFlyingRateTypeRange.PitchingRateUp => (ServerOpcodes.MoveSetAdvFlyingPitchingRateUp, flightCapabilityEntry.PitchingRateUpMin, flightCapabilityEntry.PitchingRateUpMax, AuraType.ModAdvFlyingPitchingRateUp), AdvFlyingRateTypeRange.TurnVelocityThreshold => (ServerOpcodes.MoveSetAdvFlyingTurnVelocityThreshold, flightCapabilityEntry.TurnVelocityThresholdMin, flightCapabilityEntry.TurnVelocityThresholdMax, AuraType.None), - _ => (ServerOpcodes.Max, 0, 0, AuraType.None) + _ => (ServerOpcodes.Unknown, 0, 0, AuraType.None) }; if (rateAura != AuraType.None) diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs index a5abffef0..2705e7778 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -24,6 +24,7 @@ namespace Game.Entities { public Unit(bool isWorldObject) : base(isWorldObject) { + m_unitData = new UnitData(); MoveSpline = new MoveSpline(); i_motionMaster = new MotionMaster(this); m_combatManager = new CombatManager(this); @@ -74,7 +75,7 @@ namespace Game.Entities m_serverSideVisibility.SetValue(ServerSideVisibilityType.Ghost, GhostVisibilityType.Alive); - m_unitData = new UnitData(); + } public override void Dispose() diff --git a/Source/Game/Globals/ObjectManager.cs b/Source/Game/Globals/ObjectManager.cs index 66ebd3850..8f5e9aadb 100644 --- a/Source/Game/Globals/ObjectManager.cs +++ b/Source/Game/Globals/ObjectManager.cs @@ -3675,12 +3675,12 @@ namespace Game Log.outError(LogFilter.Sql, $"Table `creature_template` lists creature (Entry: {cInfo.Entry}) with disallowed `unit_flags2` {disallowedUnitFlags2}, removing incorrect flag."); data.unit_flags2 = data.unit_flags2 & (uint)UnitFlags2.Allowed; } - } - if ((data.unit_flags2.Value & (uint)UnitFlags2.FeignDeath) != 0 && (!data.unit_flags.HasValue || (data.unit_flags.Value & (uint)(UnitFlags.ImmuneToPc | UnitFlags.ImmuneToNpc)) == 0)) - { - Log.outError(LogFilter.Sql, $"Table `creature` has creature (GUID: {guid} Entry: {data.Id}) has UNIT_FLAG2_FEIGN_DEATH set without IMMUNE_TO_PC | IMMUNE_TO_NPC, removing incorrect flag."); - data.unit_flags2 = data.unit_flags2 & ~(uint)UnitFlags2.FeignDeath; + if ((data.unit_flags2.Value & (uint)UnitFlags2.FeignDeath) != 0 && (!data.unit_flags.HasValue || (data.unit_flags.Value & (uint)(UnitFlags.ImmuneToPc | UnitFlags.ImmuneToNpc)) == 0)) + { + Log.outError(LogFilter.Sql, $"Table `creature` has creature (GUID: {guid} Entry: {data.Id}) has UNIT_FLAG2_FEIGN_DEATH set without IMMUNE_TO_PC | IMMUNE_TO_NPC, removing incorrect flag."); + data.unit_flags2 = data.unit_flags2 & ~(uint)UnitFlags2.FeignDeath; + } } if (data.unit_flags3.HasValue) @@ -3691,12 +3691,12 @@ namespace Game Log.outError(LogFilter.Sql, $"Table `creature_template` lists creature (Entry: {cInfo.Entry}) with disallowed `unit_flags3` {disallowedUnitFlags3}, removing incorrect flag."); data.unit_flags3 = data.unit_flags3 & (uint)UnitFlags3.Allowed; } - } - if ((data.unit_flags3.Value & (uint)UnitFlags3.FakeDead) != 0 && (data.unit_flags.Value & (uint)(UnitFlags.ImmuneToPc | UnitFlags.ImmuneToNpc)) == 0) - { - Log.outError(LogFilter.Sql, $"Table `creature` has creature (GUID: {guid} Entry: {data.Id}) has UNIT_FLAG3_FAKE_DEAD set without IMMUNE_TO_PC | IMMUNE_TO_NPC, removing incorrect flag."); - data.unit_flags3 = data.unit_flags3 & ~(uint)UnitFlags3.FakeDead; + if ((data.unit_flags3.Value & (uint)UnitFlags3.FakeDead) != 0 && (data.unit_flags.Value & (uint)(UnitFlags.ImmuneToPc | UnitFlags.ImmuneToNpc)) == 0) + { + Log.outError(LogFilter.Sql, $"Table `creature` has creature (GUID: {guid} Entry: {data.Id}) has UNIT_FLAG3_FAKE_DEAD set without IMMUNE_TO_PC | IMMUNE_TO_NPC, removing incorrect flag."); + data.unit_flags3 = data.unit_flags3 & ~(uint)UnitFlags3.FakeDead; + } } uint healthPct = Math.Clamp(data.curHealthPct, 1, 100); diff --git a/Source/Game/Handlers/CharacterHandler.cs b/Source/Game/Handlers/CharacterHandler.cs index 06941a386..211e7791f 100644 --- a/Source/Game/Handlers/CharacterHandler.cs +++ b/Source/Game/Handlers/CharacterHandler.cs @@ -70,7 +70,10 @@ namespace Game { do { - EnumCharactersResult.CharacterInfoBasic charInfo = new(result.GetFields()); + charResult.Characters.Add(new EnumCharactersResult.CharacterInfo(result.GetFields())); + + + EnumCharactersResult.CharacterInfoBasic charInfo = charResult.Characters.Last().Basic; var customizationsForChar = customizations.LookupByKey(charInfo.Guid.GetCounter()); if (!customizationsForChar.Empty()) @@ -105,8 +108,6 @@ namespace Game Global.CharacterCacheStorage.AddCharacterCacheEntry(charInfo.Guid, GetAccountId(), charInfo.Name, charInfo.SexId, charInfo.RaceId, (byte)charInfo.ClassId, charInfo.ExperienceLevel, false); charResult.MaxCharacterLevel = Math.Max(charResult.MaxCharacterLevel, charInfo.ExperienceLevel); - - charResult.Characters.Add(charInfo); } while (result.NextRow() && charResult.Characters.Count < 200); } @@ -149,14 +150,14 @@ namespace Game { do { - EnumCharactersResult.CharacterInfoBasic charInfo = new(result.GetFields()); + charEnum.Characters.Add(new EnumCharactersResult.CharacterInfo(result.GetFields())); + + EnumCharactersResult.CharacterInfoBasic charInfo = charEnum.Characters.Last().Basic; Log.outInfo(LogFilter.Network, "Loading undeleted char guid {0} from account {1}.", charInfo.Guid.ToString(), GetAccountId()); if (!Global.CharacterCacheStorage.HasCharacterCacheEntry(charInfo.Guid)) // This can happen if characters are inserted into the database manually. Core hasn't loaded name data yet. Global.CharacterCacheStorage.AddCharacterCacheEntry(charInfo.Guid, GetAccountId(), charInfo.Name, charInfo.SexId, charInfo.RaceId, (byte)charInfo.ClassId, charInfo.ExperienceLevel, true); - - charEnum.Characters.Add(charInfo); } while (result.NextRow()); } diff --git a/Source/Game/Movement/Generators/WaypointMovement.cs b/Source/Game/Movement/Generators/WaypointMovement.cs index 532d0816e..f84cac0e6 100644 --- a/Source/Game/Movement/Generators/WaypointMovement.cs +++ b/Source/Game/Movement/Generators/WaypointMovement.cs @@ -15,7 +15,7 @@ namespace Game.Movement public class WaypointMovementGenerator : MovementGeneratorMedium { uint _pathId; - WaypointPath _path; + WaypointPath _path = new(); int _currentNode; TimeTracker _duration; @@ -28,8 +28,8 @@ namespace Game.Movement bool _repeating; bool _generatePath; - TimeTracker _moveTimer; - TimeTracker _nextMoveTime; + TimeTracker _moveTimer = new(); + TimeTracker _nextMoveTime = new(); List _waypointTransitionSplinePoints = new(); int _waypointTransitionSplinePointsIndex; bool _isReturningToStart; diff --git a/Source/Game/Movement/WaypointManager.cs b/Source/Game/Movement/WaypointManager.cs index 32b805bb1..29204642c 100644 --- a/Source/Game/Movement/WaypointManager.cs +++ b/Source/Game/Movement/WaypointManager.cs @@ -27,8 +27,8 @@ namespace Game var oldMSTime = Time.GetMSTime(); - // 0 1 2 - SQLResult result = DB.World.Query("SELECT PathId, MoveType, Flags FROM waypoint_path"); + // 0 1 2 3 + SQLResult result = DB.World.Query("SELECT PathId, MoveType, Flags, Velocity FROM waypoint_path"); if (result.IsEmpty()) { Log.outInfo(LogFilter.ServerLoading, "Loaded 0 waypoint paths. DB table `waypoint_path` is empty!"); diff --git a/Source/Game/Networking/Packet.cs b/Source/Game/Networking/Packet.cs index b2b5ab14f..40d01dc85 100644 --- a/Source/Game/Networking/Packet.cs +++ b/Source/Game/Networking/Packet.cs @@ -82,6 +82,11 @@ namespace Game.Networking public ConnectionType GetConnection() { return connectionType; } + public bool IsValidOpcode() + { + return _worldPacket.IsValidOpcode(); + } + byte[] buffer; ConnectionType connectionType; protected WorldPacket _worldPacket; @@ -209,6 +214,48 @@ namespace Game.Networking public DateTime GetReceivedTime() { return m_receivedTime; } public void SetReceiveTime(DateTime receivedTime) { m_receivedTime = receivedTime; } + public bool IsValidOpcode() + { + int opcodeArrayIndex = GetOpcodeArrayIndex(opcode); + return opcodeArrayIndex >= 0 && opcodeArrayIndex < 1699; + } + + int GetOpcodeArrayIndex(uint opcode) + { + int idInGroup = (int)(opcode & 0xFFFF); + switch (opcode >> 16) + { + case 0x2A: return idInGroup < 26 ? idInGroup + 0 : -1; + case 0x2C: return idInGroup < 47 ? idInGroup + 26 : -1; + case 0x2D: return idInGroup < 3 ? idInGroup + 73 : -1; + case 0x2E: return idInGroup < 33 ? idInGroup + 76 : -1; + case 0x30: return idInGroup < 739 ? idInGroup + 109 : -1; + case 0x31: return idInGroup < 298 ? idInGroup + 848 : -1; + case 0x32: return idInGroup < 12 ? idInGroup + 1146 : -1; + case 0x33: return idInGroup < 130 ? idInGroup + 1158 : -1; + case 0x35: return idInGroup < 396 ? idInGroup + 1288 : -1; + case 0x36: return idInGroup < 15 ? idInGroup + 1684 : -1; + case 0x37: return idInGroup < 831 ? idInGroup + 0 : -1; + case 0x38: return idInGroup < 10 ? idInGroup + 831 : -1; + case 0x3B: return idInGroup < 18 ? idInGroup + 841 : -1; + case 0x3C: return idInGroup < 33 ? idInGroup + 859 : -1; + case 0x3D: return idInGroup < 49 ? idInGroup + 892 : -1; + case 0x3E: return idInGroup < 11 ? idInGroup + 941 : -1; + case 0x3F: return idInGroup < 12 ? idInGroup + 952 : -1; + case 0x41: return idInGroup < 82 ? idInGroup + 964 : -1; + case 0x43: return idInGroup < 67 ? idInGroup + 1046 : -1; + case 0x45: return idInGroup < 32 ? idInGroup + 1113 : -1; + case 0x47: return idInGroup < 1 ? idInGroup + 1145 : -1; + case 0x48: return idInGroup < 118 ? idInGroup + 1146 : -1; + case 0x4A: return idInGroup < 46 ? idInGroup + 1264 : -1; + case 0x4B: return idInGroup < 41 ? idInGroup + 1310 : -1; + case 0x4D: return idInGroup < 85 ? idInGroup + 1351 : -1; + case 0x4E: return idInGroup < 8 ? idInGroup + 1436 : -1; + case 0x50: return idInGroup < 1 ? idInGroup + 1444 : -1; + default: return -1; + } + } + uint opcode; DateTime m_receivedTime; // only set for a specific set of opcodes, for performance reasons. } diff --git a/Source/Game/Networking/Packets/CharacterPackets.cs b/Source/Game/Networking/Packets/CharacterPackets.cs index e89a096e5..7fe5166b2 100644 --- a/Source/Game/Networking/Packets/CharacterPackets.cs +++ b/Source/Game/Networking/Packets/CharacterPackets.cs @@ -55,7 +55,7 @@ namespace Game.Networking.Packets foreach (WarbandGroup warbandGroup in WarbandGroups) warbandGroup.Write(_worldPacket); - foreach (CharacterInfoBasic charInfo in Characters) + foreach (CharacterInfo charInfo in Characters) charInfo.Write(_worldPacket); foreach (RegionwideCharacterListEntry charInfo in RegionwideCharacters) @@ -77,7 +77,7 @@ namespace Game.Networking.Packets public int MaxCharacterLevel = 1; public uint? DisabledClassesMask = new(); - public List Characters = new(); // all characters on the list + public List Characters = new(); // all characters on the list public List RegionwideCharacters = new(); public List RaceUnlockData = new(); public List UnlockedConditionalAppearances = new(); @@ -260,7 +260,7 @@ namespace Game.Networking.Packets public uint PetCreatureFamilyId; public uint[] ProfessionIds = new uint[2]; // @todo public VisualItemInfo[] VisualItems = new VisualItemInfo[19]; - public CustomTabardInfo PersonalTabard; + public CustomTabardInfo PersonalTabard = new(); public struct VisualItemInfo { @@ -332,7 +332,7 @@ namespace Game.Networking.Packets public struct CharacterInfo { public CharacterInfoBasic Basic; - public CharacterRestrictionAndMailData RestrictionsAndMails; + public CharacterRestrictionAndMailData RestrictionsAndMails = new(); public CharacterInfo(SQLFields fields) { diff --git a/Source/Game/Networking/Packets/UpdatePackets.cs b/Source/Game/Networking/Packets/UpdatePackets.cs index 24569467c..d56540199 100644 --- a/Source/Game/Networking/Packets/UpdatePackets.cs +++ b/Source/Game/Networking/Packets/UpdatePackets.cs @@ -11,9 +11,6 @@ namespace Game.Networking.Packets public override void Write() { - _worldPacket.WriteUInt16(MapID); - _worldPacket.WriteUInt32(NumObjUpdates); - _worldPacket.WriteBit(true); // unk _worldPacket.WriteBytes(Data); } diff --git a/Source/Game/Networking/WorldSocket.cs b/Source/Game/Networking/WorldSocket.cs index 4085dd206..90c8fd69c 100644 --- a/Source/Game/Networking/WorldSocket.cs +++ b/Source/Game/Networking/WorldSocket.cs @@ -245,7 +245,7 @@ namespace Game.Networking WorldPacket packet = new(_packetBuffer.GetData()); _packetBuffer.Reset(); - if (packet.GetOpcode() >= (int)ClientOpcodes.Max) + if (!packet.IsValidOpcode()) { Log.outError(LogFilter.Network, $"WorldSocket.ReadData(): client {GetRemoteIpAddress()} sent wrong opcode (opcode: {packet.GetOpcode()})"); Log.outError(LogFilter.Network, $"Header: {_headerBuffer.GetData().ToHexString()} Data: {_packetBuffer.GetData().ToHexString()}"); @@ -361,7 +361,7 @@ namespace Game.Networking int packetSize = data.Length; if (packetSize > 0x400 && _worldCrypt.IsInitialized) { - buffer.WriteInt32(packetSize + 2); + buffer.WriteInt32(packetSize + 4); buffer.WriteUInt32(ZLib.adler32(ZLib.adler32(0x9827D8F1, BitConverter.GetBytes((uint)opcode), 4), data, (uint)packetSize)); byte[] compressedData; diff --git a/Source/Game/Server/WorldSession.cs b/Source/Game/Server/WorldSession.cs index 8659fdc52..a4c33d46c 100644 --- a/Source/Game/Server/WorldSession.cs +++ b/Source/Game/Server/WorldSession.cs @@ -385,9 +385,10 @@ namespace Game if (packet == null) return; - if (packet.GetOpcode() == ServerOpcodes.Unknown || packet.GetOpcode() == ServerOpcodes.Max) + if (!packet.IsValidOpcode()) { - Log.outError(LogFilter.Network, "Prevented sending of UnknownOpcode to {0}", GetPlayerInfo()); + string specialName = packet.GetOpcode() == ServerOpcodes.Unknown ? "UNKNOWN_OPCODE" : "INVALID_OPCODE"; + Log.outError(LogFilter.Network, $"Prevented sending of {specialName} (0x{packet.GetOpcode():04X}) to {GetPlayerInfo()}"); return; } diff --git a/Source/WorldServer/Server.cs b/Source/WorldServer/Server.cs index 8ee9388e1..44af85603 100644 --- a/Source/WorldServer/Server.cs +++ b/Source/WorldServer/Server.cs @@ -58,7 +58,7 @@ namespace WorldServer ExitNow(); // Set server offline (not connectable) - DB.Login.DirectExecute($"UPDATE realmlist SET flag = flag | {LegacyRealmFlags.Offline} WHERE id = '{realmId}'"); + DB.Login.DirectExecute($"UPDATE realmlist SET flag = flag | {(uint)LegacyRealmFlags.Offline} WHERE id = '{realmId}'"); if (!Global.WorldMgr.SetInitialWorldSettings()) ExitNow(); @@ -94,7 +94,7 @@ namespace WorldServer } // set server online (allow connecting now) - DB.Login.DirectExecute($"UPDATE realmlist SET flag = flag & ~{LegacyRealmFlags.Offline}, population = 0 WHERE id = '{realmId}'"); + DB.Login.DirectExecute($"UPDATE realmlist SET flag = flag & ~{(uint)LegacyRealmFlags.Offline}, population = 0 WHERE id = '{realmId}'"); GC.Collect(); GC.WaitForPendingFinalizers(); @@ -129,7 +129,7 @@ namespace WorldServer Global.ScriptMgr.Unload(); // set server offline - DB.Login.DirectExecute($"UPDATE realmlist SET flag = flag | {LegacyRealmFlags.Offline} WHERE id = '{realmId}'"); + DB.Login.DirectExecute($"UPDATE realmlist SET flag = flag | {(uint)LegacyRealmFlags.Offline} WHERE id = '{realmId}'"); Global.RealmMgr.Close(); ClearOnlineAccounts(realmId);