Port to WoW client 12.0.7 (build 68453)
Adapt CypherCore from 11.2.5.63796 to 12.0.7.68453 using TrinityCore as byte-exact reference. - Fase 1: build gate 68453 (build_info + build_auth_key SQL, keys from TC) - Fase 2: Opcodes.cs remapped by name to 12.0.7 values - Fase 3: 32 DB2 structs + HotfixDatabase.cs SELECTs realigned; fixed ReputationManager/SpellInfo refs - Fase 4: UpdateFields ported (GameObject/Conversation/AreaTrigger/Player/ Unit/ActivePlayer + nested VisibleItem/QuestLog/BitVectors/CraftingOrderItem/ SkillInfo) - Critical protocol fixes: CreateObject header +3 bits (Room/Decor/MeshObject); EntityFragment enum renumbered to 12.0.7 (was 11.2.5 values, breaking every object packet) - New-entity foundation: TypeId/TypeMask/HighGuid.MeshObject, fragment tags - MeshObject entity scaffold (Midnight features are wire-format only) Builds clean (dotnet build -c Release, 0 errors). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
|
||||
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Maps;
|
||||
using Game.Networking;
|
||||
using Game.Networking.Packets;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.Entities
|
||||
{
|
||||
public class MeshObject : WorldObject
|
||||
{
|
||||
MeshObjectData m_meshObjectData;
|
||||
|
||||
Position _stationaryPosition = new();
|
||||
|
||||
public MeshObject(bool isWorldObject = false) : base(isWorldObject)
|
||||
{
|
||||
ObjectTypeMask |= TypeMask.MeshObject;
|
||||
ObjectTypeId = TypeId.MeshObject;
|
||||
|
||||
m_updateFlag.Stationary = true;
|
||||
m_updateFlag.MeshObject = true;
|
||||
|
||||
m_entityFragments.Add(EntityFragment.Tag_MeshObject, false);
|
||||
|
||||
m_meshObjectData = new();
|
||||
_stationaryPosition = new();
|
||||
}
|
||||
|
||||
public override void AddToWorld()
|
||||
{
|
||||
if (!IsInWorld)
|
||||
{
|
||||
GetMap().GetObjectsStore().Add(GetGUID(), this);
|
||||
base.AddToWorld();
|
||||
}
|
||||
}
|
||||
|
||||
public override void RemoveFromWorld()
|
||||
{
|
||||
if (IsInWorld)
|
||||
{
|
||||
base.RemoveFromWorld();
|
||||
GetMap().GetObjectsStore().Remove(GetGUID());
|
||||
}
|
||||
}
|
||||
|
||||
public static MeshObject CreateMeshObject(Map map, Position pos, ObjectGuid privateObjectOwner)
|
||||
{
|
||||
if (map == null)
|
||||
return null;
|
||||
|
||||
ulong lowGuid = map.GenerateLowGuid(HighGuid.MeshObject);
|
||||
|
||||
MeshObject meshObject = new();
|
||||
if (!meshObject.Create(lowGuid, map, pos, privateObjectOwner))
|
||||
{
|
||||
meshObject.Dispose();
|
||||
return null;
|
||||
}
|
||||
|
||||
return meshObject;
|
||||
}
|
||||
|
||||
bool Create(ulong lowGuid, Map map, Position pos, ObjectGuid privateObjectOwner)
|
||||
{
|
||||
SetMap(map);
|
||||
Relocate(pos);
|
||||
RelocateStationaryPosition(pos);
|
||||
|
||||
SetPrivateObjectOwner(privateObjectOwner);
|
||||
|
||||
_Create(ObjectGuid.Create(HighGuid.MeshObject, GetMapId(), 0, lowGuid));
|
||||
|
||||
SetObjectScale(1.0f);
|
||||
|
||||
// Register the updateable mesh-object-data fragment (vendor-style updateable fragment).
|
||||
m_entityFragments.Add(EntityFragment.FMeshObjectData_C, IsInWorld);
|
||||
|
||||
if (!GetMap().AddToMap(this))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void BuildValuesCreate(WorldPacket data, UpdateFieldFlag flags, Player target)
|
||||
{
|
||||
m_objectData.WriteCreate(data, flags, this, target);
|
||||
|
||||
if (m_meshObjectData != null)
|
||||
{
|
||||
if (EntityFragmentsHolder.IsIndirectFragment(EntityFragment.FMeshObjectData_C))
|
||||
data.WriteUInt8(1); // IndirectFragmentActive: FMeshObjectData_C
|
||||
|
||||
m_meshObjectData.WriteCreate(data, flags, this, target);
|
||||
}
|
||||
}
|
||||
|
||||
public override void BuildValuesUpdate(WorldPacket data, UpdateFieldFlag flags, Player target)
|
||||
{
|
||||
if ((m_entityFragments.ContentsChangedMask & m_entityFragments.GetUpdateMaskFor(EntityFragment.CGObject)) != 0)
|
||||
{
|
||||
data.WriteUInt32(m_values.GetChangedObjectTypeMask());
|
||||
|
||||
if (m_values.HasChanged(TypeId.Object))
|
||||
m_objectData.WriteUpdate(data, flags, this, target);
|
||||
}
|
||||
|
||||
if (m_meshObjectData != null && (m_entityFragments.ContentsChangedMask & m_entityFragments.GetUpdateMaskFor(EntityFragment.FMeshObjectData_C)) != 0)
|
||||
m_meshObjectData.WriteUpdate(data, flags, this, target);
|
||||
}
|
||||
|
||||
void BuildValuesUpdateForPlayerWithMask(UpdateData data, UpdateMask requestedObjectMask, UpdateMask requestedMeshObjectMask, Player target)
|
||||
{
|
||||
UpdateFieldFlag flags = GetUpdateFieldFlagsFor(target);
|
||||
UpdateMask valuesMask = new((int)TypeId.Max);
|
||||
if (requestedObjectMask.IsAnySet())
|
||||
valuesMask.Set((int)TypeId.Object);
|
||||
|
||||
WorldPacket buffer = new();
|
||||
BuildEntityFragmentsForValuesUpdateForPlayerWithMask(buffer, flags);
|
||||
buffer.WriteUInt32(valuesMask.GetBlock(0));
|
||||
|
||||
if (valuesMask[(int)TypeId.Object])
|
||||
m_objectData.WriteUpdate(buffer, requestedObjectMask, true, this, target);
|
||||
|
||||
// MeshObjectData is an updateable fragment (FMeshObjectData_C), written after the values block.
|
||||
if (m_meshObjectData != null && requestedMeshObjectMask.IsAnySet())
|
||||
m_meshObjectData.WriteUpdate(buffer, requestedMeshObjectMask, true, this, target);
|
||||
|
||||
WorldPacket buffer1 = new();
|
||||
buffer1.WriteUInt8((byte)UpdateType.Values);
|
||||
buffer1.WritePackedGuid(GetGUID());
|
||||
buffer1.WriteUInt32(buffer.GetSize());
|
||||
buffer1.WriteBytes(buffer.GetData());
|
||||
|
||||
data.AddUpdateBlock(buffer1);
|
||||
}
|
||||
|
||||
public override void ClearUpdateMask(bool remove)
|
||||
{
|
||||
m_values.ClearChangesMask(m_meshObjectData);
|
||||
base.ClearUpdateMask(remove);
|
||||
}
|
||||
|
||||
public override uint GetFaction() { return 0; }
|
||||
|
||||
public override Position GetStationaryPosition() { return _stationaryPosition; }
|
||||
void RelocateStationaryPosition(Position pos) { _stationaryPosition.Relocate(pos); }
|
||||
|
||||
class ValuesUpdateForPlayerWithMaskSender
|
||||
{
|
||||
MeshObject Owner;
|
||||
ObjectFieldData ObjectMask = new();
|
||||
MeshObjectData MeshObjectMask = new();
|
||||
|
||||
public ValuesUpdateForPlayerWithMaskSender(MeshObject owner)
|
||||
{
|
||||
Owner = owner;
|
||||
}
|
||||
|
||||
public void Invoke(Player player)
|
||||
{
|
||||
UpdateData udata = new(Owner.GetMapId());
|
||||
|
||||
Owner.BuildValuesUpdateForPlayerWithMask(udata, ObjectMask.GetUpdateMask(), MeshObjectMask.GetUpdateMask(), player);
|
||||
|
||||
udata.BuildPacket(out UpdateObject packet);
|
||||
player.SendPacket(packet);
|
||||
}
|
||||
|
||||
public static implicit operator IDoWork<Player>(ValuesUpdateForPlayerWithMaskSender obj) => obj.Invoke;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user