Fix login
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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, " +
|
||||
|
||||
@@ -30,6 +30,8 @@ namespace Framework.ClientBuild
|
||||
build.HotfixVersion = hotfixVersion.ToCharArray();
|
||||
|
||||
build.Build = result.Read<uint>(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
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace Framework.Realm
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return new { Site, Region, Index }.GetHashCode();
|
||||
return new { Index }.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ public class RealmManager : Singleton<RealmManager>
|
||||
}
|
||||
|
||||
var realm = new Realm();
|
||||
realm.Name = name;
|
||||
realm.Addresses.Add(externalAddress);
|
||||
realm.Addresses.Add(localAddress);
|
||||
realm.Port = result.Read<ushort>(4);
|
||||
@@ -127,7 +128,7 @@ public class RealmManager : Singleton<RealmManager>
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Tuple<uint, int>, UiMapLinkRecord> uiMapLinks = new();
|
||||
Dictionary<Tuple<uint, uint>, 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<uint, List<NameGenRecord>[]> _nameGenData = new();
|
||||
List<string>[] _nameValidators = new List<string>[(int)Locale.Total + 1];
|
||||
Dictionary<uint, ParagonReputationRecord> _paragonReputations = new();
|
||||
Dictionary<uint, PathDb2> _paths;
|
||||
Dictionary<uint, PathDb2> _paths = new();
|
||||
MultiMap<uint, uint> _phasesByGroup = new();
|
||||
Dictionary<PowerType, PowerTypeRecord> _powerTypes = new();
|
||||
Dictionary<uint, byte> _pvpItemBonus = new();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -4337,7 +4337,7 @@ namespace Game.Entities
|
||||
|
||||
public class TraitSubTreeCache
|
||||
{
|
||||
public List<TraitEntry> Entries;
|
||||
public List<TraitEntry> Entries = new();
|
||||
public int TraitSubTreeID;
|
||||
public uint Active;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -3675,13 +3675,13 @@ 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_flags3.HasValue)
|
||||
{
|
||||
@@ -3691,13 +3691,13 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
uint healthPct = Math.Clamp(data.curHealthPct, 1, 100);
|
||||
if (data.curHealthPct != healthPct)
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Game.Movement
|
||||
public class WaypointMovementGenerator : MovementGeneratorMedium<Creature>
|
||||
{
|
||||
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<int> _waypointTransitionSplinePoints = new();
|
||||
int _waypointTransitionSplinePointsIndex;
|
||||
bool _isReturningToStart;
|
||||
|
||||
@@ -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!");
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
@@ -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<CharacterInfoBasic> Characters = new(); // all characters on the list
|
||||
public List<CharacterInfo> Characters = new(); // all characters on the list
|
||||
public List<RegionwideCharacterListEntry> RegionwideCharacters = new();
|
||||
public List<RaceUnlock> RaceUnlockData = new();
|
||||
public List<UnlockedConditionalAppearance> 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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user