From 6b3c7b43ade0501afee90e0e1d889da0df82a915 Mon Sep 17 00:00:00 2001 From: kaczy Date: Tue, 19 Mar 2024 10:15:59 +0100 Subject: [PATCH] Animated statics --- CentrED/AnimatedStaticsManager.cs | 128 ++++++++++++++++++++++++++++++ CentrED/Map/MapManager.cs | 17 ++++ CentrED/Map/StaticObject.cs | 12 ++- 3 files changed, 155 insertions(+), 2 deletions(-) create mode 100644 CentrED/AnimatedStaticsManager.cs diff --git a/CentrED/AnimatedStaticsManager.cs b/CentrED/AnimatedStaticsManager.cs new file mode 100644 index 0000000..d5f8b41 --- /dev/null +++ b/CentrED/AnimatedStaticsManager.cs @@ -0,0 +1,128 @@ +using ClassicUO.Assets; +using ClassicUO.IO; +using ClassicUO.Utility.Collections; +using Microsoft.Xna.Framework; + +namespace CentrED; + +// This class is almost exact copy from ClassicUO +// The only difference is that it works on GameTime passed to Process() and animated fields option is removed +sealed class AnimatedStaticsManager +{ + private readonly FastList _staticInfos = new(); + private uint _processTime; + + public unsafe void Initialize() + { + UOFile file = AnimDataLoader.Instance.AnimDataFile; + + if (file == null) + { + return; + } + + long startAddr = file.StartAddress.ToInt64(); + uint lastaddr = (uint)(startAddr + file.Length - sizeof(AnimDataFrame)); + + for (int i = 0; i < TileDataLoader.Instance.StaticData.Length; i++) + { + if (TileDataLoader.Instance.StaticData[i].IsAnimated) + { + uint addr = (uint)(i * 68 + 4 * (i / 8 + 1)); + uint offset = (uint)(startAddr + addr); + + if (offset <= lastaddr) + { + _staticInfos.Add + ( + new StaticAnimationInfo + { + Index = (ushort)i, + // IsField = IsField((ushort)i) + } + ); + } + } + } + } + + public unsafe void Process(GameTime gameTime) + { + var ticks = (uint)gameTime.TotalGameTime.TotalMilliseconds; + if (_staticInfos == null || _staticInfos.Length == 0 || _processTime >= ticks) + { + return; + } + + UOFile file = AnimDataLoader.Instance.AnimDataFile; + + if (file == null) + { + return; + } + + // fix static animations time to reflect the standard client + uint delay = 50 * 2; + uint next_time = ticks + 250; + // bool no_animated_field = ProfileManager.CurrentProfile != null && ProfileManager.CurrentProfile.FieldsType != 0; + long startAddr = file.StartAddress.ToInt64(); + UOFileIndex[] static_data = ArtLoader.Instance.Entries; + + for (int i = 0; i < _staticInfos.Length; i++) + { + ref StaticAnimationInfo o = ref _staticInfos.Buffer[i]; + + // if (no_animated_field && o.IsField) + // { + // o.AnimIndex = 0; + // + // continue; + // } + + if (o.Time < ticks) + { + uint addr = (uint)(o.Index * 68 + 4 * (o.Index / 8 + 1)); + AnimDataFrame* info = (AnimDataFrame*)(startAddr + addr); + + byte offset = o.AnimIndex; + + if (info->FrameInterval > 0) + { + o.Time = ticks + info->FrameInterval * delay + 1; + } + else + { + o.Time = ticks + delay; + } + + if (offset < info->FrameCount && o.Index + 0x4000 < static_data.Length) + { + static_data[o.Index + 0x4000].AnimOffset = info->FrameData[offset++]; + } + + if (offset >= info->FrameCount) + { + offset = 0; + } + + o.AnimIndex = offset; + } + + if (o.Time < next_time) + { + next_time = o.Time; + } + } + + _processTime = next_time; + } + + + private struct StaticAnimationInfo + { + public uint Time; + public ushort Index; + public byte AnimIndex; + // public bool IsField; + } +} \ No newline at end of file diff --git a/CentrED/Map/MapManager.cs b/CentrED/Map/MapManager.cs index 6e7b87a..42639c8 100644 --- a/CentrED/Map/MapManager.cs +++ b/CentrED/Map/MapManager.cs @@ -27,6 +27,7 @@ public class MapManager public bool DebugDrawSelectionBuffer; private RenderTarget2D _selectionBuffer; + private AnimatedStaticsManager _animatedStaticsManager; internal List Tools = new(); private Tool _activeTool; @@ -285,10 +286,13 @@ public void Load(string clientPath, string clientVersion) HuesLoader.Instance.Load(), TileDataLoader.Instance.Load(), TexmapsLoader.Instance.Load(), + AnimDataLoader.Instance.Load(), } ).Wait(TimeSpan.FromSeconds(10.0))) Log.Panic("Loading files timeout."); + _animatedStaticsManager = new AnimatedStaticsManager(); + _animatedStaticsManager.Initialize(); TextureAtlas.InitializeSharedTexture(_gfxDevice); HuesManager.Load(_gfxDevice); _mapEffect.HueCount = HuesManager.Instance.HuesCount; @@ -340,6 +344,7 @@ public static Vector2 ScreenToMapCoordinates(float x, float y) public Dictionary GhostLandTiles = new(); public List?[,] StaticTiles; public int StaticTilesCount; + public List AnimatedStaticTiles = new(); public Dictionary GhostStaticTiles = new(); public VirtualLayerObject VirtualLayer = VirtualLayerObject.Instance; //Used for drawing @@ -410,6 +415,10 @@ public void AddTile(StaticTile staticTile) list.Add(so); AllTiles.Add(so.ObjectId, so); StaticTilesCount++; + if (so.IsAnimated) + { + AnimatedStaticTiles.Add(so); + } } public void RemoveTile(StaticTile staticTile) @@ -657,6 +666,14 @@ public void Update(GameTime gameTime, bool isActive, bool processMouse, bool pro Client.LoadBlocks(requested); } } + if (Client.Initialized) + { + _animatedStaticsManager.Process(gameTime); + foreach (var animatedStaticTile in AnimatedStaticTiles) + { + animatedStaticTile.UpdateId(); + } + } Metrics.Stop("UpdateMap"); } diff --git a/CentrED/Map/StaticObject.cs b/CentrED/Map/StaticObject.cs index 6a96153..994640a 100644 --- a/CentrED/Map/StaticObject.cs +++ b/CentrED/Map/StaticObject.cs @@ -1,4 +1,3 @@ -using CentrED.Renderer; using ClassicUO.Assets; using Microsoft.Xna.Framework; @@ -8,6 +7,7 @@ public class StaticObject : TileObject { public const float INVERSE_SQRT2 = 0.70711f; public StaticTile StaticTile; + public bool IsAnimated; public StaticObject(StaticTile tile) { @@ -20,6 +20,7 @@ public StaticObject(StaticTile tile) { Vertices[i].Normal = Vector3.Zero; } + IsAnimated = TileDataLoader.Instance.StaticData[Tile.Id].IsAnimated; } public void Update() @@ -28,9 +29,15 @@ public void Update() UpdatePos(Tile.X, Tile.Y, Tile.Z); } + public void UpdateId() + { + UpdateId(Tile.Id); + } + public void UpdateId(ushort newId) { - Texture = ArtLoader.Instance.GetStaticTexture(Tile.Id, out TextureBounds); + ref var index = ref ArtLoader.Instance.GetValidRefEntry(newId + 0x4000); + Texture = ArtLoader.Instance.GetStaticTexture((ushort)(newId + index.AnimOffset), out TextureBounds); float onePixel = Math.Max(1.0f / Texture.Width, Epsilon.value); var texX = TextureBounds.X / (float)Texture.Width + onePixel / 2f; @@ -43,6 +50,7 @@ public void UpdateId(ushort newId) Vertices[2].Texture = new Vector3(texX, texY + texHeight, 0f); Vertices[3].Texture = new Vector3(texX + texWidth, texY + texHeight, 0f); UpdateDepthOffset(); + IsAnimated = TileDataLoader.Instance.StaticData[newId].IsAnimated; } public void UpdateDepthOffset()