2 using System.Collections.Generic;
3 using System.Globalization;
6 using System.Reflection;
10 using Newtonsoft.Json.Linq;
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;
22 public class JsonGenerator
24 private ICoreClientAPI ClientAPI { get; set; }
25 private ILogger Logger { get; set; }
26 private string Path { get; set; }
27 private readonly int chunkSize;
29 internal JArray ColumnMeta_Names, PointsOfInterest_Names, EntitiesOfInterest_Names;
30 internal MemberInfo[] ColumnMeta_Vals, PointsOfInterest_Vals, EntitiesOfInterest_Vals;
32 public JsonGenerator(ICoreClientAPI _ClientAPI, ILogger _Logger, string _path)
34 this.ClientAPI = _ClientAPI;
35 this.Logger = _Logger;
37 this.chunkSize = ClientAPI.World.BlockAccessor.ChunkSize;
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");
50 /// Generates the JSON Metadata. (in Map object format )
52 public void GenerateJSONMetadata(ColumnsMetadata chunkTopMetadata, Vec2i startChunkColumn, PointsOfInterest POIs, EntitiesOfInterest EOIs, Dictionary<int, string> RockIdCodes)
54 //Console.WriteLine($"53 {chunkTopMetadata.Count}");
55 string jsonFilename = System.IO.Path.Combine(Path, "Metadata.js");
57 StreamWriter stream = new StreamWriter(jsonFilename, false, Encoding.UTF8);
61 JsonTextWriter jsonWriter = new JsonTextWriter(stream);
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;
73 jsonWriter.WriteRaw("ViewFrame.chunks=");
74 jsonWriter.WriteStartObject();
75 jsonWriter.WriteKeyValue("worldSeedNum", ClientAPI.World.Seed);
77 jsonWriter.WriteKeyValue("genTime", DateTimeOffset.UtcNow);
79 jsonWriter.WriteKeyRawValue("startCoords", $"[{startChunkColumn.X},{startChunkColumn.Y}]");
81 jsonWriter.WriteKeyValue("chunkSize", chunkSize);
83 jsonWriter.WriteArray("edges", new int[]{
84 chunkTopMetadata.North_mostChunk,
85 chunkTopMetadata.East_mostChunk,
86 chunkTopMetadata.South_mostChunk,
87 chunkTopMetadata.West_mostChunk });
89 jsonWriter.WriteArray("chunkMetadataNames", ColumnMeta_Names);
91 jsonWriter.WriteArray("pointsOfInterestNames", PointsOfInterest_Names);
93 jsonWriter.WriteArray("entityOfInterestNames", EntitiesOfInterest_Names);
95 //MAP object format - [key, value]: key is "x_y"
96 jsonWriter.WriteMapForeach("chunkMetadata", chunkTopMetadata, (shard) =>
98 //Console.WriteLine($"188 {chunkTopMetadata.Count}");
99 jsonWriter.WriteMapTupleForeach(
100 $"{shard.Location.X}_{shard.Location.Y}",
104 var val = GetValue(mem, shard);
105 if (IsFloatingType(val))
106 jsonWriter.WriteValue($"{val:F3}");
107 else if (IsIntegralType(val))
108 jsonWriter.WriteValue($"{val}");
110 jsonWriter.WriteValue(val);
115 jsonWriter.WriteWhitespace("\n");
117 jsonWriter.WriteMapForeach("pointsOfInterest", POIs, (poi) =>
119 jsonWriter.WriteMapTupleForeach(
120 $"{poi.Location.X}_{poi.Location.Z}",
121 PointsOfInterest_Vals,
123 var dasField = GetValue(mem, poi);
124 jsonWriter.WriteRawValue(JsonConvert.SerializeObject(dasField));
129 jsonWriter.WriteWhitespace("\n");
131 jsonWriter.WriteMapForeach("entityOfInterest", EOIs, (poi) =>
133 jsonWriter.WriteMapTupleForeach(
134 $"{poi.Location.X}_{poi.Location.Z}",
135 EntitiesOfInterest_Vals,
136 (el) => jsonWriter.WriteValue(GetValue(el, poi))
140 jsonWriter.WriteWhitespace("\n");
142 jsonWriter.WriteWhitespace("\n");
143 jsonWriter.WriteComment("============= BlockID's for Rockmap / Rock-ratios ===============");
144 jsonWriter.WriteWhitespace("\n");
146 jsonWriter.WriteMapForeach("rockLookup", RockIdCodes, (rock) =>
148 var block = ClientAPI.World.GetBlock(rock.Key);
149 jsonWriter.WriteMapTuple(rock.Key.ToString(), Lang.GetUnformatted(block.Code.Path));
151 jsonWriter.WriteEndObject();
152 jsonWriter.WriteRaw(";");
161 internal JArray Dynamic_Names<TData>() where TData : struct
163 Dictionary<byte, string> memberNames = new Dictionary<byte, string>();
165 foreach (var memberInfo in typeof(TData).GetMembers(BindingFlags.Instance | BindingFlags.Public))
167 DisplayNameAttribute displayName = memberInfo.GetCustomAttribute<DisplayNameAttribute>();
168 if (displayName != null)
170 if (!memberNames.ContainsKey(displayName.order))
171 {//No duplicates, no overwrites
172 memberNames.Add(displayName.order, displayName.name);
177 return new JArray(memberNames.OrderBy(kf => kf.Key).Select(kf => kf.Value).ToArray());
180 internal MemberInfo[] Dynamic_Values<TData>() where TData : struct
182 Dictionary<byte, MemberInfo> memberVals = new Dictionary<byte, MemberInfo>();
184 foreach (var memberInfo in typeof(TData).GetMembers(BindingFlags.Instance | BindingFlags.Public))
186 DisplayNameAttribute displayName = memberInfo.GetCustomAttribute<DisplayNameAttribute>();
187 if (displayName != null && !memberVals.ContainsKey(displayName.order))
189 memberVals.Add(displayName.order, memberInfo);
193 return memberVals.OrderBy(kf => kf.Key).Select(kf => kf.Value).ToArray();
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);
203 throw new Exception("Property must be of type FieldInfo or PropertyInfo");
206 internal static bool IsFloatingType(object o)
208 if (o == null) return false;
209 switch (Type.GetTypeCode(o.GetType()))
211 case TypeCode.Decimal:
212 case TypeCode.Double:
213 case TypeCode.Single:
220 internal static bool IsIntegralType(object o)
222 if (o == null) return false;
223 switch (Type.GetTypeCode(o.GetType()))
227 case TypeCode.UInt16:
228 case TypeCode.UInt32:
229 case TypeCode.UInt64:
240 public static class JsonWriterExtentions
244 /// Writes an array in the form of key: [...ar] by calling .ToString() on all elements in ar.
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)
251 writer.WritePropertyName(key);
252 writer.WriteStartArray();
253 foreach (var el in ar)
255 writer.WriteValue(el);
257 writer.WriteEndArray();
262 /// Like WriteArray(string, object[]) but for JArrays.
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)
269 writer.WritePropertyName(key);
274 /// Easy extention to write JArrays.
276 /// <param name="writer"></param>
277 /// <param name="ar"></param>
278 public static void WriteValue(this JsonTextWriter writer, JArray ar)
283 public static void WriteKeyValue(this JsonTextWriter writer, string key, object value)
285 writer.WritePropertyName(key);
286 writer.WriteValue(value);
289 public static void WriteKeyRawValue(this JsonTextWriter writer, string key, string value)
291 writer.WritePropertyName(key);
292 writer.WriteRawValue(value);
296 /// Writes a Map by calling middle in the middle of the Map values array.
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)
303 writer.WritePropertyName(key);
304 writer.WriteStartConstructor("Map");
305 writer.WriteStartArray();
307 writer.WriteEndArray();
308 writer.WriteEndConstructor();
312 /// Writes a Map by calling middle on every element in en.
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)
321 writer.WritePropertyName(key);
322 writer.WriteStartConstructor("Map");
323 writer.WriteStartArray();
324 foreach (var el in en)
328 writer.WriteEndArray();
329 writer.WriteEndConstructor();
333 /// Writes a Map tuple in the form of [key, value].
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)
340 writer.WriteStartArray();
341 writer.WriteValue(key);
342 writer.WriteValue(value);
343 writer.WriteEndArray();
347 /// Writes a Map tuple in the form of [key, [val, val]]. Where each val is given by the passed function.
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)
354 writer.WriteStartArray(); // start tuple
355 writer.WriteValue(key);
356 writer.WriteStartArray(); // start val
357 foreach (var el in en)
361 writer.WriteEndArray(); // end val
362 writer.WriteEndArray(); // end tuple