/SubstrateCS/Source/ChunkRef.cs

https://github.com/jaquadro/Substrate · C# · 334 lines · 186 code · 38 blank · 110 comment · 27 complexity · 6cabeadd1d5748f4c3eda556b9e1aa73 MD5 · raw file

  1. using System;
  2. using System.IO;
  3. using System.Collections.Generic;
  4. using Substrate.Core;
  5. namespace Substrate
  6. {
  7. /// <summary>
  8. /// Provides a wrapper around a physical Chunk stored in a chunk container.
  9. /// </summary>
  10. /// <remarks>
  11. /// Modifying data in a ChunkRef will signal to the chunk container that the physical chunk needs to be saved.
  12. /// </remarks>
  13. public class ChunkRef : IChunk
  14. {
  15. private IChunkContainer _container;
  16. private IChunk _chunk;
  17. private AlphaBlockCollection _blocks;
  18. private AnvilBiomeCollection _biomes;
  19. private EntityCollection _entities;
  20. private int _cx;
  21. private int _cz;
  22. private bool _dirty;
  23. /// <summary>
  24. /// Gets the global X-coordinate of the chunk.
  25. /// </summary>
  26. public int X
  27. {
  28. get { return _container.ChunkGlobalX(_cx); }
  29. }
  30. /// <summary>
  31. /// Gets the global Z-coordinate of the chunk.
  32. /// </summary>
  33. public int Z
  34. {
  35. get { return _container.ChunkGlobalZ(_cz); }
  36. }
  37. /// <summary>
  38. /// Gets the local X-coordinate of the chunk within container.
  39. /// </summary>
  40. public int LocalX
  41. {
  42. get { return _container.ChunkLocalX(_cx); }
  43. }
  44. /// <summary>
  45. /// Gets the local Z-coordinate of the chunk within container.
  46. /// </summary>
  47. public int LocalZ
  48. {
  49. get { return _container.ChunkLocalZ(_cz); }
  50. }
  51. /// <summary>
  52. /// Gets the collection of all blocks and their data stored in the chunk.
  53. /// </summary>
  54. public AlphaBlockCollection Blocks
  55. {
  56. get
  57. {
  58. if (_blocks == null)
  59. {
  60. GetChunk();
  61. }
  62. return _blocks;
  63. }
  64. }
  65. /// <summary>
  66. /// Gets the collection of all blocks and their data stored in the chunk.
  67. /// </summary>
  68. public AnvilBiomeCollection Biomes
  69. {
  70. get
  71. {
  72. if (_biomes == null)
  73. {
  74. GetChunk();
  75. }
  76. return _biomes;
  77. }
  78. }
  79. /// <summary>
  80. /// Gets the collection of all entities stored in the chunk.
  81. /// </summary>
  82. public EntityCollection Entities
  83. {
  84. get
  85. {
  86. if (_entities == null) {
  87. GetChunk();
  88. }
  89. return _entities;
  90. }
  91. }
  92. /// <summary>
  93. /// Gets or sets the value indicating that the chunk has been modified, but not saved.
  94. /// </summary>
  95. public bool IsDirty
  96. {
  97. get
  98. {
  99. return _dirty
  100. || (_blocks != null && _blocks.IsDirty)
  101. || (_entities != null && _entities.IsDirty);
  102. }
  103. set
  104. {
  105. _dirty = value;
  106. if (_blocks != null)
  107. _blocks.IsDirty = false;
  108. if (_entities != null)
  109. _entities.IsDirty = false;
  110. }
  111. }
  112. /// <summary>
  113. /// Forbid direct instantiation of ChunkRef objects
  114. /// </summary>
  115. private ChunkRef ()
  116. {
  117. }
  118. /// <summary>
  119. /// Create a reference to a chunk stored in a chunk container.
  120. /// </summary>
  121. /// <param name="container">Chunk container</param>
  122. /// <param name="cx">Local X-coordinate of chunk within container.</param>
  123. /// <param name="cz">Local Z-coordinate of chunk within container.</param>
  124. /// <returns>ChunkRef representing a reference to a physical chunk at the specified location within the container.</returns>
  125. public static ChunkRef Create (IChunkContainer container, int cx, int cz)
  126. {
  127. if (!container.ChunkExists(cx, cz)) {
  128. return null;
  129. }
  130. ChunkRef c = new ChunkRef();
  131. c._container = container;
  132. c._cx = cx;
  133. c._cz = cz;
  134. return c;
  135. }
  136. /// <summary>
  137. /// Gets or sets the chunk's TerrainPopulated status.
  138. /// </summary>
  139. public bool IsTerrainPopulated
  140. {
  141. get { return GetChunk().IsTerrainPopulated; }
  142. set
  143. {
  144. if (GetChunk().IsTerrainPopulated != value) {
  145. GetChunk().IsTerrainPopulated = value;
  146. _dirty = true;
  147. }
  148. }
  149. }
  150. /// <summary>
  151. /// Saves the underlying physical chunk to the specified output stream.
  152. /// </summary>
  153. /// <param name="outStream">An open output stream.</param>
  154. /// <returns>A value indicating whether the chunk is no longer considered dirty.</returns>
  155. public bool Save (Stream outStream)
  156. {
  157. if (IsDirty) {
  158. if (GetChunk().Save(outStream)) {
  159. IsDirty = false;
  160. return true;
  161. }
  162. return false;
  163. }
  164. return true;
  165. }
  166. public void SetLocation (int x, int z)
  167. {
  168. int relX = LocalX + (x - X);
  169. int relZ = LocalZ + (z - Z);
  170. ChunkRef c = _container.SetChunk(relX, relZ, GetChunk());
  171. _container = c._container;
  172. _cx = c._cx;
  173. _cz = c._cz;
  174. }
  175. /// <summary>
  176. /// Gets a ChunkRef to the chunk positioned immediately north (X - 1).
  177. /// </summary>
  178. /// <returns>ChunkRef to the northern neighboring chunk.</returns>
  179. public ChunkRef GetNorthNeighbor ()
  180. {
  181. return _container.GetChunkRef(_cx - 1, _cz);
  182. }
  183. /// <summary>
  184. /// Gets a ChunkRef to the chunk positioned immediately south (X + 1).
  185. /// </summary>
  186. /// <returns>ChunkRef to the southern neighboring chunk.</returns>
  187. public ChunkRef GetSouthNeighbor ()
  188. {
  189. return _container.GetChunkRef(_cx + 1, _cz);
  190. }
  191. /// <summary>
  192. /// Gets a ChunkRef to the chunk positioned immediatly east (Z - 1).
  193. /// </summary>
  194. /// <returns>ChunkRef to the eastern neighboring chunk.</returns>
  195. public ChunkRef GetEastNeighbor ()
  196. {
  197. return _container.GetChunkRef(_cx, _cz - 1);
  198. }
  199. /// <summary>
  200. /// Gets a ChunkRef to the chunk positioned immedately west (Z + 1).
  201. /// </summary>
  202. /// <returns>ChunkRef to the western neighboring chunk.</returns>
  203. public ChunkRef GetWestNeighbor ()
  204. {
  205. return _container.GetChunkRef(_cx, _cz + 1);
  206. }
  207. /// <summary>
  208. /// Returns a deep copy of the physical chunk underlying the ChunkRef.
  209. /// </summary>
  210. /// <returns>A copy of the physical Chunk object.</returns>
  211. /*public Chunk GetChunkCopy ()
  212. {
  213. return GetChunk().Copy();
  214. }*/
  215. /// <summary>
  216. /// Returns the reference of the physical chunk underlying the ChunkRef, and releases the reference from itself.
  217. /// </summary>
  218. /// <remarks>
  219. /// This function returns the reference to the chunk stored in the chunk container. Because the ChunkRef simultaneously gives up
  220. /// its "ownership" of the Chunk, the container will not consider the Chunk dirty even if it is modified. Attempting to use the ChunkRef after
  221. /// releasing its internal reference will query the container for a new reference. If the chunk is still cached, it will get the same reference
  222. /// back, otherwise it will get an independent copy. Chunks should only be taken from ChunkRefs to transfer them to another ChunkRef, or
  223. /// to modify them without intending to permanently store the changes.
  224. /// </remarks>
  225. /// <returns>The physical Chunk object underlying the ChunkRef</returns>
  226. public IChunk GetChunkRef ()
  227. {
  228. IChunk chunk = GetChunk();
  229. _chunk = null;
  230. _dirty = false;
  231. return chunk;
  232. }
  233. /// <summary>
  234. /// Replaces the underlying physical chunk with a different one, updating its physical location to reflect the ChunkRef.
  235. /// </summary>
  236. /// <remarks>
  237. /// Use this function to save chunks that have been created or manipulated independently of a container, or to
  238. /// move a physical chunk between locations within a container (by taking the reference from another ChunkRef).
  239. /// </remarks>
  240. /// <param name="chunk">Physical Chunk to store into the location represented by this ChunkRef.</param>
  241. public void SetChunkRef (IChunk chunk)
  242. {
  243. _chunk = chunk;
  244. _chunk.SetLocation(X, Z);
  245. _dirty = true;
  246. }
  247. /// <summary>
  248. /// Gets an internal Chunk reference from cache or queries the container for it.
  249. /// </summary>
  250. /// <returns>The ChunkRef's underlying Chunk.</returns>
  251. private IChunk GetChunk ()
  252. {
  253. if (_chunk == null) {
  254. _chunk = _container.GetChunk(_cx, _cz);
  255. if (_chunk != null)
  256. {
  257. _blocks = _chunk.Blocks;
  258. _biomes = _chunk.Biomes;
  259. _entities = _chunk.Entities;
  260. // Set callback functions in the underlying block collection
  261. _blocks.ResolveNeighbor += ResolveNeighborHandler;
  262. _blocks.TranslateCoordinates += TranslateCoordinatesHandler;
  263. }
  264. }
  265. return _chunk;
  266. }
  267. /// <summary>
  268. /// Callback function to return the block collection of a ChunkRef at a relative offset to this one.
  269. /// </summary>
  270. /// <param name="relx">Relative offset from the X-coordinate.</param>
  271. /// <param name="rely">Relative offset from the Y-coordinate.</param>
  272. /// <param name="relz">Relative offset from the Z-coordinate.</param>
  273. /// <returns>Another ChunkRef's underlying block collection, or null if the ChunkRef cannot be found.</returns>
  274. private AlphaBlockCollection ResolveNeighborHandler (int relx, int rely, int relz)
  275. {
  276. ChunkRef cr = _container.GetChunkRef(_cx + relx, _cz + relz);
  277. if (cr != null) {
  278. return cr.Blocks;
  279. }
  280. return null;
  281. }
  282. /// <summary>
  283. /// Translates chunk-local block coordinates to corresponding global coordinates.
  284. /// </summary>
  285. /// <param name="lx">Chunk-local X-coordinate.</param>
  286. /// <param name="ly">Chunk-local Y-coordinate.</param>
  287. /// <param name="lz">Chunk-local Z-coordinate.</param>
  288. /// <returns>BlockKey containing the global block coordinates.</returns>
  289. private BlockKey TranslateCoordinatesHandler (int lx, int ly, int lz)
  290. {
  291. int x = X * _blocks.XDim + lx;
  292. int z = Z * _blocks.ZDim + lz;
  293. return new BlockKey(x, ly, z);
  294. }
  295. }
  296. }