<Compile Include="AutomapMod.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Helpers.cs" />
- <Compile Include="Data\PointOfInterest.cs" />
- <Compile Include="Data\BlockDesignator.cs" />
- <Compile Include="Designators\DefaultDesignators.cs" />
- <Compile Include="Data\ColumnMeta.cs" />
+ <Compile Include="Data\PointOfInterest.cs" />
+ <Compile Include="Data\BlockDesignator.cs" />
+ <Compile Include="Data\EntitiesOfInterest.cs" />
+ <Compile Include="Data\EntityDesignator.cs" />
+ <Compile Include="Data\ColumnMeta.cs" />
<Compile Include="Data\PngMetadataChunk.cs" />
+ <Compile Include="Designators\DefaultDesignators.cs" />
<Compile Include="Subsystems\AutomapSystem.cs" />
<Compile Include="Subsystems\AutomapGUIDialog.cs" />
<Compile Include="Renderers\IChunkRenderer.cs" />
- <Compile Include="Renderers\StandardRenerer.cs" />
+ <Compile Include="Renderers\StandardRenderer.cs" />
<Compile Include="Renderers\AlternateRenderer.cs" />
- <Compile Include="Data\EntitiesOfInterest.cs" />
- <Compile Include="Data\EntityDesignator.cs" />
<Compile Include="Data\StatusData.cs" />
<Compile Include="Data\CommandData.cs" />
<Compile Include="Data\CommandType.cs" />
<Compile Include="Data\PersistedConfiguration.cs" />
+ <Compile Include="Data\DisplayNameAttribute.cs" />
+ <Compile Include="Subsystems\JsonGenerator.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="VS_libs\" />
namespace Automap
{
- public delegate void BlockDesignatonAction(ICoreClientAPI clientAPI, PointsOfInterest poi, BlockPos posn, Block block);
+ public delegate void BlockDesignatorAction(ICoreClientAPI clientAPI, PointsOfInterest poi, BlockPos posn, Block block);
/// <summary>
/// Point of Interest Rule Designator
public Color OverwriteColor;
[JsonIgnore]
- public BlockDesignatonAction SpecialAction;
+ public BlockDesignatorAction SpecialAction;
[JsonProperty]
public string SpecialActionName;
this.Enabled = true;
}
- public BlockDesignator(AssetLocation pattern, Color overwriteColor, EnumBlockMaterial? material, BlockDesignatonAction specialAct)
+ public BlockDesignator(AssetLocation pattern, Color overwriteColor, EnumBlockMaterial? material, BlockDesignatorAction specialAct)
{
this.Pattern = pattern;
this.OverwriteColor = overwriteColor;
using System;
using System.Collections.Generic;
-using System.Collections.ObjectModel;
using System.Collections.Specialized;
using Vintagestory.API.Common;
using ProtoBuf;
-
+using System.IO;
+using System.Collections.ObjectModel;
+using System.Text;
+using Vintagestory.API.Client;
namespace Automap
{
public struct ColumnMeta
{
[ProtoMember(1)]
+ [DisplayName(0, "Coords.")]
public Vec2i Location;
[ProtoMember(2)]
+ [DisplayName(1, "Age")]
public TimeSpan ChunkAge;//OLDEST CHUNK. from chunk last edit
[ProtoMember(3)]
+ [DisplayName(2, "Temp.")]
public float Temperature;// Temperature - surface
[ProtoMember(4)]
+ [DisplayName(3, "Y Max.")]
public ushort YMax;// Y feature height
[ProtoMember(5)]
+ //[DisplayName(10, "Rocks")]
public Dictionary<int, uint> RockRatio;//[Column] Geographic region (rock) Ratio. [BlockID * count]
[ProtoMember(6)]
+ [DisplayName(4, "Fert.")]
public float Fertility;
[ProtoMember(7)]
+ [DisplayName(5, "Forest")]
public float ForestDensity;
[ProtoMember(8)]
+ [DisplayName(6, "Rain")]
public float Rainfall;
[ProtoMember(9)]
+ [DisplayName(7, "Shrub")]
public float ShrubDensity;
[ProtoMember(10)]
+ [DisplayName(8, "Air blocks")]
public uint AirBlocks;
[ProtoMember(11)]
+ [DisplayName(9, "Non-air")]
public uint NonAirBlocks;
[ProtoMember(12)]
public ushort[,] HeightMap;//Needs to be 'flattened' for Protocol-Buffer serialization
[ProtoMember(13)]
- private ushort[ ] _flattened_HeightMap;
+ private ushort[] _flattened_HeightMap;
public ColumnMeta(Vec2i loc, byte chunkSize = 32)
this.YMax = mapChunk.YMax;
}
-
+ public void Write(StreamWriter stream, ICoreClientAPI ClientApi)
+ {
+ // this is gross i hate this
+ stream.Write("['{0}_{1}',[",
+ Location.X,
+ Location.Y
+ );
+ stream.Write("'{0}',", Location.PrettyCoords(ClientApi));
+ stream.Write("'{0}',", ChunkAge);
+ stream.Write("'{0}',", Temperature.ToString("F3"));
+ stream.Write("'{0}',", YMax);
+ stream.Write("'{0}',", Fertility.ToString("F3"));
+ stream.Write("'{0}',", ForestDensity.ToString("F3"));
+ stream.Write("'{0}',", Rainfall.ToString("F3"));
+ stream.Write("'{0}',", ShrubDensity.ToString("F3"));
+ stream.Write("'{0}',", AirBlocks);
+ stream.Write("'{0}',", NonAirBlocks);
+ stream.Write("]]");
+ }
[ProtoBeforeSerialization]
- private void PrepareData( )
+ private void PrepareData()
{
- if (HeightMap != null) {
- _flattened_HeightMap = new ushort[ChunkSize * ChunkSize];
- int flatIndex = 0;
+ if (HeightMap != null)
+ {
+ _flattened_HeightMap = new ushort[ChunkSize * ChunkSize];
+ int flatIndex = 0;
+
+ for (byte col = 0; col < ChunkSize; col++)
+ {
+ for (byte row = 0; row < ChunkSize; row++)
+ {
+ _flattened_HeightMap[flatIndex] = HeightMap[col, row];
+ flatIndex++;
+ }
+ }
- for (byte col = 0; col < ChunkSize; col++) {
- for (byte row = 0; row < ChunkSize; row++) {
- _flattened_HeightMap[flatIndex] = HeightMap[col, row];
- flatIndex++;
}
- }
-
- }
}
[ProtoAfterDeserialization]
- private void PostProcess( )
+ private void PostProcess()
{
- if (this.HeightMap == null) this.HeightMap = new ushort[ChunkSize, ChunkSize];
-
- if (_flattened_HeightMap != null) {
- int col, row;
+ if (this.HeightMap == null) this.HeightMap = new ushort[ChunkSize, ChunkSize];
- BitVector32 bitMasker = new BitVector32(0);
- var rowSection = BitVector32.CreateSection(( short )(ChunkSize - 1));
- var colSection = BitVector32.CreateSection(( short )(ChunkSize - 1), rowSection);
-
- for (uint rowcol = 0; rowcol < (ChunkSize * ChunkSize); rowcol++) {
- bitMasker = new BitVector32(data: ( int )rowcol);
- row = bitMasker[rowSection];
- col = bitMasker[colSection];
- HeightMap[col, row] = _flattened_HeightMap[rowcol];
- }
+ if (_flattened_HeightMap != null)
+ {
+ int col, row;
+ _ = new BitVector32(0);
+ var rowSection = BitVector32.CreateSection((short) (ChunkSize - 1));
+ var colSection = BitVector32.CreateSection((short) (ChunkSize - 1), rowSection);
+
+ for (uint rowcol = 0; rowcol < (ChunkSize * ChunkSize); rowcol++)
+ {
+ BitVector32 bitMasker = new BitVector32(data: (int) rowcol);
+ row = bitMasker[rowSection];
+ col = bitMasker[colSection];
+ HeightMap[col, row] = _flattened_HeightMap[rowcol];
+ }
- }
+ }
}
}
}
-}
-
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Reflection;
+
+namespace Automap
+{
+ [AttributeUsage(AttributeTargets.Field)]
+ public class DisplayNameAttribute : Attribute
+ {
+ public string name;
+ public byte order;
+ public DisplayNameAttribute(byte order, string name)
+ {
+ this.order = order;
+ this.name = name;
+ }
+ }
+}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
-
+using System.IO;
using System.Linq;
using Vintagestory.API.Common.Entities;
using Vintagestory.API.MathTools;
+using Vintagestory.API.Client;
using ProtoBuf;
+using Newtonsoft.Json;
+
namespace Automap
{
/// <summary>
- /// Actual Physical Point in space - that is interesting.
+ /// Basically the same as a POI but for an entity
/// </summary>
[ProtoContract]
public struct EntityOfInterest
{
+
[ProtoMember(1)]
public string Name;
-
+
+ [DisplayName(1, "Notes")]
[ProtoMember(2)]
public string Notes;
+ [DisplayName(0, "Loc.")]
[ProtoMember(3)]
public BlockPos Location;
+ [DisplayName(2, "Time")]
[ProtoMember(4)]
public DateTime Timestamp;
+ [DisplayName(3, "ID")]
[ProtoMember(5)]
public long EntityId;
+
+
}
/// <summary>
/// <remarks>Tracked by ID - these never leave.</remarks>
public class EntitiesOfInterest : KeyedCollection<long, EntityOfInterest>
{
+ protected override long GetKeyForItem(EntityOfInterest item)
+ => item.EntityId;
internal void AddReplace(EntityOfInterest entity)
{
Add(entity);
}
- protected override long GetKeyForItem(EntityOfInterest item)
- => item.EntityId;
}
}
namespace Automap
{
- public delegate void EntityDesignatonAction(ICoreClientAPI clientAPI, EntitiesOfInterest poi, BlockPos posn, Entity entity);
+ public delegate void EntityDesignatorAction(ICoreClientAPI clientAPI, EntitiesOfInterest poi, BlockPos posn, Entity entity);
/// <summary>
/// Point of Interest Rule Designator
public Color Color;
[JsonIgnore]
- public EntityDesignatonAction SpecialAction;
+ public EntityDesignatorAction SpecialAction;
[JsonProperty]
public string SpecialActionName;
Enabled = true;
}
- public EntityDesignator(AssetLocation pattern, Color color, EnumEntityState? state, EntityDesignatonAction specialAct)
+ public EntityDesignator(AssetLocation pattern, Color color, EnumEntityState? state, EntityDesignatorAction specialAct)
{
Pattern = pattern;
Color = color;
using System;
using System.Collections.ObjectModel;
+using System.IO;
+using Vintagestory.API.Client;
using Vintagestory.API.Common;
using Vintagestory.API.MathTools;
using ProtoBuf;
+using Newtonsoft.Json;
+
namespace Automap
{
/// <summary>
[ProtoMember(1)]
public string Name;
+ [DisplayName(1, "Notes")]
[ProtoMember(2)]
public string Notes;
+ [DisplayName(0, "Loc.")]
[ProtoMember(3)]
public BlockPos Location;
+ [DisplayName(2, "Time")]
[ProtoMember(4)]
public DateTime Timestamp;
+
+
}
public class PointsOfInterest : KeyedCollection<BlockPos, PointOfInterest>
internal static void KeepTrackOfMerchant(ICoreClientAPI clientAPI, EntitiesOfInterest poi, BlockPos posn, Entity entity)
{
- clientAPI.Logger.VerboseDebug("Trader: {0} @ {1}", entity.GetName(), posn);
+ //clientAPI.Logger.VerboseDebug("Trader: {0} @ {1}", entity.GetName(), posn);
var traderJoe = entity as EntityTrader;
var message = $"{entity.GetName()} Alive: {traderJoe.Alive}";
--- /dev/null
+#!/usr/local/bin/node
+
+// im sorry
+// cd into MapSRC and run node ./build.js and this will concat and stuff
+const fs = require('fs');
+
+fs.readFile('./src/Automap.html', 'utf8', (err, d) => {
+ if (err) console.log(err);
+ let outD = d.replace(/<link rel=\"stylesheet\" href=\"(.*)\">/g, '<style>REP:$1</style>')
+ .replace(/(<script type=\"text\/javascript\") src=\"(.*)\">/g, '$1>REP:$2')
+ .replace(/REP:(\w*\.\w*)/g, (match, name, offset, string) => {
+ return fs.readFileSync('./src/' + name, 'utf8')
+ .replace(/\/\/.*\n?/g, '');
+ })
+ .replace(/[\t\n]/g, '');
+ fs.writeFile('./dist/automap.html', outD, err => {
+ if (err) console.log(err);
+ });
+ fs.writeFile('../assets/automap/config/automap.html', outD, err => {
+ if (err) console.log(err);
+ });
+});
\ No newline at end of file
--- /dev/null
+html, body, .map {
+ width: 100%;
+ height: 100%;
+ margin: 0;
+ overflow: hidden;
+ outline: 1px dotted black;
+}
+
+.infobox {
+ width: 15em;
+ /* height: 15em; */
+ background-color: rgba(200, 200, 200, 0.5);
+ left: 0;
+ top: 0;
+ font-family: sans-serif;
+ position: absolute;
+ z-index: 1;
+}
+
+h1 {
+ font-size: 22px;
+ margin: .6em 1em;
+ text-align: center;
+}
+
+.infoboxTable {
+ margin: .3em auto;
+ width: 90%;
+ outline: 1px solid #333;
+}
+
+.infoboxTable th {
+ width: 30%;
+}
+
+.infoboxTable td {
+ text-align: right;
+}
\ No newline at end of file
--- /dev/null
+<!DOCTYPE html>
+<html lang="en" dir="ltr">
+
+<head>
+ <meta charset="utf-8">
+ <title>Automap</title>
+ <link rel="stylesheet" href="Automap.css">
+</head>
+
+<body>
+ <script type="text/javascript" src="ViewFrame.js"></script>
+ <script type="text/javascript" src="ViewFrameUtils.js"></script>
+ <div class="infobox">
+ <h1>Chunk Info</h1>
+ <table class="infoboxTable">
+ </table>
+ </div>
+ <script type="text/javascript" src="index.js"></script>
+
+</body>
+
+</html>
\ No newline at end of file
--- /dev/null
+function ViewFrame() {
+ // dom stuff
+ const map = document.createElement('canvas'); // the map we see
+ map.className = 'map';
+ map.height = window.innerHeight;
+ map.width = window.innerWidth;
+ document.getElementsByTagName('body')[0].append(map);
+ // this is the map that we actually draw on
+ this.map = map.getContext('2d', {
+ alpha: false
+ });
+ this.map.imageSmoothingEnabled = false;
+
+ // the info box in the corner
+ this.infobox = document.getElementsByClassName('infoboxTable')[0];
+ this.infoboxSlots = new Array();
+
+ // load the metadata!
+ this.chunkScript = document.createElement('script');
+ this.chunkScript.type = 'text/javascript';
+ this.chunkScript.src = 'Metadata.js';
+ document.getElementsByTagName('body')[0].append(this.chunkScript);
+ this.chunkScript.addEventListener('load', () => {
+ ViewFrame.initInfobox(this.infobox, this.infoboxSlots);
+ this.x = ViewFrame.chunks.startCoords[0];
+ this.y = ViewFrame.chunks.startCoords[1];
+ this.availableChunks = ViewFrame.chunks.chunkMetadata;
+ this.render();
+ }, {
+ once: true
+ });
+
+ // Tracks images that have been loaded and are on the map
+ this.loadedChunksByName = new Map();
+ // this is needed because [1, 2] != [1, 2] and thats how we store coords.
+ this.loadedChunksByCoords = new Map();
+ this.availableChunks = null; // the chunks in ./Metadata.js
+ // so that we dont render twice at the same time
+ this.rendering = false;
+
+ this.x = -1;
+ this.y = -1; // can be fractional
+ this.zoom = 32; // pixels wide the images are to be
+ this.updateEdges();
+}
+// prototypes, some less... notable? methods are
+// in ViewFrameUtils.js
+ViewFrame.prototype.reloadChunkList = function () {
+ if (this.chunkScript) {
+ this.chunkScript.remove();
+ delete this.chunkScript;
+ }
+
+ this.chunkScript = document.createElement('script');
+ this.chunkScript.type = 'text/javascript';
+ this.chunkScript.src = 'Metadata.js';
+ document.getElementsByTagName('body')[0].append(this.chunkScript);
+
+ this.chunkScript.addEventListener('load', () => {
+ this.availableChunks = ViewFrame.chunks.chunkMetadata;
+ this.render();
+ });
+};
+
+ViewFrame.prototype.render = function () {
+ if (!this.availableChunks) return;
+ if (this.rendering) clearInterval(ViewFrame.intervalRef);
+ this.rendering = true;
+ this.updateEdges();
+ this.map.clearRect(0, 0, window.innerWidth, window.innerHeight);
+ // culling
+ this.loadedChunksByCoords
+ .forEach((chunk, coord) => { // check the bounds
+ if (coord[0] < this.eastChunk &&
+ coord[0] >= this.westChunk &&
+ coord[1] <= this.northChunk &&
+ coord[1] >= this.southChunk) {
+
+ this.place(chunk, coord[0], coord[1]);
+ return;
+ }
+ // its out of range!!!
+ // get 'em boys!!!!!
+ this.loadedChunksByCoords.delete(coord);
+ this.loadedChunksByName.delete(coord.join('_'));
+ chunk.remove();
+ });
+
+ // gathering what we need to load
+ const neededChunks = new Set();
+ for (var x = this.westChunk; x < this.eastChunk; x++) {
+ for (var y = this.southChunk; y < this.northChunk; y++) {
+ const chunKey = [x, y]; // chunk + key = chunKey :)
+ const name = chunKey.join('_');
+ // continue if its not available, or it is loaded
+ if (!this.availableChunks.has(name) ||
+ this.loadedChunksByName.has(name)) continue;
+ neededChunks.add(chunKey);
+ }
+ }
+ // iterating over everything we need to load
+ const it = neededChunks.values();
+ ViewFrame.intervalRef = setInterval(() => {
+ let round = it.next();
+ if (!round.done) {
+ // load
+ const img = new Image(32, 32);
+ const name = round.value.join('_');
+
+ img.src = name + '.png';
+
+ decode(img, loadedImage => {
+ this.place(img, round.value[0], round.value[1]);
+ });
+ this.loadedChunksByName.set(name, img);
+ this.loadedChunksByCoords.set(round.value, img);
+ } else {
+ clearInterval(ViewFrame.intervalRef);
+ this.rendering = false;
+ }
+ }, 4);
+};
+
+ViewFrame.prototype.place = function (img, x, y) {
+ x -= this.x;
+ y -= this.y;
+ x *= this.zoom;
+ y *= this.zoom;
+ x += this.width / 2;
+ y += this.height / 2;
+
+ this.map.drawImage(img, Math.floor(x), Math.floor(y), this.zoom, this.zoom);
+};
+
+ViewFrame.prototype.updateInfobox = function (chunkName) {
+ const chunkMeta = this.availableChunks.get(chunkName);
+ this.infoboxSlots.forEach((l, k) => {
+ l.innerText = chunkMeta ? chunkMeta[k] : '0';
+ });
+};
\ No newline at end of file
--- /dev/null
+ViewFrame.initInfobox = function (ibox, iboxSlots) {
+
+ ViewFrame.chunks
+ .chunkMetadataNames.forEach((item, i) => {
+ const slot = document.createElement('tr');
+ const head = document.createElement('th');
+ head.innerText = item;
+ const row = document.createElement('td');
+ row.innerText = '0';
+ iboxSlots[i] = row;
+ slot.append(head, row);
+ ibox.append(slot);
+ });
+};
+
+ViewFrame.prototype.updateEdges = function () {
+ if (this.width != window.innerWidth || this.height != window.innerHeight) {
+ this.width = window.innerWidth;
+ this.map.canvas.width = this.width;
+ this.height = window.innerHeight;
+ this.map.canvas.height = this.height;
+ this.map.imageSmoothingEnabled = false;
+ }
+ const chunksWide = Math.ceil(this.width / this.zoom);
+ const chunksHigh = Math.ceil(this.height / this.zoom);
+
+ this.east = this.x + chunksWide / 2; // this is fractional and is used to keep track of the edges of the window
+ this.eastChunk = Math.ceil(this.east); // this is not and is used to track the chunks that need to load
+ this.west = this.x - chunksWide / 2;
+ this.westChunk = Math.floor(this.west);
+ this.north = this.y + chunksHigh / 2;
+ this.northChunk = Math.ceil(this.north);
+ this.south = this.y - chunksHigh / 2;
+ this.southChunk = Math.floor(this.south);
+};
+
+ViewFrame.prototype.moveCenter = function (dx, dy) {
+ // to pan when we click on the map!
+ this.x += (dx - this.width / 2) / this.zoom;
+ this.y += (dy - this.height / 2) / this.zoom;
+};
+ViewFrame.prototype.setCenter = function (x, y) {
+ this.x = x;
+ this.y = y;
+};
+
+ViewFrame.prototype.clear = function () {
+ this.loadedChunksByName.clear();
+ this.loadedChunksByCoords.clear();
+ if (this.chunkScript) this.chunkScript.remove();
+ delete this.chunkScript;
+ delete ViewFrame.chunks;
+ this.map.clearRect(0, 0, window.innerWidth, window.innerHeight);
+};
+
+function decode(img, cb) {
+ img.decode()
+ .then(() => {
+ cb(img);
+ })
+ .catch(() => {}); // so images arent added on error
+}
\ No newline at end of file
--- /dev/null
+const vf = new ViewFrame();
+vf.reloadChunkList();
+
+// the event handlers are in iifes so they dont make unneeded globals.
+// resize, delay re-render to reduce lag.
+(function () {
+ var id;
+ window.addEventListener('resize', () => {
+ clearTimeout(id);
+ id = setTimeout(() => {
+ vf.render();
+ }, 500);
+ });
+}());
+
+// panning
+(function () {
+ var id;
+ vf.map.canvas.addEventListener('mousedown', event => {
+ clearTimeout(id);
+ vf.moveCenter(event.pageX, event.pageY);
+ id = setTimeout(() => {
+ vf.render();
+ }, 250);
+ });
+}());
+
+
+// #### CONTROLS ####
+// hovering
+(function () {
+ var lastX = 0;
+ var lastY = 0;
+ vf.map.canvas.addEventListener('mousemove', event => {
+ // only count if the mouse moved more than a chunk
+ let x = Math.floor(vf.x +
+ (event.clientX - vf.width / 2) / vf.zoom);
+ let y = Math.floor(vf.y +
+ (event.clientY - vf.height / 2) / vf.zoom);
+ if (x == lastX && y == lastY) return;
+ lastX = x;
+ lastY = y;
+ vf.updateInfobox(x + '_' + y);
+ });
+}());
+
+// scroll/zoom
+(function () {
+ var id;
+ vf.map.canvas.addEventListener('wheel', event => {
+ clearTimeout(id);
+ vf.zoom += -Math.sign(event.deltaY);
+ id = setTimeout(() => {
+ vf.render();
+ }, 250);
+ });
+}());
+
+// reload the chunk list every six seconds
+(function () {
+ setInterval(() => {
+ vf.reloadChunkList();
+ }, 6000);
+}());
+//
+// var i = 500;
+// setTimeout(() => {
+// vf.map.dispatchEvent(new MouseEvent('mousedown', {
+// clientX: 879,
+// clientY: 926
+// }));
+// }, i += 1000);
+//
+// setTimeout(() => {
+// vf.map.dispatchEvent(new MouseEvent('mousedown', {
+// clientX: 666,
+// clientY: 924
+// }));
+// }, i += 2000);
+//
+// setTimeout(() => {
+// vf.map.dispatchEvent(new MouseEvent('mousedown', {
+// clientX: 1090,
+// clientY: 936
+// }));
+// }, i += 2000);
+//
+// setTimeout(() => {
+// vf.map.dispatchEvent(new MouseEvent('mousedown', {
+// clientX: 29,
+// clientY: 785
+// }));
+// }, i += 2000);
\ No newline at end of file
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
private ICoreClientAPI ClientAPI { get; set; }
private ILogger Logger { get; set; }
private IChunkRenderer ChunkRenderer { get; set; }
+ private JsonGenerator JsonGenerator { get; set; }
private const string _mapPath = @"Maps";
private const string _chunkPath = @"Chunks";
private ColumnsMetadata chunkTopMetadata;
private PointsOfInterest POIs = new PointsOfInterest();
private EntitiesOfInterest EOIs = new EntitiesOfInterest();
+ private string jsonPreBuilt;
internal Dictionary<int, BlockDesignator> BlockID_Designators { get; private set; }
internal Dictionary<AssetLocation, EntityDesignator> Entity_Designators { get; private set; }
configuration = config;
-
//TODO:Choose which one from GUI
this.ChunkRenderer = new StandardRenderer(clientAPI, logger);
//Listen on bus for commands
ClientAPI.Event.RegisterEventBusListener(CommandListener, 1.0, AutomapSystem.AutomapCommandEventKey);
- if (configuration.Autostart)
+ if (configuration.Autostart)
{
CurrentState = CommandType.Run;
Logger.Debug("Autostart is Enabled.");
{
path = ClientAPI.GetOrCreateDataPath(_mapPath);
path = ClientAPI.GetOrCreateDataPath(Path.Combine(path, "World_" + ClientAPI.World.Seed));//Add name of World too...'ServerApi.WorldManager.CurrentWorldName'
-
+ JsonGenerator = new JsonGenerator(ClientAPI, Logger, path);
string mapFilename = Path.Combine(path, "automap.html");
StreamWriter outputText = new StreamWriter(File.Open(mapFilename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite));
outputText.Write(staticMap.ToText());
outputText.Flush();
+ jsonPreBuilt = JsonGenerator.MakePreBuiltJSON();
+
Prefill_POI_Designators();
startChunkColumn = new Vec2i((ClientAPI.World.Player.Entity.LocalPos.AsBlockPos.X / chunkSize), (ClientAPI.World.Player.Entity.LocalPos.AsBlockPos.Z / chunkSize));
chunkTopMetadata = new ColumnsMetadata(startChunkColumn);
if (!columnCounter.IsEmpty)
{
var tempSet = columnCounter.ToArray().OrderByDescending(kvp => kvp.Value);
- UpdateEntityMetadata( );
+ UpdateEntityMetadata();
foreach (var mostActiveCol in tempSet)
{
}
ColumnMeta chunkMeta;
- if (chunkTopMetadata.Contains(mostActiveCol.Key)) {
- chunkMeta = chunkTopMetadata[mostActiveCol.Key];
+ if (chunkTopMetadata.Contains(mostActiveCol.Key))
+ {
+ chunkMeta = chunkTopMetadata[mostActiveCol.Key];
}
- else {
- chunkMeta = CreateColumnMetadata(mostActiveCol, mapChunk);
+ else
+ {
+ chunkMeta = CreateColumnMetadata(mostActiveCol, mapChunk);
}
ProcessChunkBlocks(mostActiveCol.Key, mapChunk, ref chunkMeta);
{
//What about chunk updates themselves; a update bitmap isn't kept...
updatedChunksTotal += updatedChunks;
- GenerateJSONMetadata();
+ JsonGenerator.GenerateJSONMetadata(chunkTopMetadata, startChunkColumn, POIs, EOIs, RockIdCodes);
updatedChunks = 0;
}
}
private void Reload_POI_Designators()
- {
+ {
Logger.VerboseDebug("Connecting {0} Configured Block-Designators", configuration.BlockDesignators.Count);
foreach (var designator in configuration.BlockDesignators)
{
}
- /// <summary>
- /// Generates the JSON Metadata. (in Map object format )
- /// </summary>
- private void GenerateJSONMetadata()
- {
- string jsonFilename = Path.Combine(path, "Metadata.js");
-
- StreamWriter stream = new StreamWriter(jsonFilename, false, Encoding.UTF8);
-
- using (stream) {
- JsonTextWriter jsonWriter = new JsonTextWriter(stream);
-
- jsonWriter.Formatting = Formatting.None;
- jsonWriter.StringEscapeHandling = StringEscapeHandling.EscapeHtml;
- jsonWriter.Indentation = 0;
- //jsonWriter.AutoCompleteOnClose = true;
- jsonWriter.QuoteChar = '\'';
- jsonWriter.DateFormatHandling = DateFormatHandling.IsoDateFormat;
- jsonWriter.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
-
- using (jsonWriter)
- {
- jsonWriter.WriteRaw("ViewFrame.chunks={};\n");
- jsonWriter.WriteRaw("ViewFrame.chunks.worldSeedNum=" );
- jsonWriter.WriteValue(ClientAPI.World.Seed);
- jsonWriter.WriteRaw(";\n");
-
- jsonWriter.WriteRaw("ViewFrame.chunks.genTime=");
- jsonWriter.WriteValue(DateTimeOffset.UtcNow);
- jsonWriter.WriteRaw(";\n");
-
- jsonWriter.WriteRaw("ViewFrame.chunks.startCoords=");
- jsonWriter.WriteStartArray( );
- jsonWriter.WriteValue(startChunkColumn.X);
- jsonWriter.WriteValue(startChunkColumn.Y);
- jsonWriter.WriteEndArray( );
- jsonWriter.WriteRaw(";\n");
-
- jsonWriter.WriteRaw("ViewFrame.chunks.chunkSize=");
- jsonWriter.WriteValue(chunkSize);
- jsonWriter.WriteRaw(";\n");
-
- jsonWriter.WriteRaw("ViewFrame.chunks.northMostChunk=");
- jsonWriter.WriteValue(chunkTopMetadata.North_mostChunk);
- jsonWriter.WriteRaw(";\n");
-
- jsonWriter.WriteRaw("ViewFrame.chunks.southMostChunk=");
- jsonWriter.WriteValue(chunkTopMetadata.South_mostChunk);
- jsonWriter.WriteRaw(";\n");
-
- jsonWriter.WriteRaw("ViewFrame.chunks.westMostChunk=");
- jsonWriter.WriteValue(chunkTopMetadata.West_mostChunk);
- jsonWriter.WriteRaw(";\n");
-
- jsonWriter.WriteRaw("ViewFrame.chunks.eastMostChunk=");
- jsonWriter.WriteValue(chunkTopMetadata.East_mostChunk);
- jsonWriter.WriteRaw(";\n");
-
-
- //MAP object format - [key, value]: key is "x_y"
- jsonWriter.WriteRaw("ViewFrame.chunks.chunkMetadata=");
- jsonWriter.WriteStartConstructor("Map");
- jsonWriter.WriteStartArray( );//An array of... 2-component arrays
-
-
- foreach (var shard in chunkTopMetadata)
- {
- jsonWriter.WriteStartArray( );//Start tuple
- jsonWriter.WriteValue($"{shard.Location.X}_{shard.Location.Y}");//Key of Tuple
-
- jsonWriter.WriteStartObject( );
- jsonWriter.WritePropertyName("prettyCoord");
- jsonWriter.WriteValue( shard.Location.PrettyCoords(ClientAPI));
-
- jsonWriter.WritePropertyName("chunkAge");
- jsonWriter.WriteValue(shard.ChunkAge);
-
- jsonWriter.WritePropertyName("temp");
- jsonWriter.WriteValue(shard.Temperature);
-
- jsonWriter.WritePropertyName("YMax");
- jsonWriter.WriteValue(shard.YMax);
-
- jsonWriter.WritePropertyName("fert");
- jsonWriter.WriteValue(shard.Fertility);
-
- jsonWriter.WritePropertyName("forestDens");
- jsonWriter.WriteValue( shard.ForestDensity);
-
- jsonWriter.WritePropertyName("rain");
- jsonWriter.WriteValue( shard.Rainfall);
-
- jsonWriter.WritePropertyName("shrubDens");
- jsonWriter.WriteValue( shard.ShrubDensity);
-
- jsonWriter.WritePropertyName("airBlocks");
- jsonWriter.WriteValue( shard.AirBlocks);
-
- jsonWriter.WritePropertyName("nonAirBlocks");
- jsonWriter.WriteValue( shard.NonAirBlocks);
-
- //TODO: Heightmap ?
- //Start rockMap ; FOR a Ratio....on tooltip GUI
- jsonWriter.WritePropertyName("rockRatio");
- jsonWriter.WriteStartConstructor("Map");
- jsonWriter.WriteStartArray( );
- foreach (var rockEntry in shard.RockRatio) {
- var rockBlock = ClientAPI.World.GetBlock(rockEntry.Key);
- jsonWriter.WriteStartArray( );
- jsonWriter.WriteValue(rockBlock.Code.Path);
- jsonWriter.WriteValue(rockEntry.Value);//Total per chunk-column
- jsonWriter.WriteEndArray( );
- }
- jsonWriter.WriteEndArray( );
- jsonWriter.WriteEndConstructor( );//end rock-map
-
- jsonWriter.WriteEndObject( );//end Map value: {Object}
- jsonWriter.WriteEndArray( );//end Tuple
- }
-
- jsonWriter.WriteEndArray( );//Enclose tuples of chunkMetadata
- jsonWriter.WriteEndConstructor( );//Close constructor of Map (chunkMetadata)
- jsonWriter.WriteRaw(";\n");
-
- jsonWriter.WriteRaw("ViewFrame.chunks.pointsOfInterest=");
- jsonWriter.WriteStartConstructor("Map");
- jsonWriter.WriteStartArray( );//An array of... 2-component arrays
-
- foreach (var poi in POIs)
- {
- jsonWriter.WriteStartArray( );
- jsonWriter.WriteValue($"{poi.Location.X}_{poi.Location.Z}");
-
- jsonWriter.WriteStartObject();
- jsonWriter.WritePropertyName("Name");
- jsonWriter.WriteValue(poi.Name);
-
- jsonWriter.WritePropertyName("prettyCoord");
- jsonWriter.WriteValue(poi.Location.PrettyCoords(ClientAPI) );
-
- jsonWriter.WritePropertyName("notes");
- jsonWriter.WriteValue(poi.Notes);//Encoded to HTML Entities
-
- jsonWriter.WritePropertyName("time");
- jsonWriter.WriteValue(poi.Timestamp);
-
- jsonWriter.WritePropertyName("chunkPos");
- jsonWriter.WriteValue($"{(poi.Location.X / chunkSize)}_{(poi.Location.Z / chunkSize)}");
-
- jsonWriter.WriteEndObject( );
- jsonWriter.WriteEndArray( );
- }
-
- foreach (var poi in EOIs)
- {
- jsonWriter.WriteStartArray( );
- jsonWriter.WriteValue($"{poi.Location.X}_{poi.Location.Z}");
-
- jsonWriter.WriteStartObject( );
- jsonWriter.WritePropertyName("Name");
- jsonWriter.WriteValue(poi.Name);
-
- jsonWriter.WritePropertyName("prettyCoord");
- jsonWriter.WriteValue(poi.Location.PrettyCoords(ClientAPI));
-
- jsonWriter.WritePropertyName("notes");
- jsonWriter.WriteValue(poi.Notes);//Encoded to HTML Entities
-
- jsonWriter.WritePropertyName("time");
- jsonWriter.WriteValue(poi.Timestamp);
-
- jsonWriter.WritePropertyName("chunkPos");
- jsonWriter.WriteValue($"{(poi.Location.X / chunkSize)}_{(poi.Location.Z / chunkSize)}");
-
- jsonWriter.WriteEndObject( );
- jsonWriter.WriteEndArray( );
- }
-
- jsonWriter.WriteEndArray( );
- jsonWriter.WriteEndConstructor( );
- jsonWriter.WriteRaw(";\n");
-
- jsonWriter.WriteWhitespace("\n");
- jsonWriter.WriteComment("============= BlockID's for Rockmap / Rock-ratios ===============");
- jsonWriter.WriteWhitespace("\n");
-
- jsonWriter.WriteRaw("ViewFrame.chunks.rock_Lookup =");
- jsonWriter.WriteStartConstructor("Map");
- jsonWriter.WriteStartArray( );//An array of... 2-component arrays
-
- foreach (var entry in RockIdCodes) {
- var block = ClientAPI.World.GetBlock(entry.Key);
-
- jsonWriter.WriteStartArray( );
- jsonWriter.WriteValue(block.Code.Path);
-
- jsonWriter.WriteStartObject( );
- jsonWriter.WritePropertyName("assetCode");
- jsonWriter.WriteValue(entry.Value);
-
- jsonWriter.WritePropertyName("name");
- jsonWriter.WriteValue(Lang.GetUnformatted(block.Code.Path));
- //Color?
-
- jsonWriter.WriteEndObject( );
- jsonWriter.WriteEndArray( );
- }
- jsonWriter.WriteEndArray( );
- jsonWriter.WriteEndConstructor();
-
- jsonWriter.WriteRaw(";\n");
-
- jsonWriter.Flush();
- }
- }
-
- }
/// <summary>
/// Store Points/Entity of Interest
}
}
- //Create Easy to Parse CSV file for tool/human use....
+ //Create Easy to Parse TSV file for tool/human use....
string pointsTsvPath = Path.Combine(path, pointsTsvFileName);
using (var tsvWriter = new StreamWriter(pointsTsvPath, false, Encoding.UTF8))
private ColumnMeta CreateColumnMetadata(KeyValuePair<Vec2i, uint> mostActiveCol, IMapChunk mapChunk)
{
- ColumnMeta data = new ColumnMeta(mostActiveCol.Key.Copy(), ( byte )chunkSize);
+ ColumnMeta data = new ColumnMeta(mostActiveCol.Key.Copy(), (byte) chunkSize);
BlockPos equivBP = new BlockPos(mostActiveCol.Key.X * chunkSize,
mapChunk.YMax,
mostActiveCol.Key.Y * chunkSize);
}
}
- catch (PngjException someEx)
+ catch (PngjException someEx)
{
- Logger.Error("PNG Corruption in file '{0}' - Reason: {1}", shardFile.Name, someEx);
+ Logger.Error("PNG Corruption file '{0}' - Reason: {1}", shardFile.Name, someEx);
continue;
}
- }
+ }
}
}
}
+
+
#endregion
}
-}
\ No newline at end of file
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Text.RegularExpressions;
+
+using Newtonsoft.Json;
+
+using Vintagestory.API.Client;
+using Vintagestory.API.Common;
+using Vintagestory.API.Config;
+using Vintagestory.API.Datastructures;
+using Vintagestory.API.MathTools;
+using Vintagestory.Common;
+
+
+
+namespace Automap
+{
+ public class JsonGenerator
+ {
+ private ICoreClientAPI ClientAPI { get; set; }
+ private ILogger Logger { get; set; }
+ private string path { get; set; }
+ private readonly int chunkSize;
+
+
+ public JsonGenerator(ICoreClientAPI _ClientAPI, ILogger _Logger, string _path )
+ {
+ this.ClientAPI = _ClientAPI;
+ this.Logger = _Logger;
+ this.path = _path;
+ this.chunkSize = ClientAPI.World.BlockAccessor.ChunkSize;
+ }
+
+
+ /// <summary>
+ /// Generates the JSON Metadata. (in Map object format )
+ /// </summary>
+ public void GenerateJSONMetadata(ColumnsMetadata chunkTopMetadata, Vec2i startChunkColumn, PointsOfInterest POIs, EntitiesOfInterest EOIs, Dictionary<int, string> RockIdCodes )
+ {
+ string jsonFilename = Path.Combine(path, "Metadata.js");
+
+ StreamWriter stream = new StreamWriter(jsonFilename, false, Encoding.UTF8);
+
+ using (stream) {
+ JsonTextWriter jsonWriter = new JsonTextWriter(stream);
+
+ jsonWriter.Formatting = Formatting.None;
+ jsonWriter.StringEscapeHandling = StringEscapeHandling.EscapeHtml;
+ jsonWriter.Indentation = 0;
+ //jsonWriter.AutoCompleteOnClose = true;
+ jsonWriter.QuoteChar = '\'';
+ jsonWriter.DateFormatHandling = DateFormatHandling.IsoDateFormat;
+ jsonWriter.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
+
+ using (jsonWriter) {
+ jsonWriter.WriteRaw("ViewFrame.chunks={};\n");
+ jsonWriter.WriteRaw("ViewFrame.chunks.worldSeedNum=");
+ jsonWriter.WriteValue(ClientAPI.World.Seed);
+ jsonWriter.WriteRaw(";\n");
+
+ jsonWriter.WriteRaw("ViewFrame.chunks.genTime=");
+ jsonWriter.WriteValue(DateTimeOffset.UtcNow);
+ jsonWriter.WriteRaw(";\n");
+
+ jsonWriter.WriteRaw("ViewFrame.chunks.startCoords=");
+ jsonWriter.WriteStartArray( );
+ jsonWriter.WriteValue(startChunkColumn.X);
+ jsonWriter.WriteValue(startChunkColumn.Y);
+ jsonWriter.WriteEndArray( );
+ jsonWriter.WriteRaw(";\n");
+
+ jsonWriter.WriteRaw("ViewFrame.chunks.chunkSize=");
+ jsonWriter.WriteValue(chunkSize);
+ jsonWriter.WriteRaw(";\n");
+
+ jsonWriter.WriteRaw("ViewFrame.chunks.northMostChunk=");
+ jsonWriter.WriteValue(chunkTopMetadata.North_mostChunk);
+ jsonWriter.WriteRaw(";\n");
+
+ jsonWriter.WriteRaw("ViewFrame.chunks.southMostChunk=");
+ jsonWriter.WriteValue(chunkTopMetadata.South_mostChunk);
+ jsonWriter.WriteRaw(";\n");
+
+ jsonWriter.WriteRaw("ViewFrame.chunks.westMostChunk=");
+ jsonWriter.WriteValue(chunkTopMetadata.West_mostChunk);
+ jsonWriter.WriteRaw(";\n");
+
+ jsonWriter.WriteRaw("ViewFrame.chunks.eastMostChunk=");
+ jsonWriter.WriteValue(chunkTopMetadata.East_mostChunk);
+ jsonWriter.WriteRaw(";\n");
+
+
+ //MAP object format - [key, value]: key is "x_y"
+ jsonWriter.WriteRaw("ViewFrame.chunks.chunkMetadata=");
+ jsonWriter.WriteStartConstructor("Map");
+ jsonWriter.WriteStartArray( );//An array of... 2-component arrays
+
+
+ foreach (var shard in chunkTopMetadata) {
+ jsonWriter.WriteStartArray( );//Start tuple
+ jsonWriter.WriteValue($"{shard.Location.X}_{shard.Location.Y}");//Key of Tuple
+
+ jsonWriter.WriteStartObject( );
+ jsonWriter.WritePropertyName("prettyCoord");
+ jsonWriter.WriteValue(shard.Location.PrettyCoords(ClientAPI));
+
+ jsonWriter.WritePropertyName("chunkAge");
+ jsonWriter.WriteValue(shard.ChunkAge);
+
+ jsonWriter.WritePropertyName("temp");
+ jsonWriter.WriteValue(shard.Temperature);
+
+ jsonWriter.WritePropertyName("YMax");
+ jsonWriter.WriteValue(shard.YMax);
+
+ jsonWriter.WritePropertyName("fert");
+ jsonWriter.WriteValue(shard.Fertility);
+
+ jsonWriter.WritePropertyName("forestDens");
+ jsonWriter.WriteValue(shard.ForestDensity);
+
+ jsonWriter.WritePropertyName("rain");
+ jsonWriter.WriteValue(shard.Rainfall);
+
+ jsonWriter.WritePropertyName("shrubDens");
+ jsonWriter.WriteValue(shard.ShrubDensity);
+
+ jsonWriter.WritePropertyName("airBlocks");
+ jsonWriter.WriteValue(shard.AirBlocks);
+
+ jsonWriter.WritePropertyName("nonAirBlocks");
+ jsonWriter.WriteValue(shard.NonAirBlocks);
+
+ //TODO: Heightmap ?
+ //Start rockMap ; FOR a Ratio....on tooltip GUI
+ jsonWriter.WritePropertyName("rockRatio");
+ jsonWriter.WriteStartConstructor("Map");
+ jsonWriter.WriteStartArray( );
+ foreach (var rockEntry in shard.RockRatio) {
+ var rockBlock = ClientAPI.World.GetBlock(rockEntry.Key);
+ jsonWriter.WriteStartArray( );
+ jsonWriter.WriteValue(rockBlock.Code.Path);
+ jsonWriter.WriteValue(rockEntry.Value);//Total per chunk-column
+ jsonWriter.WriteEndArray( );
+ }
+ jsonWriter.WriteEndArray( );
+ jsonWriter.WriteEndConstructor( );//end rock-map
+
+ jsonWriter.WriteEndObject( );//end Map value: {Object}
+ jsonWriter.WriteEndArray( );//end Tuple
+ }
+
+ jsonWriter.WriteEndArray( );//Enclose tuples of chunkMetadata
+ jsonWriter.WriteEndConstructor( );//Close constructor of Map (chunkMetadata)
+ jsonWriter.WriteRaw(";\n");
+
+ jsonWriter.WriteRaw("ViewFrame.chunks.pointsOfInterest=");
+ jsonWriter.WriteStartConstructor("Map");
+ jsonWriter.WriteStartArray( );//An array of... 2-component arrays
+
+ foreach (var poi in POIs) {
+ EmitJsonMap(poi, jsonWriter);
+ }
+
+ foreach (var poi in EOIs) {
+ EmitJsonMap(poi, jsonWriter);
+ }
+
+ jsonWriter.WriteEndArray( );
+ jsonWriter.WriteEndConstructor( );
+ jsonWriter.WriteRaw(";\n");
+
+ jsonWriter.WriteWhitespace("\n");
+ jsonWriter.WriteComment("============= BlockID's for Rockmap / Rock-ratios ===============");
+ jsonWriter.WriteWhitespace("\n");
+
+ jsonWriter.WriteRaw("ViewFrame.chunks.rock_Lookup =");
+ jsonWriter.WriteStartConstructor("Map");
+ jsonWriter.WriteStartArray( );//An array of... 2-component arrays
+
+ foreach (var entry in RockIdCodes) {
+ var block = ClientAPI.World.GetBlock(entry.Key);
+ // stream.Write("{0},", Lang.GetUnformatted(block.Code.Path));
+ jsonWriter.WriteStartArray( );
+ jsonWriter.WriteValue(block.Code.Path);
+
+ jsonWriter.WriteStartObject( );
+ jsonWriter.WritePropertyName("assetCode");
+ jsonWriter.WriteValue(entry.Value);
+
+ jsonWriter.WritePropertyName("name");
+ jsonWriter.WriteValue(Lang.GetUnformatted(block.Code.Path));
+ //}
+
+ jsonWriter.WriteEndObject( );
+ jsonWriter.WriteEndArray( );
+ }
+ jsonWriter.WriteEndArray( );
+ jsonWriter.WriteEndConstructor( );
+ //stream.Write("]);\n");
+ jsonWriter.WriteRaw(";\n");
+
+ jsonWriter.Flush( );
+ }
+ }
+
+ }
+
+ public void EmitJsonMap(PointOfInterest @this, JsonTextWriter jsonWriter)
+ {
+ jsonWriter.WriteStartArray( );
+ jsonWriter.WriteValue($"{@this.Location.X}_{@this.Location.Z}");
+
+ jsonWriter.WriteStartArray( );
+ //jsonWriter.WriteValue(@this.Name);
+
+ jsonWriter.WriteValue(@this.Location.X);
+ jsonWriter.WriteValue(@this.Location.Z); //Y is HEIGHT from Mantle... Z is Right from edge of world
+
+ jsonWriter.WriteValue(@this.Location.PrettyCoords(ClientAPI));
+
+ jsonWriter.WriteValue(@this.Notes);//put more escaping in Java-script if needed
+
+ jsonWriter.WriteValue(@this.Timestamp);
+
+ jsonWriter.WriteEndArray( );
+ jsonWriter.WriteEndArray( );
+ }
+
+ public void EmitJsonMap(EntityOfInterest @this, JsonTextWriter jsonWriter)
+ {
+ jsonWriter.WriteStartArray( );
+ jsonWriter.WriteValue($"{@this.Location.X}_{@this.Location.Z}");
+
+
+ jsonWriter.WriteStartArray( );
+ //jsonWriter.WriteValue(@this.Name);
+
+ jsonWriter.WriteValue(@this.Location.X);
+ jsonWriter.WriteValue(@this.Location.Z); //Y is HEIGHT from Mantle... Z is Right from edge of world
+
+ jsonWriter.WriteValue(@this.Location.PrettyCoords(ClientAPI));
+
+ jsonWriter.WriteValue(@this.Notes);//put more escaping in Java-script if needed
+
+ jsonWriter.WriteValue(@this.Timestamp);
+
+ jsonWriter.WriteValue(@this.EntityId);
+
+ jsonWriter.WriteEndArray( );
+ jsonWriter.WriteEndArray( );
+ }
+
+ /// <summary>
+ /// Dynamically reflect Points-of-Something fields for metadata descriptors
+ /// </summary>
+ /// <returns>Json-array names of fields for use in map display.</returns>
+ public string MakePreBuiltJSON( )
+ {
+ var builder = new StringBuilder(512);
+ builder.Append("ViewFrame.chunks={};\n");
+ builder.AppendFormat("ViewFrame.chunks.worldSeedNum='{0}';",
+ ClientAPI.World.Seed
+ );
+ builder.AppendFormat("ViewFrame.chunks.chunkSize={0};",
+ chunkSize
+ );
+
+ builder.Append("ViewFrame.chunks.chunkMetadataNames=[");
+ var fields = typeof(ColumnMeta).GetFields( );
+ var attsToSort = new List<DisplayNameAttribute>( );
+ // this is so gross
+ foreach (var f in fields) {
+ var att = f.GetCustomAttribute(typeof(DisplayNameAttribute));
+ if (att != null) {
+ attsToSort.Add(( DisplayNameAttribute )att);
+ }
+
+ }
+ foreach (var att in attsToSort.OrderBy(a => a.order))
+ builder.AppendFormat("'{0}',", att.name);
+ builder.Append("];\n");
+
+ builder.Append("ViewFrame.chunks.pointsOfInterestNames=[");
+ fields = typeof(PointOfInterest).GetFields( );
+ attsToSort = new List<DisplayNameAttribute>( );
+
+ foreach (var f in fields) {
+ var att = f.GetCustomAttribute(typeof(DisplayNameAttribute));
+ if (att != null)
+ attsToSort.Add(( DisplayNameAttribute )att);
+ }
+ foreach (var att in attsToSort.OrderBy(a => a.order))
+ builder.AppendFormat("'{0}',", att.name);
+ builder.Append("];\n");
+
+ builder.Append("ViewFrame.chunks.entityOfInterestNames=[");
+ fields = typeof(EntityOfInterest).GetFields( );
+ attsToSort = new List<DisplayNameAttribute>( );
+
+ foreach (var f in fields) {
+ var att = f.GetCustomAttribute(typeof(DisplayNameAttribute));
+ if (att != null)
+ attsToSort.Add(( DisplayNameAttribute )att);
+ }
+ foreach (var att in attsToSort.OrderBy(a => a.order))
+ builder.AppendFormat("'{0}',", att.name);
+ builder.Append("];\n");
+
+ return builder.ToString( );
+ }
+ }
+}
+