OSDN Git Service

3d0a01a8d839dca3707e5a321f31c43cefbaf2dc
[automap/automap.git] / Automap / Subsystems / JsonGenerator.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Globalization;
4 using System.IO;
5 using System.Linq;
6 using System.Reflection;
7 using System.Text;
8
9 using Newtonsoft.Json;
10 using Newtonsoft.Json.Linq;
11
12 using Vintagestory.API.Client;
13 using Vintagestory.API.Common;
14 using Vintagestory.API.Config;
15 using Vintagestory.API.Datastructures;
16 using Vintagestory.API.MathTools;
17 using Vintagestory.Common;
18
19
20 namespace Automap
21 {
22         public class JsonGenerator
23         {
24                 private ICoreClientAPI ClientAPI { get; set; }
25                 private ILogger Logger { get; set; }
26                 private string Path { get; set; }
27                 private readonly int chunkSize;
28
29                 internal JArray ColumnMeta_Names, PointsOfInterest_Names, EntitiesOfInterest_Names;
30                 internal MemberInfo[] ColumnMeta_Vals, PointsOfInterest_Vals, EntitiesOfInterest_Vals;
31
32                 public JsonGenerator(ICoreClientAPI _ClientAPI, ILogger _Logger, string _path)
33                 {
34                         this.ClientAPI = _ClientAPI;
35                         this.Logger = _Logger;
36                         this.Path = _path;
37                         this.chunkSize = ClientAPI.World.BlockAccessor.ChunkSize;
38
39                         ColumnMeta_Names = Dynamic_Names<ColumnMeta>();
40                         ColumnMeta_Vals = Dynamic_Values<ColumnMeta>();
41                         PointsOfInterest_Names = Dynamic_Names<PointOfInterest>();
42                         PointsOfInterest_Vals = Dynamic_Values<PointOfInterest>();
43                         EntitiesOfInterest_Names = Dynamic_Names<EntityOfInterest>();
44                         EntitiesOfInterest_Vals = Dynamic_Values<EntityOfInterest>();
45                         Logger.VerboseDebug("JSON Ready");
46                 }
47
48
49                 /// <summary>
50                 /// Generates the JSON Metadata. (in Map object format )
51                 /// </summary>
52                 public void GenerateJSONMetadata(ColumnsMetadata chunkTopMetadata, Vec2i startChunkColumn, PointsOfInterest POIs, EntitiesOfInterest EOIs, Dictionary<int, string> RockIdCodes)
53                 {
54                         //Console.WriteLine($"53 {chunkTopMetadata.Count}");
55                         string jsonFilename = System.IO.Path.Combine(Path, "Metadata.js");
56
57                         StreamWriter stream = new StreamWriter(jsonFilename, false, Encoding.UTF8);
58
59                         using (stream)
60                         {
61                                 JsonTextWriter jsonWriter = new JsonTextWriter(stream);
62
63                                 jsonWriter.Formatting = Formatting.None;
64                                 jsonWriter.StringEscapeHandling = StringEscapeHandling.EscapeHtml;
65                                 jsonWriter.Indentation = 0;
66                                 //jsonWriter.AutoCompleteOnClose = true;
67                                 jsonWriter.QuoteChar = '\'';
68                                 jsonWriter.DateFormatHandling = DateFormatHandling.IsoDateFormat;
69                                 jsonWriter.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
70
71                                 using (jsonWriter)
72                                 {
73                                         jsonWriter.WriteRaw("ViewFrame.chunks=");
74                                         jsonWriter.WriteStartObject();
75                                         jsonWriter.WriteKeyValue("worldSeedNum", ClientAPI.World.Seed);
76
77                                         jsonWriter.WriteKeyValue("genTime", DateTimeOffset.UtcNow);
78
79                                         jsonWriter.WriteKeyRawValue("startCoords", $"[{startChunkColumn.X},{startChunkColumn.Y}]");
80
81                                         jsonWriter.WriteKeyValue("chunkSize", chunkSize);
82
83                                         jsonWriter.WriteArray("edges", new int[]{
84                                         chunkTopMetadata.North_mostChunk,
85                                         chunkTopMetadata.East_mostChunk,
86                                         chunkTopMetadata.South_mostChunk,
87                                         chunkTopMetadata.West_mostChunk });
88
89                                         jsonWriter.WriteArray("chunkMetadataNames", ColumnMeta_Names);
90
91                                         jsonWriter.WriteArray("pointsOfInterestNames", PointsOfInterest_Names);
92
93                                         jsonWriter.WriteArray("entityOfInterestNames", EntitiesOfInterest_Names);
94
95                                         //MAP object format - [key, value]: key is "x_y"
96                                         jsonWriter.WriteMapForeach("chunkMetadata", chunkTopMetadata, (shard) =>
97                                         {
98                                                 //Console.WriteLine($"188 {chunkTopMetadata.Count}");
99                                                 jsonWriter.WriteMapTupleForeach(
100                                                         $"{shard.Location.X}_{shard.Location.Y}",
101                                                         ColumnMeta_Vals,
102                                                         (mem) =>
103                                                         {
104                                                                 var val = GetValue(mem, shard);
105                                                                 if (IsFloatingType(val))
106                                                                         jsonWriter.WriteValue($"{val:F3}");
107                                                                 else if (IsIntegralType(val))
108                                                                         jsonWriter.WriteValue($"{val}");
109                                                                 else
110                                                                         jsonWriter.WriteValue(val);
111                                                         }
112                                                 );
113                                         });
114 #if DEBUG
115                                         jsonWriter.WriteWhitespace("\n");
116 #endif
117                                         jsonWriter.WriteMapForeach("pointsOfInterest", POIs, (poi) =>
118                                         {
119                                                 jsonWriter.WriteMapTupleForeach(
120                                                         $"{poi.Location.X}_{poi.Location.Z}",
121                                                         PointsOfInterest_Vals,
122                                                         (mem) => {
123                                                                 var dasField = GetValue(mem, poi);
124                                                                 jsonWriter.WriteRawValue(JsonConvert.SerializeObject(dasField));
125                                                         }
126                                                 );
127                                         });
128 #if DEBUG
129                                         jsonWriter.WriteWhitespace("\n");
130 #endif
131                                         jsonWriter.WriteMapForeach("entityOfInterest", EOIs, (poi) =>
132                                         {
133                                                 jsonWriter.WriteMapTupleForeach(
134                                                         $"{poi.Location.X}_{poi.Location.Z}",
135                                                         EntitiesOfInterest_Vals,
136                                                         (el) => jsonWriter.WriteValue(GetValue(el, poi))
137                                                 );
138                                         });
139 #if DEBUG
140                                         jsonWriter.WriteWhitespace("\n");
141 #endif
142                                         jsonWriter.WriteWhitespace("\n");
143                                         jsonWriter.WriteComment("============= BlockID's for Rockmap / Rock-ratios ===============");
144                                         jsonWriter.WriteWhitespace("\n");
145
146                                         jsonWriter.WriteMapForeach("rockLookup", RockIdCodes, (rock) =>
147                                         {
148                                                 var block = ClientAPI.World.GetBlock(rock.Key);
149                                                 jsonWriter.WriteMapTuple(rock.Key.ToString(), Lang.GetUnformatted(block.Code.Path));
150                                         });
151                                         jsonWriter.WriteEndObject();
152                                         jsonWriter.WriteRaw(";");
153
154                                         jsonWriter.Flush();
155                                 }
156                         }
157
158                 }
159
160
161                 internal JArray Dynamic_Names<TData>() where TData : struct
162                 {
163                         Dictionary<byte, string> memberNames = new Dictionary<byte, string>();
164
165                         foreach (var memberInfo in typeof(TData).GetMembers(BindingFlags.Instance | BindingFlags.Public))
166                         {
167                                 DisplayNameAttribute displayName = memberInfo.GetCustomAttribute<DisplayNameAttribute>();
168                                 if (displayName != null)
169                                 {
170                                         if (!memberNames.ContainsKey(displayName.order))
171                                         {//No duplicates, no overwrites
172                                                 memberNames.Add(displayName.order, displayName.name);
173                                         }
174                                 }
175                         }
176
177                         return new JArray(memberNames.OrderBy(kf => kf.Key).Select(kf => kf.Value).ToArray());
178                 }
179
180                 internal MemberInfo[] Dynamic_Values<TData>() where TData : struct
181                 {
182                         Dictionary<byte, MemberInfo> memberVals = new Dictionary<byte, MemberInfo>();
183
184                         foreach (var memberInfo in typeof(TData).GetMembers(BindingFlags.Instance | BindingFlags.Public))
185                         {
186                                 DisplayNameAttribute displayName = memberInfo.GetCustomAttribute<DisplayNameAttribute>();
187                                 if (displayName != null && !memberVals.ContainsKey(displayName.order))
188                                 {
189                                         memberVals.Add(displayName.order, memberInfo);
190                                 }
191                         }
192
193                         return memberVals.OrderBy(kf => kf.Key).Select(kf => kf.Value).ToArray();
194                 }
195
196                 internal static object GetValue(MemberInfo member, object property)
197                 { // copied from https://stackoverflow.com/questions/12680341/how-to-get-both-fields-and-properties-in-single-call-via-reflection
198                         if (member.MemberType == MemberTypes.Property)
199                                 return ((PropertyInfo) member).GetValue(property, null);
200                         else if (member.MemberType == MemberTypes.Field)
201                                 return ((FieldInfo) member).GetValue(property);
202                         else
203                                 throw new Exception("Property must be of type FieldInfo or PropertyInfo");
204                 }
205
206                 internal static bool IsFloatingType(object o)
207                 {
208                         if (o == null) return false;
209                         switch (Type.GetTypeCode(o.GetType()))
210                         {
211                                 case TypeCode.Decimal:
212                                 case TypeCode.Double:
213                                 case TypeCode.Single:
214                                         return true;
215                                 default:
216                                         return false;
217                         }
218                 }
219
220                 internal static bool IsIntegralType(object o)
221                 {
222                         if (o == null) return false;
223                         switch (Type.GetTypeCode(o.GetType()))
224                         {
225                                 case TypeCode.Byte:
226                                 case TypeCode.SByte:
227                                 case TypeCode.UInt16:
228                                 case TypeCode.UInt32:
229                                 case TypeCode.UInt64:
230                                 case TypeCode.Int16:
231                                 case TypeCode.Int32:
232                                 case TypeCode.Int64:
233                                         return true;
234                                 default:
235                                         return false;
236                         }
237                 }
238         }
239
240         public static class JsonWriterExtentions
241         {
242                 
243                 /// <summary>
244                 /// Writes an array in the form of key: [...ar] by calling .ToString() on all elements in ar.
245                 /// </summary>
246                 /// <param name="writer"></param>
247                 /// <param name="key"></param>
248                 /// <param name="ar"></param>
249                 public static void WriteArray<T>(this JsonTextWriter writer, string key, T[] ar)
250                 {
251                         writer.WritePropertyName(key);
252                         writer.WriteStartArray();
253                         foreach (var el in ar)
254                         {
255                                 writer.WriteValue(el);
256                         }
257                         writer.WriteEndArray();
258                 }
259
260
261                 /// <summary>
262                 /// Like WriteArray(string, object[]) but for JArrays.
263                 /// </summary>
264                 /// <param name="writer"></param>
265                 /// <param name="key"></param>
266                 /// <param name="ar"></param>
267                 public static void WriteArray(this JsonTextWriter writer, string key, JArray ar)
268                 {
269                         writer.WritePropertyName(key);
270                         ar.WriteTo(writer);
271                 }
272
273                 /// <summary>
274                 /// Easy extention to write JArrays.
275                 /// </summary>
276                 /// <param name="writer"></param>
277                 /// <param name="ar"></param>
278                 public static void WriteValue(this JsonTextWriter writer, JArray ar)
279                 {
280                         ar.WriteTo(writer);
281                 }
282
283                 public static void WriteKeyValue(this JsonTextWriter writer, string key, object value)
284                 {
285                         writer.WritePropertyName(key);
286                         writer.WriteValue(value);
287                 }
288
289                 public static void WriteKeyRawValue(this JsonTextWriter writer, string key, string value)
290                 {
291                         writer.WritePropertyName(key);
292                         writer.WriteRawValue(value);
293                 }
294
295                 /// <summary>
296                 /// Writes a Map by calling middle in the middle of the Map values array.
297                 /// </summary>
298                 /// <param name="writer"></param>
299                 /// <param name="key"></param>
300                 /// <param name="middle"></param>
301                 public static void WriteMap(this JsonTextWriter writer, string key, System.Action middle)
302                 {
303                         writer.WritePropertyName(key);
304                         writer.WriteStartConstructor("Map");
305                         writer.WriteStartArray();
306                         middle();
307                         writer.WriteEndArray();
308                         writer.WriteEndConstructor();
309                 }
310
311                 /// <summary>
312                 /// Writes a Map by calling middle on every element in en.
313                 /// </summary>
314                 /// <typeparam name="T"></typeparam>
315                 /// <param name="writer"></param>
316                 /// <param name="key"></param>
317                 /// <param name="en"></param>
318                 /// <param name="middle"></param>
319                 public static void WriteMapForeach<T>(this JsonTextWriter writer, string key, IEnumerable<T> en, System.Action<T> middle)
320                 {
321                         writer.WritePropertyName(key);
322                         writer.WriteStartConstructor("Map");
323                         writer.WriteStartArray();
324                         foreach (var el in en)
325                         {
326                                 middle(el);
327                         }
328                         writer.WriteEndArray();
329                         writer.WriteEndConstructor();
330                 }
331
332                 /// <summary>
333                 /// Writes a Map tuple in the form of [key, value].
334                 /// </summary>
335                 /// <param name="writer"></param>
336                 /// <param name="key"></param>
337                 /// <param name="value"></param>
338                 public static void WriteMapTuple(this JsonTextWriter writer, string key, string value)
339                 {
340                         writer.WriteStartArray();
341                         writer.WriteValue(key);
342                         writer.WriteValue(value);
343                         writer.WriteEndArray();
344                 }
345
346                 /// <summary>
347                 /// Writes a Map tuple in the form of [key, [val, val]]. Where each val is given by the passed function.
348                 /// </summary>
349                 /// <param name="writer"></param>
350                 /// <param name="key"></param>
351                 /// <param name="middle"></param>
352                 public static void WriteMapTupleForeach<T>(this JsonTextWriter writer, string key, IEnumerable<T> en, System.Action<T> middle)
353                 {
354                         writer.WriteStartArray(); // start tuple
355                         writer.WriteValue(key);
356                         writer.WriteStartArray(); // start val
357                         foreach (var el in en)
358                         {
359                                 middle(el);
360                         }
361                         writer.WriteEndArray(); // end val
362                         writer.WriteEndArray(); // end tuple
363                 }
364         }
365 }
366