Automap (client) [VS plugin mod]
Revision | 01a930a1c73adca96b7f4b23b4cffff18f24c45d (tree) |
---|---|
Time | 2020-03-31 00:35:38 |
Author | melchior <melchior@user...> |
Commiter | melchior |
Merge branch 'vgd' of into Split_renderers
(Pass 1, absent new Json generation, incomplete)
@@ -79,22 +79,24 @@ | ||
79 | 79 | <Compile Include="AutomapMod.cs" /> |
80 | 80 | <Compile Include="Properties\AssemblyInfo.cs" /> |
81 | 81 | <Compile Include="Helpers.cs" /> |
82 | - <Compile Include="Data\PointOfInterest.cs" /> | |
83 | - <Compile Include="Data\BlockDesignator.cs" /> | |
84 | - <Compile Include="Designators\DefaultDesignators.cs" /> | |
85 | - <Compile Include="Data\ColumnMeta.cs" /> | |
82 | + <Compile Include="Data\PointOfInterest.cs" /> | |
83 | + <Compile Include="Data\BlockDesignator.cs" /> | |
84 | + <Compile Include="Data\EntitiesOfInterest.cs" /> | |
85 | + <Compile Include="Data\EntityDesignator.cs" /> | |
86 | + <Compile Include="Data\ColumnMeta.cs" /> | |
86 | 87 | <Compile Include="Data\PngMetadataChunk.cs" /> |
88 | + <Compile Include="Designators\DefaultDesignators.cs" /> | |
87 | 89 | <Compile Include="Subsystems\AutomapSystem.cs" /> |
88 | 90 | <Compile Include="Subsystems\AutomapGUIDialog.cs" /> |
89 | 91 | <Compile Include="Renderers\IChunkRenderer.cs" /> |
90 | - <Compile Include="Renderers\StandardRenerer.cs" /> | |
92 | + <Compile Include="Renderers\StandardRenderer.cs" /> | |
91 | 93 | <Compile Include="Renderers\AlternateRenderer.cs" /> |
92 | - <Compile Include="Data\EntitiesOfInterest.cs" /> | |
93 | - <Compile Include="Data\EntityDesignator.cs" /> | |
94 | 94 | <Compile Include="Data\StatusData.cs" /> |
95 | 95 | <Compile Include="Data\CommandData.cs" /> |
96 | 96 | <Compile Include="Data\CommandType.cs" /> |
97 | 97 | <Compile Include="Data\PersistedConfiguration.cs" /> |
98 | + <Compile Include="Data\DisplayNameAttribute.cs" /> | |
99 | + <Compile Include="Subsystems\JsonGenerator.cs" /> | |
98 | 100 | </ItemGroup> |
99 | 101 | <ItemGroup> |
100 | 102 | <Folder Include="VS_libs\" /> |
@@ -12,7 +12,7 @@ using Vintagestory.API.MathTools; | ||
12 | 12 | |
13 | 13 | namespace Automap |
14 | 14 | { |
15 | - public delegate void BlockDesignatonAction(ICoreClientAPI clientAPI, PointsOfInterest poi, BlockPos posn, Block block); | |
15 | + public delegate void BlockDesignatorAction(ICoreClientAPI clientAPI, PointsOfInterest poi, BlockPos posn, Block block); | |
16 | 16 | |
17 | 17 | /// <summary> |
18 | 18 | /// Point of Interest Rule Designator |
@@ -24,7 +24,7 @@ namespace Automap | ||
24 | 24 | public Color OverwriteColor; |
25 | 25 | |
26 | 26 | [JsonIgnore] |
27 | - public BlockDesignatonAction SpecialAction; | |
27 | + public BlockDesignatorAction SpecialAction; | |
28 | 28 | |
29 | 29 | [JsonProperty] |
30 | 30 | public string SpecialActionName; |
@@ -51,7 +51,7 @@ namespace Automap | ||
51 | 51 | this.Enabled = true; |
52 | 52 | } |
53 | 53 | |
54 | - public BlockDesignator(AssetLocation pattern, Color overwriteColor, EnumBlockMaterial? material, BlockDesignatonAction specialAct) | |
54 | + public BlockDesignator(AssetLocation pattern, Color overwriteColor, EnumBlockMaterial? material, BlockDesignatorAction specialAct) | |
55 | 55 | { |
56 | 56 | this.Pattern = pattern; |
57 | 57 | this.OverwriteColor = overwriteColor; |
@@ -1,6 +1,5 @@ | ||
1 | 1 | using System; |
2 | 2 | using System.Collections.Generic; |
3 | -using System.Collections.ObjectModel; | |
4 | 3 | using System.Collections.Specialized; |
5 | 4 | |
6 | 5 |
@@ -8,7 +7,10 @@ using Vintagestory.API.MathTools; | ||
8 | 7 | using Vintagestory.API.Common; |
9 | 8 | |
10 | 9 | using ProtoBuf; |
11 | - | |
10 | +using System.IO; | |
11 | +using System.Collections.ObjectModel; | |
12 | +using System.Text; | |
13 | +using Vintagestory.API.Client; | |
12 | 14 | |
13 | 15 | namespace Automap |
14 | 16 | { |
@@ -16,36 +18,47 @@ namespace Automap | ||
16 | 18 | public struct ColumnMeta |
17 | 19 | { |
18 | 20 | [ProtoMember(1)] |
21 | + [DisplayName(0, "Coords.")] | |
19 | 22 | public Vec2i Location; |
20 | 23 | |
21 | 24 | [ProtoMember(2)] |
25 | + [DisplayName(1, "Age")] | |
22 | 26 | public TimeSpan ChunkAge;//OLDEST CHUNK. from chunk last edit |
23 | 27 | |
24 | 28 | [ProtoMember(3)] |
29 | + [DisplayName(2, "Temp.")] | |
25 | 30 | public float Temperature;// Temperature - surface |
26 | 31 | |
27 | 32 | [ProtoMember(4)] |
33 | + [DisplayName(3, "Y Max.")] | |
28 | 34 | public ushort YMax;// Y feature height |
29 | 35 | |
30 | 36 | [ProtoMember(5)] |
37 | + //[DisplayName(10, "Rocks")] | |
31 | 38 | public Dictionary<int, uint> RockRatio;//[Column] Geographic region (rock) Ratio. [BlockID * count] |
32 | 39 | |
33 | 40 | [ProtoMember(6)] |
41 | + [DisplayName(4, "Fert.")] | |
34 | 42 | public float Fertility; |
35 | 43 | |
36 | 44 | [ProtoMember(7)] |
45 | + [DisplayName(5, "Forest")] | |
37 | 46 | public float ForestDensity; |
38 | 47 | |
39 | 48 | [ProtoMember(8)] |
49 | + [DisplayName(6, "Rain")] | |
40 | 50 | public float Rainfall; |
41 | 51 | |
42 | 52 | [ProtoMember(9)] |
53 | + [DisplayName(7, "Shrub")] | |
43 | 54 | public float ShrubDensity; |
44 | 55 | |
45 | 56 | [ProtoMember(10)] |
57 | + [DisplayName(8, "Air blocks")] | |
46 | 58 | public uint AirBlocks; |
47 | 59 | |
48 | 60 | [ProtoMember(11)] |
61 | + [DisplayName(9, "Non-air")] | |
49 | 62 | public uint NonAirBlocks; |
50 | 63 | |
51 | 64 | [ProtoMember(12)] |
@@ -56,7 +69,7 @@ namespace Automap | ||
56 | 69 | public ushort[,] HeightMap;//Needs to be 'flattened' for Protocol-Buffer serialization |
57 | 70 | |
58 | 71 | [ProtoMember(13)] |
59 | - private ushort[ ] _flattened_HeightMap; | |
72 | + private ushort[] _flattened_HeightMap; | |
60 | 73 | |
61 | 74 | |
62 | 75 | public ColumnMeta(Vec2i loc, byte chunkSize = 32) |
@@ -89,48 +102,70 @@ namespace Automap | ||
89 | 102 | this.YMax = mapChunk.YMax; |
90 | 103 | } |
91 | 104 | |
92 | - | |
105 | + public void Write(StreamWriter stream, ICoreClientAPI ClientApi) | |
106 | + { | |
107 | + // this is gross i hate this | |
108 | + stream.Write("['{0}_{1}',[", | |
109 | + Location.X, | |
110 | + Location.Y | |
111 | + ); | |
112 | + stream.Write("'{0}',", Location.PrettyCoords(ClientApi)); | |
113 | + stream.Write("'{0}',", ChunkAge); | |
114 | + stream.Write("'{0}',", Temperature.ToString("F3")); | |
115 | + stream.Write("'{0}',", YMax); | |
116 | + stream.Write("'{0}',", Fertility.ToString("F3")); | |
117 | + stream.Write("'{0}',", ForestDensity.ToString("F3")); | |
118 | + stream.Write("'{0}',", Rainfall.ToString("F3")); | |
119 | + stream.Write("'{0}',", ShrubDensity.ToString("F3")); | |
120 | + stream.Write("'{0}',", AirBlocks); | |
121 | + stream.Write("'{0}',", NonAirBlocks); | |
122 | + stream.Write("]]"); | |
123 | + } | |
93 | 124 | |
94 | 125 | [ProtoBeforeSerialization] |
95 | - private void PrepareData( ) | |
126 | + private void PrepareData() | |
96 | 127 | { |
97 | 128 | |
98 | - if (HeightMap != null) { | |
99 | - _flattened_HeightMap = new ushort[ChunkSize * ChunkSize]; | |
100 | - int flatIndex = 0; | |
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 | + } | |
101 | 142 | |
102 | - for (byte col = 0; col < ChunkSize; col++) { | |
103 | - for (byte row = 0; row < ChunkSize; row++) { | |
104 | - _flattened_HeightMap[flatIndex] = HeightMap[col, row]; | |
105 | - flatIndex++; | |
106 | 143 | } |
107 | - } | |
108 | - | |
109 | - } | |
110 | 144 | |
111 | 145 | } |
112 | 146 | |
113 | 147 | |
114 | 148 | [ProtoAfterDeserialization] |
115 | - private void PostProcess( ) | |
149 | + private void PostProcess() | |
116 | 150 | { |
117 | - if (this.HeightMap == null) this.HeightMap = new ushort[ChunkSize, ChunkSize]; | |
118 | - | |
119 | - if (_flattened_HeightMap != null) { | |
120 | - int col, row; | |
151 | + if (this.HeightMap == null) this.HeightMap = new ushort[ChunkSize, ChunkSize]; | |
121 | 152 | |
122 | - BitVector32 bitMasker = new BitVector32(0); | |
123 | - var rowSection = BitVector32.CreateSection(( short )(ChunkSize - 1)); | |
124 | - var colSection = BitVector32.CreateSection(( short )(ChunkSize - 1), rowSection); | |
125 | - | |
126 | - for (uint rowcol = 0; rowcol < (ChunkSize * ChunkSize); rowcol++) { | |
127 | - bitMasker = new BitVector32(data: ( int )rowcol); | |
128 | - row = bitMasker[rowSection]; | |
129 | - col = bitMasker[colSection]; | |
130 | - HeightMap[col, row] = _flattened_HeightMap[rowcol]; | |
131 | - } | |
153 | + if (_flattened_HeightMap != null) | |
154 | + { | |
155 | + int col, row; | |
156 | + _ = new BitVector32(0); | |
157 | + var rowSection = BitVector32.CreateSection((short) (ChunkSize - 1)); | |
158 | + var colSection = BitVector32.CreateSection((short) (ChunkSize - 1), rowSection); | |
159 | + | |
160 | + for (uint rowcol = 0; rowcol < (ChunkSize * ChunkSize); rowcol++) | |
161 | + { | |
162 | + BitVector32 bitMasker = new BitVector32(data: (int) rowcol); | |
163 | + row = bitMasker[rowSection]; | |
164 | + col = bitMasker[colSection]; | |
165 | + HeightMap[col, row] = _flattened_HeightMap[rowcol]; | |
166 | + } | |
132 | 167 | |
133 | - } | |
168 | + } | |
134 | 169 | |
135 | 170 | } |
136 | 171 |
@@ -217,5 +252,4 @@ namespace Automap | ||
217 | 252 | } |
218 | 253 | |
219 | 254 | } |
220 | -} | |
221 | - | |
255 | +} | |
\ No newline at end of file |
@@ -0,0 +1,17 @@ | ||
1 | +using System; | |
2 | +using System.Reflection; | |
3 | + | |
4 | +namespace Automap | |
5 | +{ | |
6 | + [AttributeUsage(AttributeTargets.Field)] | |
7 | + public class DisplayNameAttribute : Attribute | |
8 | + { | |
9 | + public string name; | |
10 | + public byte order; | |
11 | + public DisplayNameAttribute(byte order, string name) | |
12 | + { | |
13 | + this.order = order; | |
14 | + this.name = name; | |
15 | + } | |
16 | + } | |
17 | +} | |
\ No newline at end of file |
@@ -1,36 +1,46 @@ | ||
1 | 1 | using System; |
2 | 2 | using System.Collections.Generic; |
3 | 3 | using System.Collections.ObjectModel; |
4 | - | |
4 | +using System.IO; | |
5 | 5 | using System.Linq; |
6 | 6 | |
7 | 7 | using Vintagestory.API.Common.Entities; |
8 | 8 | using Vintagestory.API.MathTools; |
9 | +using Vintagestory.API.Client; | |
9 | 10 | |
10 | 11 | using ProtoBuf; |
11 | 12 | |
13 | +using Newtonsoft.Json; | |
14 | + | |
12 | 15 | namespace Automap |
13 | 16 | { |
14 | 17 | /// <summary> |
15 | - /// Actual Physical Point in space - that is interesting. | |
18 | + /// Basically the same as a POI but for an entity | |
16 | 19 | /// </summary> |
17 | 20 | [ProtoContract] |
18 | 21 | public struct EntityOfInterest |
19 | 22 | { |
23 | + | |
20 | 24 | [ProtoMember(1)] |
21 | 25 | public string Name; |
22 | - | |
26 | + | |
27 | + [DisplayName(1, "Notes")] | |
23 | 28 | [ProtoMember(2)] |
24 | 29 | public string Notes; |
25 | 30 | |
31 | + [DisplayName(0, "Loc.")] | |
26 | 32 | [ProtoMember(3)] |
27 | 33 | public BlockPos Location; |
28 | 34 | |
35 | + [DisplayName(2, "Time")] | |
29 | 36 | [ProtoMember(4)] |
30 | 37 | public DateTime Timestamp; |
31 | 38 | |
39 | + [DisplayName(3, "ID")] | |
32 | 40 | [ProtoMember(5)] |
33 | 41 | public long EntityId; |
42 | + | |
43 | + | |
34 | 44 | } |
35 | 45 | |
36 | 46 | /// <summary> |
@@ -39,6 +49,8 @@ namespace Automap | ||
39 | 49 | /// <remarks>Tracked by ID - these never leave.</remarks> |
40 | 50 | public class EntitiesOfInterest : KeyedCollection<long, EntityOfInterest> |
41 | 51 | { |
52 | + protected override long GetKeyForItem(EntityOfInterest item) | |
53 | + => item.EntityId; | |
42 | 54 | |
43 | 55 | internal void AddReplace(EntityOfInterest entity) |
44 | 56 | { |
@@ -48,8 +60,6 @@ namespace Automap | ||
48 | 60 | Add(entity); |
49 | 61 | } |
50 | 62 | |
51 | - protected override long GetKeyForItem(EntityOfInterest item) | |
52 | - => item.EntityId; | |
53 | 63 | } |
54 | 64 | } |
55 | 65 |
@@ -13,7 +13,7 @@ using Vintagestory.API.MathTools; | ||
13 | 13 | |
14 | 14 | namespace Automap |
15 | 15 | { |
16 | - public delegate void EntityDesignatonAction(ICoreClientAPI clientAPI, EntitiesOfInterest poi, BlockPos posn, Entity entity); | |
16 | + public delegate void EntityDesignatorAction(ICoreClientAPI clientAPI, EntitiesOfInterest poi, BlockPos posn, Entity entity); | |
17 | 17 | |
18 | 18 | /// <summary> |
19 | 19 | /// Point of Interest Rule Designator |
@@ -25,7 +25,7 @@ namespace Automap | ||
25 | 25 | public Color Color; |
26 | 26 | |
27 | 27 | [JsonIgnore] |
28 | - public EntityDesignatonAction SpecialAction; | |
28 | + public EntityDesignatorAction SpecialAction; | |
29 | 29 | |
30 | 30 | [JsonProperty] |
31 | 31 | public string SpecialActionName; |
@@ -52,7 +52,7 @@ namespace Automap | ||
52 | 52 | Enabled = true; |
53 | 53 | } |
54 | 54 | |
55 | - public EntityDesignator(AssetLocation pattern, Color color, EnumEntityState? state, EntityDesignatonAction specialAct) | |
55 | + public EntityDesignator(AssetLocation pattern, Color color, EnumEntityState? state, EntityDesignatorAction specialAct) | |
56 | 56 | { |
57 | 57 | Pattern = pattern; |
58 | 58 | Color = color; |
@@ -1,11 +1,15 @@ | ||
1 | 1 | using System; |
2 | 2 | using System.Collections.ObjectModel; |
3 | +using System.IO; | |
3 | 4 | |
5 | +using Vintagestory.API.Client; | |
4 | 6 | using Vintagestory.API.Common; |
5 | 7 | using Vintagestory.API.MathTools; |
6 | 8 | |
7 | 9 | using ProtoBuf; |
8 | 10 | |
11 | +using Newtonsoft.Json; | |
12 | + | |
9 | 13 | namespace Automap |
10 | 14 | { |
11 | 15 | /// <summary> |
@@ -17,14 +21,19 @@ namespace Automap | ||
17 | 21 | [ProtoMember(1)] |
18 | 22 | public string Name; |
19 | 23 | |
24 | + [DisplayName(1, "Notes")] | |
20 | 25 | [ProtoMember(2)] |
21 | 26 | public string Notes; |
22 | 27 | |
28 | + [DisplayName(0, "Loc.")] | |
23 | 29 | [ProtoMember(3)] |
24 | 30 | public BlockPos Location; |
25 | 31 | |
32 | + [DisplayName(2, "Time")] | |
26 | 33 | [ProtoMember(4)] |
27 | 34 | public DateTime Timestamp; |
35 | + | |
36 | + | |
28 | 37 | } |
29 | 38 | |
30 | 39 | public class PointsOfInterest : KeyedCollection<BlockPos, PointOfInterest> |
@@ -135,7 +135,7 @@ namespace Automap | ||
135 | 135 | |
136 | 136 | internal static void KeepTrackOfMerchant(ICoreClientAPI clientAPI, EntitiesOfInterest poi, BlockPos posn, Entity entity) |
137 | 137 | { |
138 | - clientAPI.Logger.VerboseDebug("Trader: {0} @ {1}", entity.GetName(), posn); | |
138 | + //clientAPI.Logger.VerboseDebug("Trader: {0} @ {1}", entity.GetName(), posn); | |
139 | 139 | |
140 | 140 | var traderJoe = entity as EntityTrader; |
141 | 141 | var message = $"{entity.GetName()} Alive: {traderJoe.Alive}"; |
@@ -0,0 +1,22 @@ | ||
1 | +#!/usr/local/bin/node | |
2 | + | |
3 | +// im sorry | |
4 | +// cd into MapSRC and run node ./build.js and this will concat and stuff | |
5 | +const fs = require('fs'); | |
6 | + | |
7 | +fs.readFile('./src/Automap.html', 'utf8', (err, d) => { | |
8 | + if (err) console.log(err); | |
9 | + let outD = d.replace(/<link rel=\"stylesheet\" href=\"(.*)\">/g, '<style>REP:$1</style>') | |
10 | + .replace(/(<script type=\"text\/javascript\") src=\"(.*)\">/g, '$1>REP:$2') | |
11 | + .replace(/REP:(\w*\.\w*)/g, (match, name, offset, string) => { | |
12 | + return fs.readFileSync('./src/' + name, 'utf8') | |
13 | + .replace(/\/\/.*\n?/g, ''); | |
14 | + }) | |
15 | + .replace(/[\t\n]/g, ''); | |
16 | + fs.writeFile('./dist/automap.html', outD, err => { | |
17 | + if (err) console.log(err); | |
18 | + }); | |
19 | + fs.writeFile('../assets/automap/config/automap.html', outD, err => { | |
20 | + if (err) console.log(err); | |
21 | + }); | |
22 | +}); | |
\ No newline at end of file |
@@ -0,0 +1,38 @@ | ||
1 | +html, body, .map { | |
2 | + width: 100%; | |
3 | + height: 100%; | |
4 | + margin: 0; | |
5 | + overflow: hidden; | |
6 | + outline: 1px dotted black; | |
7 | +} | |
8 | + | |
9 | +.infobox { | |
10 | + width: 15em; | |
11 | + /* height: 15em; */ | |
12 | + background-color: rgba(200, 200, 200, 0.5); | |
13 | + left: 0; | |
14 | + top: 0; | |
15 | + font-family: sans-serif; | |
16 | + position: absolute; | |
17 | + z-index: 1; | |
18 | +} | |
19 | + | |
20 | +h1 { | |
21 | + font-size: 22px; | |
22 | + margin: .6em 1em; | |
23 | + text-align: center; | |
24 | +} | |
25 | + | |
26 | +.infoboxTable { | |
27 | + margin: .3em auto; | |
28 | + width: 90%; | |
29 | + outline: 1px solid #333; | |
30 | +} | |
31 | + | |
32 | +.infoboxTable th { | |
33 | + width: 30%; | |
34 | +} | |
35 | + | |
36 | +.infoboxTable td { | |
37 | + text-align: right; | |
38 | +} | |
\ No newline at end of file |
@@ -0,0 +1,22 @@ | ||
1 | +<!DOCTYPE html> | |
2 | +<html lang="en" dir="ltr"> | |
3 | + | |
4 | +<head> | |
5 | + <meta charset="utf-8"> | |
6 | + <title>Automap</title> | |
7 | + <link rel="stylesheet" href="Automap.css"> | |
8 | +</head> | |
9 | + | |
10 | +<body> | |
11 | + <script type="text/javascript" src="ViewFrame.js"></script> | |
12 | + <script type="text/javascript" src="ViewFrameUtils.js"></script> | |
13 | + <div class="infobox"> | |
14 | + <h1>Chunk Info</h1> | |
15 | + <table class="infoboxTable"> | |
16 | + </table> | |
17 | + </div> | |
18 | + <script type="text/javascript" src="index.js"></script> | |
19 | + | |
20 | +</body> | |
21 | + | |
22 | +</html> | |
\ No newline at end of file |
@@ -0,0 +1,140 @@ | ||
1 | +function ViewFrame() { | |
2 | + // dom stuff | |
3 | + const map = document.createElement('canvas'); // the map we see | |
4 | + map.className = 'map'; | |
5 | + map.height = window.innerHeight; | |
6 | + map.width = window.innerWidth; | |
7 | + document.getElementsByTagName('body')[0].append(map); | |
8 | + // this is the map that we actually draw on | |
9 | + this.map = map.getContext('2d', { | |
10 | + alpha: false | |
11 | + }); | |
12 | + this.map.imageSmoothingEnabled = false; | |
13 | + | |
14 | + // the info box in the corner | |
15 | + this.infobox = document.getElementsByClassName('infoboxTable')[0]; | |
16 | + this.infoboxSlots = new Array(); | |
17 | + | |
18 | + // load the metadata! | |
19 | + this.chunkScript = document.createElement('script'); | |
20 | + this.chunkScript.type = 'text/javascript'; | |
21 | + this.chunkScript.src = 'Metadata.js'; | |
22 | + document.getElementsByTagName('body')[0].append(this.chunkScript); | |
23 | + this.chunkScript.addEventListener('load', () => { | |
24 | + ViewFrame.initInfobox(this.infobox, this.infoboxSlots); | |
25 | + this.x = ViewFrame.chunks.startCoords[0]; | |
26 | + this.y = ViewFrame.chunks.startCoords[1]; | |
27 | + this.availableChunks = ViewFrame.chunks.chunkMetadata; | |
28 | + this.render(); | |
29 | + }, { | |
30 | + once: true | |
31 | + }); | |
32 | + | |
33 | + // Tracks images that have been loaded and are on the map | |
34 | + this.loadedChunksByName = new Map(); | |
35 | + // this is needed because [1, 2] != [1, 2] and thats how we store coords. | |
36 | + this.loadedChunksByCoords = new Map(); | |
37 | + this.availableChunks = null; // the chunks in ./Metadata.js | |
38 | + // so that we dont render twice at the same time | |
39 | + this.rendering = false; | |
40 | + | |
41 | + this.x = -1; | |
42 | + this.y = -1; // can be fractional | |
43 | + this.zoom = 32; // pixels wide the images are to be | |
44 | + this.updateEdges(); | |
45 | +} | |
46 | +// prototypes, some less... notable? methods are | |
47 | +// in ViewFrameUtils.js | |
48 | +ViewFrame.prototype.reloadChunkList = function () { | |
49 | + if (this.chunkScript) { | |
50 | + this.chunkScript.remove(); | |
51 | + delete this.chunkScript; | |
52 | + } | |
53 | + | |
54 | + this.chunkScript = document.createElement('script'); | |
55 | + this.chunkScript.type = 'text/javascript'; | |
56 | + this.chunkScript.src = 'Metadata.js'; | |
57 | + document.getElementsByTagName('body')[0].append(this.chunkScript); | |
58 | + | |
59 | + this.chunkScript.addEventListener('load', () => { | |
60 | + this.availableChunks = ViewFrame.chunks.chunkMetadata; | |
61 | + this.render(); | |
62 | + }); | |
63 | +}; | |
64 | + | |
65 | +ViewFrame.prototype.render = function () { | |
66 | + if (!this.availableChunks) return; | |
67 | + if (this.rendering) clearInterval(ViewFrame.intervalRef); | |
68 | + this.rendering = true; | |
69 | + this.updateEdges(); | |
70 | + this.map.clearRect(0, 0, window.innerWidth, window.innerHeight); | |
71 | + // culling | |
72 | + this.loadedChunksByCoords | |
73 | + .forEach((chunk, coord) => { // check the bounds | |
74 | + if (coord[0] < this.eastChunk && | |
75 | + coord[0] >= this.westChunk && | |
76 | + coord[1] <= this.northChunk && | |
77 | + coord[1] >= this.southChunk) { | |
78 | + | |
79 | + this.place(chunk, coord[0], coord[1]); | |
80 | + return; | |
81 | + } | |
82 | + // its out of range!!! | |
83 | + // get 'em boys!!!!! | |
84 | + this.loadedChunksByCoords.delete(coord); | |
85 | + this.loadedChunksByName.delete(coord.join('_')); | |
86 | + chunk.remove(); | |
87 | + }); | |
88 | + | |
89 | + // gathering what we need to load | |
90 | + const neededChunks = new Set(); | |
91 | + for (var x = this.westChunk; x < this.eastChunk; x++) { | |
92 | + for (var y = this.southChunk; y < this.northChunk; y++) { | |
93 | + const chunKey = [x, y]; // chunk + key = chunKey :) | |
94 | + const name = chunKey.join('_'); | |
95 | + // continue if its not available, or it is loaded | |
96 | + if (!this.availableChunks.has(name) || | |
97 | + this.loadedChunksByName.has(name)) continue; | |
98 | + neededChunks.add(chunKey); | |
99 | + } | |
100 | + } | |
101 | + // iterating over everything we need to load | |
102 | + const it = neededChunks.values(); | |
103 | + ViewFrame.intervalRef = setInterval(() => { | |
104 | + let round = it.next(); | |
105 | + if (!round.done) { | |
106 | + // load | |
107 | + const img = new Image(32, 32); | |
108 | + const name = round.value.join('_'); | |
109 | + | |
110 | + img.src = name + '.png'; | |
111 | + | |
112 | + decode(img, loadedImage => { | |
113 | + this.place(img, round.value[0], round.value[1]); | |
114 | + }); | |
115 | + this.loadedChunksByName.set(name, img); | |
116 | + this.loadedChunksByCoords.set(round.value, img); | |
117 | + } else { | |
118 | + clearInterval(ViewFrame.intervalRef); | |
119 | + this.rendering = false; | |
120 | + } | |
121 | + }, 4); | |
122 | +}; | |
123 | + | |
124 | +ViewFrame.prototype.place = function (img, x, y) { | |
125 | + x -= this.x; | |
126 | + y -= this.y; | |
127 | + x *= this.zoom; | |
128 | + y *= this.zoom; | |
129 | + x += this.width / 2; | |
130 | + y += this.height / 2; | |
131 | + | |
132 | + this.map.drawImage(img, Math.floor(x), Math.floor(y), this.zoom, this.zoom); | |
133 | +}; | |
134 | + | |
135 | +ViewFrame.prototype.updateInfobox = function (chunkName) { | |
136 | + const chunkMeta = this.availableChunks.get(chunkName); | |
137 | + this.infoboxSlots.forEach((l, k) => { | |
138 | + l.innerText = chunkMeta ? chunkMeta[k] : '0'; | |
139 | + }); | |
140 | +}; | |
\ No newline at end of file |
@@ -0,0 +1,62 @@ | ||
1 | +ViewFrame.initInfobox = function (ibox, iboxSlots) { | |
2 | + | |
3 | + ViewFrame.chunks | |
4 | + .chunkMetadataNames.forEach((item, i) => { | |
5 | + const slot = document.createElement('tr'); | |
6 | + const head = document.createElement('th'); | |
7 | + head.innerText = item; | |
8 | + const row = document.createElement('td'); | |
9 | + row.innerText = '0'; | |
10 | + iboxSlots[i] = row; | |
11 | + slot.append(head, row); | |
12 | + ibox.append(slot); | |
13 | + }); | |
14 | +}; | |
15 | + | |
16 | +ViewFrame.prototype.updateEdges = function () { | |
17 | + if (this.width != window.innerWidth || this.height != window.innerHeight) { | |
18 | + this.width = window.innerWidth; | |
19 | + this.map.canvas.width = this.width; | |
20 | + this.height = window.innerHeight; | |
21 | + this.map.canvas.height = this.height; | |
22 | + this.map.imageSmoothingEnabled = false; | |
23 | + } | |
24 | + const chunksWide = Math.ceil(this.width / this.zoom); | |
25 | + const chunksHigh = Math.ceil(this.height / this.zoom); | |
26 | + | |
27 | + this.east = this.x + chunksWide / 2; // this is fractional and is used to keep track of the edges of the window | |
28 | + this.eastChunk = Math.ceil(this.east); // this is not and is used to track the chunks that need to load | |
29 | + this.west = this.x - chunksWide / 2; | |
30 | + this.westChunk = Math.floor(this.west); | |
31 | + this.north = this.y + chunksHigh / 2; | |
32 | + this.northChunk = Math.ceil(this.north); | |
33 | + this.south = this.y - chunksHigh / 2; | |
34 | + this.southChunk = Math.floor(this.south); | |
35 | +}; | |
36 | + | |
37 | +ViewFrame.prototype.moveCenter = function (dx, dy) { | |
38 | + // to pan when we click on the map! | |
39 | + this.x += (dx - this.width / 2) / this.zoom; | |
40 | + this.y += (dy - this.height / 2) / this.zoom; | |
41 | +}; | |
42 | +ViewFrame.prototype.setCenter = function (x, y) { | |
43 | + this.x = x; | |
44 | + this.y = y; | |
45 | +}; | |
46 | + | |
47 | +ViewFrame.prototype.clear = function () { | |
48 | + this.loadedChunksByName.clear(); | |
49 | + this.loadedChunksByCoords.clear(); | |
50 | + if (this.chunkScript) this.chunkScript.remove(); | |
51 | + delete this.chunkScript; | |
52 | + delete ViewFrame.chunks; | |
53 | + this.map.clearRect(0, 0, window.innerWidth, window.innerHeight); | |
54 | +}; | |
55 | + | |
56 | +function decode(img, cb) { | |
57 | + img.decode() | |
58 | + .then(() => { | |
59 | + cb(img); | |
60 | + }) | |
61 | + .catch(() => {}); // so images arent added on error | |
62 | +} | |
\ No newline at end of file |
@@ -0,0 +1,93 @@ | ||
1 | +const vf = new ViewFrame(); | |
2 | +vf.reloadChunkList(); | |
3 | + | |
4 | +// the event handlers are in iifes so they dont make unneeded globals. | |
5 | +// resize, delay re-render to reduce lag. | |
6 | +(function () { | |
7 | + var id; | |
8 | + window.addEventListener('resize', () => { | |
9 | + clearTimeout(id); | |
10 | + id = setTimeout(() => { | |
11 | + vf.render(); | |
12 | + }, 500); | |
13 | + }); | |
14 | +}()); | |
15 | + | |
16 | +// panning | |
17 | +(function () { | |
18 | + var id; | |
19 | + vf.map.canvas.addEventListener('mousedown', event => { | |
20 | + clearTimeout(id); | |
21 | + vf.moveCenter(event.pageX, event.pageY); | |
22 | + id = setTimeout(() => { | |
23 | + vf.render(); | |
24 | + }, 250); | |
25 | + }); | |
26 | +}()); | |
27 | + | |
28 | + | |
29 | +// #### CONTROLS #### | |
30 | +// hovering | |
31 | +(function () { | |
32 | + var lastX = 0; | |
33 | + var lastY = 0; | |
34 | + vf.map.canvas.addEventListener('mousemove', event => { | |
35 | + // only count if the mouse moved more than a chunk | |
36 | + let x = Math.floor(vf.x + | |
37 | + (event.clientX - vf.width / 2) / vf.zoom); | |
38 | + let y = Math.floor(vf.y + | |
39 | + (event.clientY - vf.height / 2) / vf.zoom); | |
40 | + if (x == lastX && y == lastY) return; | |
41 | + lastX = x; | |
42 | + lastY = y; | |
43 | + vf.updateInfobox(x + '_' + y); | |
44 | + }); | |
45 | +}()); | |
46 | + | |
47 | +// scroll/zoom | |
48 | +(function () { | |
49 | + var id; | |
50 | + vf.map.canvas.addEventListener('wheel', event => { | |
51 | + clearTimeout(id); | |
52 | + vf.zoom += -Math.sign(event.deltaY); | |
53 | + id = setTimeout(() => { | |
54 | + vf.render(); | |
55 | + }, 250); | |
56 | + }); | |
57 | +}()); | |
58 | + | |
59 | +// reload the chunk list every six seconds | |
60 | +(function () { | |
61 | + setInterval(() => { | |
62 | + vf.reloadChunkList(); | |
63 | + }, 6000); | |
64 | +}()); | |
65 | +// | |
66 | +// var i = 500; | |
67 | +// setTimeout(() => { | |
68 | +// vf.map.dispatchEvent(new MouseEvent('mousedown', { | |
69 | +// clientX: 879, | |
70 | +// clientY: 926 | |
71 | +// })); | |
72 | +// }, i += 1000); | |
73 | +// | |
74 | +// setTimeout(() => { | |
75 | +// vf.map.dispatchEvent(new MouseEvent('mousedown', { | |
76 | +// clientX: 666, | |
77 | +// clientY: 924 | |
78 | +// })); | |
79 | +// }, i += 2000); | |
80 | +// | |
81 | +// setTimeout(() => { | |
82 | +// vf.map.dispatchEvent(new MouseEvent('mousedown', { | |
83 | +// clientX: 1090, | |
84 | +// clientY: 936 | |
85 | +// })); | |
86 | +// }, i += 2000); | |
87 | +// | |
88 | +// setTimeout(() => { | |
89 | +// vf.map.dispatchEvent(new MouseEvent('mousedown', { | |
90 | +// clientX: 29, | |
91 | +// clientY: 785 | |
92 | +// })); | |
93 | +// }, i += 2000); | |
\ No newline at end of file |
@@ -3,6 +3,7 @@ using System.Collections.Concurrent; | ||
3 | 3 | using System.Collections.Generic; |
4 | 4 | using System.IO; |
5 | 5 | using System.Linq; |
6 | +using System.Reflection; | |
6 | 7 | using System.Text; |
7 | 8 | using System.Text.RegularExpressions; |
8 | 9 | using System.Threading; |
@@ -29,6 +30,7 @@ namespace Automap | ||
29 | 30 | private ICoreClientAPI ClientAPI { get; set; } |
30 | 31 | private ILogger Logger { get; set; } |
31 | 32 | private IChunkRenderer ChunkRenderer { get; set; } |
33 | + private JsonGenerator JsonGenerator { get; set; } | |
32 | 34 | |
33 | 35 | private const string _mapPath = @"Maps"; |
34 | 36 | private const string _chunkPath = @"Chunks"; |
@@ -43,6 +45,7 @@ namespace Automap | ||
43 | 45 | private ColumnsMetadata chunkTopMetadata; |
44 | 46 | private PointsOfInterest POIs = new PointsOfInterest(); |
45 | 47 | private EntitiesOfInterest EOIs = new EntitiesOfInterest(); |
48 | + private string jsonPreBuilt; | |
46 | 49 | |
47 | 50 | internal Dictionary<int, BlockDesignator> BlockID_Designators { get; private set; } |
48 | 51 | internal Dictionary<AssetLocation, EntityDesignator> Entity_Designators { get; private set; } |
@@ -72,14 +75,13 @@ namespace Automap | ||
72 | 75 | configuration = config; |
73 | 76 | |
74 | 77 | |
75 | - | |
76 | 78 | //TODO:Choose which one from GUI |
77 | 79 | this.ChunkRenderer = new StandardRenderer(clientAPI, logger); |
78 | 80 | |
79 | 81 | //Listen on bus for commands |
80 | 82 | ClientAPI.Event.RegisterEventBusListener(CommandListener, 1.0, AutomapSystem.AutomapCommandEventKey); |
81 | 83 | |
82 | - if (configuration.Autostart) | |
84 | + if (configuration.Autostart) | |
83 | 85 | { |
84 | 86 | CurrentState = CommandType.Run; |
85 | 87 | Logger.Debug("Autostart is Enabled."); |
@@ -93,7 +95,7 @@ namespace Automap | ||
93 | 95 | { |
94 | 96 | path = ClientAPI.GetOrCreateDataPath(_mapPath); |
95 | 97 | path = ClientAPI.GetOrCreateDataPath(Path.Combine(path, "World_" + ClientAPI.World.Seed));//Add name of World too...'ServerApi.WorldManager.CurrentWorldName' |
96 | - | |
98 | + JsonGenerator = new JsonGenerator(ClientAPI, Logger, path); | |
97 | 99 | |
98 | 100 | string mapFilename = Path.Combine(path, "automap.html"); |
99 | 101 | StreamWriter outputText = new StreamWriter(File.Open(mapFilename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)); |
@@ -102,6 +104,8 @@ namespace Automap | ||
102 | 104 | outputText.Write(staticMap.ToText()); |
103 | 105 | outputText.Flush(); |
104 | 106 | |
107 | + jsonPreBuilt = JsonGenerator.MakePreBuiltJSON(); | |
108 | + | |
105 | 109 | Prefill_POI_Designators(); |
106 | 110 | startChunkColumn = new Vec2i((ClientAPI.World.Player.Entity.LocalPos.AsBlockPos.X / chunkSize), (ClientAPI.World.Player.Entity.LocalPos.AsBlockPos.Z / chunkSize)); |
107 | 111 | chunkTopMetadata = new ColumnsMetadata(startChunkColumn); |
@@ -173,7 +177,7 @@ namespace Automap | ||
173 | 177 | if (!columnCounter.IsEmpty) |
174 | 178 | { |
175 | 179 | var tempSet = columnCounter.ToArray().OrderByDescending(kvp => kvp.Value); |
176 | - UpdateEntityMetadata( ); | |
180 | + UpdateEntityMetadata(); | |
177 | 181 | |
178 | 182 | foreach (var mostActiveCol in tempSet) |
179 | 183 | { |
@@ -188,11 +192,13 @@ namespace Automap | ||
188 | 192 | } |
189 | 193 | |
190 | 194 | ColumnMeta chunkMeta; |
191 | - if (chunkTopMetadata.Contains(mostActiveCol.Key)) { | |
192 | - chunkMeta = chunkTopMetadata[mostActiveCol.Key]; | |
195 | + if (chunkTopMetadata.Contains(mostActiveCol.Key)) | |
196 | + { | |
197 | + chunkMeta = chunkTopMetadata[mostActiveCol.Key]; | |
193 | 198 | } |
194 | - else { | |
195 | - chunkMeta = CreateColumnMetadata(mostActiveCol, mapChunk); | |
199 | + else | |
200 | + { | |
201 | + chunkMeta = CreateColumnMetadata(mostActiveCol, mapChunk); | |
196 | 202 | } |
197 | 203 | |
198 | 204 | ProcessChunkBlocks(mostActiveCol.Key, mapChunk, ref chunkMeta); |
@@ -225,7 +231,7 @@ namespace Automap | ||
225 | 231 | { |
226 | 232 | //What about chunk updates themselves; a update bitmap isn't kept... |
227 | 233 | updatedChunksTotal += updatedChunks; |
228 | - GenerateJSONMetadata(); | |
234 | + JsonGenerator.GenerateJSONMetadata(chunkTopMetadata, startChunkColumn, POIs, EOIs, RockIdCodes); | |
229 | 235 | updatedChunks = 0; |
230 | 236 | } |
231 | 237 |
@@ -275,7 +281,7 @@ namespace Automap | ||
275 | 281 | } |
276 | 282 | |
277 | 283 | private void Reload_POI_Designators() |
278 | - { | |
284 | + { | |
279 | 285 | Logger.VerboseDebug("Connecting {0} Configured Block-Designators", configuration.BlockDesignators.Count); |
280 | 286 | foreach (var designator in configuration.BlockDesignators) |
281 | 287 | { |
@@ -310,223 +316,6 @@ namespace Automap | ||
310 | 316 | } |
311 | 317 | |
312 | 318 | |
313 | - /// <summary> | |
314 | - /// Generates the JSON Metadata. (in Map object format ) | |
315 | - /// </summary> | |
316 | - private void GenerateJSONMetadata() | |
317 | - { | |
318 | - string jsonFilename = Path.Combine(path, "Metadata.js"); | |
319 | - | |
320 | - StreamWriter stream = new StreamWriter(jsonFilename, false, Encoding.UTF8); | |
321 | - | |
322 | - using (stream) { | |
323 | - JsonTextWriter jsonWriter = new JsonTextWriter(stream); | |
324 | - | |
325 | - jsonWriter.Formatting = Formatting.None; | |
326 | - jsonWriter.StringEscapeHandling = StringEscapeHandling.EscapeHtml; | |
327 | - jsonWriter.Indentation = 0; | |
328 | - //jsonWriter.AutoCompleteOnClose = true; | |
329 | - jsonWriter.QuoteChar = '\''; | |
330 | - jsonWriter.DateFormatHandling = DateFormatHandling.IsoDateFormat; | |
331 | - jsonWriter.DateTimeZoneHandling = DateTimeZoneHandling.Utc; | |
332 | - | |
333 | - using (jsonWriter) | |
334 | - { | |
335 | - jsonWriter.WriteRaw("ViewFrame.chunks={};\n"); | |
336 | - jsonWriter.WriteRaw("ViewFrame.chunks.worldSeedNum=" ); | |
337 | - jsonWriter.WriteValue(ClientAPI.World.Seed); | |
338 | - jsonWriter.WriteRaw(";\n"); | |
339 | - | |
340 | - jsonWriter.WriteRaw("ViewFrame.chunks.genTime="); | |
341 | - jsonWriter.WriteValue(DateTimeOffset.UtcNow); | |
342 | - jsonWriter.WriteRaw(";\n"); | |
343 | - | |
344 | - jsonWriter.WriteRaw("ViewFrame.chunks.startCoords="); | |
345 | - jsonWriter.WriteStartArray( ); | |
346 | - jsonWriter.WriteValue(startChunkColumn.X); | |
347 | - jsonWriter.WriteValue(startChunkColumn.Y); | |
348 | - jsonWriter.WriteEndArray( ); | |
349 | - jsonWriter.WriteRaw(";\n"); | |
350 | - | |
351 | - jsonWriter.WriteRaw("ViewFrame.chunks.chunkSize="); | |
352 | - jsonWriter.WriteValue(chunkSize); | |
353 | - jsonWriter.WriteRaw(";\n"); | |
354 | - | |
355 | - jsonWriter.WriteRaw("ViewFrame.chunks.northMostChunk="); | |
356 | - jsonWriter.WriteValue(chunkTopMetadata.North_mostChunk); | |
357 | - jsonWriter.WriteRaw(";\n"); | |
358 | - | |
359 | - jsonWriter.WriteRaw("ViewFrame.chunks.southMostChunk="); | |
360 | - jsonWriter.WriteValue(chunkTopMetadata.South_mostChunk); | |
361 | - jsonWriter.WriteRaw(";\n"); | |
362 | - | |
363 | - jsonWriter.WriteRaw("ViewFrame.chunks.westMostChunk="); | |
364 | - jsonWriter.WriteValue(chunkTopMetadata.West_mostChunk); | |
365 | - jsonWriter.WriteRaw(";\n"); | |
366 | - | |
367 | - jsonWriter.WriteRaw("ViewFrame.chunks.eastMostChunk="); | |
368 | - jsonWriter.WriteValue(chunkTopMetadata.East_mostChunk); | |
369 | - jsonWriter.WriteRaw(";\n"); | |
370 | - | |
371 | - | |
372 | - //MAP object format - [key, value]: key is "x_y" | |
373 | - jsonWriter.WriteRaw("ViewFrame.chunks.chunkMetadata="); | |
374 | - jsonWriter.WriteStartConstructor("Map"); | |
375 | - jsonWriter.WriteStartArray( );//An array of... 2-component arrays | |
376 | - | |
377 | - | |
378 | - foreach (var shard in chunkTopMetadata) | |
379 | - { | |
380 | - jsonWriter.WriteStartArray( );//Start tuple | |
381 | - jsonWriter.WriteValue($"{shard.Location.X}_{shard.Location.Y}");//Key of Tuple | |
382 | - | |
383 | - jsonWriter.WriteStartObject( ); | |
384 | - jsonWriter.WritePropertyName("prettyCoord"); | |
385 | - jsonWriter.WriteValue( shard.Location.PrettyCoords(ClientAPI)); | |
386 | - | |
387 | - jsonWriter.WritePropertyName("chunkAge"); | |
388 | - jsonWriter.WriteValue(shard.ChunkAge); | |
389 | - | |
390 | - jsonWriter.WritePropertyName("temp"); | |
391 | - jsonWriter.WriteValue(shard.Temperature); | |
392 | - | |
393 | - jsonWriter.WritePropertyName("YMax"); | |
394 | - jsonWriter.WriteValue(shard.YMax); | |
395 | - | |
396 | - jsonWriter.WritePropertyName("fert"); | |
397 | - jsonWriter.WriteValue(shard.Fertility); | |
398 | - | |
399 | - jsonWriter.WritePropertyName("forestDens"); | |
400 | - jsonWriter.WriteValue( shard.ForestDensity); | |
401 | - | |
402 | - jsonWriter.WritePropertyName("rain"); | |
403 | - jsonWriter.WriteValue( shard.Rainfall); | |
404 | - | |
405 | - jsonWriter.WritePropertyName("shrubDens"); | |
406 | - jsonWriter.WriteValue( shard.ShrubDensity); | |
407 | - | |
408 | - jsonWriter.WritePropertyName("airBlocks"); | |
409 | - jsonWriter.WriteValue( shard.AirBlocks); | |
410 | - | |
411 | - jsonWriter.WritePropertyName("nonAirBlocks"); | |
412 | - jsonWriter.WriteValue( shard.NonAirBlocks); | |
413 | - | |
414 | - //TODO: Heightmap ? | |
415 | - //Start rockMap ; FOR a Ratio....on tooltip GUI | |
416 | - jsonWriter.WritePropertyName("rockRatio"); | |
417 | - jsonWriter.WriteStartConstructor("Map"); | |
418 | - jsonWriter.WriteStartArray( ); | |
419 | - foreach (var rockEntry in shard.RockRatio) { | |
420 | - var rockBlock = ClientAPI.World.GetBlock(rockEntry.Key); | |
421 | - jsonWriter.WriteStartArray( ); | |
422 | - jsonWriter.WriteValue(rockBlock.Code.Path); | |
423 | - jsonWriter.WriteValue(rockEntry.Value);//Total per chunk-column | |
424 | - jsonWriter.WriteEndArray( ); | |
425 | - } | |
426 | - jsonWriter.WriteEndArray( ); | |
427 | - jsonWriter.WriteEndConstructor( );//end rock-map | |
428 | - | |
429 | - jsonWriter.WriteEndObject( );//end Map value: {Object} | |
430 | - jsonWriter.WriteEndArray( );//end Tuple | |
431 | - } | |
432 | - | |
433 | - jsonWriter.WriteEndArray( );//Enclose tuples of chunkMetadata | |
434 | - jsonWriter.WriteEndConstructor( );//Close constructor of Map (chunkMetadata) | |
435 | - jsonWriter.WriteRaw(";\n"); | |
436 | - | |
437 | - jsonWriter.WriteRaw("ViewFrame.chunks.pointsOfInterest="); | |
438 | - jsonWriter.WriteStartConstructor("Map"); | |
439 | - jsonWriter.WriteStartArray( );//An array of... 2-component arrays | |
440 | - | |
441 | - foreach (var poi in POIs) | |
442 | - { | |
443 | - jsonWriter.WriteStartArray( ); | |
444 | - jsonWriter.WriteValue($"{poi.Location.X}_{poi.Location.Z}"); | |
445 | - | |
446 | - jsonWriter.WriteStartObject(); | |
447 | - jsonWriter.WritePropertyName("Name"); | |
448 | - jsonWriter.WriteValue(poi.Name); | |
449 | - | |
450 | - jsonWriter.WritePropertyName("prettyCoord"); | |
451 | - jsonWriter.WriteValue(poi.Location.PrettyCoords(ClientAPI) ); | |
452 | - | |
453 | - jsonWriter.WritePropertyName("notes"); | |
454 | - jsonWriter.WriteValue(poi.Notes);//Encoded to HTML Entities | |
455 | - | |
456 | - jsonWriter.WritePropertyName("time"); | |
457 | - jsonWriter.WriteValue(poi.Timestamp); | |
458 | - | |
459 | - jsonWriter.WritePropertyName("chunkPos"); | |
460 | - jsonWriter.WriteValue($"{(poi.Location.X / chunkSize)}_{(poi.Location.Z / chunkSize)}"); | |
461 | - | |
462 | - jsonWriter.WriteEndObject( ); | |
463 | - jsonWriter.WriteEndArray( ); | |
464 | - } | |
465 | - | |
466 | - foreach (var poi in EOIs) | |
467 | - { | |
468 | - jsonWriter.WriteStartArray( ); | |
469 | - jsonWriter.WriteValue($"{poi.Location.X}_{poi.Location.Z}"); | |
470 | - | |
471 | - jsonWriter.WriteStartObject( ); | |
472 | - jsonWriter.WritePropertyName("Name"); | |
473 | - jsonWriter.WriteValue(poi.Name); | |
474 | - | |
475 | - jsonWriter.WritePropertyName("prettyCoord"); | |
476 | - jsonWriter.WriteValue(poi.Location.PrettyCoords(ClientAPI)); | |
477 | - | |
478 | - jsonWriter.WritePropertyName("notes"); | |
479 | - jsonWriter.WriteValue(poi.Notes);//Encoded to HTML Entities | |
480 | - | |
481 | - jsonWriter.WritePropertyName("time"); | |
482 | - jsonWriter.WriteValue(poi.Timestamp); | |
483 | - | |
484 | - jsonWriter.WritePropertyName("chunkPos"); | |
485 | - jsonWriter.WriteValue($"{(poi.Location.X / chunkSize)}_{(poi.Location.Z / chunkSize)}"); | |
486 | - | |
487 | - jsonWriter.WriteEndObject( ); | |
488 | - jsonWriter.WriteEndArray( ); | |
489 | - } | |
490 | - | |
491 | - jsonWriter.WriteEndArray( ); | |
492 | - jsonWriter.WriteEndConstructor( ); | |
493 | - jsonWriter.WriteRaw(";\n"); | |
494 | - | |
495 | - jsonWriter.WriteWhitespace("\n"); | |
496 | - jsonWriter.WriteComment("============= BlockID's for Rockmap / Rock-ratios ==============="); | |
497 | - jsonWriter.WriteWhitespace("\n"); | |
498 | - | |
499 | - jsonWriter.WriteRaw("ViewFrame.chunks.rock_Lookup ="); | |
500 | - jsonWriter.WriteStartConstructor("Map"); | |
501 | - jsonWriter.WriteStartArray( );//An array of... 2-component arrays | |
502 | - | |
503 | - foreach (var entry in RockIdCodes) { | |
504 | - var block = ClientAPI.World.GetBlock(entry.Key); | |
505 | - | |
506 | - jsonWriter.WriteStartArray( ); | |
507 | - jsonWriter.WriteValue(block.Code.Path); | |
508 | - | |
509 | - jsonWriter.WriteStartObject( ); | |
510 | - jsonWriter.WritePropertyName("assetCode"); | |
511 | - jsonWriter.WriteValue(entry.Value); | |
512 | - | |
513 | - jsonWriter.WritePropertyName("name"); | |
514 | - jsonWriter.WriteValue(Lang.GetUnformatted(block.Code.Path)); | |
515 | - //Color? | |
516 | - | |
517 | - jsonWriter.WriteEndObject( ); | |
518 | - jsonWriter.WriteEndArray( ); | |
519 | - } | |
520 | - jsonWriter.WriteEndArray( ); | |
521 | - jsonWriter.WriteEndConstructor(); | |
522 | - | |
523 | - jsonWriter.WriteRaw(";\n"); | |
524 | - | |
525 | - jsonWriter.Flush(); | |
526 | - } | |
527 | - } | |
528 | - | |
529 | - } | |
530 | 319 | |
531 | 320 | /// <summary> |
532 | 321 | /// Store Points/Entity of Interest |
@@ -550,7 +339,7 @@ namespace Automap | ||
550 | 339 | } |
551 | 340 | } |
552 | 341 | |
553 | - //Create Easy to Parse CSV file for tool/human use.... | |
342 | + //Create Easy to Parse TSV file for tool/human use.... | |
554 | 343 | string pointsTsvPath = Path.Combine(path, pointsTsvFileName); |
555 | 344 | |
556 | 345 | using (var tsvWriter = new StreamWriter(pointsTsvPath, false, Encoding.UTF8)) |
@@ -578,7 +367,7 @@ namespace Automap | ||
578 | 367 | |
579 | 368 | private ColumnMeta CreateColumnMetadata(KeyValuePair<Vec2i, uint> mostActiveCol, IMapChunk mapChunk) |
580 | 369 | { |
581 | - ColumnMeta data = new ColumnMeta(mostActiveCol.Key.Copy(), ( byte )chunkSize); | |
370 | + ColumnMeta data = new ColumnMeta(mostActiveCol.Key.Copy(), (byte) chunkSize); | |
582 | 371 | BlockPos equivBP = new BlockPos(mostActiveCol.Key.X * chunkSize, |
583 | 372 | mapChunk.YMax, |
584 | 373 | mostActiveCol.Key.Y * chunkSize); |
@@ -630,12 +419,12 @@ namespace Automap | ||
630 | 419 | } |
631 | 420 | |
632 | 421 | } |
633 | - catch (PngjException someEx) | |
422 | + catch (PngjException someEx) | |
634 | 423 | { |
635 | - Logger.Error("PNG Corruption in file '{0}' - Reason: {1}", shardFile.Name, someEx); | |
424 | + Logger.Error("PNG Corruption file '{0}' - Reason: {1}", shardFile.Name, someEx); | |
636 | 425 | continue; |
637 | 426 | } |
638 | - } | |
427 | + } | |
639 | 428 | |
640 | 429 | } |
641 | 430 | } |
@@ -860,8 +649,10 @@ namespace Automap | ||
860 | 649 | } |
861 | 650 | |
862 | 651 | |
652 | + | |
653 | + | |
863 | 654 | #endregion |
864 | 655 | |
865 | 656 | } |
866 | 657 | |
867 | -} | |
\ No newline at end of file | ||
658 | +} |
@@ -0,0 +1,318 @@ | ||
1 | +using System; | |
2 | +using System.Collections.Generic; | |
3 | +using System.IO; | |
4 | +using System.Linq; | |
5 | +using System.Reflection; | |
6 | +using System.Text; | |
7 | +using System.Text.RegularExpressions; | |
8 | + | |
9 | +using Newtonsoft.Json; | |
10 | + | |
11 | +using Vintagestory.API.Client; | |
12 | +using Vintagestory.API.Common; | |
13 | +using Vintagestory.API.Config; | |
14 | +using Vintagestory.API.Datastructures; | |
15 | +using Vintagestory.API.MathTools; | |
16 | +using Vintagestory.Common; | |
17 | + | |
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 | + | |
30 | + public JsonGenerator(ICoreClientAPI _ClientAPI, ILogger _Logger, string _path ) | |
31 | + { | |
32 | + this.ClientAPI = _ClientAPI; | |
33 | + this.Logger = _Logger; | |
34 | + this.path = _path; | |
35 | + this.chunkSize = ClientAPI.World.BlockAccessor.ChunkSize; | |
36 | + } | |
37 | + | |
38 | + | |
39 | + /// <summary> | |
40 | + /// Generates the JSON Metadata. (in Map object format ) | |
41 | + /// </summary> | |
42 | + public void GenerateJSONMetadata(ColumnsMetadata chunkTopMetadata, Vec2i startChunkColumn, PointsOfInterest POIs, EntitiesOfInterest EOIs, Dictionary<int, string> RockIdCodes ) | |
43 | + { | |
44 | + string jsonFilename = Path.Combine(path, "Metadata.js"); | |
45 | + | |
46 | + StreamWriter stream = new StreamWriter(jsonFilename, false, Encoding.UTF8); | |
47 | + | |
48 | + using (stream) { | |
49 | + JsonTextWriter jsonWriter = new JsonTextWriter(stream); | |
50 | + | |
51 | + jsonWriter.Formatting = Formatting.None; | |
52 | + jsonWriter.StringEscapeHandling = StringEscapeHandling.EscapeHtml; | |
53 | + jsonWriter.Indentation = 0; | |
54 | + //jsonWriter.AutoCompleteOnClose = true; | |
55 | + jsonWriter.QuoteChar = '\''; | |
56 | + jsonWriter.DateFormatHandling = DateFormatHandling.IsoDateFormat; | |
57 | + jsonWriter.DateTimeZoneHandling = DateTimeZoneHandling.Utc; | |
58 | + | |
59 | + using (jsonWriter) { | |
60 | + jsonWriter.WriteRaw("ViewFrame.chunks={};\n"); | |
61 | + jsonWriter.WriteRaw("ViewFrame.chunks.worldSeedNum="); | |
62 | + jsonWriter.WriteValue(ClientAPI.World.Seed); | |
63 | + jsonWriter.WriteRaw(";\n"); | |
64 | + | |
65 | + jsonWriter.WriteRaw("ViewFrame.chunks.genTime="); | |
66 | + jsonWriter.WriteValue(DateTimeOffset.UtcNow); | |
67 | + jsonWriter.WriteRaw(";\n"); | |
68 | + | |
69 | + jsonWriter.WriteRaw("ViewFrame.chunks.startCoords="); | |
70 | + jsonWriter.WriteStartArray( ); | |
71 | + jsonWriter.WriteValue(startChunkColumn.X); | |
72 | + jsonWriter.WriteValue(startChunkColumn.Y); | |
73 | + jsonWriter.WriteEndArray( ); | |
74 | + jsonWriter.WriteRaw(";\n"); | |
75 | + | |
76 | + jsonWriter.WriteRaw("ViewFrame.chunks.chunkSize="); | |
77 | + jsonWriter.WriteValue(chunkSize); | |
78 | + jsonWriter.WriteRaw(";\n"); | |
79 | + | |
80 | + jsonWriter.WriteRaw("ViewFrame.chunks.northMostChunk="); | |
81 | + jsonWriter.WriteValue(chunkTopMetadata.North_mostChunk); | |
82 | + jsonWriter.WriteRaw(";\n"); | |
83 | + | |
84 | + jsonWriter.WriteRaw("ViewFrame.chunks.southMostChunk="); | |
85 | + jsonWriter.WriteValue(chunkTopMetadata.South_mostChunk); | |
86 | + jsonWriter.WriteRaw(";\n"); | |
87 | + | |
88 | + jsonWriter.WriteRaw("ViewFrame.chunks.westMostChunk="); | |
89 | + jsonWriter.WriteValue(chunkTopMetadata.West_mostChunk); | |
90 | + jsonWriter.WriteRaw(";\n"); | |
91 | + | |
92 | + jsonWriter.WriteRaw("ViewFrame.chunks.eastMostChunk="); | |
93 | + jsonWriter.WriteValue(chunkTopMetadata.East_mostChunk); | |
94 | + jsonWriter.WriteRaw(";\n"); | |
95 | + | |
96 | + | |
97 | + //MAP object format - [key, value]: key is "x_y" | |
98 | + jsonWriter.WriteRaw("ViewFrame.chunks.chunkMetadata="); | |
99 | + jsonWriter.WriteStartConstructor("Map"); | |
100 | + jsonWriter.WriteStartArray( );//An array of... 2-component arrays | |
101 | + | |
102 | + | |
103 | + foreach (var shard in chunkTopMetadata) { | |
104 | + jsonWriter.WriteStartArray( );//Start tuple | |
105 | + jsonWriter.WriteValue($"{shard.Location.X}_{shard.Location.Y}");//Key of Tuple | |
106 | + | |
107 | + jsonWriter.WriteStartObject( ); | |
108 | + jsonWriter.WritePropertyName("prettyCoord"); | |
109 | + jsonWriter.WriteValue(shard.Location.PrettyCoords(ClientAPI)); | |
110 | + | |
111 | + jsonWriter.WritePropertyName("chunkAge"); | |
112 | + jsonWriter.WriteValue(shard.ChunkAge); | |
113 | + | |
114 | + jsonWriter.WritePropertyName("temp"); | |
115 | + jsonWriter.WriteValue(shard.Temperature); | |
116 | + | |
117 | + jsonWriter.WritePropertyName("YMax"); | |
118 | + jsonWriter.WriteValue(shard.YMax); | |
119 | + | |
120 | + jsonWriter.WritePropertyName("fert"); | |
121 | + jsonWriter.WriteValue(shard.Fertility); | |
122 | + | |
123 | + jsonWriter.WritePropertyName("forestDens"); | |
124 | + jsonWriter.WriteValue(shard.ForestDensity); | |
125 | + | |
126 | + jsonWriter.WritePropertyName("rain"); | |
127 | + jsonWriter.WriteValue(shard.Rainfall); | |
128 | + | |
129 | + jsonWriter.WritePropertyName("shrubDens"); | |
130 | + jsonWriter.WriteValue(shard.ShrubDensity); | |
131 | + | |
132 | + jsonWriter.WritePropertyName("airBlocks"); | |
133 | + jsonWriter.WriteValue(shard.AirBlocks); | |
134 | + | |
135 | + jsonWriter.WritePropertyName("nonAirBlocks"); | |
136 | + jsonWriter.WriteValue(shard.NonAirBlocks); | |
137 | + | |
138 | + //TODO: Heightmap ? | |
139 | + //Start rockMap ; FOR a Ratio....on tooltip GUI | |
140 | + jsonWriter.WritePropertyName("rockRatio"); | |
141 | + jsonWriter.WriteStartConstructor("Map"); | |
142 | + jsonWriter.WriteStartArray( ); | |
143 | + foreach (var rockEntry in shard.RockRatio) { | |
144 | + var rockBlock = ClientAPI.World.GetBlock(rockEntry.Key); | |
145 | + jsonWriter.WriteStartArray( ); | |
146 | + jsonWriter.WriteValue(rockBlock.Code.Path); | |
147 | + jsonWriter.WriteValue(rockEntry.Value);//Total per chunk-column | |
148 | + jsonWriter.WriteEndArray( ); | |
149 | + } | |
150 | + jsonWriter.WriteEndArray( ); | |
151 | + jsonWriter.WriteEndConstructor( );//end rock-map | |
152 | + | |
153 | + jsonWriter.WriteEndObject( );//end Map value: {Object} | |
154 | + jsonWriter.WriteEndArray( );//end Tuple | |
155 | + } | |
156 | + | |
157 | + jsonWriter.WriteEndArray( );//Enclose tuples of chunkMetadata | |
158 | + jsonWriter.WriteEndConstructor( );//Close constructor of Map (chunkMetadata) | |
159 | + jsonWriter.WriteRaw(";\n"); | |
160 | + | |
161 | + jsonWriter.WriteRaw("ViewFrame.chunks.pointsOfInterest="); | |
162 | + jsonWriter.WriteStartConstructor("Map"); | |
163 | + jsonWriter.WriteStartArray( );//An array of... 2-component arrays | |
164 | + | |
165 | + foreach (var poi in POIs) { | |
166 | + EmitJsonMap(poi, jsonWriter); | |
167 | + } | |
168 | + | |
169 | + foreach (var poi in EOIs) { | |
170 | + EmitJsonMap(poi, jsonWriter); | |
171 | + } | |
172 | + | |
173 | + jsonWriter.WriteEndArray( ); | |
174 | + jsonWriter.WriteEndConstructor( ); | |
175 | + jsonWriter.WriteRaw(";\n"); | |
176 | + | |
177 | + jsonWriter.WriteWhitespace("\n"); | |
178 | + jsonWriter.WriteComment("============= BlockID's for Rockmap / Rock-ratios ==============="); | |
179 | + jsonWriter.WriteWhitespace("\n"); | |
180 | + | |
181 | + jsonWriter.WriteRaw("ViewFrame.chunks.rock_Lookup ="); | |
182 | + jsonWriter.WriteStartConstructor("Map"); | |
183 | + jsonWriter.WriteStartArray( );//An array of... 2-component arrays | |
184 | + | |
185 | + foreach (var entry in RockIdCodes) { | |
186 | + var block = ClientAPI.World.GetBlock(entry.Key); | |
187 | + // stream.Write("{0},", Lang.GetUnformatted(block.Code.Path)); | |
188 | + jsonWriter.WriteStartArray( ); | |
189 | + jsonWriter.WriteValue(block.Code.Path); | |
190 | + | |
191 | + jsonWriter.WriteStartObject( ); | |
192 | + jsonWriter.WritePropertyName("assetCode"); | |
193 | + jsonWriter.WriteValue(entry.Value); | |
194 | + | |
195 | + jsonWriter.WritePropertyName("name"); | |
196 | + jsonWriter.WriteValue(Lang.GetUnformatted(block.Code.Path)); | |
197 | + //} | |
198 | + | |
199 | + jsonWriter.WriteEndObject( ); | |
200 | + jsonWriter.WriteEndArray( ); | |
201 | + } | |
202 | + jsonWriter.WriteEndArray( ); | |
203 | + jsonWriter.WriteEndConstructor( ); | |
204 | + //stream.Write("]);\n"); | |
205 | + jsonWriter.WriteRaw(";\n"); | |
206 | + | |
207 | + jsonWriter.Flush( ); | |
208 | + } | |
209 | + } | |
210 | + | |
211 | + } | |
212 | + | |
213 | + public void EmitJsonMap(PointOfInterest @this, JsonTextWriter jsonWriter) | |
214 | + { | |
215 | + jsonWriter.WriteStartArray( ); | |
216 | + jsonWriter.WriteValue($"{@this.Location.X}_{@this.Location.Z}"); | |
217 | + | |
218 | + jsonWriter.WriteStartArray( ); | |
219 | + //jsonWriter.WriteValue(@this.Name); | |
220 | + | |
221 | + jsonWriter.WriteValue(@this.Location.X); | |
222 | + jsonWriter.WriteValue(@this.Location.Z); //Y is HEIGHT from Mantle... Z is Right from edge of world | |
223 | + | |
224 | + jsonWriter.WriteValue(@this.Location.PrettyCoords(ClientAPI)); | |
225 | + | |
226 | + jsonWriter.WriteValue(@this.Notes);//put more escaping in Java-script if needed | |
227 | + | |
228 | + jsonWriter.WriteValue(@this.Timestamp); | |
229 | + | |
230 | + jsonWriter.WriteEndArray( ); | |
231 | + jsonWriter.WriteEndArray( ); | |
232 | + } | |
233 | + | |
234 | + public void EmitJsonMap(EntityOfInterest @this, JsonTextWriter jsonWriter) | |
235 | + { | |
236 | + jsonWriter.WriteStartArray( ); | |
237 | + jsonWriter.WriteValue($"{@this.Location.X}_{@this.Location.Z}"); | |
238 | + | |
239 | + | |
240 | + jsonWriter.WriteStartArray( ); | |
241 | + //jsonWriter.WriteValue(@this.Name); | |
242 | + | |
243 | + jsonWriter.WriteValue(@this.Location.X); | |
244 | + jsonWriter.WriteValue(@this.Location.Z); //Y is HEIGHT from Mantle... Z is Right from edge of world | |
245 | + | |
246 | + jsonWriter.WriteValue(@this.Location.PrettyCoords(ClientAPI)); | |
247 | + | |
248 | + jsonWriter.WriteValue(@this.Notes);//put more escaping in Java-script if needed | |
249 | + | |
250 | + jsonWriter.WriteValue(@this.Timestamp); | |
251 | + | |
252 | + jsonWriter.WriteValue(@this.EntityId); | |
253 | + | |
254 | + jsonWriter.WriteEndArray( ); | |
255 | + jsonWriter.WriteEndArray( ); | |
256 | + } | |
257 | + | |
258 | + /// <summary> | |
259 | + /// Dynamically reflect Points-of-Something fields for metadata descriptors | |
260 | + /// </summary> | |
261 | + /// <returns>Json-array names of fields for use in map display.</returns> | |
262 | + public string MakePreBuiltJSON( ) | |
263 | + { | |
264 | + var builder = new StringBuilder(512); | |
265 | + builder.Append("ViewFrame.chunks={};\n"); | |
266 | + builder.AppendFormat("ViewFrame.chunks.worldSeedNum='{0}';", | |
267 | + ClientAPI.World.Seed | |
268 | + ); | |
269 | + builder.AppendFormat("ViewFrame.chunks.chunkSize={0};", | |
270 | + chunkSize | |
271 | + ); | |
272 | + | |
273 | + builder.Append("ViewFrame.chunks.chunkMetadataNames=["); | |
274 | + var fields = typeof(ColumnMeta).GetFields( ); | |
275 | + var attsToSort = new List<DisplayNameAttribute>( ); | |
276 | + // this is so gross | |
277 | + foreach (var f in fields) { | |
278 | + var att = f.GetCustomAttribute(typeof(DisplayNameAttribute)); | |
279 | + if (att != null) { | |
280 | + attsToSort.Add(( DisplayNameAttribute )att); | |
281 | + } | |
282 | + | |
283 | + } | |
284 | + foreach (var att in attsToSort.OrderBy(a => a.order)) | |
285 | + builder.AppendFormat("'{0}',", att.name); | |
286 | + builder.Append("];\n"); | |
287 | + | |
288 | + builder.Append("ViewFrame.chunks.pointsOfInterestNames=["); | |
289 | + fields = typeof(PointOfInterest).GetFields( ); | |
290 | + attsToSort = new List<DisplayNameAttribute>( ); | |
291 | + | |
292 | + foreach (var f in fields) { | |
293 | + var att = f.GetCustomAttribute(typeof(DisplayNameAttribute)); | |
294 | + if (att != null) | |
295 | + attsToSort.Add(( DisplayNameAttribute )att); | |
296 | + } | |
297 | + foreach (var att in attsToSort.OrderBy(a => a.order)) | |
298 | + builder.AppendFormat("'{0}',", att.name); | |
299 | + builder.Append("];\n"); | |
300 | + | |
301 | + builder.Append("ViewFrame.chunks.entityOfInterestNames=["); | |
302 | + fields = typeof(EntityOfInterest).GetFields( ); | |
303 | + attsToSort = new List<DisplayNameAttribute>( ); | |
304 | + | |
305 | + foreach (var f in fields) { | |
306 | + var att = f.GetCustomAttribute(typeof(DisplayNameAttribute)); | |
307 | + if (att != null) | |
308 | + attsToSort.Add(( DisplayNameAttribute )att); | |
309 | + } | |
310 | + foreach (var att in attsToSort.OrderBy(a => a.order)) | |
311 | + builder.AppendFormat("'{0}',", att.name); | |
312 | + builder.Append("];\n"); | |
313 | + | |
314 | + return builder.ToString( ); | |
315 | + } | |
316 | + } | |
317 | +} | |
318 | + |