OSDN Git Service

1st attempt to fix Protocol buffer corruption issue
[automap/automap.git] / Automap / Data / ColumnMeta.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Collections.Specialized;
4 using System.Diagnostics;
5 using System.IO;
6 using System.Collections.ObjectModel;
7 using System.Text;
8
9 using Vintagestory.API.MathTools;
10 using Vintagestory.API.Common;
11 using Vintagestory.API.Client;
12
13 using ProtoBuf;
14
15 namespace Automap
16 {
17         [ProtoContract(ImplicitFields = ImplicitFields.None)]
18         public struct ColumnMeta
19         {
20                 [ProtoMember(1)]
21                 public Vec2i Location;
22
23                 [DisplayName(0, "Coords.")]
24                 [ProtoIgnore]
25                 public string PrettyLocation;
26
27                 [ProtoMember(2)]
28                 public TimeSpan ChunkAge;//OLDEST CHUNK. from chunk last edit
29
30                 [DisplayName(1, "Age")]
31                 [ProtoIgnore]
32                 public string ShortChunkAge { get => ChunkAge.ToString("c"); }
33
34                 [DisplayName(2, "Temp.")]
35                 [ProtoMember(3)]
36                 public float Temperature;// Temperature - surface
37
38                 [DisplayName(3, "Y Max.")]
39                 [ProtoMember(4)]
40                 public ushort YMax;// Y feature height
41
42                 [ProtoMember(5)]
43                 public Dictionary<int, uint> RockRatio;//[Column] Geographic region (rock) Ratio. [BlockID * count]
44
45                 //[DisplayName(10, "Rocks")]
46                 //public JArray FlatRocks
47                 //{
48                 //      get {
49                 //              string[] rocks = new string[this.RockRatio.Count];
50                 //              int i = 0;
51                 //              foreach (var roc in RockRatio)
52                 //              {
53                 //                      rocks[i++] = $"\"{roc.Key}\":\"{roc.Value}\"";
54                 //              }
55                 //              return new JArray(rocks);
56                 //      }
57                 //}
58
59
60                 [DisplayName(4, "Fert.")]
61                 [ProtoMember(6)]
62                 public float Fertility;
63
64                 //[DisplayName(5, "Forest")]
65                 [ProtoMember(7)]
66                 public float ForestDensity; // not given to client
67
68                 [DisplayName(6, "Rain")]
69                 [ProtoMember(8)]
70                 public float Rainfall;
71
72                 //[DisplayName(7, "Shrub")]
73                 [ProtoMember(9)]
74                 public float ShrubDensity; // not given to client
75
76                 [DisplayName(8, "Air blocks")]
77                 [ProtoMember(10)]
78                 public uint AirBlocks;
79
80                 [DisplayName(9, "Non-air")]
81                 [ProtoMember(11)]
82                 public uint NonAirBlocks;
83
84                 [ProtoMember(12)]
85                 public byte ChunkSize;
86
87
88                 [ProtoIgnore]
89                 public ushort[,] HeightMap;//Needs to be 'flattened' for Protocol-Buffer serialization
90
91                 [ProtoMember(13)]
92                 private ushort[] _flattened_HeightMap;
93
94                 public ColumnMeta(Vec2i loc, ICoreClientAPI clientAPI, byte chunkSize = 32)
95                 {
96                         Location = loc;
97                         PrettyLocation = loc.PrettyCoords(clientAPI);
98                         ChunkAge = TimeSpan.Zero;
99                         Temperature = 0f;
100                         YMax = 0;
101                         RockRatio = new Dictionary<int, uint>(10);
102                         Fertility = 0f;
103                         ForestDensity = 0f;
104                         Rainfall = 0f;
105                         ShrubDensity = 0f;
106                         AirBlocks = 0;
107                         NonAirBlocks = 0;
108                         ChunkSize = chunkSize;
109                         HeightMap = new ushort[ChunkSize, ChunkSize];
110                         _flattened_HeightMap = null;
111                 }
112
113                 internal void UpdateFieldsFrom(ClimateCondition climate, IMapChunk mapChunk, TimeSpan chunkAge)
114                 {
115                         this.ChunkAge = chunkAge;
116                         this.Temperature = climate.Temperature;
117                         this.Fertility = climate.Fertility;
118                         this.ForestDensity = climate.ForestDensity;
119                         this.Rainfall = climate.Rainfall;
120                         this.ShrubDensity = climate.ShrubDensity;
121
122                         this.YMax = mapChunk.YMax;
123                 }
124
125                 [ProtoBeforeSerialization]
126                 private void PrepareData()
127                 {
128
129                         if (HeightMap != null)
130                         {
131                                 _flattened_HeightMap = new ushort[ChunkSize * ChunkSize];
132                                 int flatIndex = 0;
133
134                                 for (byte col = 0; col < ChunkSize; col++)
135                                 {
136                                         for (byte row = 0; row < ChunkSize; row++)
137                                         {
138                                                 _flattened_HeightMap[flatIndex] = HeightMap[col, row];
139                                                 flatIndex++;
140                                         }
141                                 }
142
143                         }
144
145                 }
146
147
148                 [ProtoAfterDeserialization]
149                 private void PostProcess()
150                 {
151                         ChunkSize = (ChunkSize == byte.MinValue) ? (byte)32 : ChunkSize;//Not good - if chunk wasn't 32 orignally!
152
153                         if (this.HeightMap == null || this.HeightMap.Length != (ChunkSize * ChunkSize)) {
154                         this.HeightMap = new ushort[ChunkSize, ChunkSize];
155                         }
156
157                         if (_flattened_HeightMap != null)
158                         {
159                                 int col, row;
160                                 var bitMasker = new BitVector32(0);
161                                 var rowSection = BitVector32.CreateSection((short) (ChunkSize - 1));
162                                 var colSection = BitVector32.CreateSection((short) (ChunkSize - 1), rowSection);
163
164                                 for (uint rowcol = 0; rowcol < (ChunkSize * ChunkSize); rowcol++)
165                                 {
166                                         bitMasker = new BitVector32(data: (int) rowcol);
167                                         row = bitMasker[rowSection];
168                                         col = bitMasker[colSection];
169                                         HeightMap[col, row] = _flattened_HeightMap[rowcol];
170                                 }
171
172                         }
173
174                 }
175
176
177                 internal ColumnMeta Reload(ICoreClientAPI clientAPI)
178                 {
179                         this.PrettyLocation = Location.PrettyCoords(clientAPI);
180                         Debug.Write(PrettyLocation == null ? "*" : ",");
181                         return this;
182                 }
183         }
184
185         public class ColumnsMetadata : KeyedCollection<Vec2i, ColumnMeta>
186         {
187                 private ColumnsMetadata()
188                 {
189                         throw new NotSupportedException();
190                 }
191
192                 public ColumnsMetadata(Vec2i startChunkColumn)
193                 {
194                         North_mostChunk = startChunkColumn.Y;
195                         South_mostChunk = startChunkColumn.Y;
196                         East_mostChunk = startChunkColumn.X;
197                         West_mostChunk = startChunkColumn.X;
198                 }
199
200                 public int North_mostChunk
201                 {
202                         get; private set;
203                 }
204
205                 public int South_mostChunk
206                 {
207                         get; private set;
208                 }
209
210                 public int East_mostChunk
211                 {
212                         get; private set;
213                 }
214
215                 public int West_mostChunk
216                 {
217                         get; private set;
218                 }
219
220                 protected override Vec2i GetKeyForItem(ColumnMeta item)
221                 {
222                         return item.Location;
223                 }
224
225                 internal void Update(ColumnMeta metaData)
226                 {
227                         if (this.Contains(metaData.Location))
228                         {
229                                 this.Remove(metaData.Location);
230                                 this.Add(metaData);
231                         }
232                         else
233                         {
234                                 this.Add(metaData);
235                         }
236
237                 }
238
239                 public new void Add(ColumnMeta newItem)
240                 {
241                         if (North_mostChunk > newItem.Location.Y)
242                         {
243                                 North_mostChunk = newItem.Location.Y;
244                         }
245
246                         if (South_mostChunk < newItem.Location.Y)
247                         {
248                                 South_mostChunk = newItem.Location.Y;
249                         }
250
251                         if (East_mostChunk < newItem.Location.X)
252                         {
253                                 East_mostChunk = newItem.Location.X;
254                         }
255
256                         if (West_mostChunk > newItem.Location.X)
257                         {
258                                 West_mostChunk = newItem.Location.X;
259                         }
260
261                         base.Add(newItem);
262                 }
263
264                 public void ClearMetadata( )
265                 {
266                 for (int i = 0, maxItemsCount = this.Items.Count; i < maxItemsCount; i++) {
267                 ColumnMeta entry = this.Items[i];
268                 entry.HeightMap = null;
269                 entry.RockRatio = null;//Also regenerated when any chunk in a column is changed...
270                 }
271                 }
272
273         }
274 }