I forgot to do rolling commits
This commit is contained in:
parent
a6e99ffa2d
commit
bb0991ef21
13 changed files with 7866 additions and 5863 deletions
Binary file not shown.
Before Width: | Height: | Size: 9 KiB After Width: | Height: | Size: 9.1 KiB |
35
assets/scripts/KaplayMap/events.js
Normal file
35
assets/scripts/KaplayMap/events.js
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
export class EventManager {
|
||||||
|
map;
|
||||||
|
ui;
|
||||||
|
gameobj;
|
||||||
|
floormanager;
|
||||||
|
|
||||||
|
events = new Map([]);
|
||||||
|
|
||||||
|
constructor(map, ui, gameobj) {
|
||||||
|
this.map = map;
|
||||||
|
this.ui = ui;
|
||||||
|
this.ui.eventmanager = this;
|
||||||
|
this.gameobj = gameobj;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getFloorEvents() {
|
||||||
|
let floorEventsReqSend = fetch(
|
||||||
|
`/data/${this.floormanager.lang}/events/${this.floormanager.currentFloor}`
|
||||||
|
);
|
||||||
|
|
||||||
|
this.ui.setLoading(true);
|
||||||
|
|
||||||
|
let floorEventsReq = await floorEventsReqSend;
|
||||||
|
let floorEvents;
|
||||||
|
if (floorEventsReq.ok) floorEvents = await floorEventsReq.json();
|
||||||
|
|
||||||
|
this.events.clear();
|
||||||
|
|
||||||
|
floorEvents.forEach((event) => this.events.set(event.id, event));
|
||||||
|
|
||||||
|
this.ui.setLoading(false);
|
||||||
|
|
||||||
|
return this.events;
|
||||||
|
}
|
||||||
|
}
|
84
assets/scripts/KaplayMap/floors.js
Normal file
84
assets/scripts/KaplayMap/floors.js
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
export class FloorManager {
|
||||||
|
map;
|
||||||
|
ui;
|
||||||
|
gameobj;
|
||||||
|
events;
|
||||||
|
lang;
|
||||||
|
|
||||||
|
floors = new Map([]);
|
||||||
|
rooms = new Map([]);
|
||||||
|
currentFloor = "";
|
||||||
|
|
||||||
|
constructor(map, ui, gameobj, events, lang) {
|
||||||
|
this.map = map;
|
||||||
|
this.ui = ui;
|
||||||
|
this.ui.floormanager = this;
|
||||||
|
this.gameobj = gameobj;
|
||||||
|
this.gameobj.floormanager = this;
|
||||||
|
this.events = events;
|
||||||
|
this.events.floormanager = this;
|
||||||
|
this.lang = lang;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getFloors() {
|
||||||
|
let allFloorsReqSend = fetch(`/data/${this.lang}/map`);
|
||||||
|
|
||||||
|
this.ui.setLoading(true);
|
||||||
|
|
||||||
|
let allFloorsReq = await allFloorsReqSend;
|
||||||
|
let allFloors;
|
||||||
|
if (allFloorsReq.ok) allFloors = await allFloorsReq.json();
|
||||||
|
|
||||||
|
allFloors.forEach((floor) => this.floors.set(floor.id, floor));
|
||||||
|
|
||||||
|
this.changeFloor(allFloors[0].id);
|
||||||
|
|
||||||
|
this.ui.setLoading(false);
|
||||||
|
|
||||||
|
return this.floors;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRooms(id) {
|
||||||
|
const curRoom = this.rooms.get(id);
|
||||||
|
|
||||||
|
if (curRoom != null) return curRoom;
|
||||||
|
|
||||||
|
let allRoomsReqSend = fetch(`/data/${this.lang}/map/${id}`);
|
||||||
|
|
||||||
|
this.ui.setLoading(true);
|
||||||
|
|
||||||
|
let allRoomsReq = await allRoomsReqSend;
|
||||||
|
let allRooms;
|
||||||
|
if (allRoomsReq.ok) allRooms = await allRoomsReq.json();
|
||||||
|
|
||||||
|
this.rooms.set(id, allRooms);
|
||||||
|
|
||||||
|
this.ui.setLoading(false);
|
||||||
|
|
||||||
|
return this.rooms;
|
||||||
|
}
|
||||||
|
|
||||||
|
async changeFloor(id) {
|
||||||
|
const floor = this.floors.get(id);
|
||||||
|
if (floor != null) this.currentFloor = id;
|
||||||
|
|
||||||
|
if (this.ui.floorsEmpty) this.ui.__updateFloorsHard();
|
||||||
|
else this.ui.__updateFloorsSoft();
|
||||||
|
|
||||||
|
this.ui.setLoading(true);
|
||||||
|
|
||||||
|
this.gameobj.generateFloor();
|
||||||
|
|
||||||
|
await this.getRooms(id);
|
||||||
|
|
||||||
|
this.gameobj.generateRooms();
|
||||||
|
|
||||||
|
await this.events.getFloorEvents();
|
||||||
|
|
||||||
|
this.ui.__updateEvents();
|
||||||
|
|
||||||
|
this.ui.setLoading(false);
|
||||||
|
|
||||||
|
return floor;
|
||||||
|
}
|
||||||
|
}
|
132
assets/scripts/KaplayMap/gameobj.js
Normal file
132
assets/scripts/KaplayMap/gameobj.js
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
export class GameObjManager {
|
||||||
|
map;
|
||||||
|
floormanager;
|
||||||
|
|
||||||
|
floorObject;
|
||||||
|
roomObjects = new Map([]);
|
||||||
|
currentRoom;
|
||||||
|
|
||||||
|
constructor(map) {
|
||||||
|
this.map = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
generateFloor() {
|
||||||
|
if (this.floorObject) this.floorObject.destroy();
|
||||||
|
|
||||||
|
const currentFloor = this.floormanager.floors.get(
|
||||||
|
this.floormanager.currentFloor
|
||||||
|
);
|
||||||
|
|
||||||
|
const polygon = new this.map.kp.Polygon(
|
||||||
|
currentFloor.poly.map(([x, y]) => this.map.kp.vec2(x, y))
|
||||||
|
);
|
||||||
|
|
||||||
|
this.floorObject = this.map.kp.make([
|
||||||
|
this.map.kp.polygon(polygon.pts),
|
||||||
|
this.map.kp.outline(1, this.map.kp.BLACK),
|
||||||
|
this.map.kp.color(this.map.kp.Color.fromHex("303030")),
|
||||||
|
// this.map.kp.area(),
|
||||||
|
this.map.kp.pos(),
|
||||||
|
this.map.kp.z(5),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const bounds = polygon.bbox();
|
||||||
|
|
||||||
|
this.map.camBounds = bounds;
|
||||||
|
|
||||||
|
this.floorObject.onUpdate(() => {
|
||||||
|
const camScale = 1 / this.map.kp.camScale().y;
|
||||||
|
this.floorObject.outline.width = 8 * camScale;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.floorObject.onDraw(() => {
|
||||||
|
const camScale = 1 / this.map.kp.camScale().y;
|
||||||
|
this.map.kp.drawText({
|
||||||
|
text: currentFloor.name,
|
||||||
|
size: 24 * camScale,
|
||||||
|
pos: this.map.kp.vec2(-4 * camScale, -8 * camScale),
|
||||||
|
color: this.map.kp.WHITE,
|
||||||
|
anchor: "botleft",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.map.kp.add(this.floorObject);
|
||||||
|
|
||||||
|
this.map.zoomToAbs(this.map.opts.minZoomLevel, bounds.center());
|
||||||
|
}
|
||||||
|
|
||||||
|
generateRooms() {
|
||||||
|
if (this.roomObjects.size > 0) {
|
||||||
|
this.roomObjects.forEach((x) => x.destroy());
|
||||||
|
this.roomObjects.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentRooms = this.floormanager.rooms.get(
|
||||||
|
this.floormanager.currentFloor
|
||||||
|
);
|
||||||
|
|
||||||
|
currentRooms.forEach((room) => {
|
||||||
|
const polygon = new this.map.kp.Polygon(
|
||||||
|
room.poly.map(([x, y]) => this.map.kp.vec2(x, y))
|
||||||
|
);
|
||||||
|
|
||||||
|
const obj = this.map.kp.make([
|
||||||
|
this.map.kp.polygon(polygon.pts),
|
||||||
|
this.map.kp.outline(1, this.map.kp.BLACK),
|
||||||
|
this.map.kp.color(this.map.kp.Color.fromHex("303030")),
|
||||||
|
this.map.kp.area(),
|
||||||
|
this.map.kp.pos(),
|
||||||
|
this.map.kp.z(6),
|
||||||
|
{
|
||||||
|
clickForgiveness: 1,
|
||||||
|
startClickPosition: null,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
obj.onHover(() => {
|
||||||
|
obj.color = this.map.kp.Color.fromHex("505050");
|
||||||
|
});
|
||||||
|
|
||||||
|
obj.onHoverEnd(() => {
|
||||||
|
obj.color = this.map.kp.Color.fromHex("303030");
|
||||||
|
});
|
||||||
|
|
||||||
|
this.roomObjects.set(room.id, obj);
|
||||||
|
|
||||||
|
obj.onUpdate(() => {
|
||||||
|
const camScale = 1 / this.map.kp.camScale().y;
|
||||||
|
obj.outline.width = 8 * camScale;
|
||||||
|
|
||||||
|
if (this.map.kp.isMousePressed() && obj.isHovering()) {
|
||||||
|
obj.startClickPosition = this.map.kp.mousePos();
|
||||||
|
obj.color = this.map.kp.Color.fromHex("202020");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.map.kp.isMouseReleased() && obj.isHovering()) {
|
||||||
|
const endClickPosition = this.map.kp.mousePos();
|
||||||
|
if (
|
||||||
|
obj.startClickPosition &&
|
||||||
|
obj.startClickPosition.dist(endClickPosition) < obj.clickForgiveness
|
||||||
|
) {
|
||||||
|
this.currentRoom = room.id;
|
||||||
|
}
|
||||||
|
obj.color = this.map.kp.Color.fromHex("505050");
|
||||||
|
this.map.clearMouseMode();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
obj.onDraw(() => {
|
||||||
|
const camScale = 1 / this.map.kp.camScale().y;
|
||||||
|
this.map.kp.drawText({
|
||||||
|
text: room.name,
|
||||||
|
size: 24 * camScale,
|
||||||
|
pos: polygon.bbox().center(),
|
||||||
|
color: this.map.kp.WHITE,
|
||||||
|
anchor: "center",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.floorObject.add(obj);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,26 +1,27 @@
|
||||||
export class KaplayMap {
|
export class KaplayMap {
|
||||||
kp;
|
kp;
|
||||||
opts = {
|
opts = {
|
||||||
minZoomLevel: 0,
|
minZoomLevel: 2,
|
||||||
maxZoomLevel: 3,
|
maxZoomLevel: 5,
|
||||||
dblClickDuration: 0.2, // s
|
dblClickDuration: 0.2, // s
|
||||||
dblClickForgiveness: 30, // px
|
dblClickForgiveness: 30, // px
|
||||||
};
|
};
|
||||||
|
|
||||||
uiLayer;
|
uiLayer;
|
||||||
|
|
||||||
#zoomLevel = 0;
|
#zoomLevel = this.opts.minZoomLevel;
|
||||||
#scaleTween = null;
|
#scaleTween = null;
|
||||||
|
|
||||||
startMousePos = null;
|
startMousePos = null;
|
||||||
startCamPos = null;
|
startCamPos = null;
|
||||||
startZoomLevel = null;
|
startZoomLevel = null;
|
||||||
prevCamPos = null;
|
prevCamPos = null;
|
||||||
moveVelocity = null;
|
|
||||||
moveFriction = 0.25;
|
moveFriction = 0.25;
|
||||||
moveDead = 1;
|
moveDead = 1;
|
||||||
#moveTween = null;
|
#moveTween = null;
|
||||||
|
|
||||||
|
camBounds = null;
|
||||||
|
|
||||||
lastReleaseTime;
|
lastReleaseTime;
|
||||||
lastReleasePos;
|
lastReleasePos;
|
||||||
lastPressTime;
|
lastPressTime;
|
||||||
|
@ -39,9 +40,8 @@ export class KaplayMap {
|
||||||
...opts,
|
...opts,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.uiLayer = this.initUI();
|
this.zoomLevel_NoTween = this.opts.minZoomLevel;
|
||||||
|
this.kp.camPos(0);
|
||||||
this.kp.add(this.uiLayer);
|
|
||||||
|
|
||||||
this.kp.onScroll((delta) => {
|
this.kp.onScroll((delta) => {
|
||||||
const scrollDist = -delta.y / 120;
|
const scrollDist = -delta.y / 120;
|
||||||
|
@ -80,6 +80,10 @@ export class KaplayMap {
|
||||||
|
|
||||||
this.fingers.delete(touch.identifier);
|
this.fingers.delete(touch.identifier);
|
||||||
|
|
||||||
|
if (this.fingers.size < 1) {
|
||||||
|
this.checkBounds();
|
||||||
|
}
|
||||||
|
|
||||||
if (this.fingers.size < 2) {
|
if (this.fingers.size < 2) {
|
||||||
const fingerArr = Array.from(this.fingers.values());
|
const fingerArr = Array.from(this.fingers.values());
|
||||||
this.startFingerCenterPos = fingerArr[0];
|
this.startFingerCenterPos = fingerArr[0];
|
||||||
|
@ -118,26 +122,10 @@ export class KaplayMap {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const size = 16;
|
|
||||||
this.kp.onDraw(() => {
|
|
||||||
this.fingers.forEach((pos) => {
|
|
||||||
this.kp.drawRect({
|
|
||||||
width: size,
|
|
||||||
height: size,
|
|
||||||
pos: pos.sub(size / 2),
|
|
||||||
color: this.kp.RED,
|
|
||||||
fixed: true,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.kp.onUpdate(() => {
|
this.kp.onUpdate(() => {
|
||||||
const curCamPos = this.kp.camPos();
|
const curCamPos = this.kp.camPos();
|
||||||
const camScale = 1 / this.kp.camScale().y;
|
const camScale = 1 / this.kp.camScale().y;
|
||||||
|
|
||||||
// ||| Completely unintelligible to the average person |||
|
|
||||||
// vvv Sorry y'all xwx vvv
|
|
||||||
|
|
||||||
if (this.kp.isMousePressed()) {
|
if (this.kp.isMousePressed()) {
|
||||||
// ignore if no double click
|
// ignore if no double click
|
||||||
if (this.lastPressTime != null && this.lastPressPos != null) {
|
if (this.lastPressTime != null && this.lastPressPos != null) {
|
||||||
|
@ -185,10 +173,9 @@ export class KaplayMap {
|
||||||
this.lastReleaseTime = this.kp.time();
|
this.lastReleaseTime = this.kp.time();
|
||||||
this.lastReleasePos = this.kp.mousePos();
|
this.lastReleasePos = this.kp.mousePos();
|
||||||
|
|
||||||
// if (this.prevCamPos != null)
|
// Check bounds
|
||||||
// this.moveVelocity = this.prevCamPos
|
|
||||||
// .sub(curCamPos)
|
this.checkBounds();
|
||||||
// .scale(1 / camScale);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.kp.isMouseDown()) {
|
if (this.kp.isMouseDown()) {
|
||||||
|
@ -208,52 +195,9 @@ export class KaplayMap {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
|
||||||
this.moveVelocity != null &&
|
|
||||||
this.moveVelocity?.x != 0 &&
|
|
||||||
this.moveVelocity?.y != 0
|
|
||||||
)
|
|
||||||
this.kp.camPos(curCamPos.sub(this.moveVelocity?.scale(camScale) ?? 0));
|
|
||||||
|
|
||||||
this.kp.camPos(
|
|
||||||
Math.round(this.kp.camPos().x * this.kp.camScale().y) /
|
|
||||||
this.kp.camScale().y,
|
|
||||||
Math.round(this.kp.camPos().y * this.kp.camScale().y) /
|
|
||||||
this.kp.camScale().y
|
|
||||||
);
|
|
||||||
|
|
||||||
// ^^^ Completely unintelligible to the average person ^^^
|
|
||||||
// ||| Sorry y'all xwx |||
|
|
||||||
|
|
||||||
if (this.moveVelocity == null) return;
|
|
||||||
|
|
||||||
if (
|
|
||||||
this.moveVelocity.x <= this.moveDead &&
|
|
||||||
this.moveVelocity.x >= -this.moveDead
|
|
||||||
)
|
|
||||||
this.moveVelocity.x = 0;
|
|
||||||
if (
|
|
||||||
this.moveVelocity.y <= this.moveDead &&
|
|
||||||
this.moveVelocity.y >= -this.moveDead
|
|
||||||
)
|
|
||||||
this.moveVelocity.y = 0;
|
|
||||||
|
|
||||||
this.moveVelocity = this.moveVelocity.scale(1 - this.moveFriction);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
initUI() {
|
|
||||||
const uiLayer = this.kp.make([
|
|
||||||
this.kp.pos(0),
|
|
||||||
this.kp.fixed(),
|
|
||||||
this.kp.stay(),
|
|
||||||
this.kp.z(1000),
|
|
||||||
]);
|
|
||||||
|
|
||||||
return uiLayer;
|
|
||||||
}
|
|
||||||
|
|
||||||
initGrid() {
|
initGrid() {
|
||||||
const grid = this.kp.loadSprite(null, "/assets/images/grid.png");
|
const grid = this.kp.loadSprite(null, "/assets/images/grid.png");
|
||||||
|
|
||||||
|
@ -262,11 +206,12 @@ export class KaplayMap {
|
||||||
sprite: grid,
|
sprite: grid,
|
||||||
tiled: true,
|
tiled: true,
|
||||||
opacity: 0.25,
|
opacity: 0.25,
|
||||||
width: this.kp.width() + 100,
|
width: this.kp.width() + 200,
|
||||||
height: this.kp.height() + 100,
|
height: this.kp.height() + 200,
|
||||||
|
anchor: "center",
|
||||||
pos: this.kp.vec2(
|
pos: this.kp.vec2(
|
||||||
Math.floor(this.kp.camPos().x / 100) * 100 - this.kp.width() * 0.5,
|
Math.floor(this.kp.camPos().x / 100) * 100 + 50.5,
|
||||||
Math.floor(this.kp.camPos().y / 100) * 100 - this.kp.height() * 0.5
|
Math.floor(this.kp.camPos().y / 100) * 100 + 0.5
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -282,6 +227,37 @@ export class KaplayMap {
|
||||||
this.prevCamPos = null;
|
this.prevCamPos = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkBounds() {
|
||||||
|
const camPos = this.kp.camPos();
|
||||||
|
|
||||||
|
if (this.camBounds == null) return;
|
||||||
|
|
||||||
|
if (this.kp.testRectPoint(this.camBounds, camPos)) return;
|
||||||
|
|
||||||
|
const boundsCenter = this.camBounds.center();
|
||||||
|
const cast = this.camBounds.raycast(
|
||||||
|
camPos,
|
||||||
|
this.kp.Vec2.fromAngle(camPos.angle(boundsCenter) + 180).scale(40000)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (cast == null) return;
|
||||||
|
|
||||||
|
if (this.#moveTween != null) {
|
||||||
|
this.#moveTween.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#moveTween = this.kp.tween(
|
||||||
|
camPos,
|
||||||
|
cast.point,
|
||||||
|
0.25,
|
||||||
|
this.kp.camPos,
|
||||||
|
this.kp.easings.easeOutQuad
|
||||||
|
);
|
||||||
|
this.#moveTween.then(() => {
|
||||||
|
this.#moveTween = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
get zoomLevelLimit() {
|
get zoomLevelLimit() {
|
||||||
if (this.#zoomLevel == this.opts.minZoomLevel) return -1;
|
if (this.#zoomLevel == this.opts.minZoomLevel) return -1;
|
||||||
if (this.#zoomLevel == this.opts.maxZoomLevel) return 1;
|
if (this.#zoomLevel == this.opts.maxZoomLevel) return 1;
|
||||||
|
@ -342,8 +318,8 @@ export class KaplayMap {
|
||||||
|
|
||||||
const newDiff = this.kp.center().sub(position).scale(newZoomLog);
|
const newDiff = this.kp.center().sub(position).scale(newZoomLog);
|
||||||
|
|
||||||
if (newZoom <= this.opts.minZoomLevel) return;
|
if (newZoom < this.opts.minZoomLevel) return;
|
||||||
if (newZoom >= this.opts.maxZoomLevel) return;
|
if (newZoom > this.opts.maxZoomLevel) return;
|
||||||
|
|
||||||
if (this.#moveTween != null) {
|
if (this.#moveTween != null) {
|
||||||
this.#moveTween.finish();
|
this.#moveTween.finish();
|
||||||
|
@ -358,6 +334,29 @@ export class KaplayMap {
|
||||||
);
|
);
|
||||||
this.#moveTween.then(() => {
|
this.#moveTween.then(() => {
|
||||||
this.#moveTween = null;
|
this.#moveTween = null;
|
||||||
|
this.checkBounds();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
zoomToAbs(newZoom, position) {
|
||||||
|
const curCamPos = this.kp.camPos();
|
||||||
|
|
||||||
|
this.zoomLevel = newZoom;
|
||||||
|
|
||||||
|
if (this.#moveTween != null) {
|
||||||
|
this.#moveTween.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#moveTween = this.kp.tween(
|
||||||
|
curCamPos,
|
||||||
|
position,
|
||||||
|
0.25,
|
||||||
|
this.kp.camPos,
|
||||||
|
this.kp.easings.easeOutQuad
|
||||||
|
);
|
||||||
|
this.#moveTween.then(() => {
|
||||||
|
this.#moveTween = null;
|
||||||
|
this.checkBounds();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -372,14 +371,16 @@ export class KaplayMap {
|
||||||
|
|
||||||
const newDiff = this.kp.center().sub(position).scale(newZoomLog);
|
const newDiff = this.kp.center().sub(position).scale(newZoomLog);
|
||||||
|
|
||||||
if (newZoom <= this.opts.minZoomLevel) return;
|
if (newZoom < this.opts.minZoomLevel) return;
|
||||||
if (newZoom >= this.opts.maxZoomLevel) return;
|
if (newZoom > this.opts.maxZoomLevel) return;
|
||||||
|
|
||||||
this.kp.camPos(curCamPos.sub(diff).add(newDiff));
|
this.kp.camPos(curCamPos.sub(diff).add(newDiff));
|
||||||
|
this.checkBounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
zoomToNoTweenAbs(newZoom, position) {
|
zoomToNoTweenAbs(newZoom, position) {
|
||||||
this.zoomLevel_NoTween = newZoom;
|
this.zoomLevel_NoTween = newZoom;
|
||||||
this.kp.camPos(position);
|
this.kp.camPos(position);
|
||||||
|
this.checkBounds();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
158
assets/scripts/KaplayMap/ui.js
Normal file
158
assets/scripts/KaplayMap/ui.js
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
export class UIManager {
|
||||||
|
ui;
|
||||||
|
map;
|
||||||
|
floormanager;
|
||||||
|
eventmanager;
|
||||||
|
|
||||||
|
uiElements = {};
|
||||||
|
floorsEmpty = true;
|
||||||
|
eventsEmpty = true;
|
||||||
|
|
||||||
|
constructor(ui, map) {
|
||||||
|
this.ui = ui;
|
||||||
|
this.map = map;
|
||||||
|
|
||||||
|
// Zoom
|
||||||
|
this.uiElements.zoomButtons = this.ui.querySelector("#zoom");
|
||||||
|
this.uiElements.zoomIn =
|
||||||
|
this.uiElements.zoomButtons.querySelector("#zoom-in");
|
||||||
|
this.uiElements.zoomOut =
|
||||||
|
this.uiElements.zoomButtons.querySelector("#zoom-out");
|
||||||
|
|
||||||
|
// Floors
|
||||||
|
this.uiElements.floors = this.ui.querySelector("#floors");
|
||||||
|
this.uiElements.floorButtons =
|
||||||
|
this.uiElements.floors.querySelector("#floor-buttons");
|
||||||
|
|
||||||
|
// Events
|
||||||
|
this.uiElements.eventsContainer =
|
||||||
|
this.ui.querySelector("#events-container");
|
||||||
|
this.uiElements.events =
|
||||||
|
this.uiElements.eventsContainer.querySelector("#events");
|
||||||
|
this.uiElements.eventList =
|
||||||
|
this.uiElements.events.querySelector("#event-list");
|
||||||
|
this.uiElements.eventsMinimized =
|
||||||
|
this.uiElements.eventsContainer.querySelector("#events-minimized");
|
||||||
|
|
||||||
|
// Loading
|
||||||
|
this.uiElements.loading = this.ui.querySelector("#loading");
|
||||||
|
|
||||||
|
// Zoom buttons
|
||||||
|
this.__initZoom();
|
||||||
|
|
||||||
|
this.__initEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
__initZoom() {
|
||||||
|
this.uiElements.zoomIn.addEventListener("click", () => {
|
||||||
|
this.map.zoomLevel += 1;
|
||||||
|
});
|
||||||
|
this.uiElements.zoomOut.addEventListener("click", () => {
|
||||||
|
this.map.zoomLevel -= 1;
|
||||||
|
});
|
||||||
|
this.map.kp.onUpdate(() => {
|
||||||
|
if (this.map.zoomLevelLimit > 0) {
|
||||||
|
this.uiElements.zoomIn.disabled = true;
|
||||||
|
this.uiElements.zoomOut.disabled = false;
|
||||||
|
} else if (this.map.zoomLevelLimit < 0) {
|
||||||
|
this.uiElements.zoomIn.disabled = false;
|
||||||
|
this.uiElements.zoomOut.disabled = true;
|
||||||
|
} else {
|
||||||
|
this.uiElements.zoomIn.disabled = false;
|
||||||
|
this.uiElements.zoomOut.disabled = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
__initEvents() {
|
||||||
|
const minimizeButton = this.uiElements.events.querySelector(
|
||||||
|
"#footer #footer-buttons #minimize"
|
||||||
|
);
|
||||||
|
minimizeButton.addEventListener("click", () => {
|
||||||
|
this.uiElements.eventsContainer.classList.add("minimized");
|
||||||
|
});
|
||||||
|
const maximizeButton =
|
||||||
|
this.uiElements.eventsMinimized.querySelector("#maximize");
|
||||||
|
maximizeButton.addEventListener("click", () => {
|
||||||
|
this.uiElements.eventsContainer.classList.remove("minimized");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
__updateEvents() {
|
||||||
|
// Remove all children
|
||||||
|
this.uiElements.eventList.replaceChildren();
|
||||||
|
|
||||||
|
console.log(this.eventmanager.events);
|
||||||
|
// Put them back
|
||||||
|
this.eventmanager.events.forEach((event, id) => {
|
||||||
|
const eventListContainer = document.createElement("details");
|
||||||
|
eventListContainer.classList.add("event-list-container");
|
||||||
|
eventListContainer.id = "event-" + id;
|
||||||
|
|
||||||
|
const eventListContainerSummary = document.createElement("summary");
|
||||||
|
eventListContainerSummary.textContent = event.name;
|
||||||
|
|
||||||
|
eventListContainer.appendChild(eventListContainerSummary);
|
||||||
|
|
||||||
|
const eventListContainerDescription = document.createElement("p");
|
||||||
|
eventListContainerDescription.textContent = event.description;
|
||||||
|
|
||||||
|
eventListContainer.appendChild(eventListContainerDescription);
|
||||||
|
|
||||||
|
this.uiElements.eventList.appendChild(eventListContainer);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.eventmanager.events.size < 1) {
|
||||||
|
this.uiElements.eventList.classList.add("empty");
|
||||||
|
this.eventsEmpty = true;
|
||||||
|
} else {
|
||||||
|
this.uiElements.eventList.classList.remove("empty");
|
||||||
|
this.eventsEmpty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(state) {
|
||||||
|
if (state) {
|
||||||
|
this.ui.classList.add("loading");
|
||||||
|
} else {
|
||||||
|
this.ui.classList.remove("loading");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__updateFloorsHard() {
|
||||||
|
// Remove all children
|
||||||
|
this.uiElements.floorButtons.replaceChildren();
|
||||||
|
|
||||||
|
// Put them back
|
||||||
|
this.floormanager.floors.forEach(({ name }, id) => {
|
||||||
|
const floorButton = document.createElement("button");
|
||||||
|
floorButton.textContent = name;
|
||||||
|
floorButton.classList.add("floor-button");
|
||||||
|
floorButton.id = "floor-" + id;
|
||||||
|
if (id === this.floormanager.currentFloor)
|
||||||
|
floorButton.classList.add("selected");
|
||||||
|
floorButton.addEventListener("click", () =>
|
||||||
|
this.floormanager.changeFloor(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.uiElements.floorButtons.appendChild(floorButton);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.floormanager.floors.size < 1) {
|
||||||
|
this.uiElements.floors.classList.add("empty");
|
||||||
|
this.floorsEmpty = true;
|
||||||
|
} else {
|
||||||
|
this.uiElements.floors.classList.remove("empty");
|
||||||
|
this.floorsEmpty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__updateFloorsSoft() {
|
||||||
|
this.floormanager.floors.forEach(({ name }, id) => {
|
||||||
|
const child = this.uiElements.floorButtons.querySelector("#floor-" + id);
|
||||||
|
if (id === this.floormanager.currentFloor)
|
||||||
|
child.classList.add("selected");
|
||||||
|
else child.classList.remove("selected");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,60 +0,0 @@
|
||||||
export function addZoomButtons(map) {
|
|
||||||
// Zoom buttons
|
|
||||||
const plus = map.kp.loadSprite(null, "/assets/images/plus.png", {
|
|
||||||
sliceX: 2,
|
|
||||||
});
|
|
||||||
|
|
||||||
const minus = map.kp.loadSprite(null, "/assets/images/minus.png", {
|
|
||||||
sliceX: 2,
|
|
||||||
});
|
|
||||||
|
|
||||||
const zoomIn = map.kp.make([
|
|
||||||
map.kp.sprite(plus),
|
|
||||||
map.kp.pos(16),
|
|
||||||
map.kp.scale(2),
|
|
||||||
map.kp.area(),
|
|
||||||
map.kp.opacity(1),
|
|
||||||
"ui",
|
|
||||||
]);
|
|
||||||
const zoomOut = map.kp.make([
|
|
||||||
map.kp.sprite(minus),
|
|
||||||
map.kp.pos(16, 42),
|
|
||||||
map.kp.scale(2),
|
|
||||||
map.kp.area(),
|
|
||||||
map.kp.opacity(1),
|
|
||||||
"ui",
|
|
||||||
]);
|
|
||||||
|
|
||||||
let ziw;
|
|
||||||
zoomIn.onClick(() => {
|
|
||||||
map.mouseMode = "ui";
|
|
||||||
map.zoomLevel += 1;
|
|
||||||
zoomIn.frame = 1;
|
|
||||||
if (ziw?.finish) ziw.finish();
|
|
||||||
ziw = map.kp.wait(0.25, () => (zoomIn.frame = 0));
|
|
||||||
|
|
||||||
map.clearMouseMode();
|
|
||||||
});
|
|
||||||
|
|
||||||
zoomIn.onUpdate(() => {
|
|
||||||
zoomIn.opacity = map.zoomLevelLimit > 0 ? 0.25 : 1;
|
|
||||||
});
|
|
||||||
|
|
||||||
let zow;
|
|
||||||
zoomOut.onClick(() => {
|
|
||||||
map.mouseMode = "ui";
|
|
||||||
map.zoomLevel -= 1;
|
|
||||||
zoomOut.frame = 1;
|
|
||||||
if (zow?.finish) zow.finish();
|
|
||||||
zow = map.kp.wait(0.25, () => (zoomOut.frame = 0));
|
|
||||||
|
|
||||||
map.clearMouseMode();
|
|
||||||
});
|
|
||||||
|
|
||||||
zoomOut.onUpdate(() => {
|
|
||||||
zoomOut.opacity = map.zoomLevelLimit < 0 ? 0.25 : 1;
|
|
||||||
});
|
|
||||||
|
|
||||||
map.uiLayer.add(zoomIn);
|
|
||||||
map.uiLayer.add(zoomOut);
|
|
||||||
}
|
|
File diff suppressed because one or more lines are too long
|
@ -1,8 +1,12 @@
|
||||||
import kaplay from "./modules/kaplay.js";
|
import kaplay from "./modules/kaplay.js";
|
||||||
import { KaplayMap } from "./KaplayMap/index.js";
|
import { KaplayMap } from "./KaplayMap/index.js";
|
||||||
import { addZoomButtons } from "./KaplayMap/zoom.js";
|
import { FloorManager } from "./KaplayMap/floors.js";
|
||||||
|
import { UIManager } from "./KaplayMap/ui.js";
|
||||||
|
import { GameObjManager } from "./KaplayMap/gameobj.js";
|
||||||
|
import { EventManager } from "./KaplayMap/events.js";
|
||||||
|
|
||||||
const map = document.querySelector("#map");
|
const map = document.querySelector("#map");
|
||||||
|
const mapUi = document.querySelector("#map-ui");
|
||||||
|
|
||||||
const kp = kaplay({
|
const kp = kaplay({
|
||||||
canvas: map,
|
canvas: map,
|
||||||
|
@ -21,8 +25,17 @@ const kaplaymap = new KaplayMap(kp, {});
|
||||||
|
|
||||||
kaplaymap.initGrid();
|
kaplaymap.initGrid();
|
||||||
|
|
||||||
addZoomButtons(kaplaymap);
|
// addZoomButtons(kaplaymap);
|
||||||
|
|
||||||
const bean = kp.loadBean();
|
const uimanager = new UIManager(mapUi, kaplaymap);
|
||||||
|
const gameobjmanager = new GameObjManager(kaplaymap);
|
||||||
|
const eventmanager = new EventManager(kaplaymap, uimanager, gameobjmanager);
|
||||||
|
const floormanager = new FloorManager(
|
||||||
|
kaplaymap,
|
||||||
|
uimanager,
|
||||||
|
gameobjmanager,
|
||||||
|
eventmanager,
|
||||||
|
"en_US"
|
||||||
|
);
|
||||||
|
|
||||||
kp.add([kp.sprite("bean"), kp.pos(kp.center())]);
|
floormanager.getFloors();
|
|
@ -1,11 +1,220 @@
|
||||||
|
@keyframes load {
|
||||||
|
to { transform: rotate(1turn) }
|
||||||
|
}
|
||||||
|
|
||||||
body, html {
|
body, html {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
background-color: #404040;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1.widget-heading {
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
letter-spacing: 0.25em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
/* border-bottom: 1px solid currentColor;
|
||||||
|
padding-bottom: 2px; */
|
||||||
|
}
|
||||||
|
|
||||||
|
p.widget-description {
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
/* border-bottom: 1px solid currentColor;
|
||||||
|
padding-bottom: 2px; */
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
color: inherit;
|
||||||
|
font: inherit;
|
||||||
|
padding: 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
height: 36px;
|
||||||
|
border: 1px solid #0008;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background-color: #0004;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:active {
|
||||||
|
background-color: #0008;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:disabled {
|
||||||
|
background-color: #8884;
|
||||||
}
|
}
|
||||||
|
|
||||||
#map {
|
#map {
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map-ui {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map-ui #zoom {
|
||||||
|
pointer-events: all;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
position: absolute;
|
||||||
|
padding: 8px;
|
||||||
|
top: 16px;
|
||||||
|
left: 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #202020;
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 0 8px 0 #0008;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map-ui #zoom .zoom-button {
|
||||||
|
width: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map-ui #floors {
|
||||||
|
pointer-events: all;
|
||||||
|
display: inline-block;
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: absolute;
|
||||||
|
padding: 8px;
|
||||||
|
top: 16px;
|
||||||
|
right: 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #202020;
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 0 8px 0 #0008;
|
||||||
|
transition: right 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map-ui #floors.empty {
|
||||||
|
right: -100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map-ui #floors #floor-buttons {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map-ui #floors #floor-buttons .floor-button {
|
||||||
|
text-align: left;
|
||||||
|
width: 200px;
|
||||||
|
padding: 12px;
|
||||||
|
height: unset;
|
||||||
|
}
|
||||||
|
#map-ui #floors #floor-buttons .floor-button.selected {
|
||||||
|
padding-left: 9px;
|
||||||
|
border: 1px solid #fff;
|
||||||
|
border-left: 4px solid #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map-ui #events-container {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
overflow: visible;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map-ui #events-container #events,
|
||||||
|
#map-ui #events-container #events-minimized {
|
||||||
|
pointer-events: all;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
padding: 8px;
|
||||||
|
bottom: 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #202020;
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 0 8px 0 #0008;
|
||||||
|
transition: left 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map-ui #events-container #events {
|
||||||
|
left: 16px;
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map-ui #events-container.minimized #events {
|
||||||
|
left: -100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map-ui #events-container #events-minimized {
|
||||||
|
left: -100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map-ui #events-container.minimized #events-minimized {
|
||||||
|
left: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map-ui #events-container #events #footer #footer-buttons {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map-ui #events-container #events #event-list {
|
||||||
|
min-height: 100px;
|
||||||
|
max-height: calc(50% - 16px);
|
||||||
|
margin: 8px 0;
|
||||||
|
padding: 8px;
|
||||||
|
background-color: #0002;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map-ui #events-container #events #event-list .event-list-container p {
|
||||||
|
margin: 2px 0;
|
||||||
|
white-space: pre-line;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map-ui #events-container #footer #footer-buttons button,
|
||||||
|
#map-ui #events-container #events-minimized button {
|
||||||
|
width: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map-ui #loading {
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
width: 96px;
|
||||||
|
height: 96px;
|
||||||
|
left: calc(50vw - 48px);
|
||||||
|
top: calc(50vh - 48px);
|
||||||
|
background-color: #2228;
|
||||||
|
border-radius: 8px;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map-ui.loading #loading {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map-ui #loading #loading-circle {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
top: 16px;
|
||||||
|
left: 16px;
|
||||||
|
background: conic-gradient(from 0deg,#fff0,#fff);
|
||||||
|
-webkit-mask-image: radial-gradient(circle, #fff0 0%, #fff0 33%, #ffff 33%, #ffff 66%, #fff0 66%, #fff0 100%);
|
||||||
|
mask-image: radial-gradient(circle, #fff0 0%, #fff0 33%, #ffff 33%, #ffff 66%, #fff0 66%, #fff0 100%);
|
||||||
|
animation: load 0.5s linear infinite;
|
||||||
}
|
}
|
|
@ -1,3 +1,3 @@
|
||||||
{
|
{
|
||||||
"ignore": [".gitignore", ".git/**", "data/**"]
|
"ignore": [".gitignore", ".git/**", "data/**", "assets/**", "pages/**"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,41 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<canvas id="map"></canvas>
|
<canvas id="map"></canvas>
|
||||||
|
<div id="map-ui" class="loading">
|
||||||
|
<div id="zoom">
|
||||||
|
<button class="zoom-button" id="zoom-in">+</button>
|
||||||
|
<button class="zoom-button" id="zoom-out">-</button>
|
||||||
|
</div>
|
||||||
|
<div id="floors" class="empty">
|
||||||
|
<h1 class="widget-heading">Floors</h1>
|
||||||
|
<div id="floor-buttons">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="events-container">
|
||||||
|
<div id="events">
|
||||||
|
<h1 class="widget-heading" id="room-name">Events</h1>
|
||||||
|
<p class="widget-description" id="room-description">Lorem ipsum dolor sit amet.</p>
|
||||||
|
<div id="event-list">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div id="footer">
|
||||||
|
<div id="footer-buttons">
|
||||||
|
<button id="minimize">_</button>
|
||||||
|
<button id="back" disabled>←</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="events-minimized">
|
||||||
|
<button id="maximize">+</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="loading">
|
||||||
|
<div id="loading-circle">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<script src="/assets/scripts/script.js" type="module"></script>
|
<script src="/assets/scripts/script.js" type="module"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -56,10 +56,13 @@ app.get('/data/:lang/events/:layer', async (req, res) => {
|
||||||
else
|
else
|
||||||
return res.status(404).send("Localization not found!");
|
return res.status(404).send("Localization not found!");
|
||||||
|
|
||||||
const clippedEvents = events.filter((event) => event.where.layer == req.params.layer);
|
const clippedEvents = events.filter((event) => event.where.layer == req.params.layer).map((event) => {
|
||||||
|
event.where = event.where.room;
|
||||||
|
return event;
|
||||||
|
});
|
||||||
|
|
||||||
// Merge events and localization
|
// Merge events and localization
|
||||||
const merged = events.map(event => {
|
const merged = clippedEvents.map(event => {
|
||||||
const localizationKey = l10n.__events[event.id];
|
const localizationKey = l10n.__events[event.id];
|
||||||
return {
|
return {
|
||||||
...event,
|
...event,
|
||||||
|
|
Loading…
Reference in a new issue