OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
TerrainData.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 using System;
29 using System.Collections.Generic;
30 using System.IO;
31 using System.IO.Compression;
32 using System.Reflection;
33 
34 using OpenMetaverse;
35 
36 using log4net;
37 
38 namespace OpenSim.Framework
39 {
40  public abstract class TerrainData
41  {
42  // Terrain always is a square
43  public int SizeX { get; protected set; }
44  public int SizeY { get; protected set; }
45  public int SizeZ { get; protected set; }
46 
47  // A height used when the user doesn't specify anything
48  public const float DefaultTerrainHeight = 21f;
49 
50  public abstract float this[int x, int y] { get; set; }
51  // Someday terrain will have caves
52  // at most holes :p
53  public abstract float this[int x, int y, int z] { get; set; }
54 
55  public abstract bool IsTaintedAt(int xx, int yy);
56  public abstract bool IsTaintedAt(int xx, int yy, bool clearOnTest);
57  public abstract void TaintAllTerrain();
58  public abstract void ClearTaint();
59 
60  public abstract void ClearLand();
61  public abstract void ClearLand(float height);
62 
63  // Return a representation of this terrain for storing as a blob in the database.
64  // Returns 'true' to say blob was stored in the 'out' locations.
65  public abstract bool GetDatabaseBlob(out int DBFormatRevisionCode, out Array blob);
66 
67  // Given a revision code and a blob from the database, create and return the right type of TerrainData.
68  // The sizes passed are the expected size of the region. The database info will be used to
69  // initialize the heightmap of that sized region with as much data is in the blob.
70  // Return created TerrainData or 'null' if unsuccessful.
71  public static TerrainData CreateFromDatabaseBlobFactory(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob)
72  {
73  // For the moment, there is only one implementation class
74  return new HeightmapTerrainData(pSizeX, pSizeY, pSizeZ, pFormatCode, pBlob);
75  }
76 
77  // return a special compressed representation of the heightmap in ushort
78  public abstract float[] GetCompressedMap();
79  public abstract float CompressionFactor { get; }
80 
81  public abstract float[] GetFloatsSerialized();
82  public abstract double[,] GetDoubles();
83  public abstract TerrainData Clone();
84  }
85 
86  // The terrain is stored in the database as a blob with a 'revision' field.
87  // Some implementations of terrain storage would fill the revision field with
88  // the time the terrain was stored. When real revisions were added and this
89  // feature removed, that left some old entries with the time in the revision
90  // field.
91  // Thus, if revision is greater than 'RevisionHigh' then terrain db entry is
92  // left over and it is presumed to be 'Legacy256'.
93  // Numbers are arbitrary and are chosen to to reduce possible mis-interpretation.
94  // If a revision does not match any of these, it is assumed to be Legacy256.
95  public enum DBTerrainRevision
96  {
97  // Terrain is 'double[256,256]'
98  Legacy256 = 11,
99 
100  // Terrain is 'int32, int32, float[,]' where the ints are X and Y dimensions
101  // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256.
102  Variable2D = 22,
103  Variable2DGzip = 23,
104 
105  // Terrain is 'int32, int32, int32, int16[]' where the ints are X and Y dimensions
106  // and third int is the 'compression factor'. The heights are compressed as
107  // "ushort compressedHeight = (ushort)(height * compressionFactor);"
108  // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256.
109  Compressed2D = 27,
110 
111  // A revision that is not listed above or any revision greater than this value is 'Legacy256'.
112  RevisionHigh = 1234
113  }
114 
115  // Version of terrain that is a heightmap.
116  // This should really be 'LLOptimizedHeightmapTerrainData' as it includes knowledge
117  // of 'patches' which are 16x16 terrain areas which can be sent separately to the viewer.
118  // The heighmap is kept as an array of ushorts. The ushort values are converted to
119  // and from floats by TerrainCompressionFactor.
121  {
122  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
123  private static string LogHeader = "[HEIGHTMAP TERRAIN DATA]";
124 
125  // TerrainData.this[x, y]
126  public override float this[int x, int y]
127  {
128  get { return m_heightmap[x, y]; }
129  set
130  {
131  if (m_heightmap[x, y] != value)
132  {
133  m_heightmap[x, y] = value;
134  m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize] = true;
135  }
136  }
137  }
138 
139  // TerrainData.this[x, y, z]
140  public override float this[int x, int y, int z]
141  {
142  get { return this[x, y]; }
143  set { this[x, y] = value; }
144  }
145 
146  // TerrainData.ClearTaint
147  public override void ClearTaint()
148  {
149  SetAllTaint(false);
150  }
151 
152  // TerrainData.TaintAllTerrain
153  public override void TaintAllTerrain()
154  {
155  SetAllTaint(true);
156  }
157 
158  private void SetAllTaint(bool setting)
159  {
160  for (int ii = 0; ii < m_taint.GetLength(0); ii++)
161  for (int jj = 0; jj < m_taint.GetLength(1); jj++)
162  m_taint[ii, jj] = setting;
163  }
164 
165  // TerrainData.ClearLand
166  public override void ClearLand()
167  {
168  ClearLand(DefaultTerrainHeight);
169  }
170  // TerrainData.ClearLand(float)
171  public override void ClearLand(float pHeight)
172  {
173  for (int xx = 0; xx < SizeX; xx++)
174  for (int yy = 0; yy < SizeY; yy++)
175  m_heightmap[xx, yy] = pHeight;
176  }
177 
178  // Return 'true' of the patch that contains these region coordinates has been modified.
179  // Note that checking the taint clears it.
180  // There is existing code that relies on this feature.
181  public override bool IsTaintedAt(int xx, int yy, bool clearOnTest)
182  {
183  int tx = xx / Constants.TerrainPatchSize;
184  int ty = yy / Constants.TerrainPatchSize;
185  bool ret = m_taint[tx, ty];
186  if (ret && clearOnTest)
187  m_taint[tx, ty] = false;
188  return ret;
189  }
190 
191  // Old form that clears the taint flag when we check it.
192  // ubit: this dangerus naming should be only check without clear
193  // keeping for old modules outthere
194  public override bool IsTaintedAt(int xx, int yy)
195  {
196  return IsTaintedAt(xx, yy, true /* clearOnTest */);
197  }
198 
199  // TerrainData.GetDatabaseBlob
200  // The user wants something to store in the database.
201  public override bool GetDatabaseBlob(out int DBRevisionCode, out Array blob)
202  {
203  bool ret = false;
204  if (SizeX == Constants.RegionSize && SizeY == Constants.RegionSize)
205  {
206  DBRevisionCode = (int)DBTerrainRevision.Legacy256;
207  blob = ToLegacyTerrainSerialization();
208  ret = true;
209  }
210  else
211  {
212  DBRevisionCode = (int)DBTerrainRevision.Variable2DGzip;
213 // DBRevisionCode = (int)DBTerrainRevision.Variable2D;
214  blob = ToCompressedTerrainSerializationV2DGzip();
215 // blob = ToCompressedTerrainSerializationV2D();
216  ret = true;
217  }
218  return ret;
219  }
220 
221  // TerrainData.CompressionFactor
222  private float m_compressionFactor = 100.0f;
223  public override float CompressionFactor { get { return m_compressionFactor; } }
224 
225  // TerrainData.GetCompressedMap
226  public override float[] GetCompressedMap()
227  {
228  float[] newMap = new float[SizeX * SizeY];
229 
230  int ind = 0;
231  for (int xx = 0; xx < SizeX; xx++)
232  for (int yy = 0; yy < SizeY; yy++)
233  newMap[ind++] = m_heightmap[xx, yy];
234 
235  return newMap;
236 
237  }
238  // TerrainData.Clone
239  public override TerrainData Clone()
240  {
241  HeightmapTerrainData ret = new HeightmapTerrainData(SizeX, SizeY, SizeZ);
242  ret.m_heightmap = (float[,])this.m_heightmap.Clone();
243  return ret;
244  }
245 
246  // TerrainData.GetFloatsSerialized
247  // This one dimensional version is ordered so height = map[y*sizeX+x];
248  // DEPRECATED: don't use this function as it does not retain the dimensions of the terrain
249  // and the caller will probably do the wrong thing if the terrain is not the legacy 256x256.
250  public override float[] GetFloatsSerialized()
251  {
252  int points = SizeX * SizeY;
253  float[] heights = new float[points];
254 
255  int idx = 0;
256  for (int jj = 0; jj < SizeY; jj++)
257  for (int ii = 0; ii < SizeX; ii++)
258  {
259  heights[idx++] = m_heightmap[ii, jj];
260  }
261 
262  return heights;
263  }
264 
265  // TerrainData.GetDoubles
266  public override double[,] GetDoubles()
267  {
268  double[,] ret = new double[SizeX, SizeY];
269  for (int xx = 0; xx < SizeX; xx++)
270  for (int yy = 0; yy < SizeY; yy++)
271  ret[xx, yy] = (double)m_heightmap[xx, yy];
272 
273  return ret;
274  }
275 
276 
277  // =============================================================
278 
279  private float[,] m_heightmap;
280  // Remember subregions of the heightmap that has changed.
281  private bool[,] m_taint;
282 
283  // that is coded as the float height times the compression factor (usually '100'
284  // to make for two decimal points).
285  public short ToCompressedHeightshort(float pHeight)
286  {
287  // clamp into valid range
288  pHeight *= CompressionFactor;
289  if (pHeight < short.MinValue)
290  return short.MinValue;
291  else if (pHeight > short.MaxValue)
292  return short.MaxValue;
293  return (short)pHeight;
294  }
295 
296  public ushort ToCompressedHeightushort(float pHeight)
297  {
298  // clamp into valid range
299  pHeight *= CompressionFactor;
300  if (pHeight < ushort.MinValue)
301  return ushort.MinValue;
302  else if (pHeight > ushort.MaxValue)
303  return ushort.MaxValue;
304  return (ushort)pHeight;
305  }
306 
307  public float FromCompressedHeight(short pHeight)
308  {
309  return ((float)pHeight) / CompressionFactor;
310  }
311 
312  public float FromCompressedHeight(ushort pHeight)
313  {
314  return ((float)pHeight) / CompressionFactor;
315  }
316 
317  // To keep with the legacy theme, create an instance of this class based on the
318  // way terrain used to be passed around.
319  public HeightmapTerrainData(double[,] pTerrain)
320  {
321  SizeX = pTerrain.GetLength(0);
322  SizeY = pTerrain.GetLength(1);
323  SizeZ = (int)Constants.RegionHeight;
324  m_compressionFactor = 100.0f;
325 
326  m_heightmap = new float[SizeX, SizeY];
327  for (int ii = 0; ii < SizeX; ii++)
328  {
329  for (int jj = 0; jj < SizeY; jj++)
330  {
331  m_heightmap[ii, jj] = (float)pTerrain[ii, jj];
332 
333  }
334  }
335  // m_log.DebugFormat("{0} new by doubles. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ);
336 
337  m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize];
338  ClearTaint();
339  }
340 
341  // Create underlying structures but don't initialize the heightmap assuming the caller will immediately do that
342  public HeightmapTerrainData(int pX, int pY, int pZ)
343  {
344  SizeX = pX;
345  SizeY = pY;
346  SizeZ = pZ;
347  m_compressionFactor = 100.0f;
348  m_heightmap = new float[SizeX, SizeY];
349  m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize];
350  // m_log.DebugFormat("{0} new by dimensions. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ);
351  ClearTaint();
352  ClearLand(0f);
353  }
354 
355  public HeightmapTerrainData(float[] cmap, float pCompressionFactor, int pX, int pY, int pZ)
356  : this(pX, pY, pZ)
357  {
358  m_compressionFactor = pCompressionFactor;
359  int ind = 0;
360  for (int xx = 0; xx < SizeX; xx++)
361  for (int yy = 0; yy < SizeY; yy++)
362  m_heightmap[xx, yy] = cmap[ind++];
363  // m_log.DebugFormat("{0} new by compressed map. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ);
364  }
365 
366  // Create a heighmap from a database blob
367  public HeightmapTerrainData(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob)
368  : this(pSizeX, pSizeY, pSizeZ)
369  {
370  switch ((DBTerrainRevision)pFormatCode)
371  {
372  case DBTerrainRevision.Variable2DGzip:
373  FromCompressedTerrainSerializationV2DGZip(pBlob);
374  m_log.DebugFormat("{0} HeightmapTerrainData create from Variable2DGzip serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY);
375  break;
376 
377  case DBTerrainRevision.Variable2D:
378  FromCompressedTerrainSerializationV2D(pBlob);
379  m_log.DebugFormat("{0} HeightmapTerrainData create from Variable2D serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY);
380  break;
381  case DBTerrainRevision.Compressed2D:
382  FromCompressedTerrainSerialization2D(pBlob);
383  m_log.DebugFormat("{0} HeightmapTerrainData create from Compressed2D serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY);
384  break;
385  default:
386  FromLegacyTerrainSerialization(pBlob);
387  m_log.DebugFormat("{0} HeightmapTerrainData create from legacy serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY);
388  break;
389  }
390  }
391 
392  // Just create an array of doubles. Presumes the caller implicitly knows the size.
394  {
395  Array ret = null;
396 
397  using (MemoryStream str = new MemoryStream((int)Constants.RegionSize * (int)Constants.RegionSize * sizeof(double)))
398  {
399  using (BinaryWriter bw = new BinaryWriter(str))
400  {
401  for (int xx = 0; xx < Constants.RegionSize; xx++)
402  {
403  for (int yy = 0; yy < Constants.RegionSize; yy++)
404  {
405  double height = this[xx, yy];
406  if (height == 0.0)
407  height = double.Epsilon;
408  bw.Write(height);
409  }
410  }
411  }
412  ret = str.ToArray();
413  }
414  return ret;
415  }
416 
417  // Presumes the caller implicitly knows the size.
418  public void FromLegacyTerrainSerialization(byte[] pBlob)
419  {
420  // In case database info doesn't match real terrain size, initialize the whole terrain.
421  ClearLand();
422 
423  try
424  {
425  using (MemoryStream mstr = new MemoryStream(pBlob))
426  {
427  using (BinaryReader br = new BinaryReader(mstr))
428  {
429  for (int xx = 0; xx < (int)Constants.RegionSize; xx++)
430  {
431  for (int yy = 0; yy < (int)Constants.RegionSize; yy++)
432  {
433  float val = (float)br.ReadDouble();
434 
435  if (xx < SizeX && yy < SizeY)
436  m_heightmap[xx, yy] = val;
437  }
438  }
439  }
440  }
441  }
442  catch
443  {
444  ClearLand();
445  }
446  ClearTaint();
447  }
448 
449 
450  // stores as variable2D
451  // int32 sizeX
452  // int32 sizeY
453  // float[,] array
454 
456  {
457  Array ret = null;
458  try
459  {
460  using (MemoryStream str = new MemoryStream((2 * sizeof(Int32)) + (SizeX * SizeY * sizeof(float))))
461  {
462  using (BinaryWriter bw = new BinaryWriter(str))
463  {
464  bw.Write((Int32)SizeX);
465  bw.Write((Int32)SizeY);
466  for (int yy = 0; yy < SizeY; yy++)
467  for (int xx = 0; xx < SizeX; xx++)
468  {
469  // reduce to 1cm resolution
470  float val = (float)Math.Round(m_heightmap[xx, yy],2,MidpointRounding.ToEven);
471  bw.Write(val);
472  }
473  }
474  ret = str.ToArray();
475  }
476  }
477  catch
478  {
479 
480  }
481 
482  m_log.DebugFormat("{0} V2D {1} bytes",
483  LogHeader, ret.Length);
484 
485  return ret;
486  }
487 
488  // as above with Gzip compression
490  {
491  Array ret = null;
492  try
493  {
494  using (MemoryStream inp = new MemoryStream((2 * sizeof(Int32)) + (SizeX * SizeY * sizeof(float))))
495  {
496  using (BinaryWriter bw = new BinaryWriter(inp))
497  {
498  bw.Write((Int32)SizeX);
499  bw.Write((Int32)SizeY);
500  for (int yy = 0; yy < SizeY; yy++)
501  for (int xx = 0; xx < SizeX; xx++)
502  {
503  bw.Write((float)m_heightmap[xx, yy]);
504  }
505 
506  bw.Flush();
507  inp.Seek(0, SeekOrigin.Begin);
508 
509  using (MemoryStream outputStream = new MemoryStream())
510  {
511  using (GZipStream compressionStream = new GZipStream(outputStream, CompressionMode.Compress))
512  {
513  inp.CopyStream(compressionStream, int.MaxValue);
514  compressionStream.Close();
515  ret = outputStream.ToArray();
516  }
517  }
518  }
519  }
520  }
521  catch
522  {
523 
524  }
525  m_log.DebugFormat("{0} V2DGzip {1} bytes",
526  LogHeader, ret.Length);
527  return ret;
528  }
529 
530  // Initialize heightmap from blob consisting of:
531  // int32, int32, int32, int32, int16[]
532  // where the first int32 is format code, next two int32s are the X and y of heightmap data and
533  // the forth int is the compression factor for the following int16s
534  // This is just sets heightmap info. The actual size of the region was set on this instance's
535  // creation and any heights not initialized by theis blob are set to the default height.
536  public void FromCompressedTerrainSerialization2D(byte[] pBlob)
537  {
538  Int32 hmFormatCode, hmSizeX, hmSizeY, hmCompressionFactor;
539 
540  using (MemoryStream mstr = new MemoryStream(pBlob))
541  {
542  using (BinaryReader br = new BinaryReader(mstr))
543  {
544  hmFormatCode = br.ReadInt32();
545  hmSizeX = br.ReadInt32();
546  hmSizeY = br.ReadInt32();
547  hmCompressionFactor = br.ReadInt32();
548 
549  m_compressionFactor = hmCompressionFactor;
550 
551  // In case database info doesn't match real terrain size, initialize the whole terrain.
552  ClearLand();
553 
554  for (int yy = 0; yy < hmSizeY; yy++)
555  {
556  for (int xx = 0; xx < hmSizeX; xx++)
557  {
558  float val = FromCompressedHeight(br.ReadInt16());
559  if (xx < SizeX && yy < SizeY)
560  m_heightmap[xx, yy] = val;
561  }
562  }
563  }
564  ClearTaint();
565 
566  m_log.DebugFormat("{0} Read (compressed2D) heightmap. Heightmap size=<{1},{2}>. Region size=<{3},{4}>. CompFact={5}",
567  LogHeader, hmSizeX, hmSizeY, SizeX, SizeY, hmCompressionFactor);
568  }
569  }
570 
571  // Initialize heightmap from blob consisting of:
572  // int32, int32, int32, float[]
573  // where the first int32 is format code, next two int32s are the X and y of heightmap data
574  // This is just sets heightmap info. The actual size of the region was set on this instance's
575  // creation and any heights not initialized by theis blob are set to the default height.
576  public void FromCompressedTerrainSerializationV2D(byte[] pBlob)
577  {
578  Int32 hmSizeX, hmSizeY;
579  try
580  {
581  using (MemoryStream mstr = new MemoryStream(pBlob))
582  {
583  using (BinaryReader br = new BinaryReader(mstr))
584  {
585  hmSizeX = br.ReadInt32();
586  hmSizeY = br.ReadInt32();
587 
588  // In case database info doesn't match real terrain size, initialize the whole terrain.
589  ClearLand();
590 
591  for (int yy = 0; yy < hmSizeY; yy++)
592  {
593  for (int xx = 0; xx < hmSizeX; xx++)
594  {
595  float val = br.ReadSingle();
596  if (xx < SizeX && yy < SizeY)
597  m_heightmap[xx, yy] = val;
598  }
599  }
600  }
601  }
602  }
603  catch (Exception e)
604  {
605  ClearTaint();
606  m_log.ErrorFormat("{0} 2D error: {1} - terrain may be damaged",
607  LogHeader, e.Message);
608  return;
609  }
610  ClearTaint();
611 
612  m_log.DebugFormat("{0} V2D Heightmap size=<{1},{2}>. Region size=<{3},{4}>",
613  LogHeader, hmSizeX, hmSizeY, SizeX, SizeY);
614 
615  }
616 
617  // as above but Gzip compressed
619  {
620  m_log.InfoFormat("{0} VD2Gzip {1} bytes input",
621  LogHeader, pBlob.Length);
622 
623  Int32 hmSizeX, hmSizeY;
624 
625  try
626  {
627  using (MemoryStream outputStream = new MemoryStream())
628  {
629  using (MemoryStream inputStream = new MemoryStream(pBlob))
630  {
631  using (GZipStream decompressionStream = new GZipStream(inputStream, CompressionMode.Decompress))
632  {
633  decompressionStream.Flush();
634  decompressionStream.CopyTo(outputStream);
635  }
636  }
637 
638  outputStream.Seek(0, SeekOrigin.Begin);
639 
640  using (BinaryReader br = new BinaryReader(outputStream))
641  {
642  hmSizeX = br.ReadInt32();
643  hmSizeY = br.ReadInt32();
644 
645  // In case database info doesn't match real terrain size, initialize the whole terrain.
646  ClearLand();
647 
648  for (int yy = 0; yy < hmSizeY; yy++)
649  {
650  for (int xx = 0; xx < hmSizeX; xx++)
651  {
652  float val = br.ReadSingle();
653  if (xx < SizeX && yy < SizeY)
654  m_heightmap[xx, yy] = val;
655  }
656  }
657  }
658  }
659  }
660  catch( Exception e)
661  {
662  ClearTaint();
663  m_log.ErrorFormat("{0} V2DGzip error: {1} - terrain may be damaged",
664  LogHeader, e.Message);
665  return;
666  }
667 
668  ClearTaint();
669  m_log.DebugFormat("{0} V2DGzip. Heightmap size=<{1},{2}>. Region size=<{3},{4}>",
670  LogHeader, hmSizeX, hmSizeY, SizeX, SizeY);
671 
672  }
673  }
674 }
HeightmapTerrainData(double[,] pTerrain)
Definition: TerrainData.cs:319
override bool IsTaintedAt(int xx, int yy)
Definition: TerrainData.cs:194
HeightmapTerrainData(float[] cmap, float pCompressionFactor, int pX, int pY, int pZ)
Definition: TerrainData.cs:355
short ToCompressedHeightshort(float pHeight)
Definition: TerrainData.cs:285
HeightmapTerrainData(int pX, int pY, int pZ)
Definition: TerrainData.cs:342
void FromCompressedTerrainSerialization2D(byte[] pBlob)
Definition: TerrainData.cs:536
float FromCompressedHeight(short pHeight)
Definition: TerrainData.cs:307
Ionic.Zlib.GZipStream GZipStream
ushort ToCompressedHeightushort(float pHeight)
Definition: TerrainData.cs:296
HeightmapTerrainData(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob)
Definition: TerrainData.cs:367
void FromCompressedTerrainSerializationV2D(byte[] pBlob)
Definition: TerrainData.cs:576
override bool GetDatabaseBlob(out int DBRevisionCode, out Array blob)
Definition: TerrainData.cs:201
float FromCompressedHeight(ushort pHeight)
Definition: TerrainData.cs:312
void FromCompressedTerrainSerializationV2DGZip(byte[] pBlob)
Definition: TerrainData.cs:618
void FromLegacyTerrainSerialization(byte[] pBlob)
Definition: TerrainData.cs:418
override bool IsTaintedAt(int xx, int yy, bool clearOnTest)
Definition: TerrainData.cs:181
Ionic.Zlib.CompressionMode CompressionMode
static TerrainData CreateFromDatabaseBlobFactory(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob)
Definition: TerrainData.cs:71
override void ClearLand(float pHeight)
Definition: TerrainData.cs:171