diff --git a/CodeWalker.Core/GameFiles/FileTypes/YmapFile.cs b/CodeWalker.Core/GameFiles/FileTypes/YmapFile.cs index 0f56b23..5107fec 100644 --- a/CodeWalker.Core/GameFiles/FileTypes/YmapFile.cs +++ b/CodeWalker.Core/GameFiles/FileTypes/YmapFile.cs @@ -226,6 +226,10 @@ namespace CodeWalker.GameFiles //{ } #endregion + +#if !DEBUG + Meta = null; +#endif } diff --git a/CodeWalker.Core/GameFiles/GameFileCache.cs b/CodeWalker.Core/GameFiles/GameFileCache.cs index 45e49d5..2d22f88 100644 --- a/CodeWalker.Core/GameFiles/GameFileCache.cs +++ b/CodeWalker.Core/GameFiles/GameFileCache.cs @@ -2257,6 +2257,13 @@ namespace CodeWalker.GameFiles } + public void BeginFrame() + { + lock (requestSyncRoot) + { + mainCache.BeginFrame(); + } + } public bool ContentThreadProc() diff --git a/CodeWalker.Core/Utils/Cache.cs b/CodeWalker.Core/Utils/Cache.cs index 2917069..aac6ce1 100644 --- a/CodeWalker.Core/Utils/Cache.cs +++ b/CodeWalker.Core/Utils/Cache.cs @@ -11,7 +11,8 @@ namespace CodeWalker { public long MaxMemoryUsage = 536870912; //512mb public long CurrentMemoryUsage = 0; - public double CacheTime = 5.0; //seconds to keep something that's not used + public double CacheTime = 10.0; //seconds to keep something that's not used + public DateTime CurrentTime = DateTime.Now; private LinkedList loadedList = new LinkedList(); private Dictionary> loadedListDict = new Dictionary>(); @@ -33,6 +34,12 @@ namespace CodeWalker CacheTime = cacheTime; } + public void BeginFrame() + { + CurrentTime = DateTime.Now; + Compact(); + } + public TVal TryGet(TKey key) { LinkedListNode lln = null; @@ -40,7 +47,7 @@ namespace CodeWalker { loadedList.Remove(lln); loadedList.AddLast(lln); - lln.Value.LastUseTime = DateTime.Now; + lln.Value.LastUseTime = CurrentTime; } return (lln != null) ? lln.Value : null; } @@ -65,7 +72,7 @@ namespace CodeWalker int iter = 0, maxiter = 2; while (!CanAdd() && (iter cachetime)) + while ((!CanAdd()) && (oldlln != null) && ((CurrentTime - oldlln.Value.LastUseTime).TotalSeconds > cachetime)) { Interlocked.Add(ref CurrentMemoryUsage, -oldlln.Value.MemoryUsage); loadedListDict.Remove(oldlln.Value.Key); @@ -113,16 +120,33 @@ namespace CodeWalker { loadedListDict.Remove(key); loadedList.Remove(n); - CurrentMemoryUsage -= n.Value.MemoryUsage; + Interlocked.Add(ref CurrentMemoryUsage, -n.Value.MemoryUsage); } } + + public void Compact() + { + var oldlln = loadedList.First; + while (oldlln != null) + { + if ((CurrentTime - oldlln.Value.LastUseTime).TotalSeconds < CacheTime) break; + var nextln = oldlln.Next; + Interlocked.Add(ref CurrentMemoryUsage, -oldlln.Value.MemoryUsage); + loadedListDict.Remove(oldlln.Value.Key); + loadedList.Remove(oldlln); //gc should free up memory later.. + oldlln.Value = null; + oldlln = nextln; + } + } + + } public abstract class Cacheable { public TKey Key; - public DateTime LastUseTime = DateTime.Now; + public DateTime LastUseTime; public long MemoryUsage; } diff --git a/ExploreForm.cs b/ExploreForm.cs index 5cd8603..9c4c143 100644 --- a/ExploreForm.cs +++ b/ExploreForm.cs @@ -165,6 +165,8 @@ namespace CodeWalker { if (FileCache.IsInited) { + FileCache.BeginFrame(); + bool fcItemsPending = FileCache.ContentThreadProc(); if (!fcItemsPending) diff --git a/PedsForm.cs b/PedsForm.cs index 937051a..f7f8b64 100644 --- a/PedsForm.cs +++ b/PedsForm.cs @@ -213,13 +213,14 @@ namespace CodeWalker.Peds if (pauserendering) return; + GameFileCache.BeginFrame(); + if (!Monitor.TryEnter(Renderer.RenderSyncRoot, 50)) { return; } //couldn't get a lock, try again next time UpdateControlInputs(elapsed); //space.Update(elapsed); - Renderer.Update(elapsed, MouseLastPoint.X, MouseLastPoint.Y); diff --git a/Rendering/Renderer.cs b/Rendering/Renderer.cs index 9f102cb..9c6aac0 100644 --- a/Rendering/Renderer.cs +++ b/Rendering/Renderer.cs @@ -1652,6 +1652,23 @@ namespace CodeWalker.Rendering + for (int i = 0; i < ents.Count; i++) //make sure to remove the renderable references to avoid hogging memory + { + var ent = ents[i]; + ent.LodManagerRenderable = null; + } + foreach (var ent in RequiredParents.Keys) + { + var pcnode = ent.LodManagerChildren?.First; + while (pcnode != null)//maybe can improve performance of this + { + var pcent = pcnode.Value; + pcent.LodManagerRenderable = null; + pcnode = pcnode.Next; + } + } + + RenderWorldYmapExtras(); } @@ -3586,6 +3603,8 @@ namespace CodeWalker.Rendering var ent = ymap.AllEntities[i]; RootEntities.Remove(ent); ent.LodManagerChildren?.Clear(); + ent.LodManagerChildren = null; + ent.LodManagerRenderable = null; if ((ent.Parent != null) && (ent.Parent.Ymap != ymap)) { ent.Parent.LodManagerRemoveChild(ent); diff --git a/VehicleForm.cs b/VehicleForm.cs index 48ba738..66545d9 100644 --- a/VehicleForm.cs +++ b/VehicleForm.cs @@ -164,13 +164,14 @@ namespace CodeWalker.Vehicles if (pauserendering) return; + GameFileCache.BeginFrame(); + if (!Monitor.TryEnter(Renderer.RenderSyncRoot, 50)) { return; } //couldn't get a lock, try again next time UpdateControlInputs(elapsed); //space.Update(elapsed); - Renderer.Update(elapsed, MouseLastPoint.X, MouseLastPoint.Y); diff --git a/WorldForm.cs b/WorldForm.cs index 243fb19..d85039c 100644 --- a/WorldForm.cs +++ b/WorldForm.cs @@ -398,6 +398,8 @@ namespace CodeWalker if (pauserendering) return; + GameFileCache.BeginFrame(); + if (!Monitor.TryEnter(Renderer.RenderSyncRoot, 50)) { return; } //couldn't get a lock, try again next time