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}]");
80 jsonWriter.WriteKeyRawValue("defaultSpawnPos", $"[{ClientAPI.World.DefaultSpawnPosition.AsBlockPos.X},{ClientAPI.World.DefaultSpawnPosition.AsBlockPos.Y},{ClientAPI.World.DefaultSpawnPosition.AsBlockPos.Z}]" );
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 if (Type.GetTypeCode(mem.GetType( )) == TypeCode.String) {
125 string dasString = dasField as string;
126 jsonWriter.WriteValue(dasString.Replace('\'', ' '));
128 else { jsonWriter.WriteRawValue(JsonConvert.SerializeObject(dasField)); }
133 jsonWriter.WriteWhitespace("\n");
135 jsonWriter.WriteMapForeach("entityOfInterest", EOIs, (poi) =>
137 jsonWriter.WriteMapTupleForeach(
138 $"{poi.Location.X}_{poi.Location.Z}",
139 EntitiesOfInterest_Vals,
140 (el) => jsonWriter.WriteValue(GetValue(el, poi))
144 jsonWriter.WriteWhitespace("\n");
146 jsonWriter.WriteWhitespace("\n");
147 jsonWriter.WriteComment("============= BlockID's for Rockmap / Rock-ratios ===============");
148 jsonWriter.WriteWhitespace("\n");
150 jsonWriter.WriteMapForeach("rockLookup", RockIdCodes, (rock) =>
152 var block = ClientAPI.World.GetBlock(rock.Key);
153 jsonWriter.WriteMapTuple(rock.Key.ToString(), Lang.GetUnformatted(block.Code.Path));
155 jsonWriter.WriteEndObject();
156 jsonWriter.WriteRaw(";");
165 internal JArray Dynamic_Names<TData>() where TData : struct
167 Dictionary<byte, string> memberNames = new Dictionary<byte, string>();
169 foreach (var memberInfo in typeof(TData).GetMembers(BindingFlags.Instance | BindingFlags.Public))
171 DisplayNameAttribute displayName = memberInfo.GetCustomAttribute<DisplayNameAttribute>();
172 if (displayName != null)
174 if (!memberNames.ContainsKey(displayName.order))
175 {//No duplicates, no overwrites
176 memberNames.Add(displayName.order, displayName.name);
181 return new JArray(memberNames.OrderBy(kf => kf.Key).Select(kf => kf.Value).ToArray());
184 internal MemberInfo[] Dynamic_Values<TData>() where TData : struct
186 Dictionary<byte, MemberInfo> memberVals = new Dictionary<byte, MemberInfo>();
188 foreach (var memberInfo in typeof(TData).GetMembers(BindingFlags.Instance | BindingFlags.Public))
190 DisplayNameAttribute displayName = memberInfo.GetCustomAttribute<DisplayNameAttribute>();
191 if (displayName != null && !memberVals.ContainsKey(displayName.order))
193 memberVals.Add(displayName.order, memberInfo);
197 return memberVals.OrderBy(kf => kf.Key).Select(kf => kf.Value).ToArray();
200 internal static object GetValue(MemberInfo member, object property)
201 { // copied from https://stackoverflow.com/questions/12680341/how-to-get-both-fields-and-properties-in-single-call-via-reflection
202 if (member.MemberType == MemberTypes.Property)
203 return ((PropertyInfo) member).GetValue(property, null);
204 else if (member.MemberType == MemberTypes.Field)
205 return ((FieldInfo) member).GetValue(property);
207 throw new Exception("Property must be of type FieldInfo or PropertyInfo");
210 internal static bool IsFloatingType(object o)
212 if (o == null) return false;
213 switch (Type.GetTypeCode(o.GetType()))
215 case TypeCode.Decimal:
216 case TypeCode.Double:
217 case TypeCode.Single:
224 internal static bool IsIntegralType(object o)
226 if (o == null) return false;
227 switch (Type.GetTypeCode(o.GetType()))
231 case TypeCode.UInt16:
232 case TypeCode.UInt32:
233 case TypeCode.UInt64:
244 public static class JsonWriterExtentions
248 /// Writes an array in the form of key: [...ar] by calling .ToString() on all elements in ar.
250 /// <param name="writer"></param>
251 /// <param name="key"></param>
252 /// <param name="ar"></param>
253 public static void WriteArray<T>(this JsonTextWriter writer, string key, T[] ar)
255 writer.WritePropertyName(key);
256 writer.WriteStartArray();
257 foreach (var el in ar)
259 writer.WriteValue(el);
261 writer.WriteEndArray();
266 /// Like WriteArray(string, object[]) but for JArrays.
268 /// <param name="writer"></param>
269 /// <param name="key"></param>
270 /// <param name="ar"></param>
271 public static void WriteArray(this JsonTextWriter writer, string key, JArray ar)
273 writer.WritePropertyName(key);
278 /// Easy extention to write JArrays.
280 /// <param name="writer"></param>
281 /// <param name="ar"></param>
282 public static void WriteValue(this JsonTextWriter writer, JArray ar)
287 public static void WriteKeyValue(this JsonTextWriter writer, string key, object value)
289 writer.WritePropertyName(key);
290 writer.WriteValue(value);
293 public static void WriteKeyRawValue(this JsonTextWriter writer, string key, string value)
295 writer.WritePropertyName(key);
296 writer.WriteRawValue(value);
300 /// Writes a Map by calling middle in the middle of the Map values array.
302 /// <param name="writer"></param>
303 /// <param name="key"></param>
304 /// <param name="middle"></param>
305 public static void WriteMap(this JsonTextWriter writer, string key, System.Action middle)
307 writer.WritePropertyName(key);
308 writer.WriteStartConstructor("Map");
309 writer.WriteStartArray();
311 writer.WriteEndArray();
312 writer.WriteEndConstructor();
316 /// Writes a Map by calling middle on every element in en.
318 /// <typeparam name="T"></typeparam>
319 /// <param name="writer"></param>
320 /// <param name="key"></param>
321 /// <param name="en"></param>
322 /// <param name="middle"></param>
323 public static void WriteMapForeach<T>(this JsonTextWriter writer, string key, IEnumerable<T> en, System.Action<T> middle)
325 writer.WritePropertyName(key);
326 writer.WriteStartConstructor("Map");
327 writer.WriteStartArray();
328 foreach (var el in en)
332 writer.WriteEndArray();
333 writer.WriteEndConstructor();
337 /// Writes a Map tuple in the form of [key, value].
339 /// <param name="writer"></param>
340 /// <param name="key"></param>
341 /// <param name="value"></param>
342 public static void WriteMapTuple(this JsonTextWriter writer, string key, string value)
344 writer.WriteStartArray();
345 writer.WriteValue(key);
346 writer.WriteValue(value);
347 writer.WriteEndArray();
351 /// Writes a Map tuple in the form of [key, [val, val]]. Where each val is given by the passed function.
353 /// <param name="writer"></param>
354 /// <param name="key"></param>
355 /// <param name="middle"></param>
356 public static void WriteMapTupleForeach<T>(this JsonTextWriter writer, string key, IEnumerable<T> en, System.Action<T> middle)
358 writer.WriteStartArray(); // start tuple
359 writer.WriteValue(key);
360 writer.WriteStartArray(); // start val
361 foreach (var el in en)
365 writer.WriteEndArray(); // end val
366 writer.WriteEndArray(); // end tuple