Automap (client) [VS plugin mod]
Revision | 3941fee8faa827b45fac01086745b040ce4f4448 (tree) |
---|---|
Time | 2020-06-04 09:18:29 |
Author | The Grand Dog <alex.h@me.c...> |
Commiter | The Grand Dog |
fixed map i think
@@ -8,15 +8,15 @@ fs.readFile(__dirname + '/src/Automap.html', 'utf8', (err, d) => { | ||
8 | 8 | if (err) console.log(err); |
9 | 9 | let outD = d.replace(/<link rel=\"stylesheet\" href=\"(.*)\">/g, (match, name, offset, string) => { |
10 | 10 | return '<style>' + fs.readFileSync(__dirname + '/src/' + name, 'utf8') |
11 | - .replace(/\/\/.*\n?/g, '') | |
11 | + // .replace(/\/\/.*\n?/g, '') | |
12 | 12 | + '</style>'; |
13 | 13 | }) |
14 | 14 | .replace(/<script type=\"text\/javascript\" src=\"(.*)\">/g, (match, name, offset, string) => { |
15 | 15 | return '<script type=\"text\/javascript\">' + fs.readFileSync(__dirname + '/src/' + name, 'utf8') |
16 | - .replace(/\/\/.*\n?/g, '') | |
16 | + // .replace(/\/\/.*\n?/g, '') | |
17 | 17 | + '</script>'; |
18 | - }) | |
19 | - .replace(/[\t\n]/g, ''); | |
18 | + }); | |
19 | + // .replace(/[\t\n]/g, ''); | |
20 | 20 | fs.writeFile(__dirname + '/../assets/automap/config/automap.html', outD, err => { |
21 | 21 | if (err) console.log(err); |
22 | 22 | }); |
@@ -3,7 +3,7 @@ html, body, .map { | ||
3 | 3 | height: 100%; |
4 | 4 | margin: 0; |
5 | 5 | overflow: hidden; |
6 | - outline: 1px dotted black; | |
6 | + /* outline: 1px dotted black; */ | |
7 | 7 | } |
8 | 8 | |
9 | 9 | .infobox { |
@@ -107,7 +107,7 @@ ViewFrame.prototype.render = function () { | ||
107 | 107 | const img = new Image(32, 32); |
108 | 108 | const name = round.value.join('_'); |
109 | 109 | |
110 | - img.src = name + '.png'; | |
110 | + img.src = 'Chunks/'+ name + '.png'; | |
111 | 111 | |
112 | 112 | decode(img, loadedImage => { |
113 | 113 | this.place(img, round.value[0], round.value[1]); |
@@ -4,140 +4,321 @@ | ||
4 | 4 | <head> |
5 | 5 | <meta charset="utf-8"> |
6 | 6 | <title>Automap</title> |
7 | - <style media="screen">.m,body,html{width:100%;height:100%;margin:0;outline:1px dotted #000}.m img{position:absolute;image-rendering:pixelated}.i{width:15em;background-color:rgba(200,200,200,.5);left:0;top:0;font-family:sans-serif;position:absolute;z-index:1}h1{font-size:22px;margin:.6em 1em;text-align:center}.t{margin:.3em auto;width:90%;outline:1px solid #333}.t th{width:30%}.t td{text-align:right}</style> | |
7 | + <style>html, body, .map { | |
8 | + width: 100%; | |
9 | + height: 100%; | |
10 | + margin: 0; | |
11 | + overflow: hidden; | |
12 | + /* outline: 1px dotted black; */ | |
13 | +} | |
14 | + | |
15 | +.infobox { | |
16 | + width: 15em; | |
17 | + /* height: 15em; */ | |
18 | + background-color: rgba(200, 200, 200, 0.5); | |
19 | + left: 0; | |
20 | + top: 0; | |
21 | + font-family: sans-serif; | |
22 | + position: absolute; | |
23 | + z-index: 1; | |
24 | +} | |
25 | + | |
26 | +h1 { | |
27 | + font-size: 22px; | |
28 | + margin: .6em 1em; | |
29 | + text-align: center; | |
30 | +} | |
31 | + | |
32 | +.infoboxTable { | |
33 | + margin: .3em auto; | |
34 | + width: 90%; | |
35 | + outline: 1px solid #333; | |
36 | +} | |
37 | + | |
38 | +.infoboxTable th { | |
39 | + width: 30%; | |
40 | +} | |
41 | + | |
42 | +.infoboxTable td { | |
43 | + text-align: right; | |
44 | +}</style> | |
8 | 45 | </head> |
9 | 46 | |
10 | 47 | <body> |
11 | - <div class="i"> | |
12 | - <h1>Chunk Info</h1> | |
13 | - <table class="t"></table> | |
14 | - </div> | |
15 | - <script type="text/javascript"> | |
16 | - function ViewFrame() { | |
17 | - this.map = document.createElement("div"), this.map.className = "m", this.infobox = document.getElementsByClassName("t")[0], this.infoboxSlots = new Map, ViewFrame.initInfobox(this.infobox, this.infoboxSlots), document.getElementsByTagName("body")[ | |
18 | - 0].append(this.map), this.loadedChunksByName = new Map, this.loadedChunksByCoords = new Map, this.availableChunks = null, this.chunkScript = null, this.renderOnReload = !0, this.dirty = !1, this.rendering = !1, this.x = null, this.y = null, | |
19 | - this._zoom = 32, this.updateEdges() | |
20 | - } | |
48 | + <script type="text/javascript">function ViewFrame() { | |
49 | + // dom stuff | |
50 | + const map = document.createElement('canvas'); // the map we see | |
51 | + map.className = 'map'; | |
52 | + map.height = window.innerHeight; | |
53 | + map.width = window.innerWidth; | |
54 | + document.getElementsByTagName('body')[0].append(map); | |
55 | + // this is the map that we actually draw on | |
56 | + this.map = map.getContext('2d', { | |
57 | + alpha: false | |
58 | + }); | |
59 | + this.map.imageSmoothingEnabled = false; | |
60 | + | |
61 | + // the info box in the corner | |
62 | + this.infobox = document.getElementsByClassName('infoboxTable')[0]; | |
63 | + this.infoboxSlots = new Array(); | |
64 | + | |
65 | + // load the metadata! | |
66 | + this.chunkScript = document.createElement('script'); | |
67 | + this.chunkScript.type = 'text/javascript'; | |
68 | + this.chunkScript.src = 'Metadata.js'; | |
69 | + document.getElementsByTagName('body')[0].append(this.chunkScript); | |
70 | + this.chunkScript.addEventListener('load', () => { | |
71 | + ViewFrame.initInfobox(this.infobox, this.infoboxSlots); | |
72 | + this.x = ViewFrame.chunks.startCoords[0]; | |
73 | + this.y = ViewFrame.chunks.startCoords[1]; | |
74 | + this.availableChunks = ViewFrame.chunks.chunkMetadata; | |
75 | + this.render(); | |
76 | + }, { | |
77 | + once: true | |
78 | + }); | |
21 | 79 | |
22 | - function decode(t, e) { | |
23 | - t.decode().then(() => { | |
24 | - e(t) | |
25 | - }).catch(() => {}) | |
80 | + // Tracks images that have been loaded and are on the map | |
81 | + this.loadedChunksByName = new Map(); | |
82 | + // this is needed because [1, 2] != [1, 2] and thats how we store coords. | |
83 | + this.loadedChunksByCoords = new Map(); | |
84 | + this.availableChunks = null; // the chunks in ./Metadata.js | |
85 | + // so that we dont render twice at the same time | |
86 | + this.rendering = false; | |
87 | + | |
88 | + this.x = -1; | |
89 | + this.y = -1; // can be fractional | |
90 | + this.zoom = 32; // pixels wide the images are to be | |
91 | + this.updateEdges(); | |
92 | +} | |
93 | +// prototypes, some less... notable? methods are | |
94 | +// in ViewFrameUtils.js | |
95 | +ViewFrame.prototype.reloadChunkList = function () { | |
96 | + if (this.chunkScript) { | |
97 | + this.chunkScript.remove(); | |
98 | + delete this.chunkScript; | |
99 | + } | |
100 | + | |
101 | + this.chunkScript = document.createElement('script'); | |
102 | + this.chunkScript.type = 'text/javascript'; | |
103 | + this.chunkScript.src = 'Metadata.js'; | |
104 | + document.getElementsByTagName('body')[0].append(this.chunkScript); | |
105 | + | |
106 | + this.chunkScript.addEventListener('load', () => { | |
107 | + this.availableChunks = ViewFrame.chunks.chunkMetadata; | |
108 | + this.render(); | |
109 | + }); | |
110 | +}; | |
111 | + | |
112 | +ViewFrame.prototype.render = function () { | |
113 | + if (!this.availableChunks) return; | |
114 | + if (this.rendering) clearInterval(ViewFrame.intervalRef); | |
115 | + this.rendering = true; | |
116 | + this.updateEdges(); | |
117 | + this.map.clearRect(0, 0, window.innerWidth, window.innerHeight); | |
118 | + // culling | |
119 | + this.loadedChunksByCoords | |
120 | + .forEach((chunk, coord) => { // check the bounds | |
121 | + if (coord[0] < this.eastChunk && | |
122 | + coord[0] >= this.westChunk && | |
123 | + coord[1] <= this.northChunk && | |
124 | + coord[1] >= this.southChunk) { | |
125 | + | |
126 | + this.place(chunk, coord[0], coord[1]); | |
127 | + return; | |
128 | + } | |
129 | + // its out of range!!! | |
130 | + // get 'em boys!!!!! | |
131 | + this.loadedChunksByCoords.delete(coord); | |
132 | + this.loadedChunksByName.delete(coord.join('_')); | |
133 | + chunk.remove(); | |
134 | + }); | |
135 | + | |
136 | + // gathering what we need to load | |
137 | + const neededChunks = new Set(); | |
138 | + for (var x = this.westChunk; x < this.eastChunk; x++) { | |
139 | + for (var y = this.southChunk; y < this.northChunk; y++) { | |
140 | + const chunKey = [x, y]; // chunk + key = chunKey :) | |
141 | + const name = chunKey.join('_'); | |
142 | + // continue if its not available, or it is loaded | |
143 | + if (!this.availableChunks.has(name) || | |
144 | + this.loadedChunksByName.has(name)) continue; | |
145 | + neededChunks.add(chunKey); | |
26 | 146 | } |
27 | - ViewFrame.prototype.reloadChunkList = function() { | |
28 | - console.log("Reloading chunks!"), this.chunkScript && (this.chunkScript.remove(), delete this.chunkScript), this.chunkScript = document.createElement("script"), this.chunkScript.type = "text/javascript", this.chunkScript.src = "Metadata.js", | |
29 | - document.getElementsByTagName("body")[0].append(this.chunkScript), this.chunkScript.onload = (() => { | |
30 | - this.availableChunks = ViewFrame.chunks.chunkMetadata, null !== this.x && null !== this.y || (this.x = ViewFrame.chunks.startCoords[0], this.y = ViewFrame.chunks.startCoords[1]), this.renderOnReload && this.render() | |
31 | - }), this.dirty = !0 | |
32 | - }, ViewFrame.prototype.render = function() { | |
33 | - if (!this.availableChunks) return; | |
34 | - if (this.rendering) return; | |
35 | - this.rendering = !0, this.dirty && this.updateEdges(), this.loadedChunksByCoords.forEach((t, e) => { | |
36 | - if (e[0] < this.eastChunk && e[0] >= this.westChunk && e[1] <= this.northChunk && e[1] >= this.southChunk) { | |
37 | - let [s, i] = this.chunkToScreen(e[0], e[1]); | |
38 | - t.style.left = s + "px", t.style.top = i + "px"; | |
39 | - const n = this.zoom / 32; | |
40 | - 1 != n && (t.style.transform = `scale(${n})`) | |
41 | - } else this.loadedChunksByCoords.delete(e), this.loadedChunksByName.delete(e.join("_")), t.remove() | |
147 | + } | |
148 | + // iterating over everything we need to load | |
149 | + const it = neededChunks.values(); | |
150 | + ViewFrame.intervalRef = setInterval(() => { | |
151 | + let round = it.next(); | |
152 | + if (!round.done) { | |
153 | + // load | |
154 | + const img = new Image(32, 32); | |
155 | + const name = round.value.join('_'); | |
156 | + | |
157 | + img.src = 'Chunks/'+ name + '.png'; | |
158 | + | |
159 | + decode(img, loadedImage => { | |
160 | + this.place(img, round.value[0], round.value[1]); | |
42 | 161 | }); |
43 | - const t = new Set; | |
44 | - for (var e = this.westChunk; e < this.eastChunk; e++) | |
45 | - for (var s = this.southChunk; s < this.northChunk; s++) { | |
46 | - const i = [e, s], | |
47 | - n = i.join("_"); | |
48 | - this.availableChunks.has(n) && !this.loadedChunksByName.has(n) && t.add(i) | |
49 | - } | |
50 | - const i = t.values(); | |
51 | - let n = setInterval(() => { | |
52 | - let t = i.next(); | |
53 | - if (t.done) clearInterval(n), this.rendering = !1; | |
54 | - else { | |
55 | - const e = new Image(32, 32), | |
56 | - s = t.value.join("_"); | |
57 | - e.src = s + ".png", e.alt = s, decode(e, e => { | |
58 | - let [s, i] = this.chunkToScreen(t.value[0], t.value[1]); | |
59 | - e.style.left = s + "px", e.style.top = i + "px"; | |
60 | - const n = this.zoom / 32; | |
61 | - 1 != n && (chunk.style.transform = `scale(${n})`), this.map.append(e) | |
62 | - }), this.loadedChunksByName.set(s, e), this.loadedChunksByCoords.set(t.value, e) | |
63 | - } | |
64 | - }, 4) | |
65 | - }, ViewFrame.prototype.updateInfobox = function(t) { | |
66 | - const e = this.availableChunks.get(t); | |
67 | - this.infoboxSlots.forEach((t, s) => { | |
68 | - t.innerText = e[s] | |
69 | - }) | |
70 | - }, ViewFrame.initInfobox = function(t, e) { | |
71 | - ["prettyCoord:Loc.", "chunkAge:Age", "temp:Temp.", "YMax:Y Max", "fert:Fert.", "forestDens:Forest", "rain:Rain", "shrubDens:Shrub", "airBlocks:Air", "nonAirBlocks:Non-Air"].map(t => t.split(":")).forEach(s => { | |
72 | - const i = s[0], | |
73 | - n = s[1], | |
74 | - h = document.createElement("tr"), | |
75 | - o = document.createElement("th"); | |
76 | - o.innerText = n; | |
77 | - const r = document.createElement("td"); | |
78 | - r.innerText = "0", e.set(i, r), h.append(o, r), t.append(h) | |
79 | - }) | |
80 | - }, ViewFrame.prototype.screenToChunk = function(t, e) { | |
81 | - return [(t - this.width / 2) / this.zoom, (e - this.height / 2) / this.zoom] | |
82 | - }, ViewFrame.prototype.chunkToScreen = function(t, e) { | |
83 | - return [(t - this.west) * this.zoom, (e - this.south) * this.zoom] | |
84 | - }, ViewFrame.prototype.updateEdges = function() { | |
85 | - if (!this.dirty) return; | |
86 | - const t = Math.ceil(this.width / this.zoom), | |
87 | - e = Math.ceil(this.height / this.zoom); | |
88 | - this.east = this.x + t / 2, this.eastChunk = Math.ceil(this.east), this.west = this.x - t / 2, this.westChunk = Math.floor(this.west), this.north = this.y + e / 2, this.northChunk = Math.ceil(this.north), this.south = this.y - e / 2, this.southChunk = | |
89 | - Math.floor(this.south), this.dirty = !1 | |
90 | - }, ViewFrame.prototype.moveCenter = function(t, e) { | |
91 | - let [s, i] = this.screenToChunk(t, e); | |
92 | - this.x += s, this.y += i, this.dirty = !0 | |
93 | - }, ViewFrame.prototype.clear = function() { | |
94 | - this.loadedChunksByName.clear(), this.loadedChunksByCoords.clear(), this.chunkScript && this.chunkScript.remove(), delete this.chunkScript, delete ViewFrame.chunks, this.map.innerHTML = "" | |
95 | - }, Object.defineProperties(ViewFrame.prototype, { | |
96 | - width: { | |
97 | - get() { | |
98 | - return this.map.clientWidth | |
99 | - } | |
100 | - }, | |
101 | - height: { | |
102 | - get() { | |
103 | - return this.map.clientHeight | |
104 | - } | |
105 | - }, | |
106 | - zoom: { | |
107 | - get() { | |
108 | - return this._zoom | |
109 | - }, | |
110 | - set(t) { | |
111 | - this._zoom = t, this.dirty = !0 | |
112 | - } | |
113 | - } | |
162 | + this.loadedChunksByName.set(name, img); | |
163 | + this.loadedChunksByCoords.set(round.value, img); | |
164 | + } else { | |
165 | + clearInterval(ViewFrame.intervalRef); | |
166 | + this.rendering = false; | |
167 | + } | |
168 | + }, 4); | |
169 | +}; | |
170 | + | |
171 | +ViewFrame.prototype.place = function (img, x, y) { | |
172 | + x -= this.x; | |
173 | + y -= this.y; | |
174 | + x *= this.zoom; | |
175 | + y *= this.zoom; | |
176 | + x += this.width / 2; | |
177 | + y += this.height / 2; | |
178 | + | |
179 | + this.map.drawImage(img, Math.floor(x), Math.floor(y), this.zoom, this.zoom); | |
180 | +}; | |
181 | + | |
182 | +ViewFrame.prototype.updateInfobox = function (chunkName) { | |
183 | + const chunkMeta = this.availableChunks.get(chunkName); | |
184 | + this.infoboxSlots.forEach((l, k) => { | |
185 | + l.innerText = chunkMeta ? chunkMeta[k] : '0'; | |
186 | + }); | |
187 | +};</script></script> | |
188 | + <script type="text/javascript">ViewFrame.initInfobox = function (ibox, iboxSlots) { | |
189 | + | |
190 | + ViewFrame.chunks | |
191 | + .chunkMetadataNames.forEach((item, i) => { | |
192 | + const slot = document.createElement('tr'); | |
193 | + const head = document.createElement('th'); | |
194 | + head.innerText = item; | |
195 | + const row = document.createElement('td'); | |
196 | + row.innerText = '0'; | |
197 | + iboxSlots[i] = row; | |
198 | + slot.append(head, row); | |
199 | + ibox.append(slot); | |
114 | 200 | }); |
115 | - const vf = new ViewFrame; | |
116 | - vf.reloadChunkList(), | |
117 | - function() { | |
118 | - var t; | |
119 | - window.addEventListener("resize", () => { | |
120 | - clearTimeout(t), vf.clear(), t = setTimeout(() => { | |
121 | - vf.updateEdges(), vf.render() | |
122 | - }, 500) | |
123 | - }) | |
124 | - }(), vf.map.addEventListener("mousedown", t => { | |
125 | - vf.moveCenter(t.x, t.y), setTimeout(() => { | |
126 | - vf.render() | |
127 | - }, 250) | |
128 | - }), | |
129 | - function() { | |
130 | - var t; | |
131 | - vf.map.addEventListener("mousemove", e => { | |
132 | - e.target instanceof HTMLImageElement && t !== e.target && (t = e.target, vf.updateInfobox(e.target.alt)) | |
133 | - }) | |
134 | - }(); | |
135 | - (function() { | |
136 | - setInterval(() => { | |
137 | - vf.reloadChunkList(); | |
138 | - }, 6000); | |
139 | - }()); | |
140 | - </script> | |
201 | +}; | |
202 | + | |
203 | +ViewFrame.prototype.updateEdges = function () { | |
204 | + if (this.width != window.innerWidth || this.height != window.innerHeight) { | |
205 | + this.width = window.innerWidth; | |
206 | + this.map.canvas.width = this.width; | |
207 | + this.height = window.innerHeight; | |
208 | + this.map.canvas.height = this.height; | |
209 | + this.map.imageSmoothingEnabled = false; | |
210 | + } | |
211 | + const chunksWide = Math.ceil(this.width / this.zoom); | |
212 | + const chunksHigh = Math.ceil(this.height / this.zoom); | |
213 | + | |
214 | + this.east = this.x + chunksWide / 2; // this is fractional and is used to keep track of the edges of the window | |
215 | + this.eastChunk = Math.ceil(this.east); // this is not and is used to track the chunks that need to load | |
216 | + this.west = this.x - chunksWide / 2; | |
217 | + this.westChunk = Math.floor(this.west); | |
218 | + this.north = this.y + chunksHigh / 2; | |
219 | + this.northChunk = Math.ceil(this.north); | |
220 | + this.south = this.y - chunksHigh / 2; | |
221 | + this.southChunk = Math.floor(this.south); | |
222 | +}; | |
223 | + | |
224 | +ViewFrame.prototype.moveCenter = function (dx, dy) { | |
225 | + // to pan when we click on the map! | |
226 | + this.x += (dx - this.width / 2) / this.zoom; | |
227 | + this.y += (dy - this.height / 2) / this.zoom; | |
228 | +}; | |
229 | +ViewFrame.prototype.setCenter = function (x, y) { | |
230 | + this.x = x; | |
231 | + this.y = y; | |
232 | +}; | |
233 | + | |
234 | +ViewFrame.prototype.clear = function () { | |
235 | + this.loadedChunksByName.clear(); | |
236 | + this.loadedChunksByCoords.clear(); | |
237 | + if (this.chunkScript) this.chunkScript.remove(); | |
238 | + delete this.chunkScript; | |
239 | + delete ViewFrame.chunks; | |
240 | + this.map.clearRect(0, 0, window.innerWidth, window.innerHeight); | |
241 | +}; | |
242 | + | |
243 | +function decode(img, cb) { | |
244 | + img.decode() | |
245 | + .then(() => { | |
246 | + cb(img); | |
247 | + }) | |
248 | + .catch(() => {}); // so images arent added on error | |
249 | +}</script></script> | |
250 | + <div class="infobox"> | |
251 | + <h1>Chunk Info</h1> | |
252 | + <table class="infoboxTable"> | |
253 | + </table> | |
254 | + </div> | |
255 | + <script type="text/javascript">const vf = new ViewFrame(); | |
256 | +vf.reloadChunkList(); | |
257 | + | |
258 | +// the event handlers are in iifes so they dont make unneeded globals. | |
259 | +// resize, delay re-render to reduce lag. | |
260 | +(function () { | |
261 | + var id; | |
262 | + window.addEventListener('resize', () => { | |
263 | + clearTimeout(id); | |
264 | + id = setTimeout(() => { | |
265 | + vf.render(); | |
266 | + }, 500); | |
267 | + }); | |
268 | +}()); | |
269 | + | |
270 | +// panning | |
271 | +(function () { | |
272 | + var id; | |
273 | + vf.map.canvas.addEventListener('mousedown', event => { | |
274 | + clearTimeout(id); | |
275 | + vf.moveCenter(event.pageX, event.pageY); | |
276 | + id = setTimeout(() => { | |
277 | + vf.render(); | |
278 | + }, 250); | |
279 | + }); | |
280 | +}()); | |
281 | + | |
282 | + | |
283 | +// #### CONTROLS #### | |
284 | +// hovering | |
285 | +(function () { | |
286 | + var lastX = 0; | |
287 | + var lastY = 0; | |
288 | + vf.map.canvas.addEventListener('mousemove', event => { | |
289 | + // only count if the mouse moved more than a chunk | |
290 | + let x = Math.floor(vf.x + | |
291 | + (event.clientX - vf.width / 2) / vf.zoom); | |
292 | + let y = Math.floor(vf.y + | |
293 | + (event.clientY - vf.height / 2) / vf.zoom); | |
294 | + if (x == lastX && y == lastY) return; | |
295 | + lastX = x; | |
296 | + lastY = y; | |
297 | + vf.updateInfobox(x + '_' + y); | |
298 | + }); | |
299 | +}()); | |
300 | + | |
301 | +// scroll/zoom | |
302 | +(function () { | |
303 | + var id; | |
304 | + vf.map.canvas.addEventListener('wheel', event => { | |
305 | + clearTimeout(id); | |
306 | + vf.zoom += -Math.sign(event.deltaY)*2; | |
307 | + id = setTimeout(() => { | |
308 | + vf.render(); | |
309 | + }, 250); | |
310 | + }); | |
311 | +}()); | |
312 | + | |
313 | +// reload the chunk list every six seconds | |
314 | +var devBlockReload = false; // disable via command line | |
315 | +(function () { | |
316 | + setInterval(() => { | |
317 | + if (devBlockReload) return; | |
318 | + vf.reloadChunkList(); | |
319 | + }, 6000); | |
320 | +}());</script></script> | |
321 | + | |
141 | 322 | </body> |
142 | 323 | |
143 | 324 | </html> |
\ No newline at end of file |