diff --git a/Substrate/SubstrateCS/Examples/Examples.sln b/Substrate/SubstrateCS/Examples/Examples.sln index b21f17f..95d0a0c 100644 --- a/Substrate/SubstrateCS/Examples/Examples.sln +++ b/Substrate/SubstrateCS/Examples/Examples.sln @@ -13,7 +13,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MoveSpawn", "MoveSpawn\Move EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Skyscraper", "Skyscraper\Skyscraper.csproj", "{83F55F54-7253-4B4D-BC37-E9D1CB63E0B8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{B34A66B6-6A3B-42FC-AF39-74A30F487840}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Relight", "Relight\Relight.csproj", "{EBDD447B-01FA-4A29-B4AB-380EC4379B5F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -45,10 +45,10 @@ Global {83F55F54-7253-4B4D-BC37-E9D1CB63E0B8}.Debug|Any CPU.Build.0 = Debug|Any CPU {83F55F54-7253-4B4D-BC37-E9D1CB63E0B8}.Release|Any CPU.ActiveCfg = Release|Any CPU {83F55F54-7253-4B4D-BC37-E9D1CB63E0B8}.Release|Any CPU.Build.0 = Release|Any CPU - {B34A66B6-6A3B-42FC-AF39-74A30F487840}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B34A66B6-6A3B-42FC-AF39-74A30F487840}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B34A66B6-6A3B-42FC-AF39-74A30F487840}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B34A66B6-6A3B-42FC-AF39-74A30F487840}.Release|Any CPU.Build.0 = Release|Any CPU + {EBDD447B-01FA-4A29-B4AB-380EC4379B5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EBDD447B-01FA-4A29-B4AB-380EC4379B5F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EBDD447B-01FA-4A29-B4AB-380EC4379B5F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EBDD447B-01FA-4A29-B4AB-380EC4379B5F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Substrate/SubstrateCS/Examples/Relight/Program.cs b/Substrate/SubstrateCS/Examples/Relight/Program.cs new file mode 100644 index 0000000..7c8e540 --- /dev/null +++ b/Substrate/SubstrateCS/Examples/Relight/Program.cs @@ -0,0 +1,49 @@ +using System; +using Substrate; + +namespace Relight +{ + class Program + { + static void Main (string[] args) + { + if (args.Length < 1) { + Console.WriteLine("You must specify a target directory"); + return; + } + string dest = args[0]; + + // Load the world, supporting either alpha or beta format + INBTWorld world; + if (args.Length >= 2 && args[1] == "alpha") { + world = AlphaWorld.Open(dest); + } + else { + world = BetaWorld.Open(dest); + } + + // Grab a generic chunk manager reference + IChunkManager cm = world.GetChunkManager(); + + // First blank out all of the lighting in all of the chunks + foreach (ChunkRef chunk in cm) { + chunk.ResetBlockLight(); + chunk.ResetSkyLight(); + cm.Save(); + + Console.WriteLine("Reset Chunk {0},{1}", chunk.X, chunk.Z); + } + + // In a separate pass, reconstruct the light + foreach (ChunkRef chunk in cm) { + chunk.RebuildBlockLight(); + chunk.RebuildSkyLight(); + + // Save the chunk to disk so it doesn't hang around in RAM + cm.Save(); + + Console.WriteLine("Lit Chunk {0},{1}", chunk.X, chunk.Z); + } + } + } +} diff --git a/Substrate/SubstrateCS/Examples/Relight/Properties/AssemblyInfo.cs b/Substrate/SubstrateCS/Examples/Relight/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..474634a --- /dev/null +++ b/Substrate/SubstrateCS/Examples/Relight/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Relight")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("Relight")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("b21635dd-f744-4740-842a-f86781787961")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Substrate/SubstrateCS/Examples/Relight/Relight.csproj b/Substrate/SubstrateCS/Examples/Relight/Relight.csproj new file mode 100644 index 0000000..1919f5b --- /dev/null +++ b/Substrate/SubstrateCS/Examples/Relight/Relight.csproj @@ -0,0 +1,52 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {EBDD447B-01FA-4A29-B4AB-380EC4379B5F} + Exe + Properties + Relight + Relight + v3.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + ..\..\bin\Release\Substrate.dll + + + + + + + + + + \ No newline at end of file diff --git a/Substrate/SubstrateCS/Source/ChunkCache.cs b/Substrate/SubstrateCS/Source/ChunkCache.cs new file mode 100644 index 0000000..39c15b9 --- /dev/null +++ b/Substrate/SubstrateCS/Source/ChunkCache.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Collections; + +namespace Substrate +{ + public class ChunkCache : IChunkCache + { + private Dictionary _cache; + private Dictionary _dirty; + + public ChunkCache () + { + _cache = new Dictionary(); + _dirty = new Dictionary(); + } + + #region IChunkCache Members + + public bool Insert (ChunkRef chunk) + { + ChunkKey key = new ChunkKey(chunk.X, chunk.Z); + + WeakReference wref; + if (!_cache.TryGetValue(key, out wref)) { + _cache[key] = new WeakReference(chunk); + return true; + } + + if (!wref.IsAlive) { + wref.Target = chunk; + return true; + } + + return false; + } + + public bool Remove (ChunkKey key) + { + _dirty.Remove(key); + return _cache.Remove(key); + } + + public ChunkRef Fetch (ChunkKey key) + { + WeakReference wref; + if (!_cache.TryGetValue(key, out wref)) { + return null; + } + + return wref.Target as ChunkRef; + } + + public IEnumerator GetDirtyEnumerator () + { + return _dirty.Values.GetEnumerator(); + } + + public void ClearDirty () + { + _dirty.Clear(); + } + + public bool MarkChunkDirty (ChunkRef chunk) + { + int cx = chunk.X; + int cz = chunk.Z; + + ChunkKey k = new ChunkKey(cx, cz); + if (!_dirty.ContainsKey(k)) { + _dirty.Add(k, chunk); + return true; + } + return false; + } + + public bool MarkChunkClean (ChunkRef chunk) + { + int cx = chunk.X; + int cz = chunk.Z; + + ChunkKey k = new ChunkKey(cx, cz); + if (_dirty.ContainsKey(k)) { + _dirty.Remove(k); + return true; + } + return false; + } + + #endregion + } +} diff --git a/Substrate/SubstrateCS/Source/ChunkManager.cs b/Substrate/SubstrateCS/Source/ChunkManager.cs index eedf08c..254730d 100644 --- a/Substrate/SubstrateCS/Source/ChunkManager.cs +++ b/Substrate/SubstrateCS/Source/ChunkManager.cs @@ -5,7 +5,7 @@ using System.Collections; namespace Substrate { - public class ChunkManager : IChunkManager, IChunkCache, IEnumerable + public class ChunkManager : IChunkManager, IEnumerable { public const int REGION_XLEN = 32; public const int REGION_ZLEN = 32; @@ -18,21 +18,25 @@ namespace Substrate protected RegionManager _regionMan; - protected Dictionary _cache; - protected Dictionary _dirty; + //protected Dictionary _cache; + //protected Dictionary _dirty; - public ChunkManager (RegionManager rm) + protected ChunkCache _cache; + + public ChunkManager (RegionManager rm, ChunkCache cache) { _regionMan = rm; - _cache = new Dictionary(); - _dirty = new Dictionary(); + _cache = cache; + //_cache = new Dictionary(); + //_dirty = new Dictionary(); } public ChunkManager (ChunkManager cm) { _regionMan = cm._regionMan; - _cache = new Dictionary(); - _dirty = new Dictionary(); + _cache = cm._cache; + //_cache = new Dictionary(); + //_dirty = new Dictionary(); } public int ChunkGlobalX (int cx) @@ -72,7 +76,7 @@ namespace Substrate return null; } - return r.GetChunkRef(cx & REGION_XMASK, cz & REGION_ZMASK, this); + return r.GetChunkRef(cx & REGION_XMASK, cz & REGION_ZMASK); } public bool ChunkExists (int cx, int cz) @@ -94,10 +98,10 @@ namespace Substrate r = _regionMan.CreateRegion(rx, rz); } - return r.CreateChunk(cx & REGION_XMASK, cz & REGION_ZMASK, this); + return r.CreateChunk(cx & REGION_XMASK, cz & REGION_ZMASK); } - public bool MarkChunkDirty (ChunkRef chunk) + /*public bool MarkChunkDirty (ChunkRef chunk) { Region r = GetRegion(chunk.X, chunk.Z); if (r == null) { @@ -125,16 +129,25 @@ namespace Substrate r.MarkChunkClean(chunk); return true; - } + }*/ public int Save () { int saved = 0; - foreach (Region r in _dirty.Values) { - saved += r.Save(); + IEnumerator en = _cache.GetDirtyEnumerator(); + while (en.MoveNext()) { + ChunkRef chunk = en.Current; + + Region r = GetRegion(chunk.X, chunk.Z); + if (r == null) { + continue; + } + + chunk.Save(r.GetChunkOutStream(chunk.LocalX, chunk.LocalZ)); + saved++; } - _dirty.Clear(); + _cache.ClearDirty(); return saved; } @@ -160,10 +173,6 @@ namespace Substrate } if (r.ChunkCount() == 0) { - RegionKey k = new RegionKey(r.X, r.Z); - _cache.Remove(k); - _dirty.Remove(k); - _regionMan.DeleteRegion(r.X, r.Z); } @@ -245,7 +254,7 @@ namespace Substrate _region = _enum.Current; } if (MoveNextInRegion()) { - _chunk = _region.GetChunkRef(_x, _z, _cm); + _chunk = _region.GetChunkRef(_x, _z); return true; } } diff --git a/Substrate/SubstrateCS/Source/Region.cs b/Substrate/SubstrateCS/Source/Region.cs index 152cb49..6b83ed2 100644 --- a/Substrate/SubstrateCS/Source/Region.cs +++ b/Substrate/SubstrateCS/Source/Region.cs @@ -8,7 +8,7 @@ namespace Substrate { using NBT; - public class Region : IDisposable, IChunkContainer, IChunkCache + public class Region : IDisposable, IChunkContainer { private const int XDIM = 32; private const int ZDIM = 32; @@ -27,8 +27,10 @@ namespace Substrate protected WeakReference _regionFile; - protected Dictionary _cache; - protected Dictionary _dirty; + //protected Dictionary _cache; + //protected Dictionary _dirty; + + protected ChunkCache _cache; public int X { @@ -50,24 +52,26 @@ namespace Substrate get { return ZDIM; } } - public Region (RegionManager rm, int rx, int rz) + public Region (RegionManager rm, ChunkCache cache, int rx, int rz) { _regionMan = rm; + _cache = cache; _regionFile = new WeakReference(null); _rx = rx; _rz = rz; - _cache = new Dictionary(); - _dirty = new Dictionary(); + //_cache = new Dictionary(); + //_dirty = new Dictionary(); if (!File.Exists(GetFilePath())) { throw new FileNotFoundException(); } } - public Region (RegionManager rm, string filename) + public Region (RegionManager rm, ChunkCache cache, string filename) { _regionMan = rm; + _cache = cache; _regionFile = new WeakReference(null); ParseFileName(filename, out _rx, out _rz); @@ -217,32 +221,25 @@ namespace Substrate return count; } - public ChunkRef GetChunkRef (int lcx, int lcz, IChunkCache cache) + public ChunkRef GetChunkRef (int lcx, int lcz) { if (!LocalBoundsCheck(lcx, lcz)) { Region alt = GetForeignRegion(lcx, lcz); - return (alt == null) ? null : alt.GetChunkRef(ForeignX(lcx), ForeignZ(lcz), cache); + return (alt == null) ? null : alt.GetChunkRef(ForeignX(lcx), ForeignZ(lcz)); } - ChunkKey k = new ChunkKey(lcx, lcz); - - ChunkRef c = null; - - WeakReference chunkref = null; - if (_cache.TryGetValue(k, out chunkref)) { - c = chunkref.Target as ChunkRef; - } - else { - _cache.Add(k, new WeakReference(null)); - } + int cx = lcx + _rx * ChunkManager.REGION_XLEN; + int cz = lcz + _rz * ChunkManager.REGION_ZLEN; + ChunkKey k = new ChunkKey(cx, cz); + ChunkRef c = _cache.Fetch(k); if (c != null) { return c; } try { - c = new ChunkRef(this, cache, lcx, lcz); - _cache[k].Target = c; + c = new ChunkRef(this, _cache, lcx, lcz); + _cache.Insert(c); return c; } catch (MissingChunkException) { @@ -251,15 +248,10 @@ namespace Substrate } public ChunkRef CreateChunk (int lcx, int lcz) - { - return CreateChunk(lcx, lcz, this); - } - - public ChunkRef CreateChunk (int lcx, int lcz, IChunkCache cache) { if (!LocalBoundsCheck(lcx, lcz)) { Region alt = GetForeignRegion(lcx, lcz); - return (alt == null) ? null : alt.CreateChunk(ForeignX(lcx), ForeignZ(lcz), cache); + return (alt == null) ? null : alt.CreateChunk(ForeignX(lcx), ForeignZ(lcz)); } DeleteChunk(lcx, lcz); @@ -270,9 +262,8 @@ namespace Substrate Chunk c = new Chunk(cx, cz); c.Save(GetChunkOutStream(lcx, lcz)); - ChunkRef cr = new ChunkRef(this, cache, lcx, lcz); - ChunkKey k = new ChunkKey(lcx, lcz); - _cache[k] = new WeakReference(cr); + ChunkRef cr = new ChunkRef(this, _cache, lcx, lcz); + _cache.Insert(cr); return cr; } @@ -314,11 +305,6 @@ namespace Substrate return new Chunk(GetChunkTree(lcx, lcz)); } - public ChunkRef GetChunkRef (int lcx, int lcz) - { - return GetChunkRef(lcx, lcz, this); - } - public bool ChunkExists (int lcx, int lcz) { if (!LocalBoundsCheck(lcx, lcz)) { @@ -346,7 +332,6 @@ namespace Substrate ChunkKey k = new ChunkKey(lcx, lcz); _cache.Remove(k); - _dirty.Remove(k); if (ChunkCount() == 0) { _regionMan.DeleteRegion(X, Z); @@ -358,22 +343,20 @@ namespace Substrate public int Save () { int saved = 0; - foreach (ChunkRef c in _dirty.Values) { - int cx = c.X; - int cz = c.Z; - int lcx = cx - _rx * ChunkManager.REGION_XLEN; - int lcz = cz - _rz * ChunkManager.REGION_ZLEN; + IEnumerator en = _cache.GetDirtyEnumerator(); + while (en.MoveNext()) { + ChunkRef chunk = en.Current; - if (!ChunkExists(lcx, lcz)) { + if (!ChunkExists(chunk.LocalX, chunk.LocalZ)) { throw new MissingChunkException(); } - if (c.Save(GetChunkOutStream(lcx, lcz))) { + if (chunk.Save(GetChunkOutStream(chunk.LocalX, chunk.LocalZ))) { saved++; } } - _dirty.Clear(); + _cache.ClearDirty(); return saved; } @@ -387,7 +370,7 @@ namespace Substrate #region IChunkCache Members - public bool MarkChunkDirty (ChunkRef chunk) + /*public bool MarkChunkDirty (ChunkRef chunk) { int cx = chunk.X; int cz = chunk.Z; @@ -415,7 +398,7 @@ namespace Substrate return true; } return false; - } + }*/ #endregion diff --git a/Substrate/SubstrateCS/Source/RegionManager.cs b/Substrate/SubstrateCS/Source/RegionManager.cs index 0f3dc7c..7572a59 100644 --- a/Substrate/SubstrateCS/Source/RegionManager.cs +++ b/Substrate/SubstrateCS/Source/RegionManager.cs @@ -25,9 +25,12 @@ namespace Substrate protected Dictionary _cache; - public RegionManager (string regionDir) + protected ChunkCache _chunkCache; + + public RegionManager (string regionDir, ChunkCache cache) { _regionPath = regionDir; + _chunkCache = cache; _cache = new Dictionary(); } @@ -38,7 +41,7 @@ namespace Substrate try { if (_cache.TryGetValue(k, out r) == false) { - r = new Region(this, rx, rz); + r = new Region(this, _chunkCache, rx, rz); _cache.Add(k, r); } return r; @@ -64,7 +67,7 @@ namespace Substrate } - r = new Region(this, rx, rz); + r = new Region(this, _chunkCache, rx, rz); RegionKey k = new RegionKey(rx, rz); _cache[k] = r; @@ -113,7 +116,7 @@ namespace Substrate return true; } - public int Save () + /*public int Save () { int saved = 0; foreach (Region r in _cache.Values) { @@ -121,7 +124,7 @@ namespace Substrate } return saved; - } + }*/ #region IEnumerable Members diff --git a/Substrate/SubstrateCS/Source/World.cs b/Substrate/SubstrateCS/Source/World.cs index 7dbe9ba..f6e98df 100644 --- a/Substrate/SubstrateCS/Source/World.cs +++ b/Substrate/SubstrateCS/Source/World.cs @@ -281,8 +281,8 @@ namespace Substrate { _level.Save(); - foreach (KeyValuePair rm in _regionMgrs) { - rm.Value.Save(); + foreach (KeyValuePair cm in _chunkMgrs) { + cm.Value.Save(); } } @@ -301,8 +301,10 @@ namespace Substrate Directory.CreateDirectory(path); } - RegionManager rm = new RegionManager(path); - ChunkManager cm = new ChunkManager(rm); + ChunkCache cc = new ChunkCache(); + + RegionManager rm = new RegionManager(path, cc); + ChunkManager cm = new ChunkManager(rm, cc); BlockManager bm = new BlockManager(cm); _regionMgrs[dim] = rm; diff --git a/Substrate/SubstrateCS/Substrate.csproj b/Substrate/SubstrateCS/Substrate.csproj index 0724676..e71527a 100644 --- a/Substrate/SubstrateCS/Substrate.csproj +++ b/Substrate/SubstrateCS/Substrate.csproj @@ -59,8 +59,11 @@ Assemblies\Ionic.Zlib.dll + + +