diff --git a/app/src/editor/ArchitectMode.ts b/app/src/editor/ArchitectMode.ts
index 944fc89..426c9c5 100755
--- a/app/src/editor/ArchitectMode.ts
+++ b/app/src/editor/ArchitectMode.ts
@@ -1,7 +1,7 @@
import type MapScene from './scene/MapScene';
-import Layer from './util/Layer';
import { Vec2 } from './util/Vec';
+import { Layer } from './util/Layer';
export default class ArchitectMode {
scene: MapScene;
@@ -16,7 +16,7 @@ export default class ArchitectMode {
pointerPrimaryDown: boolean = false;
activeTileset: number = 0;
- activeLayer: Layer = Layer.wall;
+ activeLayer: Layer = 'wall';
manipulated: {pos: Vec2; layer: Layer; lastTile: number; tile: number}[] = [];
@@ -25,19 +25,18 @@ export default class ArchitectMode {
}
init() {
- // Create cursor hover sprite
this.cursor = this.scene.add.sprite(0, 0, 'cursor');
- this.cursor.setScale(4, 4);
this.cursor.setDepth(1000);
this.cursor.setOrigin(0, 0);
+ this.cursor.setScale(1 / 16);
}
update() {
this.active = true;
this.cursor!.setVisible(true);
- let selectedTilePos = new Vec2(Math.floor(this.scene.view.cursorWorld.x / 64), Math.floor(this.scene.view.cursorWorld.y / 64));
- this.cursor!.setPosition(selectedTilePos.x * 64, selectedTilePos.y * 64);
+ let selectedTilePos = new Vec2(Math.floor(this.scene.view.cursorWorld.x), Math.floor(this.scene.view.cursorWorld.y));
+ this.cursor!.setPosition(selectedTilePos.x, selectedTilePos.y);
this.cursor!.setVisible((selectedTilePos.x >= 0 && selectedTilePos.y >= 0 &&
selectedTilePos.x < this.scene.map.size.x && selectedTilePos.y < this.scene.map.size.y));
@@ -91,7 +90,7 @@ export default class ArchitectMode {
if (Math.abs(b.x - a.x) > Math.abs(b.y - a.y)) b.y = a.y;
else b.x = a.x;
- this.cursor!.setPosition(b.x * 64, b.y * 64);
+ this.cursor!.setPosition(b.x, b.y);
this.primitives.forEach((v) => v.destroy());
this.primitives = [];
@@ -100,21 +99,19 @@ export default class ArchitectMode {
this.primitives.forEach((v) => {
v.setOrigin(0, 0);
- v.setScale(64, 64);
- v.setLineWidth(0.03);
v.setDepth(300);
+ v.setLineWidth(0.03);
});
- this.primitives.push(this.scene.add.sprite(this.startTilePos.x * 64, this.startTilePos.y * 64,
- 'cursor') as any as Phaser.GameObjects.Line);
+ this.primitives.push(this.scene.add.sprite(this.startTilePos.x, this.startTilePos.y, 'cursor') as any);
this.primitives[1].setOrigin(0, 0);
- this.primitives[1].setScale(4, 4);
+ this.primitives[1].setScale(1 / 16);
this.primitives[1].setAlpha(0.5);
}
else if (!this.scene.i.mouseLeftDown() && !this.scene.i.mouseRightDown() && this.pointerDown) {
- let a = new Vec2(this.startTilePos.x * 64, this.startTilePos.y * 64);
- let b = new Vec2(selectedTilePos.x * 64, selectedTilePos.y * 64);
+ let a = new Vec2(this.startTilePos.x, this.startTilePos.y);
+ let b = new Vec2(selectedTilePos.x, selectedTilePos.y);
if (Math.abs(b.x - a.x) > Math.abs(b.y - a.y)) b.y = a.y;
else b.x = a.x;
@@ -125,12 +122,12 @@ export default class ArchitectMode {
change.y /= normalizeFactor;
while (Math.abs(b.x - a.x) >= 1 || Math.abs(b.y - a.y) >= 1) {
- this.placeTileAndPushManip(new Vec2(Math.floor(a.x / 64), Math.floor(a.y / 64)), this.pointerPrimaryDown);
+ this.placeTileAndPushManip(new Vec2(Math.floor(a.x), Math.floor(a.y)), this.pointerPrimaryDown);
a.x += change.x;
a.y += change.y;
}
- this.placeTileAndPushManip(new Vec2(b.x / 64, b.y / 64), this.pointerPrimaryDown);
+ this.placeTileAndPushManip(new Vec2(b.x, b.y), this.pointerPrimaryDown);
this.primitives.forEach((v) => v.destroy());
this.primitives = [];
}
@@ -154,7 +151,6 @@ export default class ArchitectMode {
this.primitives.forEach((v) => {
v.setOrigin(0, 0);
- v.setScale(64, 64);
v.setLineWidth(0.03);
v.setDepth(300);
});
@@ -180,14 +176,14 @@ export default class ArchitectMode {
let change = new Vec2(this.scene.view.cursorWorld.x - this.scene.view.lastCursorWorld.x,
this.scene.view.cursorWorld.y - this.scene.view.lastCursorWorld.y);
- let normalizeFactor = Math.sqrt(change.x * change.x + change.y * change.y);
+ let normalizeFactor = Math.sqrt(change.x * change.x + change.y * change.y) * 10;
change.x /= normalizeFactor;
change.y /= normalizeFactor;
let place = new Vec2(this.scene.view.lastCursorWorld.x, this.scene.view.lastCursorWorld.y);
- while (Math.abs(this.scene.view.cursorWorld.x - place.x) >= 1 || Math.abs(this.scene.view.cursorWorld.y - place.y) >= 1) {
- this.placeTileAndPushManip(new Vec2(Math.floor(place.x / 64), Math.floor(place.y / 64)), this.scene.i.mouseLeftDown());
+ while (Math.abs(this.scene.view.cursorWorld.x - place.x) >= 0.1 || Math.abs(this.scene.view.cursorWorld.y - place.y) >= 0.1) {
+ this.placeTileAndPushManip(new Vec2(Math.floor(place.x), Math.floor(place.y)), this.scene.i.mouseLeftDown());
place.x += change.x;
place.y += change.y;
}
@@ -198,12 +194,12 @@ export default class ArchitectMode {
placeTileAndPushManip(manipPos: Vec2, solid: boolean) {
let tile = solid ? this.activeTileset : -1;
- let layer = (tile === -1 && this.activeLayer === Layer.floor) ? Layer.wall : this.activeLayer;
+ let layer = (tile === -1 && this.activeLayer === 'floor') ? 'wall' : this.activeLayer;
- let lastTile = this.scene.map.getTileset(layer, manipPos.x, manipPos.y);
+ let lastTile = this.scene.map.activeLayer.getTile(layer, manipPos.x, manipPos.y);
if (tile === lastTile) return;
- this.scene.map.setTile(layer, tile, manipPos.x, manipPos.y);
+ this.scene.map.activeLayer.setTile(layer, tile, manipPos.x, manipPos.y);
this.manipulated.push({
pos: manipPos,
@@ -211,7 +207,6 @@ export default class ArchitectMode {
lastTile: lastTile,
tile: tile
});
-
}
cleanup() {
diff --git a/app/src/editor/MapChunk.ts b/app/src/editor/MapChunk.ts
deleted file mode 100755
index fc5c305..0000000
--- a/app/src/editor/MapChunk.ts
+++ /dev/null
@@ -1,96 +0,0 @@
-import MapData from './MapData';
-
-import Layer from './util/Layer';
-import { Vec2 } from './util/Vec';
-
-export default class MapChunk {
- static CHUNK_SIZE = 16;
- static TILE_SIZE = 16;
- static DIRTY_LIMIT = 32;
-
- private pos: Vec2;
- private map: MapData;
- private canvas: Phaser.GameObjects.RenderTexture;
-
- private dirtyList: Vec2[] = [];
- private fullyDirty: boolean = false;
-
- constructor(map: MapData, x: number, y: number) {
- this.pos = new Vec2(x, y);
- this.canvas = map.scene.add.renderTexture(
- x * MapChunk.CHUNK_SIZE * MapChunk.TILE_SIZE * 4, y * MapChunk.CHUNK_SIZE * MapChunk.TILE_SIZE * 4,
- MapChunk.CHUNK_SIZE * MapChunk.TILE_SIZE, MapChunk.CHUNK_SIZE * MapChunk.TILE_SIZE);
-
- this.map = map;
- this.canvas.setScale(4);
- this.canvas.setOrigin(0, 0);
-
- for (let i = 0; i < MapChunk.CHUNK_SIZE * MapChunk.CHUNK_SIZE; i++) {
- let x = i % MapChunk.CHUNK_SIZE;
- let y = Math.floor(i / MapChunk.CHUNK_SIZE);
-
- let mX = x + this.pos.x * MapChunk.CHUNK_SIZE;
- let mY = y + this.pos.y * MapChunk.CHUNK_SIZE;
- if (mX >= this.map.size.x || mY >= this.map.size.y) continue;
-
- this.drawTile(x, y);
- }
- }
-
- dirty(pos: Vec2): void {
- if (!this.fullyDirty) {
- for (let v of this.dirtyList) if (v.equals(pos)) return;
- this.dirtyList.push(pos);
-
- if (this.dirtyList.length > MapChunk.DIRTY_LIMIT) {
- this.fullyDirty = true;
- this.dirtyList = [];
- }
- }
- }
-
- rebuild(): boolean {
- if (this.fullyDirty) {
- for (let i = 0; i < MapChunk.CHUNK_SIZE * MapChunk.CHUNK_SIZE; i++) {
- let x = i % MapChunk.CHUNK_SIZE;
- let y = Math.floor(i / MapChunk.CHUNK_SIZE);
-
- let mX = x + this.pos.x * MapChunk.CHUNK_SIZE;
- let mY = y + this.pos.y * MapChunk.CHUNK_SIZE;
- if (mX >= this.map.size.x || mY >= this.map.size.y) continue;
-
- this.drawTile(x, y);
- }
- this.fullyDirty = false;
- return true;
- }
-
- if (this.dirtyList.length === 0) return false;
-
- for (let elem of this.dirtyList) this.drawTile(elem.x, elem.y);
- this.dirtyList = [];
- return true;
- }
-
- private drawTile(x: number, y: number): void {
- let mX = x + this.pos.x * MapChunk.CHUNK_SIZE;
- let mY = y + this.pos.y * MapChunk.CHUNK_SIZE;
-
- let wallTile = this.map.getTile(Layer.wall, mX, mY);
- if (this.map.getTileset(Layer.wall, mX, mY) === -1 || (wallTile < 54 || wallTile > 60)) {
- this.canvas.drawFrame(this.map.manager.groundLocations[this.map.getTileset(Layer.floor, mX, mY)].identifier,
- this.map.getTile(Layer.floor, mX, mY), x * MapChunk.TILE_SIZE, y * MapChunk.TILE_SIZE);
-
- if (this.map.getTileset(Layer.overlay, mX, mY) !== -1)
- this.canvas.drawFrame(this.map.manager.overlayLocations[this.map.getTileset(Layer.overlay, mX, mY)].identifier,
- this.map.getTile(Layer.overlay, mX, mY), x * MapChunk.TILE_SIZE, y * MapChunk.TILE_SIZE);
- }
-
- if (this.map.getTileset(Layer.wall, mX, mY) !== -1)
- this.canvas.drawFrame(this.map.manager.wallLocations[this.map.getTileset(Layer.wall, mX, mY)].identifier,
- this.map.getTile(Layer.wall, mX, mY), x * MapChunk.TILE_SIZE, y * MapChunk.TILE_SIZE);
-
- if ((x % 2 === 0 && y % 2 === 0) || (x % 2 !== 0 && y % 2 !== 0))
- this.canvas.drawFrame('grid_tile', 0, x * MapChunk.TILE_SIZE, y * MapChunk.TILE_SIZE);
- }
-}
diff --git a/app/src/editor/MapData.ts b/app/src/editor/MapData.ts
deleted file mode 100755
index f3d0cae..0000000
--- a/app/src/editor/MapData.ts
+++ /dev/null
@@ -1,198 +0,0 @@
-import MapChunk from './MapChunk';
-import * as SmartTiler from './SmartTiler';
-import type MapScene from './scene/MapScene';
-import TilesetManager from './TilesetManager';
-
-import Layer from './util/Layer';
-import { Vec2 } from './util/Vec';
-import { Asset } from './util/Asset';
-import { clamp } from './util/Helpers';
-
-export default class MapData {
- scene: MapScene;
- size: Vec2 = new Vec2(0, 0);
-
- savedMapData: number[][] = [];
-
- manager: TilesetManager;
- private layers: {[key: number]: { tiles: number[][]; tilesets: number[][] }} = {};
- private chunks: MapChunk[][] = [];
-
- constructor(scene: MapScene) {
- this.scene = scene;
- this.manager = new TilesetManager(scene);
- }
-
- init(size: Vec2, assets: Asset[]) {
- this.size = size;
- this.manager.init(assets);
-
- this.registerLayer(Layer.floor, () => Math.floor(Math.random() * 6) + 54, 0);
- this.registerLayer(Layer.wall, 0, -1);
- this.registerLayer(Layer.overlay, 0, -1);
-
- for (let i = 0; i < Math.ceil(size.y / MapChunk.CHUNK_SIZE); i++) {
- this.chunks[i] = [];
- for (let j = 0; j < Math.ceil(size.x / MapChunk.CHUNK_SIZE); j++) {
- this.chunks[i][j] = new MapChunk(this, j, i);
- }
- }
- }
-
- update(): void {
- let start = Date.now();
- for (let arr of this.chunks) for (let chunk of arr) {
- chunk.rebuild();
- if (Date.now() - start > 10) break;
- }
-
- if (this.scene.i.keyPressed('S')) this.saveMap();
- if (this.scene.i.keyPressed('L')) this.loadMap(this.savedMapData);
- }
-
- setTile(layer: Layer, tileset: number, xx: number | Vec2, yy?: number): boolean {
- let x: number, y: number;
- if (xx instanceof Vec2) { x = xx.x; y = xx.y; }
- else { x = xx; y = yy!; }
-
- if (x < 0 || y < 0 || x >= this.size.x || y >= this.size.y) return false;
-
- let oldTileset = this.getTileset(layer, x, y);
- if (oldTileset === tileset) return false;
- this.setTileset(layer, x, y, tileset);
- this.smartTile(x, y);
-
- return true;
- }
-
- setTileset(key: number, x: number | Vec2, a?: number, b?: number): void {
- if (x instanceof Vec2) this.layers[key].tilesets[x.y][x.x] = a!;
- else this.layers[key].tilesets[a!][x] = b!;
- }
-
- getTile(key: number, xx: number | Vec2, yy?: number): number {
- let x: number, y: number;
- if (xx instanceof Vec2) { x = xx.x; y = xx.y; }
- else { x = xx; y = yy!; }
-
- return this.layers[key].tiles[clamp(y, 0, this.size.y - 1)][clamp(x, 0, this.size.x - 1)];
- }
-
- getTileset(key: number, xx: number | Vec2, yy?: number): number {
- let x: number, y: number;
- if (xx instanceof Vec2) { x = xx.x; y = xx.y; }
- else { x = xx; y = yy!; }
-
- return this.layers[key].tilesets[clamp(y, 0, this.size.y - 1)][clamp(x, 0, this.size.x - 1)];
- }
-
- private smartTile(x: number, y: number): void {
- for (let i = clamp(x - 1, this.size.x - 1, 0); i <= clamp(x + 1, this.size.x - 1, 0); i++) {
- for (let j = clamp(y - 1, this.size.y - 1, 0); j <= clamp(y + 1, this.size.y - 1, 0); j++) {
- const solids = this.getTilesetsAt(Layer.wall, i, j).map(i => i !== -1);
-
- // const bits = SmartTiler.bitsToIndices(solids);
- // if (i === x && j === y) console.log(bits, Math.floor(bits / 16), bits % 16);
-
- const wall = SmartTiler.wall(solids, this.getTile(Layer.wall, i, j));
- if (wall !== -1) this.setTileRaw(Layer.wall, i, j, wall);
-
- const floor = SmartTiler.floor(solids, this.getTile(Layer.floor, i, j));
- if (floor !== -1) this.setTileRaw(Layer.floor, i, j, floor);
-
- const overlay = SmartTiler.overlay(this.getTilesetsAt(Layer.overlay, i, j)
- .map(t => t === this.getTileset(Layer.overlay, i, j)), this.getTileset(Layer.overlay, i, j));
- if (overlay !== -1) this.setTileRaw(Layer.overlay, i, j, overlay);
- }
- }
-
- // this.scene.lighting.tileUpdatedAt(x, y);
- }
-
- private setTileRaw(key: number, x: number | Vec2, a?: number, b?: number, c?: number): void {
- if (x instanceof Vec2) {
- this.layers[key].tiles[x.y][x.x] = a!;
- if (b !== undefined) this.setTileset(key, x, b);
-
- this.chunks[Math.floor(x.y / MapChunk.CHUNK_SIZE)][Math.floor(x.x / MapChunk.CHUNK_SIZE)]
- .dirty(new Vec2(x.x % MapChunk.CHUNK_SIZE, x.y % MapChunk.CHUNK_SIZE));
- }
- else {
- this.layers[key].tiles[a!][x] = b!;
- if (c !== undefined) this.setTileset(key, x, a, c);
-
- this.chunks[Math.floor(a! / MapChunk.CHUNK_SIZE)][Math.floor(x / MapChunk.CHUNK_SIZE)]
- .dirty(new Vec2(x % MapChunk.CHUNK_SIZE, a! % MapChunk.CHUNK_SIZE));
- }
- }
-
- private getTilesetsAt(layer: Layer, x: number, y: number): number[] {
- let tilesets: number[] = [];
- for (let i = -1; i <= 1; i++)
- for (let j = -1; j <= 1; j++)
- tilesets.push(this.getTileset(layer, clamp(x + j, 0, this.size.x - 1), clamp(y + i, 0, this.size.y - 1)));
- return tilesets;
- }
-
- private registerLayer(key: number, startTile: any = 0, startTileset: number = -1): void {
- let layer: {tiles: number[][]; tilesets: number[][]} = { tiles: [], tilesets: [] };
-
- for (let i = 0; i < this.size.y; i++) {
- layer.tiles[i] = [];
- layer.tilesets[i] = [];
- for (let j = 0; j < this.size.x; j++) {
- let tile = typeof(startTile) === 'number' ? startTile : startTile();
- layer.tiles[i][j] = tile;
- layer.tilesets[i][j] = startTileset;
- }
- }
-
- this.layers[key] = layer;
- }
-
- private saveMap() {
-
- let mapData: number[][] = [];
-
- for (let k = 0; k < 3; k++) {
- let tile = 0;
- let count = 0;
- mapData[k] = [];
-
- for (let i = 0; i < this.size.x * this.size.y; i++) {
- let x = i % this.size.x;
- let y = Math.floor(i / this.size.x);
-
- if (this.getTileset(k, x, y) === tile) count++;
- else {
- if (i !== 0) {
- mapData[k].push(tile);
- mapData[k].push(count);
- }
- tile = this.getTileset(k, x, y);
- count = 1;
- }
- }
- }
-
- this.savedMapData = mapData;
- }
-
- private loadMap(dat: number[][]) {
- for (let k = 0; k < 3; k++) {
- let offset = 0;
- for (let i = 0; i < dat[k].length / 2; i++) {
- let tile = dat[k][i * 2];
- let count = dat[k][i * 2 + 1];
-
- for (let t = 0; t < count; t++) {
- let x = (offset + t) % this.size.x;
- let y = Math.floor((offset + t) / this.size.x);
-
- this.setTile(k, tile, x, y);
- }
- offset += count;
- }
- }
- }
-}
diff --git a/app/src/editor/SmartTiler.ts b/app/src/editor/SmartTiler.ts
deleted file mode 100755
index 6b0d847..0000000
--- a/app/src/editor/SmartTiler.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-const wallField = [
- 33, 33, 6, 6, 33, 33, 6, 6, 5, 5, 10, 17, 5, 5, 10, 17, 15, 15, 9, 9, 15, 15, 16, 16, 2, 2, 4, 50, 2, 2, 49, 32,
- 33, 33, 6, 6, 33, 33, 6, 6, 5, 5, 10, 17, 5, 5, 10, 17, 15, 15, 9, 9, 15, 15, 16, 16, 2, 2, 4, 50, 2, 2, 49, 32,
- 14, 14, 11, 11, 14, 14, 11, 11, 1, 1, 13, 48, 1, 1, 13, 48, 0, 0, 12, 12, 0, 0, 47, 47, 3, 3, 25, 46, 3, 3, 45, 20,
- 14, 14, 11, 11, 14, 14, 11, 11, 8, 8, 39, 23, 8, 8, 39, 23, 0, 0, 12, 12, 0, 0, 47, 47, 41, 41, 37, 29, 41, 41, 51, 18,
- 33, 33, 6, 6, 33, 33, 6, 6, 5, 5, 10, 17, 5, 5, 10, 17, 15, 15, 9, 9, 15, 15, 16, 16, 2, 2, 4, 50, 2, 2, 49, 32,
- 33, 33, 6, 6, 33, 33, 6, 6, 5, 5, 10, 17, 5, 5, 10, 17, 15, 15, 9, 9, 15, 15, 16, 16, 2, 2, 4, 50, 2, 2, 49, 32,
- 14, 14, 11, 11, 14, 14, 11, 11, 1, 1, 13, 48, 1, 1, 13, 48, 7, 7, 38, 38, 7, 7, 22, 22, 40, 40, 36, 42, 40, 40, 30, 19,
- 14, 14, 11, 11, 14, 14, 11, 11, 8, 8, 39, 23, 8, 8, 39, 23, 7, 7, 38, 38, 7, 7, 22, 22, 31, 31, 21, 27, 31, 31, 28, 54
-];
-
-const floorField = [
- 54, 20, 19, 19, 18, 4, 19, 19, 11, 11, 3, 3, 51, 51, 3, 3, 9, 52, 5, 5, 9, 52, 5, 5, 39, 39, 30, 30, 39, 39, 30, 30,
- 2, 12, 32, 32, 34, 6, 32, 32, 11, 11, 3, 3, 51, 51, 3, 3, 43, 38, 29, 29, 43, 38, 29, 29, 39, 39, 30, 30, 39, 39, 30, 30,
- 1, 41, 17, 17, 40, 46, 17, 17, 21, 21, 8, 8, 45, 45, 8, 8, 23, 47, 26, 26, 23, 47, 26, 26, 48, 48, 49, 49, 48, 48, 49, 49,
- 1, 41, 17, 17, 40, 46, 17, 17, 21, 21, 8, 8, 45, 45, 8, 8, 23, 47, 26, 26, 23, 47, 26, 26, 48, 48, 49, 49, 48, 48, 49, 49,
- 0, 33, 31, 31, 14, 7, 31, 31, 42, 42, 27, 27, 36, 36, 27, 27, 9, 52, 5, 5, 9, 52, 5, 5, 39, 39, 30, 30, 39, 39, 30, 30,
- 22, 15, 28, 28, 16, 37, 28, 28, 42, 42, 27, 27, 36, 36, 27, 27, 43, 38, 29, 29, 43, 38, 29, 29, 39, 39, 30, 30, 39, 39, 30, 30,
- 1, 41, 17, 17, 40, 46, 17, 17, 21, 21, 8, 8, 45, 45, 8, 8, 23, 47, 26, 26, 23, 47, 26, 26, 48, 48, 49, 49, 48, 48, 49, 49,
- 1, 41, 17, 17, 40, 46, 17, 17, 21, 21, 8, 8, 45, 45, 8, 8, 23, 47, 26, 26, 23, 47, 26, 26, 48, 48, 49, 49, 48, 48, 49, 49
-];
-
-export function bitsToIndices(walls: boolean[]) {
- return (
- (+walls[0] << 0) +
- (+walls[1] << 1) +
- (+walls[2] << 2) +
- (+walls[3] << 3) +
- (+walls[5] << 4) +
- (+walls[6] << 5) +
- (+walls[7] << 6) +
- (+walls[8] << 7));
-}
-
-export function wall(walls: boolean[], current: number): number {
- if (current === -1) return -1;
- const ind = wallField[bitsToIndices(walls)];
- if (ind < 54) return ind;
- return 54 + Math.floor(Math.random() * 6);
-}
-
-export function overlay(overlays: boolean[], current: number): number {
- if (current === -1) return -1;
- const ind = floorField[bitsToIndices(overlays)];
- if (ind < 54) return ind;
- return 54 + Math.floor(Math.random() * 6);
-}
-
-export function floor(walls: boolean[], current: number): number {
- if (current === -1) return -1;
- const ind = floorField[bitsToIndices(walls)];
- if (ind < 54) return ind;
- return 54 + Math.floor(Math.random() * 6);
-}
-
-// const l = [];
-// for (let i = 0; i < (1 << 8); ++i ) {
-// let arr = [ i & 0x001, i & 0x002, i & 0x004, i & 0x008, 0,
-// i & 0x010, i & 0x020, i & 0x040, i & 0x080 ].map(a => !!a);
-// l.push(overlay(arr, 1));
-// }
-
-// let lines = [];
-// for (let i = 0; i < 16; i++) {
-// lines.push(l.slice(i * 16, (i + 1) * 16).map(n => n < 10 ? n + ', ' : n + ',').join(' '));
-// }
-
-// console.log(lines.join('\n'));
diff --git a/app/src/editor/TilesetManager.ts b/app/src/editor/TilesetManager.ts
deleted file mode 100755
index 458705c..0000000
--- a/app/src/editor/TilesetManager.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import type MapScene from './scene/MapScene';
-
-import Layer from './util/Layer';
-import { Asset } from './util/Asset';
-
-export default class TilesetManager {
- scene: MapScene;
-
- wallLocations: {[index: number]: { res: number; ind: number; identifier: string }} = {};
- groundLocations: {[index: number]: { res: number; ind: number; identifier: string }} = {};
- overlayLocations: {[index: number]: { res: number; ind: number; identifier: string }} = {};
- indexes: {[tileset_key: string]: number} = {};
-
- private currentWallInd: number = 0;
- private currentGroundInd: number = 0;
- private currentOverlayInd: number = 0;
-
- constructor(scene: MapScene) {
- this.scene = scene;
- }
-
- init(assets: Asset[]) {
- for (let tileset of assets.filter(a => a.type === 'wall' )) this.addTileset(tileset.identifier, Layer.wall);
- for (let tileset of assets.filter(a => a.type === 'ground' )) this.addTileset(tileset.identifier, Layer.floor);
- // for (let tileset of assets.filter(a => a.type === 'overlay')) this.addTileset(tileset.key, Layer.overlay);
- }
-
- private addTileset(identifier: string, layer: Layer): void {
- let res = this.scene.textures.get(identifier).getSourceImage(0).width / 9;
- let ind = (layer === Layer.wall ? this.currentWallInd : layer === Layer.floor ? this.currentGroundInd : this.currentOverlayInd);
- this[layer === Layer.wall ? 'wallLocations' : layer === Layer.floor ?
- 'groundLocations' : 'overlayLocations'][ind] = { res, ind, identifier };
- this.indexes[identifier] = ind;
-
- if (layer === Layer.wall) this.currentWallInd++;
- else if (layer === Layer.floor) this.currentGroundInd++;
- else this.currentOverlayInd++;
- }
-}
diff --git a/app/src/editor/TilesetPatcher.ts b/app/src/editor/TilesetPatcher.ts
index add76fa..b882805 100644
--- a/app/src/editor/TilesetPatcher.ts
+++ b/app/src/editor/TilesetPatcher.ts
@@ -5,154 +5,160 @@ import { Vec2, Vec4 } from './util/Vec';
export default class TilesetPatcher {
constructor(private scene: Phaser.Scene) {}
- patch(tileset_key: string, tile_size: number): void {
- const s = Date.now();
+ async patch(tileset_key: string, tile_size: number): Promise
{
+ return new Promise(resolve => {
+ const s = Date.now();
- const canvas = new Phaser.GameObjects.RenderTexture(this.scene, 0, 0, 10 * tile_size, 5 * tile_size);
- canvas.draw(tileset_key);
+ const canvas = new Phaser.GameObjects.RenderTexture(this.scene, 0, 0, 10 * tile_size, 5 * tile_size);
+ canvas.draw(tileset_key);
- let part: Phaser.GameObjects.Sprite | Phaser.GameObjects.RenderTexture
- = new Phaser.GameObjects.Sprite(this.scene, 0, 0, tileset_key);
- part.setOrigin(0, 0);
+ let part: Phaser.GameObjects.Sprite | Phaser.GameObjects.RenderTexture
+ = new Phaser.GameObjects.Sprite(this.scene, 0, 0, tileset_key, '__BASE');
+ part.setOrigin(0, 0);
- function draw(source: Vec4, dest: Vec2) {
- part.setCrop(source.x * tile_size, source.y * tile_size, (source.z - source.x) * tile_size, (source.w - source.y) * tile_size);
- part.setPosition((dest.x - source.x) * tile_size, (dest.y - source.y) * tile_size);
- canvas.draw(part);
- }
+ function draw(source: Vec4, dest: Vec2) {
+ part.setCrop(source.x * tile_size, source.y * tile_size, (source.z - source.x) * tile_size, (source.w - source.y) * tile_size);
+ part.setPosition((dest.x - source.x) * tile_size, (dest.y - source.y) * tile_size);
+ canvas.draw(part);
+ }
- // End Pieces and Walls
+ // End Pieces and Walls
- draw(new Vec4(2, 0, 3, 0.5), new Vec2(7, 0));
- draw(new Vec4(2, 1.5, 3, 2), new Vec2(7, 0.5));
+ draw(new Vec4(2, 0, 3, 0.5), new Vec2(7, 0));
+ draw(new Vec4(2, 1.5, 3, 2), new Vec2(7, 0.5));
- draw(new Vec4(2, 0, 2.5, 1), new Vec2(8, 0));
- draw(new Vec4(3.5, 0, 4, 1), new Vec2(8.5, 0));
+ draw(new Vec4(2, 0, 2.5, 1), new Vec2(8, 0));
+ draw(new Vec4(3.5, 0, 4, 1), new Vec2(8.5, 0));
- draw(new Vec4(1, 0, 2, 0.5), new Vec2(9, 0));
- draw(new Vec4(0, 1.5, 1, 2), new Vec2(9, 0.5));
+ draw(new Vec4(1, 0, 2, 0.5), new Vec2(9, 0));
+ draw(new Vec4(0, 1.5, 1, 2), new Vec2(9, 0.5));
- draw(new Vec4(2, 1, 2.5, 2), new Vec2(7, 1));
- draw(new Vec4(3.5, 1, 4, 2), new Vec2(7.5, 1));
+ draw(new Vec4(2, 1, 2.5, 2), new Vec2(7, 1));
+ draw(new Vec4(3.5, 1, 4, 2), new Vec2(7.5, 1));
- draw(new Vec4(3, 0, 4, 0.5), new Vec2(8, 1));
- draw(new Vec4(3, 1.5, 4, 2), new Vec2(8, 1.5));
+ draw(new Vec4(3, 0, 4, 0.5), new Vec2(8, 1));
+ draw(new Vec4(3, 1.5, 4, 2), new Vec2(8, 1.5));
- draw(new Vec4(0, 0, 0.5, 1), new Vec2(9, 1));
- draw(new Vec4(1.5, 1, 2, 2), new Vec2(9.5, 1));
+ draw(new Vec4(0, 0, 0.5, 1), new Vec2(9, 1));
+ draw(new Vec4(1.5, 1, 2, 2), new Vec2(9.5, 1));
- // Advanced Corners (Orange)
+ // Advanced Corners (Orange)
- draw(new Vec4(6, 1, 7, 1.5), new Vec2(0, 2));
- draw(new Vec4(6, 0.5, 7, 1), new Vec2(0, 2.5));
+ draw(new Vec4(6, 1, 7, 1.5), new Vec2(0, 2));
+ draw(new Vec4(6, 0.5, 7, 1), new Vec2(0, 2.5));
- draw(new Vec4(6, 1, 6.5, 2), new Vec2(1, 2));
- draw(new Vec4(5.5, 1, 6, 2), new Vec2(1.5, 2));
+ draw(new Vec4(6, 1, 6.5, 2), new Vec2(1, 2));
+ draw(new Vec4(5.5, 1, 6, 2), new Vec2(1.5, 2));
- draw(new Vec4(5, 0, 6, 1), new Vec2(2, 2));
- draw(new Vec4(6, 1, 6.5, 1.5), new Vec2(2, 2));
+ draw(new Vec4(5, 0, 6, 1), new Vec2(2, 2));
+ draw(new Vec4(6, 1, 6.5, 1.5), new Vec2(2, 2));
- draw(new Vec4(6, 0, 6.5, 1), new Vec2(0, 3));
- draw(new Vec4(5.5, 0, 6, 1), new Vec2(0.5, 3));
+ draw(new Vec4(6, 0, 6.5, 1), new Vec2(0, 3));
+ draw(new Vec4(5.5, 0, 6, 1), new Vec2(0.5, 3));
- draw(new Vec4(5, 1, 6, 1.5), new Vec2(1, 3));
- draw(new Vec4(5, 0.5, 6, 1), new Vec2(1, 3.5));
+ draw(new Vec4(5, 1, 6, 1.5), new Vec2(1, 3));
+ draw(new Vec4(5, 0.5, 6, 1), new Vec2(1, 3.5));
- draw(new Vec4(6, 0, 7, 1), new Vec2(2, 3));
- draw(new Vec4(5.5, 1, 6, 1.5), new Vec2(2.5, 3));
+ draw(new Vec4(6, 0, 7, 1), new Vec2(2, 3));
+ draw(new Vec4(5.5, 1, 6, 1.5), new Vec2(2.5, 3));
- draw(new Vec4(5.5, 1, 6, 1.5), new Vec2(0.5, 4));
- draw(new Vec4(6, 1, 6.5, 1.5), new Vec2(0, 4));
- draw(new Vec4(6, 0.5, 6.5, 1), new Vec2(0, 4.5));
- draw(new Vec4(5.5, 0.5, 6, 1), new Vec2(0.5, 4.5));
+ draw(new Vec4(5.5, 1, 6, 1.5), new Vec2(0.5, 4));
+ draw(new Vec4(6, 1, 6.5, 1.5), new Vec2(0, 4));
+ draw(new Vec4(6, 0.5, 6.5, 1), new Vec2(0, 4.5));
+ draw(new Vec4(5.5, 0.5, 6, 1), new Vec2(0.5, 4.5));
- /**
- * So here's why this is horrible:
- * - Phaser doesn't let you copy a region of a RenderTexture to the same RenderTexture.
- * - Creating a new RenderTexture and drawing the original directly onto it flips it upside down for some reason?
- * - Scaling that upside-down RenderTexture to upside-right fucks with the draw() function's positioning.
- *
- * In other words, yeah, it's fucked man. The janky solution below is the only way I've found to make it work,
- * so if future-Auri is looking at this and making a snarky comment to her friends about how she could do it
- * *so much better*, please, just don't. Don't do it.
- */
+ /**
+ * So here's why this is horrible:
+ * - Phaser doesn't let you copy a region of a RenderTexture to the same RenderTexture.
+ * - Creating a new RenderTexture and drawing the original directly onto it flips it upside down for some reason?
+ * - Scaling that upside-down RenderTexture to upside-right fucks with the draw() function's positioning.
+ *
+ * In other words, yeah, it's fucked man. The janky solution below is the only way I've found to make it work,
+ * so if future-Auri is looking at this and making a snarky comment to her friends about how she could do it
+ * *so much better*, please, just don't. Don't do it.
+ */
- part.setCrop();
- part = new Phaser.GameObjects.RenderTexture(this.scene, 0, 0, canvas.width, canvas.height);
- part.setOrigin(0, 0);
- const temp = new Phaser.GameObjects.Sprite(this.scene, 0, 0, canvas.texture);
- temp.setOrigin(0, 0);
- part.draw(temp);
+ part.setCrop();
+ part = new Phaser.GameObjects.RenderTexture(this.scene, 0, 0, canvas.width, canvas.height);
+ part.setOrigin(0, 0);
+ const temp = new Phaser.GameObjects.Sprite(this.scene, 0, 0, canvas.texture);
+ temp.setOrigin(0, 0);
+ part.draw(temp);
- // Derived Forms (Pink)
+ // Derived Forms (Pink)
- draw(new Vec4(2, 0, 3, 1), new Vec2(3, 2));
- draw(new Vec4(5.5, 0.5, 6, 1), new Vec2(3.5, 2.5));
+ draw(new Vec4(2, 0, 3, 1), new Vec2(3, 2));
+ draw(new Vec4(5.5, 0.5, 6, 1), new Vec2(3.5, 2.5));
- draw(new Vec4(3, 0, 4, 1), new Vec2(4, 2));
- draw(new Vec4(6, 0.5, 6.5, 1), new Vec2(4, 2.5));
+ draw(new Vec4(3, 0, 4, 1), new Vec2(4, 2));
+ draw(new Vec4(6, 0.5, 6.5, 1), new Vec2(4, 2.5));
- draw(new Vec4(1, 0, 2, 1), new Vec2(5, 2));
- draw(new Vec4(5.5, 0.5, 6, 1), new Vec2(5.5, 2.5));
+ draw(new Vec4(1, 0, 2, 1), new Vec2(5, 2));
+ draw(new Vec4(5.5, 0.5, 6, 1), new Vec2(5.5, 2.5));
- draw(new Vec4(1, 0, 2, 1), new Vec2(6, 2));
- draw(new Vec4(0, 3.5, 1, 4), new Vec2(6, 2.5));
+ draw(new Vec4(1, 0, 2, 1), new Vec2(6, 2));
+ draw(new Vec4(0, 3.5, 1, 4), new Vec2(6, 2.5));
- draw(new Vec4(1, 0, 2, 1), new Vec2(7, 2));
- draw(new Vec4(6, 0.5, 6.5, 1), new Vec2(7, 2.5));
+ draw(new Vec4(1, 0, 2, 1), new Vec2(7, 2));
+ draw(new Vec4(6, 0.5, 6.5, 1), new Vec2(7, 2.5));
- draw(new Vec4(0, 0, 1, 1), new Vec2(8, 2));
- draw(new Vec4(5.5, 0.5, 6, 1), new Vec2(8.5, 2.5));
+ draw(new Vec4(0, 0, 1, 1), new Vec2(8, 2));
+ draw(new Vec4(5.5, 0.5, 6, 1), new Vec2(8.5, 2.5));
- draw(new Vec4(1, 1, 2, 2), new Vec2(9, 2));
- draw(new Vec4(6, 0.5, 6.5, 1), new Vec2(9, 2.5));
+ draw(new Vec4(1, 1, 2, 2), new Vec2(9, 2));
+ draw(new Vec4(6, 0.5, 6.5, 1), new Vec2(9, 2.5));
- draw(new Vec4(2, 1, 3, 2), new Vec2(3, 3));
- draw(new Vec4(5.5, 1, 6, 1.5), new Vec2(3.5, 3));
+ draw(new Vec4(2, 1, 3, 2), new Vec2(3, 3));
+ draw(new Vec4(5.5, 1, 6, 1.5), new Vec2(3.5, 3));
- draw(new Vec4(3, 1, 4, 2), new Vec2(4, 3));
- draw(new Vec4(6, 1, 6.5, 1.5), new Vec2(4, 3));
+ draw(new Vec4(3, 1, 4, 2), new Vec2(4, 3));
+ draw(new Vec4(6, 1, 6.5, 1.5), new Vec2(4, 3));
- draw(new Vec4(0, 1, 1, 2), new Vec2(5, 3));
- draw(new Vec4(5.5, 1, 6, 1.5), new Vec2(5.5, 3));
+ draw(new Vec4(0, 1, 1, 2), new Vec2(5, 3));
+ draw(new Vec4(5.5, 1, 6, 1.5), new Vec2(5.5, 3));
- draw(new Vec4(0, 1, 1, 2), new Vec2(6, 3));
- draw(new Vec4(1, 2, 2, 2.5), new Vec2(6, 3));
+ draw(new Vec4(0, 1, 1, 2), new Vec2(6, 3));
+ draw(new Vec4(1, 2, 2, 2.5), new Vec2(6, 3));
- draw(new Vec4(0, 1, 1, 2), new Vec2(7, 3));
- draw(new Vec4(6, 1, 6.5, 1.5), new Vec2(7, 3));
+ draw(new Vec4(0, 1, 1, 2), new Vec2(7, 3));
+ draw(new Vec4(6, 1, 6.5, 1.5), new Vec2(7, 3));
- draw(new Vec4(0, 0, 1, 1), new Vec2(8, 3));
- draw(new Vec4(1.5, 3, 2, 4), new Vec2(8.5, 3));
+ draw(new Vec4(0, 0, 1, 1), new Vec2(8, 3));
+ draw(new Vec4(1.5, 3, 2, 4), new Vec2(8.5, 3));
- draw(new Vec4(1, 1, 2, 2), new Vec2(9, 3));
- draw(new Vec4(0, 2, 0.5, 3), new Vec2(9, 3));
+ draw(new Vec4(1, 1, 2, 2), new Vec2(9, 3));
+ draw(new Vec4(0, 2, 0.5, 3), new Vec2(9, 3));
- draw(new Vec4(0, 2, 1, 3), new Vec2(4, 4));
- draw(new Vec4(5.5, 1, 6, 1.5), new Vec2(4.5, 4));
+ draw(new Vec4(0, 2, 1, 3), new Vec2(4, 4));
+ draw(new Vec4(5.5, 1, 6, 1.5), new Vec2(4.5, 4));
- draw(new Vec4(1, 3, 2, 4), new Vec2(5, 4));
- draw(new Vec4(6, 1, 6.5, 1.5), new Vec2(5, 4));
+ draw(new Vec4(1, 3, 2, 4), new Vec2(5, 4));
+ draw(new Vec4(6, 1, 6.5, 1.5), new Vec2(5, 4));
- draw(new Vec4(0, 2, 1, 3), new Vec2(6, 4));
- draw(new Vec4(5.5, 0.5, 6, 1), new Vec2(6.5, 4.5));
+ draw(new Vec4(0, 2, 1, 3), new Vec2(6, 4));
+ draw(new Vec4(5.5, 0.5, 6, 1), new Vec2(6.5, 4.5));
- draw(new Vec4(1, 3, 2, 4), new Vec2(7, 4));
- draw(new Vec4(6, 0.5, 6.5, 1), new Vec2(7, 4.5));
+ draw(new Vec4(1, 3, 2, 4), new Vec2(7, 4));
+ draw(new Vec4(6, 0.5, 6.5, 1), new Vec2(7, 4.5));
- draw(new Vec4(0, 0, 1, 1), new Vec2(8, 4));
- draw(new Vec4(5.5, 1, 6, 1.5), new Vec2(8.5, 4));
+ draw(new Vec4(0, 0, 1, 1), new Vec2(8, 4));
+ draw(new Vec4(5.5, 1, 6, 1.5), new Vec2(8.5, 4));
- draw(new Vec4(1, 1, 2, 2), new Vec2(9, 4));
- draw(new Vec4(6, 1, 6.5, 1.5), new Vec2(9, 4));
+ draw(new Vec4(1, 1, 2, 2), new Vec2(9, 4));
+ draw(new Vec4(6, 1, 6.5, 1.5), new Vec2(9, 4));
- this.scene.textures.removeKey(tileset_key);
- canvas.saveTexture(tileset_key);
+ canvas.snapshot((img: any) => {
+ this.scene.textures.removeKey(tileset_key);
+ this.scene.textures.addSpriteSheet(tileset_key, img, { frameWidth: tile_size, frameHeight: tile_size });
- console.log(`Patched '${tileset_key}' in ${Date.now() - s} ms.`);
+ console.log(`Patched '${tileset_key}' in ${Date.now() - s} ms.`);
+
+ resolve();
+ });
+ });
}
}
diff --git a/app/src/editor/Token.ts b/app/src/editor/Token.ts
index 8f0ecb2..495747d 100755
--- a/app/src/editor/Token.ts
+++ b/app/src/editor/Token.ts
@@ -1,4 +1,3 @@
-import { Vec2 } from './util/Vec';
import { generateId } from './util/Helpers';
export interface SerializedToken {
@@ -10,8 +9,8 @@ export interface SerializedToken {
}
export default class Token extends Phaser.GameObjects.Container {
- sprite: Phaser.GameObjects.Sprite | null = null;
- shadow: Phaser.GameObjects.Sprite | null = null;
+ sprite: Phaser.GameObjects.Sprite;
+ shadow: Phaser.GameObjects.Sprite;
currentFrame: number = 0;
@@ -25,6 +24,20 @@ export default class Token extends Phaser.GameObjects.Container {
constructor(scene: Phaser.Scene, x: number, y: number, tex: string) {
super(scene, x, y);
+
+ this.shadow = new Phaser.GameObjects.Sprite(this.scene, 0, 0, '');
+ this.shadow.setOrigin(0, 0);
+ this.shadow.setScale(1 / this.shadow.width, 0.25 / this.shadow.height);
+ this.shadow.setTint(0x000000);
+ this.shadow.setAlpha(0.1, 0.1, 0.3, 0.3);
+ this.list.push(this.shadow);
+
+ this.sprite = new Phaser.GameObjects.Sprite(this.scene, 0, 0, '');
+ this.sprite.setOrigin(0, 0);
+ this.sprite.setScale(1 / this.sprite.width, 1 / this.sprite.height);
+ this.setPosition(this.x, this.y);
+ this.list.push(this.sprite);
+
this.setTexture(tex);
this.uuid = generateId(32);
@@ -37,28 +50,16 @@ export default class Token extends Phaser.GameObjects.Container {
}
setTexture(tex: string) {
- if (this.shadow != null) this.shadow.setTexture(tex);
- else {
- this.shadow = new Phaser.GameObjects.Sprite(this.scene, -4, -4, tex);
- this.shadow.setOrigin(0, 0);
- this.shadow.setScale(4, 1);
- this.shadow.setTint(0x000000);
- this.shadow.setAlpha(0.1, 0.1, 0.3, 0.3);
- this.list.push(this.shadow);
- }
+ this.shadow.setTexture(tex);
+ this.sprite.setTexture(tex);
- this.width = this.shadow.width * 4;
- this.height = this.shadow.height * 4;
- this.shadow.y = this.height - 26;
+ this.shadow.setScale(1 / this.shadow.width, 0.25 / this.shadow.height);
+ this.sprite.setScale(1 / this.sprite.width, 1 / this.sprite.height);
- if (this.sprite != null) this.sprite.setTexture(tex);
- else {
- this.sprite = new Phaser.GameObjects.Sprite(this.scene, -4, -4, tex);
- this.sprite.setOrigin(0, 0);
- this.sprite.setScale(4, 4);
- this.setPosition(this.x / 4, this.y / 4);
- this.list.push(this.sprite);
- }
+ this.shadow.y = this.sprite.displayHeight - this.shadow.displayHeight - 0.025;
+
+ this.width = this.sprite.displayWidth;
+ this.height = this.sprite.displayHeight;
}
setFrame(frame: number): void {
@@ -83,11 +84,14 @@ export default class Token extends Phaser.GameObjects.Container {
this.hovered = hovered;
if (!hovered && !this.selected) {
- this.sprite.resetPipeline();
+ // this.sprite.resetPipeline();
+ this.sprite.setTint(0xffffff);
return;
}
- if (!this.selected) this.sprite.setPipeline('brighten');
+ if (!this.selected) this.sprite.setTint(0x999999);
+
+ // if (!this.selected) this.sprite.setPipeline('brighten');
}
setSelected(selected: boolean) {
@@ -96,33 +100,27 @@ export default class Token extends Phaser.GameObjects.Container {
this.selected = selected;
if (!selected) {
- if (!this.hovered) this.sprite.resetPipeline();
- else this.sprite.setPipeline('brighten');
+ // if (!this.hovered) this.sprite.resetPipeline();
+ // else this.sprite.setPipeline('brighten');
+ if (!this.hovered) this.sprite.setTint(0xffffff);
+ else this.sprite.setTint(0x999999);
}
else {
- this.sprite.setPipeline('outline');
+ // this.sprite.setPipeline('outline');
+ this.sprite.setTint(0x000000);
// @ts-ignore
// this.sprite.pipeline.setFloat1('tex_size', this.sprite.texture.source[0].width);
}
}
- setPosition(x?: number, y?: number, z?: number, w?: number): this {
- Phaser.GameObjects.Container.prototype.setPosition.call(this, (x || 0) * 4, (y || 0) * 4, z, w);
- return this;
- }
-
- getPosition(): Vec2 {
- return new Vec2(this.x / 4, this.y / 4);
- }
-
// Serialization Methods
serialize(): string {
return JSON.stringify(({
uuid: this.uuid,
sprite: this.sprite ? this.sprite.texture.key : '',
frame: this.currentFrame,
- x: this.x / 4,
- y: this.y / 4
+ x: this.x,
+ y: this.y
} as SerializedToken));
}
diff --git a/app/src/editor/TokenMode.ts b/app/src/editor/TokenMode.ts
index 69f645d..00655cc 100755
--- a/app/src/editor/TokenMode.ts
+++ b/app/src/editor/TokenMode.ts
@@ -31,7 +31,7 @@ export default class TokenMode {
init() {
// Create cursor hover sprite
this.cursor = this.scene.add.sprite(0, 0, 'cursor');
- this.cursor.setScale(4, 4);
+ this.cursor.setScale(1 / 16, 1 / 16);
this.cursor.setDepth(1000);
this.cursor.setOrigin(0, 0);
this.cursor.setVisible(false);
@@ -58,15 +58,15 @@ export default class TokenMode {
update() {
this.active = true;
- let selectedTilePos = new Vec2(Math.floor(this.scene.view.cursorWorld.x / 64), Math.floor(this.scene.view.cursorWorld.y / 64));
+ let selectedTilePos = new Vec2(Math.floor(this.scene.view.cursorWorld.x), Math.floor(this.scene.view.cursorWorld.y));
if (this.movingTokens) this.moving();
if (!this.movingTokens) this.selecting();
if (this.selectedTokens.length > 0 && !this.movingTokens) this.tokenMoveControls();
- this.tokenPreview!.setPosition(selectedTilePos.x * 16, selectedTilePos.y * 16);
- this.cursor!.setPosition(selectedTilePos.x * 64, selectedTilePos.y * 64);
+ this.tokenPreview!.setPosition(selectedTilePos.x, selectedTilePos.y);
+ this.cursor!.setPosition(selectedTilePos.x, selectedTilePos.y);
if (this.selectedTokenType === '') this.tokenPreview!.setVisible(false);
if (this.selectedTokenType !== '') this.cursor!.setVisible(false);
@@ -80,7 +80,7 @@ export default class TokenMode {
updateRectangleSelect() {
const cursor = this.scene.view.cursorWorld;
- let selectedTilePos = new Vec2(Math.floor(cursor.x / 64), Math.floor(cursor.y / 64));
+ let selectedTilePos = new Vec2(Math.floor(cursor.x), Math.floor(cursor.y));
this.primitives.forEach((v) => v.destroy());
this.primitives = [];
@@ -97,7 +97,6 @@ export default class TokenMode {
this.primitives.forEach((v) => {
v.setOrigin(0, 0);
- v.setScale(64, 64);
v.setLineWidth(0.03);
v.setDepth(300);
});
@@ -109,14 +108,14 @@ export default class TokenMode {
this.movingTokens = true;
const cursor = this.scene.view.cursorWorld;
- this.tileGrabPos = new Vec2(Math.floor(cursor.x / 64), Math.floor(cursor.y / 64));
+ this.tileGrabPos = new Vec2(Math.floor(cursor.x), Math.floor(cursor.y));
this.prevSerialized = [];
this.selectedTokens.forEach(t => this.prevSerialized.push(t.serialize()));
}
createToken(): Token {
- let token = new Token(this.scene, Math.floor(this.scene.view.cursorWorld.x / 4 / 16) * 16,
- Math.floor(this.scene.view.cursorWorld.y / 4 / 16) * 16, this.selectedTokenType);
+ let token = new Token(this.scene, Math.floor(this.scene.view.cursorWorld.x),
+ Math.floor(this.scene.view.cursorWorld.y), this.selectedTokenType);
this.scene.add.existing(token);
this.scene.tokens.push(token);
@@ -150,16 +149,16 @@ export default class TokenMode {
private tokenMoveControls(): void {
if (this.scene.i.keyPressed('UP')) {
- this.moveToken(0, -16, 2);
+ this.moveToken(0, -1, 2);
}
if (this.scene.i.keyPressed('LEFT')) {
- this.moveToken(-16, 0, 1);
+ this.moveToken(-1, 0, 1);
}
if (this.scene.i.keyPressed('DOWN')) {
- this.moveToken(0, 16, 0);
+ this.moveToken(0, 1, 0);
}
if (this.scene.i.keyPressed('RIGHT')) {
- this.moveToken(16, 0, 3);
+ this.moveToken(1, 0, 3);
}
}
@@ -175,8 +174,8 @@ export default class TokenMode {
let prevSerialized: string[] = [];
this.selectedTokens.forEach((token) => {
prevSerialized.push(token.serialize());
- token.x += x * 4;
- token.y += y * 4;
+ token.x += x;
+ token.y += y;
token.setFrame(frame);
});
@@ -201,7 +200,7 @@ export default class TokenMode {
for (let i = this.scene.tokens.length - 1; i >= 0; i--) {
let token = this.scene.tokens[i];
- if (cursor.x >= token.x && cursor.y >= token.y && cursor.x <= token.x + token.width - 8 && cursor.y <= token.y + token.height - 8) {
+ if (cursor.x >= token.x && cursor.y >= token.y && cursor.x <= token.x + token.width && cursor.y <= token.y + token.height) {
this.hoveredToken = token;
break;
}
@@ -237,7 +236,7 @@ export default class TokenMode {
}
// Start a rectangle selection
else {
- this.startTilePos = new Vec2(Math.floor(cursor.x / 64), Math.floor(cursor.y / 64));
+ this.startTilePos = new Vec2(Math.floor(cursor.x), Math.floor(cursor.y));
}
}
// Selecting existing token to move
@@ -251,7 +250,7 @@ export default class TokenMode {
}
else {
this.selectedTokens.forEach(t => t.setSelected(false));
- this.selectedTokens = [this.hoveredToken];
+ this.selectedTokens = [ this.hoveredToken ];
this.clickedLastFrame = true;
clickedAddedThisFrame = true;
this.hoveredToken.setSelected(true);
@@ -266,7 +265,7 @@ export default class TokenMode {
this.primitives.forEach((v) => v.destroy());
this.primitives = [];
- let selectedTilePos = new Vec2(Math.floor(cursor.x / 64), Math.floor(cursor.y / 64));
+ let selectedTilePos = new Vec2(Math.floor(cursor.x), Math.floor(cursor.y));
let a = new Vec2(Math.min(this.startTilePos.x, selectedTilePos.x), Math.min(this.startTilePos.y, selectedTilePos.y));
let b = new Vec2(Math.max(this.startTilePos.x, selectedTilePos.x), Math.max(this.startTilePos.y, selectedTilePos.y));
@@ -278,7 +277,7 @@ export default class TokenMode {
}
for (let token of this.scene.tokens) {
- let tokenTilePos = new Vec2(Math.floor(token.x / 64), Math.floor(token.y / 64));
+ let tokenTilePos = new Vec2(Math.floor(token.x), Math.floor(token.y));
if (tokenTilePos.x >= a.x && tokenTilePos.y >= a.y && tokenTilePos.x <= b.x && tokenTilePos.y <= b.y) {
let selected = this.scene.i.keyDown('CTRL') ? !this.selectedIncludes(token) : true;
@@ -360,13 +359,13 @@ export default class TokenMode {
return;
}
- let newTileGrabPos = new Vec2(Math.floor(cursor.x / 64), Math.floor(cursor.y / 64));
+ let newTileGrabPos = new Vec2(Math.floor(cursor.x), Math.floor(cursor.y));
let offset = new Vec2(newTileGrabPos.x - this.tileGrabPos.x, newTileGrabPos.y - this.tileGrabPos.y);
if (offset.x === 0 && offset.y === 0) return;
this.movedTokens = true;
this.tileGrabPos = newTileGrabPos;
- this.selectedTokens.forEach(tkn => tkn.setPosition(tkn.x / 4 + offset.x * 16, tkn.y / 4 + offset.y * 16));
+ this.selectedTokens.forEach(tkn => tkn.setPosition(tkn.x + offset.x, tkn.y + offset.y));
}
}
}
diff --git a/app/src/editor/WorldView.ts b/app/src/editor/WorldView.ts
index 623af05..aa007d9 100755
--- a/app/src/editor/WorldView.ts
+++ b/app/src/editor/WorldView.ts
@@ -12,8 +12,8 @@ export default class WorldView {
cursorWorld: Vec2 = new Vec2();
lastCursorWorld: Vec2 = new Vec2();
- zoomLevels: number[] = [10, 17, 25, 33, 40, 50, 60, 67, 75, 80, 90, 100, 110, 125, 150, 175, 200, 250, 300, 400, 500];
- zoomLevel = 11;
+ zoomLevels: number[] = [ 5, 6, 8, 10, 15, 20, 25, 33, 40, 50, 60, 75, 100, 125, 150, 200, 300 ];
+ zoomLevel = 9;
constructor(scene: MapScene) {
this.scene = scene;
@@ -22,11 +22,26 @@ export default class WorldView {
init(): void {
this.camera = this.scene.cameras.main;
this.camera.setBackgroundColor('#090d24');
+ this.camera.setZoom(this.zoomLevels[this.zoomLevel]);
+ this.camera.setScroll(-this.camera.width / 2.2, -this.camera.height / 2.2);
this.scene.i.bindScrollEvent((delta: number) => {
if (!this.scene.token.movingTokens && !this.scene.ui.uiActive) {
+
+ const lastZoom = this.zoomLevels[this.zoomLevel];
this.zoomLevel = clamp(this.zoomLevel + delta, 0, this.zoomLevels.length - 1);
- this.camera!.setZoom(this.zoomLevels[this.zoomLevel] / 100);
+ const zoom = this.zoomLevels[this.zoomLevel];
+
+ this.scene.tweens.add({
+ targets: this.camera,
+ zoom: { from: lastZoom, to: zoom },
+ ease: 'Cubic',
+ duration: 150,
+ repeat: 0
+ });
+
+ // this.scene.tweens.add({ targets: this.camera!, duration: 150, props: { zoom: this.zoomLevels[this.zoomLevel / 100]}});
+ // this.camera!.setZoom(this.zoomLevels[this.zoomLevel] / 100);
}
});
}
@@ -47,8 +62,8 @@ export default class WorldView {
private pan() {
if (this.scene.input.activePointer.middleButtonDown()) {
- this.camera!.scrollX += Math.round((this.lastCursorScreen.x - this.cursorScreen.x) / this.camera!.zoom);
- this.camera!.scrollY += Math.round((this.lastCursorScreen.y - this.cursorScreen.y) / this.camera!.zoom);
+ this.camera!.scrollX += (this.lastCursorScreen.x - this.cursorScreen.x) / this.camera!.zoom;
+ this.camera!.scrollY += (this.lastCursorScreen.y - this.cursorScreen.y) / this.camera!.zoom;
}
}
}
diff --git a/app/src/editor/history/HistoryElement.ts b/app/src/editor/history/HistoryElement.ts
index 1852064..607c4ff 100755
--- a/app/src/editor/history/HistoryElement.ts
+++ b/app/src/editor/history/HistoryElement.ts
@@ -1,8 +1,8 @@
import Token from '../Token';
import type MapScene from '../scene/MapScene';
-import Layer from '../util/Layer';
import { Vec2 } from '../util/Vec';
+import { Layer } from '../util/Layer';
export default class HistoryElement {
scene: MapScene;
@@ -19,7 +19,7 @@ export default class HistoryElement {
console.log('Undo', this.type);
if (this.type === 'tile') {
for (let tile of this.data as {pos: Vec2; layer: Layer; lastTile: number; tile: number}[]) {
- this.scene.map.setTile(tile.layer, tile.lastTile, tile.pos.x, tile.pos.y);
+ this.scene.map.activeLayer.setTile(tile.layer, tile.lastTile, tile.pos.x, tile.pos.y);
this.scene.lighting.tileUpdatedAt(tile.pos.x, tile.pos.y);
}
}
@@ -69,7 +69,7 @@ export default class HistoryElement {
console.log('Redo', this.type);
if (this.type === 'tile') {
for (let tile of this.data as {pos: Vec2; layer: Layer; lastTile: number; tile: number}[]) {
- this.scene.map.setTile(tile.layer, tile.tile, tile.pos.x, tile.pos.y);
+ this.scene.map.activeLayer.setTile(tile.layer, tile.tile, tile.pos.x, tile.pos.y);
this.scene.lighting.tileUpdatedAt(tile.pos.x, tile.pos.y);
}
}
diff --git a/app/src/editor/interface/components/UITileSidebar.ts b/app/src/editor/interface/components/UITileSidebar.ts
index d0f42cb..840c03a 100755
--- a/app/src/editor/interface/components/UITileSidebar.ts
+++ b/app/src/editor/interface/components/UITileSidebar.ts
@@ -1,14 +1,13 @@
import UISidebar from './UISidebar';
import type MapScene from '../../scene/MapScene';
-import Layer from '../../util/Layer';
import { Asset } from '../../util/Asset';
export default class UITileSidebar extends UISidebar {
walls: string[] = [];
grounds: string[] = [];
- overlays: string[] = [];
+ details: string[] = [];
constructor(scene: MapScene, x: number, y: number, assets: Asset[]) {
super(scene, x, y);
@@ -30,18 +29,18 @@ export default class UITileSidebar extends UISidebar {
this.list.push(add_ground);
this.sprites.push(add_ground);
- for (let tileset of assets.filter((a) => a.type === 'ground'))
+ for (let tileset of assets.filter((a) => a.type === 'floor'))
this.addGround(tileset.identifier);
- let add_overlay = new Phaser.GameObjects.Sprite(this.scene, 9 + x * 21 * 3, 9 + 9 * 21 * 3, 'ui_sidebar_browse');
- add_overlay.setName('add_overlay');
- add_overlay.setScale(3);
- add_overlay.setOrigin(0, 0);
- this.list.push(add_overlay);
- this.sprites.push(add_overlay);
+ let add_detail = new Phaser.GameObjects.Sprite(this.scene, 9 + x * 21 * 3, 9 + 9 * 21 * 3, 'ui_sidebar_browse');
+ add_detail.setName('add_detail');
+ add_detail.setScale(3);
+ add_detail.setOrigin(0, 0);
+ this.list.push(add_detail);
+ this.sprites.push(add_detail);
- for (let tileset of assets.filter((a) => a.type === 'ground'))
- this.addOverlay(tileset.identifier);
+ for (let tileset of assets.filter((a) => a.type === 'detail'))
+ this.addDetail(tileset.identifier);
for (let i = 0; i < 12; i++) {
if (i % 4 !== 0) this.backgrounds[i].setFrame(0);
@@ -50,21 +49,21 @@ export default class UITileSidebar extends UISidebar {
elemClick(x: number, y: number): void {
if (y < 4) {
- this.scene.architect.activeTileset = this.scene.map.manager.indexes[this.walls[x + y * 3]];
- this.scene.architect.activeLayer = Layer.wall;
+ this.scene.architect.activeTileset = this.scene.map.tileStore.indices[this.walls[x + y * 3]];
+ this.scene.architect.activeLayer = 'wall';
}
else if (y < 8) {
- this.scene.architect.activeTileset = this.scene.map.manager.indexes[this.grounds[x + (y - 4) * 3]];
- this.scene.architect.activeLayer = Layer.floor;
+ this.scene.architect.activeTileset = this.scene.map.tileStore.indices[this.grounds[x + (y - 4) * 3]];
+ this.scene.architect.activeLayer = 'floor';
}
else {
- this.scene.architect.activeTileset = this.scene.map.manager.indexes[this.overlays[x + (y - 8) * 3]];
- this.scene.architect.activeLayer = Layer.overlay;
+ this.scene.architect.activeTileset = this.scene.map.tileStore.indices[this.details[x + (y - 8) * 3]];
+ this.scene.architect.activeLayer = 'detail';
}
}
private addWall(tileset: string): void {
- this.addTilesetSprite(tileset, this.walls.length % 3, Math.floor(this.walls.length / 3) + 1, 17);
+ this.addTilesetSprite(tileset, this.walls.length % 3, Math.floor(this.walls.length / 3) + 1, 13);
(this.getByName('add_wall') as Phaser.GameObjects.Sprite).x = 9 + ((this.walls.length + 1) % 3 * 21 * 3);
(this.getByName('add_wall') as Phaser.GameObjects.Sprite).y = 9 + (Math.floor((this.walls.length + 1) / 3 + 1) * 21 * 3);
this.walls.push(tileset);
@@ -77,11 +76,11 @@ export default class UITileSidebar extends UISidebar {
this.grounds.push(tileset);
}
- private addOverlay(tileset: string): void {
- this.addTilesetSprite(tileset, this.overlays.length % 3, Math.floor(this.overlays.length / 3) + 9, 33);
- (this.getByName('add_overlay') as Phaser.GameObjects.Sprite).x = 9 + ((this.overlays.length + 1) % 3 * 21 * 3);
- (this.getByName('add_overlay') as Phaser.GameObjects.Sprite).y = 9 + (Math.floor((this.overlays.length + 1) / 3 + 9) * 21 * 3);
- this.overlays.push(tileset);
+ private addDetail(tileset: string): void {
+ this.addTilesetSprite(tileset, this.details.length % 3, Math.floor(this.details.length / 3) + 9, 33);
+ (this.getByName('add_detail') as Phaser.GameObjects.Sprite).x = 9 + ((this.details.length + 1) % 3 * 21 * 3);
+ (this.getByName('add_detail') as Phaser.GameObjects.Sprite).y = 9 + (Math.floor((this.details.length + 1) / 3 + 9) * 21 * 3);
+ this.details.push(tileset);
}
private addTilesetSprite(key: string, x: number, y: number, frame: number) {
diff --git a/app/src/editor/interface/components/UITokenSidebar.ts b/app/src/editor/interface/components/UITokenSidebar.ts
index 5148a3c..ee7c8fc 100755
--- a/app/src/editor/interface/components/UITokenSidebar.ts
+++ b/app/src/editor/interface/components/UITokenSidebar.ts
@@ -74,7 +74,7 @@ export default class UITokenSidebar extends UISidebar {
let token = new Token(this.scene, 0, 0, sprite);
Phaser.GameObjects.Sprite.prototype.setPosition.call(token, 12 + x * 21 * 3, 12 + y * 21 * 3);
- token.setScale(3 / 4);
+ token.setScale(3);
this.sprites.push(token);
this.list.push(token);
diff --git a/app/src/editor/lighting/LightSource.ts b/app/src/editor/lighting/LightSource.ts
index bf78298..6b5bea0 100755
--- a/app/src/editor/lighting/LightSource.ts
+++ b/app/src/editor/lighting/LightSource.ts
@@ -1,6 +1,5 @@
import type Lighting from './Lighting';
-import Layer from '../util/Layer';
import { Vec2 } from '../util/Vec';
export default class LightSource {
@@ -36,7 +35,7 @@ export default class LightSource {
let dir = new Vec2(Math.cos(i * 1.25 * (Math.PI / 180)) / 32, Math.sin(i * 1.25 * (Math.PI / 180)) / 32);
let dist = 0;
- while (this.light.scene.map.getTileset(Layer.wall, Math.floor(start.x + ray.x), Math.floor(start.y + ray.y)) === -1 &&
+ while (this.light.scene.map.activeLayer.getTile('wall', Math.floor(start.x + ray.x), Math.floor(start.y + ray.y)) === -1 &&
(dist = Math.sqrt(Math.pow(ray.x, 2) + Math.pow(ray.y, 2))) < this.radius / 16) {
ray.x += dir.x;
diff --git a/app/src/editor/lighting/Lighting.ts b/app/src/editor/lighting/Lighting.ts
index f2541c3..8b8a40b 100755
--- a/app/src/editor/lighting/Lighting.ts
+++ b/app/src/editor/lighting/Lighting.ts
@@ -1,4 +1,4 @@
-import MapChunk from '../MapChunk';
+import { CHUNK_SIZE } from '../map/MapChunk';
import type MapScene from '../scene/MapScene';
import LightChunk from './LightChunk';
@@ -23,9 +23,9 @@ export default class Lighting {
init(size: Vec2) {
this.size = size;
- for (let i = 0; i < Math.ceil(size.y / (MapChunk.CHUNK_SIZE * 2)); i++) {
+ for (let i = 0; i < Math.ceil(size.y / (CHUNK_SIZE * 2)); i++) {
this.chunks[i] = [];
- for (let j = 0; j < Math.ceil(size.x / (MapChunk.CHUNK_SIZE * 2)); j++) {
+ for (let j = 0; j < Math.ceil(size.x / (CHUNK_SIZE * 2)); j++) {
this.chunks[i][j] = new LightChunk(this, j, i);
}
}
diff --git a/app/src/editor/map/Map.ts b/app/src/editor/map/Map.ts
new file mode 100755
index 0000000..7184cc6
--- /dev/null
+++ b/app/src/editor/map/Map.ts
@@ -0,0 +1,99 @@
+import * as Phaser from 'phaser';
+
+import MapLayer from './MapLayer';
+import TileStore from './TileStore';
+import MapChunk, { CHUNK_SIZE } from './MapChunk';
+
+import { Vec2 } from '../util/Vec';
+import { Asset } from '../util/Asset';
+
+
+
+export default class MapData {
+ tileStore: TileStore = new TileStore();
+ size: Vec2 = new Vec2(0, 0);
+
+ activeLayer: MapLayer = {} as MapLayer;
+ private layers: MapLayer[] = [];
+
+ private chunks: MapChunk[][] = [];
+
+ init(scene: Phaser.Scene, size: Vec2, assets: Asset[]) {
+ this.size = size;
+ this.tileStore.init(scene.textures, assets);
+
+ this.layers.push(new MapLayer(size, this.handleDirty));
+ this.activeLayer = this.layers[0];
+
+ for (let i = 0; i < Math.ceil(size.y / CHUNK_SIZE); i++) {
+ this.chunks[i] = [];
+ for (let j = 0; j < Math.ceil(size.x / CHUNK_SIZE); j++) {
+ this.chunks[i][j] = new MapChunk(scene, new Vec2(j, i), this.activeLayer, this.tileStore);
+ }
+ }
+ }
+
+ update(): void {
+ let start = Date.now();
+
+ for (let arr of this.chunks) {
+ for (let chunk of arr) {
+ chunk.redraw();
+ if (Date.now() - start > 10) break;
+ }
+ }
+
+ // if (this.scene.i.keyPressed('S')) this.saveMap();
+ // if (this.scene.i.keyPressed('L')) this.loadMap(this.savedMapData);
+ }
+
+ private handleDirty = (x: number, y: number) => {
+ this.chunks[Math.floor(y / CHUNK_SIZE)][Math.floor(x / CHUNK_SIZE)].setDirty(new Vec2(x % CHUNK_SIZE, y % CHUNK_SIZE));
+ };
+
+ // private saveMap() {
+
+ // let mapData: number[][] = [];
+
+ // for (let k = 0; k < 3; k++) {
+ // let tile = 0;
+ // let count = 0;
+ // mapData[k] = [];
+
+ // for (let i = 0; i < this.size.x * this.size.y; i++) {
+ // let x = i % this.size.x;
+ // let y = Math.floor(i / this.size.x);
+
+ // if (this.getTileset(k, x, y) === tile) count++;
+ // else {
+ // if (i !== 0) {
+ // mapData[k].push(tile);
+ // mapData[k].push(count);
+ // }
+ // tile = this.getTileset(k, x, y);
+ // count = 1;
+ // }
+ // }
+ // }
+
+ // this.savedMapData = mapData;
+ // }
+
+ // private loadMap(dat: number[][]) {
+ // for (let k = 0; k < 3; k++) {
+ // let offset = 0;
+ // for (let i = 0; i < dat[k].length / 2; i++) {
+ // let tile = dat[k][i * 2];
+ // let count = dat[k][i * 2 + 1];
+
+ // for (let t = 0; t < count; t++) {
+ // let x = (offset + t) % this.size.x;
+ // let y = Math.floor((offset + t) / this.size.x);
+
+ // this.setTile(k, tile, x, y);
+ // }
+ // offset += count;
+ // }
+ // }
+ // }
+}
diff --git a/app/src/editor/map/MapChunk.ts b/app/src/editor/map/MapChunk.ts
new file mode 100755
index 0000000..37b4598
--- /dev/null
+++ b/app/src/editor/map/MapChunk.ts
@@ -0,0 +1,114 @@
+import * as Phaser from 'phaser';
+
+import MapLayer from './MapLayer';
+import TileStore from './TileStore';
+
+import { Vec2 } from '../util/Vec';
+
+export const TILE_SIZE = 16;
+export const CHUNK_SIZE = 32;
+export const DIRTY_LIMIT = (CHUNK_SIZE * CHUNK_SIZE) / 2;
+
+
+/**
+ * A visual representation of a chunk of a MapLayer.
+ */
+
+export default class MapChunk extends Phaser.GameObjects.RenderTexture {
+ private dirtyList: Vec2[] = [];
+ private fullyDirty: boolean = true;
+
+ constructor(scene: Phaser.Scene, private pos: Vec2, private layer: MapLayer, private tileStore: TileStore) {
+ super(scene, CHUNK_SIZE * pos.x - 2 / TILE_SIZE, CHUNK_SIZE * pos.y - 2 / TILE_SIZE,
+ CHUNK_SIZE * TILE_SIZE + 4, CHUNK_SIZE * TILE_SIZE + 4);
+ this.setScale(1 / TILE_SIZE);
+ this.setOrigin(0, 0);
+
+ scene.add.existing(this);
+ }
+
+
+ /**
+ * Indicates that a position on the chunk is dirty so it will be re-rendered.
+ *
+ * @param {Vec2} pos - The position that is dirtied.
+ */
+
+ setDirty(pos: Vec2): void {
+ if (!this.fullyDirty) {
+ for (let v of this.dirtyList) if (v.equals(pos)) return;
+ this.dirtyList.push(pos);
+
+ if (this.dirtyList.length > DIRTY_LIMIT) {
+ this.fullyDirty = true;
+ this.dirtyList = [];
+ }
+ }
+ }
+
+
+ /**
+ * Redraws all dirty tiles on the chunk.
+ *
+ * @returns {boolean} - A boolean indicating if tiles have changed since the last render.
+ */
+
+ redraw(): boolean {
+ if (this.fullyDirty) {
+ for (let i = 0; i < CHUNK_SIZE * CHUNK_SIZE; i++) {
+ let x = i % CHUNK_SIZE;
+ let y = Math.floor(i / CHUNK_SIZE);
+
+ if (x + this.pos.x * CHUNK_SIZE >= this.layer.size.x ||
+ y + this.pos.y * CHUNK_SIZE >= this.layer.size.y) continue;
+
+ this.drawTile(x, y);
+ }
+
+ this.fullyDirty = false;
+ return true;
+ }
+
+ if (this.dirtyList.length === 0) return false;
+
+ for (let elem of this.dirtyList) this.drawTile(elem.x, elem.y);
+ this.dirtyList = [];
+
+ return true;
+ }
+
+
+ /**
+ * Redraws the tile at the specified position,
+ * based on the current data on the MapLayer.
+ *
+ * @param {number} x - The x position to draw at.
+ * @param {number} y - The y position to draw at.
+ */
+
+ private drawTile(x: number, y: number): void {
+ let mX = x + this.pos.x * CHUNK_SIZE;
+ let mY = y + this.pos.y * CHUNK_SIZE;
+
+ let wallTile = this.layer.getTile('wall', mX, mY);
+ let wallTileIndex = this.layer.getTileIndex('wall', mX, mY);
+
+ let floorTile = this.layer.getTile('floor', mX, mY);
+ let floorTileIndex = this.layer.getTileIndex('floor', mX, mY);
+
+ let detailTile = this.layer.getTile('detail', mX, mY);
+ let detailTileIndex = this.layer.getTileIndex('detail', mX, mY);
+
+ if (floorTile !== -1)
+ this.drawFrame(this.tileStore.floorTiles[floorTile].identifier, floorTileIndex, x * TILE_SIZE + 2, y * TILE_SIZE + 2);
+
+ if (detailTile !== -1)
+ this.drawFrame(this.tileStore.detailTiles[detailTile].identifier, detailTileIndex, x * TILE_SIZE + 2, y * TILE_SIZE + 2);
+
+ if (wallTile !== -1)
+ this.drawFrame(this.tileStore.wallTiles[wallTile].identifier, wallTileIndex, x * TILE_SIZE + 2, y * TILE_SIZE + 2);
+
+ if ((x % 2 === 0 && y % 2 === 0) || (x % 2 !== 0 && y % 2 !== 0))
+ this.drawFrame('grid_tile', 0, x * TILE_SIZE + 2, y * TILE_SIZE + 2);
+ }
+}
diff --git a/app/src/editor/map/MapLayer.ts b/app/src/editor/map/MapLayer.ts
new file mode 100644
index 0000000..66d2239
--- /dev/null
+++ b/app/src/editor/map/MapLayer.ts
@@ -0,0 +1,250 @@
+import { Vec2 } from '../util/Vec';
+import { Layer } from '../util/Layer';
+import { clamp } from '../util/Helpers';
+
+
+const WALL_FIELD = [
+ 4, 4, 17, 17, 4, 4, 17, 17, 18, 18, 34, 13, 18, 18, 34, 13, 7, 7, 33, 33, 7, 7, 12, 12, 9, 9, 36, 35, 9, 9, 37, 10,
+ 4, 4, 17, 17, 4, 4, 17, 17, 18, 18, 34, 13, 18, 18, 34, 13, 7, 7, 33, 33, 7, 7, 12, 12, 9, 9, 36, 35, 9, 9, 37, 10,
+ 8, 8, 19, 19, 8, 8, 19, 19, 24, 24, 39, 29, 24, 24, 39, 29, 23, 23, 38, 38, 23, 23, 28, 28, 26, 26, 40, 47, 26, 26, 46, 30,
+ 8, 8, 19, 19, 8, 8, 19, 19, 3, 3, 49, 11, 3, 3, 49, 11, 23, 23, 38, 38, 23, 23, 28, 28, 25, 25, 45, 31, 25, 25, 22, 5,
+ 4, 4, 17, 17, 4, 4, 17, 17, 18, 18, 34, 13, 18, 18, 34, 13, 7, 7, 33, 33, 7, 7, 12, 12, 9, 9, 36, 35, 9, 9, 37, 10,
+ 4, 4, 17, 17, 4, 4, 17, 17, 18, 18, 34, 13, 18, 18, 34, 13, 7, 7, 33, 33, 7, 7, 12, 12, 9, 9, 36, 35, 9, 9, 37, 10,
+ 8, 8, 19, 19, 8, 8, 19, 19, 24, 24, 39, 29, 24, 24, 39, 29, 2, 2, 48, 48, 2, 2, 0, 0, 27, 27, 44, 32, 27, 27, 20, 6,
+ 8, 8, 19, 19, 8, 8, 19, 19, 3, 3, 49, 11, 3, 3, 49, 11, 2, 2, 48, 48, 2, 2, 0, 0, 1, 1, 21, 15, 1, 1, 16, 14
+];
+
+const FLOOR_FIELD = [
+ 54, 20, 19, 19, 18, 4, 19, 19, 11, 11, 3, 3, 51, 51, 3, 3, 9, 52, 5, 5, 9, 52, 5, 5, 39, 39, 30, 30, 39, 39, 30, 30,
+ 2, 12, 32, 32, 34, 6, 32, 32, 11, 11, 3, 3, 51, 51, 3, 3, 43, 38, 29, 29, 43, 38, 29, 29, 39, 39, 30, 30, 39, 39, 30, 30,
+ 1, 41, 17, 17, 40, 46, 17, 17, 21, 21, 8, 8, 45, 45, 8, 8, 23, 47, 26, 26, 23, 47, 26, 26, 48, 48, 49, 49, 48, 48, 49, 49,
+ 1, 41, 17, 17, 40, 46, 17, 17, 21, 21, 8, 8, 45, 45, 8, 8, 23, 47, 26, 26, 23, 47, 26, 26, 48, 48, 49, 49, 48, 48, 49, 49,
+ 0, 33, 31, 31, 14, 7, 31, 31, 42, 42, 27, 27, 36, 36, 27, 27, 9, 52, 5, 5, 9, 52, 5, 5, 39, 39, 30, 30, 39, 39, 30, 30,
+ 22, 15, 28, 28, 16, 37, 28, 28, 42, 42, 27, 27, 36, 36, 27, 27, 43, 38, 29, 29, 43, 38, 29, 29, 39, 39, 30, 30, 39, 39, 30, 30,
+ 1, 41, 17, 17, 40, 46, 17, 17, 21, 21, 8, 8, 45, 45, 8, 8, 23, 47, 26, 26, 23, 47, 26, 26, 48, 48, 49, 49, 48, 48, 49, 49,
+ 1, 41, 17, 17, 40, 46, 17, 17, 21, 21, 8, 8, 45, 45, 8, 8, 23, 47, 26, 26, 23, 47, 26, 26, 48, 48, 49, 49, 48, 48, 49, 49
+];
+
+type LayerData = { tiles: number[][]; tilesets: number[][] };
+
+export default class MapLayer {
+ private data: { [ key in Layer ]: LayerData } = {
+ wall: { tiles: [], tilesets: [] }, floor: { tiles: [], tilesets: [] }, detail: { tiles: [], tilesets: [] } };
+
+ constructor(public size: Vec2, private onDirty: (x: number, y: number) => void) {
+ const createLayerData = (startTile: number | (() => number), startTileset: number): LayerData => {
+ let layer: LayerData = { tiles: [], tilesets: [] };
+
+ for (let i = 0; i < this.size.y; i++) {
+ layer.tiles[i] = [];
+ layer.tilesets[i] = [];
+ for (let j = 0; j < this.size.x; j++) {
+ let tile = typeof(startTile) === 'number' ? startTile : startTile();
+ layer.tiles[i][j] = tile;
+ layer.tilesets[i][j] = startTileset;
+ }
+ }
+
+ return layer;
+ };
+
+ this.data.wall = createLayerData(0, -1);
+ this.data.floor = createLayerData(() => Math.floor(Math.random() * 6) + 54, 0);
+ this.data.detail = createLayerData(0, -1);
+ }
+
+
+ /**
+ * Convert a 3x3 array of wall states into a numeric value between 0 and 255.
+ *
+ * @param {boolean} walls - The walls
+ */
+
+ static bitsToIndices(walls: boolean[]): number {
+ return (
+ (+walls[0] << 0) +
+ (+walls[1] << 1) +
+ (+walls[2] << 2) +
+ (+walls[3] << 3) +
+ (+walls[5] << 4) +
+ (+walls[6] << 5) +
+ (+walls[7] << 6) +
+ (+walls[8] << 7));
+ }
+
+
+ /**
+ * Returns a tile index for a wall based on it's surrounding walls.
+ *
+ * @param {boolean[]} walls - Surrounding walls boolean array.
+ * @param {number} current - The current wall value.
+ */
+
+ static wall(walls: boolean[], current: number): number {
+ if (current === -1) return -1;
+ const ind = WALL_FIELD[MapLayer.bitsToIndices(walls)];
+ if (ind < 54) return ind;
+ return 54 + Math.floor(Math.random() * 6);
+ }
+
+
+ /**
+ * Returns a tile index for a floor based on it's surrounding walls.
+ *
+ * @param {boolean[]} walls - Surrounding walls boolean array.
+ * @param {number} current - The current floor value.
+ */
+
+ static floor(walls: boolean[], current: number): number {
+ if (current === -1) return -1;
+ const ind = FLOOR_FIELD[MapLayer.bitsToIndices(walls)];
+ if (ind < 54) return ind;
+ return 54 + Math.floor(Math.random() * 6);
+ }
+
+
+ /**
+ * Returns a tile index for a detail based on it's surrounding details.
+ *
+ * @param {boolean[]} details - Surrounding details boolean array.
+ * @param {number} current - The current floor value.
+ */
+
+ static detail(details: boolean[], current: number): number {
+ if (current === -1) return -1;
+ const ind = WALL_FIELD[MapLayer.bitsToIndices(details)];
+ if (ind < 54) return ind;
+ return 54 + Math.floor(Math.random() * 6);
+ }
+
+
+ /**
+ * Sets a tile to the tileset provided, automatically smart-tiling as needed.
+ *
+ * @param {Layer} layer - The internal layer to set the tile at.
+ * @param {number} tileset - The tileset to set the tile to.
+ * @param {number | Vec2} x - Either the x value of the position to set the tile at, or a vector for the full position.
+ * @param {number} y - The y value of the position if the x value is a number.
+ *
+ * @returns {boolean} - True if the tileset was changed, false otherwise.
+ */
+
+ setTile(layer: Layer, tileset: number, x: number | Vec2, y?: number): boolean {
+ if (x instanceof Vec2) { y = x.y; x = x.x; }
+ if (x < 0 || y! < 0 || x >= this.size.x || y! >= this.size.y) return false;
+
+ if (this.setTileset(layer, x, y!, tileset)) {
+ // this.setTileIndex(layer, x, y!, 3);
+ this.autoTile(x, y!);
+ return true;
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Gets the tileset at the specified position.
+ *
+ * @param layer - The internal layer to get the tileset at.
+ * @param {number} x - Either the x value of the position to get the tile set at, or a vector for the full position.
+ * @param {number} y - The y value of the position if the x value is a number.
+ */
+
+ getTile(layer: Layer, x: number | Vec2, y?: number): number {
+ if (x instanceof Vec2) { y = x.y; x = x.x; }
+ return this.data[layer].tilesets[clamp(y!, 0, this.size.y - 1)][clamp(x, 0, this.size.x - 1)];
+ }
+
+
+ /**
+ * Gets the current tile index at a position.
+ *
+ * @param {Layer} layer - The internal layer to get the tile at.
+ * @param {number | Vec2} x - Either the x value of the position to get the tile at, or a vector for the full position.
+ * @param {number} y - The y value of the position if the x value is a number.
+ *
+ * @returns {number} - The tile index at the position specified.
+ */
+
+ getTileIndex(layer: Layer, x: number | Vec2, y?: number): number {
+ if (x instanceof Vec2) { y = x.y; x = x.x; }
+ return this.data[layer].tiles[clamp(y!, 0, this.size.y - 1)][clamp(x, 0, this.size.x - 1)];
+ }
+
+
+ /**
+ * Sets a tile to the one provided.
+ *
+ * @param {Layer} layer - The layer to set the tileset at.
+ * @param {number | Vec2} x - Either the x value of the position to set the tileset at, or a vector for the full position.
+ * @param {number} y - Either the y value of the position if x is a number, or the tileset to set.
+ * @param {number} tile - The tileset to set if the x value is a number.
+ *
+ * @returns {boolean} - True if the tileset was changed, false otherwise.
+ */
+
+ private setTileset(layer: Layer, x: number | Vec2, y: number, tile?: number): boolean {
+ if (x instanceof Vec2) { tile = y; y = x.y; x = x.x; };
+
+ const oldTileset = this.getTile(layer, x, y);
+ if (oldTileset === tile!) return false;
+
+ this.data[layer].tilesets[y][x] = tile!;
+ return true;
+ }
+
+
+ /**
+ * Sets the tile at the specified position to the index provided.
+ */
+
+ private setTileIndex(layer: Layer, x: number, y: number, index: number): void {
+ this.data[layer].tiles[y][x] = index;
+ this.onDirty(x, y);
+ }
+
+
+ /**
+ * Automatically updates the tile indexes surrounding a position.
+ *
+ * @param {number} x - The x value of the position to center around.
+ * @param {number} y - The y value of the position to center around.
+ */
+
+ private autoTile(x: number, y: number): void {
+ for (let i = clamp(x - 1, this.size.x - 1, 0); i <= clamp(x + 1, this.size.x - 1, 0); i++) {
+ for (let j = clamp(y - 1, this.size.y - 1, 0); j <= clamp(y + 1, this.size.y - 1, 0); j++) {
+ const solids = this.getTilesAround('wall', i, j).map(i => i !== -1);
+
+ const wall = MapLayer.wall(solids, this.getTileIndex('wall', i, j));
+ if (wall !== -1) this.setTileIndex('wall', i, j, wall);
+
+ const floor = MapLayer.floor(solids, this.getTileIndex('floor', i, j));
+ if (floor !== -1) this.setTileIndex('floor', i, j, floor);
+
+ const detail = MapLayer.detail(this.getTilesAround('detail', i, j).map(i => i !== -1), -1);
+ if (detail !== -1) this.setTileIndex('detail', i, j, detail);
+ }
+ }
+ }
+
+
+ /**
+ * Gets the 9 tiles in a 3x3 grid around the position specified.
+ *
+ * @param {Layer} layer - The internal layer to get the tileset at.
+ * @param {number} x - The x value of the position to center around.
+ * @param {number} y - The y value of the position to center around.
+ *
+ * @returns {number[]} a nine-element long array of the tiles around.
+ */
+
+ private getTilesAround(layer: Layer, x: number, y: number): number[] {
+ let tilesets: number[] = [];
+ for (let i = -1; i <= 1; i++)
+ for (let j = -1; j <= 1; j++)
+ tilesets.push(this.getTile(layer, clamp(x + j, 0, this.size.x - 1), clamp(y + i, 0, this.size.y - 1)));
+ return tilesets;
+ }
+}
diff --git a/app/src/editor/map/TileStore.ts b/app/src/editor/map/TileStore.ts
new file mode 100755
index 0000000..70500db
--- /dev/null
+++ b/app/src/editor/map/TileStore.ts
@@ -0,0 +1,49 @@
+import * as Phaser from 'phaser';
+
+import { Layer } from '../util/Layer';
+import { Asset, AssetType } from '../util/Asset';
+
+interface TileInfo {
+ res: number;
+ ind: number;
+ identifier: string;
+}
+
+/**
+ * Stores a map of tileset indexes to tiles.
+ */
+
+export default class TileStore {
+ indices: { [tileset_key: string]: number } = {};
+ wallTiles: { [index: number]: TileInfo } = {};
+ floorTiles: { [index: number]: TileInfo } = {};
+ detailTiles: { [index: number]: TileInfo } = {};
+
+ private currentInd: { [layer in Layer]: number } = { wall: 0, floor: 0, detail: 0 };
+
+
+ /**
+ * Initializes tilesets from a list of assets.
+ */
+
+ init(textures: Phaser.Textures.TextureManager, assets: Asset[]) {
+ for (const tileset of assets.filter(a => a.type !== 'token'))
+ this.addTileset(textures, tileset.type, tileset.identifier);
+ }
+
+
+ /**
+ * Adds the specified tileset to the map.
+ */
+
+ private addTileset(textures: Phaser.Textures.TextureManager, layer: AssetType, identifier: string): void {
+ const ind = this.currentInd[layer as Layer]++;
+ const res = textures.get(identifier).getSourceImage(0).width / 9;
+
+ if (layer === 'wall') this.wallTiles[ind] = { res, ind, identifier };
+ else if (layer === 'floor') this.floorTiles[ind] = { res, ind, identifier };
+ else if (layer === 'detail') this.detailTiles[ind] = { res, ind, identifier };
+
+ this.indices[identifier] = ind;
+ }
+}
diff --git a/app/src/editor/scene/LoadScene.ts b/app/src/editor/scene/LoadScene.ts
index 5ec6474..be9fb06 100755
--- a/app/src/editor/scene/LoadScene.ts
+++ b/app/src/editor/scene/LoadScene.ts
@@ -1,7 +1,9 @@
import * as Phaser from 'phaser';
-import EditorData from '../EditorData';
+import TilesetPatcher from '../TilesetPatcher';
+
import { Asset } from '../util/Asset';
+import EditorData from '../EditorData';
export default class LoadScene extends Phaser.Scene {
loaderOutline: Phaser.GameObjects.Sprite | null = null;
@@ -24,8 +26,6 @@ export default class LoadScene extends Phaser.Scene {
this.load.image('cursor', '/app/static/cursor.png');
this.load.image('grid_tile', '/app/static/grid_tile.png');
- this.load.image('tileset_partial', '/app/static/tileset/water_new.png');
- this.load.image('tileset_template', '/app/static/tileset_template.png');
this.load.image('ui_button_grid', '/app/static/ui/button_grid.png');
this.load.spritesheet('ui_button_side_menu', '/app/static/ui/button_side_menu.png', {frameWidth: 21, frameHeight: 18});
this.load.spritesheet('ui_history_manipulation', '/app/static/ui/history_manipulation.png', {frameWidth: 39, frameHeight: 18});
@@ -43,17 +43,22 @@ export default class LoadScene extends Phaser.Scene {
this.assets = JSON.parse(this.cache.text.get('assets'));
for (let asset of this.assets) {
- if (asset.tileSize) this.load.spritesheet(asset.identifier, '/app/asset/' + asset.path,
- { frameWidth: asset.tileSize, frameHeight: asset.tileSize });
- else this.load.image(asset.identifier, asset.path);
+ if (asset.tileSize && asset.type !== 'wall' && asset.type !== 'detail')
+ this.load.spritesheet(asset.identifier, '/app/asset/' + asset.path, { frameWidth: asset.tileSize, frameHeight: asset.tileSize });
+ else this.load.image(asset.identifier, '/app/asset/' + asset.path);
}
}
create(): void {
- this.game.scene.start('MapScene', { ...this.editorData, data: JSON.parse(this.cache.text.get('data')), assets: this.assets });
- this.cache.text.remove('assets');
- this.game.scene.stop('LoadScene');
- this.game.scene.swapPosition('MapScene', 'LoadScene');
+ const t = new TilesetPatcher(this);
+ Promise.all(this.assets.filter(a => a.type === 'wall' || a.type === 'detail')
+ .map(async (a) => await t.patch(a.identifier, a.tileSize)))
+ .then(() => {
+ this.game.scene.start('MapScene', { ...this.editorData, data: JSON.parse(this.cache.text.get('data')), assets: this.assets });
+ this.cache.text.remove('assets');
+ this.game.scene.stop('LoadScene');
+ this.game.scene.swapPosition('MapScene', 'LoadScene');
+ });
}
private setup(): void {
@@ -66,8 +71,8 @@ export default class LoadScene extends Phaser.Scene {
this.add.sprite(this.cameras.main.width / 2, this.cameras.main.height - 140, 'logo');
this.load.on('progress', (val: number) => {
- this.loaderFilled!.setCrop(0, this.loaderFilled!.height - this.loaderFilled!.height * val,
- this.loaderFilled!.width, this.loaderFilled!.height * val);
+ this.loaderFilled!.setCrop(0, this.loaderFilled!.height - this.loaderFilled!.height * val,
+ this.loaderFilled!.width, this.loaderFilled!.height * val);
});
}
}
diff --git a/app/src/editor/scene/MapScene.ts b/app/src/editor/scene/MapScene.ts
index 229fb9e..33a1dfb 100755
--- a/app/src/editor/scene/MapScene.ts
+++ b/app/src/editor/scene/MapScene.ts
@@ -9,10 +9,9 @@ import WorldView from '../WorldView';
import TokenMode from '../TokenMode';
import ArchitectMode from '../ArchitectMode';
+import Map from '../map/Map';
import Token from '../Token';
-import MapData from '../MapData';
import Lighting from '../lighting/Lighting';
-import TilesetPatcher from '../TilesetPatcher';
// import OutlinePipeline from '../shader/OutlinePipeline';
// import BrightenPipeline from '../shader/BrightenPipeline';
@@ -34,7 +33,7 @@ export default class MapScene extends Phaser.Scene {
size: Vec2 = new Vec2();
- map: MapData = new MapData(this);
+ map: Map = new Map();
lighting: Lighting = new Lighting(this);
mode: number = 0;
@@ -48,18 +47,11 @@ export default class MapScene extends Phaser.Scene {
// webRenderer.pipelines.add('outline', new OutlinePipeline(this.game));
// webRenderer.pipelines.add('brighten', new BrightenPipeline(this.game));
- const t = new TilesetPatcher(this);
- t.patch('tileset_partial', 16);
-
- const s = this.add.sprite(300, 300, 'tileset_partial');
- s.setOrigin(0, 0);
- s.setScale(4);
-
this.i.init();
this.view.init();
this.size = new Vec2(data.data.size);
- this.map.init(this.size, this.assets!);
+ this.map.init(this, this.size, this.assets!);
this.ui.init(this.assets!);
this.architect.init();
diff --git a/app/src/editor/util/Asset.ts b/app/src/editor/util/Asset.ts
index 1a8ab86..9e43fcb 100755
--- a/app/src/editor/util/Asset.ts
+++ b/app/src/editor/util/Asset.ts
@@ -1,6 +1,6 @@
import { Vec2 } from './Vec';
-export type AssetType = 'ground' | 'wall' | 'token';
+export type AssetType = 'floor' | 'detail' | 'wall' | 'token';
export interface Asset {
type: AssetType;
diff --git a/app/src/editor/util/Layer.ts b/app/src/editor/util/Layer.ts
index 88d5729..87fd5df 100644
--- a/app/src/editor/util/Layer.ts
+++ b/app/src/editor/util/Layer.ts
@@ -1,7 +1 @@
-enum Layer {
- floor = 0,
- wall = 1,
- overlay = 2
-};
-
-export default Layer;
+export type Layer = 'floor' | 'wall' | 'detail';
diff --git a/assets/auri_16x_fantasy_floor_rock.png b/assets/1212b3f83385f518d41fd5d60924617f.png
similarity index 100%
rename from assets/auri_16x_fantasy_floor_rock.png
rename to assets/1212b3f83385f518d41fd5d60924617f.png
diff --git a/assets/129e90e0cc9499733a12c1604429fa62.png b/assets/129e90e0cc9499733a12c1604429fa62.png
deleted file mode 100644
index c5c8e59..0000000
Binary files a/assets/129e90e0cc9499733a12c1604429fa62.png and /dev/null differ
diff --git a/assets/19f80922c8ec85b838aecbb58e83ebb5.png b/assets/19f80922c8ec85b838aecbb58e83ebb5.png
deleted file mode 100644
index d4471e9..0000000
Binary files a/assets/19f80922c8ec85b838aecbb58e83ebb5.png and /dev/null differ
diff --git a/assets/1d47e7bf3a7e92475630090704215c3d.png b/assets/1d47e7bf3a7e92475630090704215c3d.png
new file mode 100644
index 0000000..80d4bf4
Binary files /dev/null and b/assets/1d47e7bf3a7e92475630090704215c3d.png differ
diff --git a/assets/1d8c662852f88f8b0eab68764b6075a9.png b/assets/1d8c662852f88f8b0eab68764b6075a9.png
new file mode 100644
index 0000000..3b6ded9
Binary files /dev/null and b/assets/1d8c662852f88f8b0eab68764b6075a9.png differ
diff --git a/assets/2506d31b947fda4295475c191f2dd0db.png b/assets/2506d31b947fda4295475c191f2dd0db.png
deleted file mode 100644
index f5e2e29..0000000
Binary files a/assets/2506d31b947fda4295475c191f2dd0db.png and /dev/null differ
diff --git a/assets/4d382cb3f4956f5b3acacb84cc75b242.png b/assets/4d382cb3f4956f5b3acacb84cc75b242.png
deleted file mode 100644
index 11827f2..0000000
Binary files a/assets/4d382cb3f4956f5b3acacb84cc75b242.png and /dev/null differ
diff --git a/assets/51bb14491a3ec884269416faac03cafa.png b/assets/51bb14491a3ec884269416faac03cafa.png
deleted file mode 100644
index f257d86..0000000
Binary files a/assets/51bb14491a3ec884269416faac03cafa.png and /dev/null differ
diff --git a/assets/595347ff1a6fe6a52fbde2255860fdd7.png b/assets/595347ff1a6fe6a52fbde2255860fdd7.png
deleted file mode 100644
index 13d9fc7..0000000
Binary files a/assets/595347ff1a6fe6a52fbde2255860fdd7.png and /dev/null differ
diff --git a/assets/5cafce367161af38becdcfbd4e965baf.png b/assets/5cafce367161af38becdcfbd4e965baf.png
new file mode 100644
index 0000000..f853645
Binary files /dev/null and b/assets/5cafce367161af38becdcfbd4e965baf.png differ
diff --git a/assets/65172fd93b3361a53f63e6a964f47152.png b/assets/65172fd93b3361a53f63e6a964f47152.png
deleted file mode 100644
index 535d8ab..0000000
Binary files a/assets/65172fd93b3361a53f63e6a964f47152.png and /dev/null differ
diff --git a/assets/6900ec9f541e1d7d010aee1f57c7f1a9.png b/assets/6900ec9f541e1d7d010aee1f57c7f1a9.png
deleted file mode 100644
index b82b259..0000000
Binary files a/assets/6900ec9f541e1d7d010aee1f57c7f1a9.png and /dev/null differ
diff --git a/assets/8a344775bc45eaae8c7a399985f336e9.png b/assets/8a344775bc45eaae8c7a399985f336e9.png
deleted file mode 100644
index d4471e9..0000000
Binary files a/assets/8a344775bc45eaae8c7a399985f336e9.png and /dev/null differ
diff --git a/assets/99f8ad5dbf19c983e8decd61a1ab0efc.png b/assets/8aad9d92a9a622d664c3362c69154aca.png
similarity index 100%
rename from assets/99f8ad5dbf19c983e8decd61a1ab0efc.png
rename to assets/8aad9d92a9a622d664c3362c69154aca.png
diff --git a/assets/a532af9feb981f9302ecf865b5d9c7d0.png b/assets/a532af9feb981f9302ecf865b5d9c7d0.png
deleted file mode 100644
index f257d86..0000000
Binary files a/assets/a532af9feb981f9302ecf865b5d9c7d0.png and /dev/null differ
diff --git a/assets/auri_16x_fantasy_cadin_1.png b/assets/auri_16x_fantasy_cadin_1.png
deleted file mode 100644
index 2009e55..0000000
Binary files a/assets/auri_16x_fantasy_cadin_1.png and /dev/null differ
diff --git a/assets/auri_16x_fantasy_wall_dungeon.png b/assets/auri_16x_fantasy_wall_dungeon.png
deleted file mode 100644
index ff157c1..0000000
Binary files a/assets/auri_16x_fantasy_wall_dungeon.png and /dev/null differ
diff --git a/assets/c57c07c340da5af1c066def99abf7a25.png b/assets/c57c07c340da5af1c066def99abf7a25.png
deleted file mode 100644
index 190b845..0000000
Binary files a/assets/c57c07c340da5af1c066def99abf7a25.png and /dev/null differ
diff --git a/assets/c58cb184401388ad65c9e3509e83b706.png b/assets/c58cb184401388ad65c9e3509e83b706.png
deleted file mode 100644
index 8822e9b..0000000
Binary files a/assets/c58cb184401388ad65c9e3509e83b706.png and /dev/null differ
diff --git a/assets/cc88be196a49a85b30d8f075cface18e.png b/assets/cc88be196a49a85b30d8f075cface18e.png
deleted file mode 100644
index 4d82d6c..0000000
Binary files a/assets/cc88be196a49a85b30d8f075cface18e.png and /dev/null differ
diff --git a/assets/d365e29f01067ade7b15566e97656999.png b/assets/d365e29f01067ade7b15566e97656999.png
deleted file mode 100644
index f257d86..0000000
Binary files a/assets/d365e29f01067ade7b15566e97656999.png and /dev/null differ
diff --git a/assets/d38c5fc89edfc8feb26af435c84bda95.png b/assets/d38c5fc89edfc8feb26af435c84bda95.png
deleted file mode 100644
index 8ed64bb..0000000
Binary files a/assets/d38c5fc89edfc8feb26af435c84bda95.png and /dev/null differ
diff --git a/assets/7ff3add8ef026bdf6e0dad0d5ba85642.png b/assets/df059aba8e6c8d0afc77acf3a9713c27.png
similarity index 100%
rename from assets/7ff3add8ef026bdf6e0dad0d5ba85642.png
rename to assets/df059aba8e6c8d0afc77acf3a9713c27.png
diff --git a/assets/e8e61062f0889dffca9a1439d9678201.png b/assets/e8e61062f0889dffca9a1439d9678201.png
deleted file mode 100644
index 4d82d6c..0000000
Binary files a/assets/e8e61062f0889dffca9a1439d9678201.png and /dev/null differ
diff --git a/assets/f975160fe390339d57d077a6ff0085aa.png b/assets/f975160fe390339d57d077a6ff0085aa.png
deleted file mode 100644
index a4f7aba..0000000
Binary files a/assets/f975160fe390339d57d077a6ff0085aa.png and /dev/null differ
diff --git a/assets/fcb05842c62423b61ca44e39e68380d9.png b/assets/fcb05842c62423b61ca44e39e68380d9.png
deleted file mode 100644
index f5e2e29..0000000
Binary files a/assets/fcb05842c62423b61ca44e39e68380d9.png and /dev/null differ
diff --git a/common/AppData.ts b/common/AppData.ts
index 58028bc..b9bb4b3 100644
--- a/common/AppData.ts
+++ b/common/AppData.ts
@@ -1,9 +1,10 @@
import * as DB from './DBStructs';
-export type AppDataSpecifier = 'user' | 'campaigns' | 'assets';
+export type AppDataSpecifier = 'user' | 'campaigns' | 'collections' | 'assets';
export interface AppData {
user: { user: string, name: string };
+ collections: DB.AssetCollection[];
campaigns: DB.Campaign[];
assets: DB.Asset[];
}
diff --git a/common/DBStructs.ts b/common/DBStructs.ts
index de9c213..1a8f485 100755
--- a/common/DBStructs.ts
+++ b/common/DBStructs.ts
@@ -41,7 +41,7 @@ export interface Map {
tiles: string;
}
-export type AssetType = 'wall' | 'ground' | 'token';
+export type AssetType = 'wall' | 'detail' | 'ground' | 'token';
export interface AssetCollection {
_id?: ObjectID;
diff --git a/server/src/Database.ts b/server/src/Database.ts
index f856cdf..2824a8f 100755
--- a/server/src/Database.ts
+++ b/server/src/Database.ts
@@ -14,6 +14,7 @@ const sizeOf = promisify(sizeOfRaw);
const logger = log4js.getLogger();
const PERSONAL_IDENTIFIER = '_';
+const ASSET_PATH = path.join(path.dirname(path.dirname(__dirname)), 'assets');
export const uploadLimit = 2 * 1024 * 1024;
export const accountLimit = 5 * 1024 * 1024;
@@ -25,7 +26,7 @@ interface BaseAssetData {
}
interface TilesetData {
- type: 'ground' | 'wall'
+ type: 'floor' | 'wall' | 'detail'
}
interface TokenData {
@@ -310,11 +311,43 @@ export default class Database {
/**
- * Get a users's uploaded assets.
+ * Gets a users's uploaded assets.
*/
async getUserAssets(user: string): Promise {
- return await this.db!.collection('assets').find({ user: user }).toArray();
+ return await this.db!.collection('assets').find({ user }).toArray();
+ }
+
+
+ /**
+ * Gets a user's collections.
+ */
+
+
+ async getUserCollections(user: string): Promise {
+ return await this.db!.collection('collections').find({ user }).toArray();
+ }
+
+
+ /**
+ * Adds an asset to a user's collection
+ *
+ * @param user - The user that owns the collection.
+ * @param collection - The collection to insert an item into.
+ * @param asset - An Asset string to add to the collection.
+ */
+
+
+ async addCollectionAsset(user: string, collection: string, asset: string) {
+ const res = await this.db!.collection('assets').find({
+ user: asset.slice(0, asset.indexOf(':')),
+ identifier: asset.slice(asset.indexOf(':') + 1)
+ });
+ if (!res) throw 'Asset doesn\'t exist.';
+
+ const matched = await this.db!.collection('collections')
+ .updateOne({ user: user, identifier: collection }, { $addToSet: { items: asset }});
+ if (!matched.matchedCount) throw 'Collection doesn\'t exist.';
}
@@ -342,7 +375,7 @@ export default class Database {
let assetName = '', assetPath = '';
while (true) {
assetName = crypto.createHash('md5').update(data.identifier + await crypto.randomBytes(8)).digest('hex') + '.png';
- assetPath = path.join(path.dirname(path.dirname(__dirname)), 'assets', assetName);
+ assetPath = path.join(ASSET_PATH, assetName);
try { await fs.access(assetPath, fsc.R_OK | fsc.W_OK); }
catch (e) { if (e.code === 'ENOENT') break; }
}
@@ -378,6 +411,26 @@ export default class Database {
}
+ /**
+ * Deletes a user's asset, removing it from the filesystem.
+ *
+ * @param {string} user - The user identifier.
+ * @param {string} identifier - The asset identifier.
+ */
+
+ async deleteAsset(user: string, identifier: string): Promise {
+ const asset: DB.Asset | null = await this.db!.collection('assets').findOne({ user, identifier });
+ if (!asset) return;
+
+ try { await fs.unlink(path.join(ASSET_PATH, asset.path)) } catch {}
+ await this.db!.collection('assets').remove({ user, identifier });
+
+ const query = user + ':' + identifier;
+ await this.db!.collection('collections').updateMany(
+ { items: { $all: [ query ] } }, { $pull: { items: query } });
+ }
+
+
/**
* Creates and returns an authentication token for a user using a username / password pair.
* Throws if the username and password do not refer to a valid user.
diff --git a/server/src/routers/DataRouter.ts b/server/src/routers/DataRouter.ts
index eac0d4b..e75a8fe 100755
--- a/server/src/routers/DataRouter.ts
+++ b/server/src/routers/DataRouter.ts
@@ -35,12 +35,17 @@ export default class DataRouter extends Router {
case 'assets':
data.assets = await this.db.getUserAssets(user);
break;
+
+ case 'collections':
+ data.collections = await this.db.getUserCollections(user);
+ break;
}
}));
return data;
};
+
/**
* Attempts to authenticate a user from a username and password.
*/
@@ -97,7 +102,7 @@ export default class DataRouter extends Router {
/**
- * Creates a new campaign.
+ * Creates a new map within a campaign.
*/
this.router.post('/map/new', this.authRoute(async (user, req, res) => {
@@ -118,16 +123,16 @@ export default class DataRouter extends Router {
}));
this.router.post('/asset/upload/', this.authRoute(async (user, req, res) => {
- const type: 'ground' | 'token' | 'wall' = req.body.type;
+ const type: 'floor' | 'token' | 'detail' | 'wall' = req.body.type;
const tokenType: '1' | '4' | '8' = req.body.tokenType;
const name = req.body.name;
const identifier = req.body.identifier;
- if (typeof name != 'string' || typeof identifier != 'string' ||
- (type != 'token' && type != 'ground' && type != 'wall') ||
+ if (typeof name !== 'string' || typeof identifier !== 'string' ||
+ (type !== 'token' && type !== 'floor' && type !== 'wall' && type !== 'detail') ||
(type === 'token' && tokenType !== '1' && tokenType !== '4' && tokenType !== '8'))
- return res.status(400)
+ return res.sendStatus(400);
const file = req.files?.file;
if (!file || Array.isArray(file)) return res.sendStatus(400);
@@ -144,6 +149,33 @@ export default class DataRouter extends Router {
}));
+ /**
+ * Deletes an asset from the database & filesystem.
+ */
+
+ this.router.post('/asset/delete/', this.authRoute(async (user, req, res) => {
+ const identifier = req.body.identifier;
+
+ if (typeof identifier !== 'string') res.sendStatus(400);
+ else {
+ await this.db.deleteAsset(user, identifier);
+ res.sendStatus(200);
+ }
+ }));
+
+
+ /**
+ * Adds an asset to a collection.
+ */
+
+ this.router.post('/collection/add', this.authRoute(async (user, req, res) => {
+ if (typeof req.body.collection !== 'string' || typeof req.body.asset !== 'string') throw 'Invalid parameters.';
+
+ await this.db.addCollectionAsset(user, req.body.collection, req.body.asset);
+ res.send(await getAppData(user, 'collections'));
+ }));
+
+
this.app.use('/data', this.router);
}
}