diff --git a/common/webapp/src/components/Menu/MarkerItem.vue b/common/webapp/src/components/Menu/MarkerItem.vue index 12e88300c..1a78f85da 100644 --- a/common/webapp/src/components/Menu/MarkerItem.vue +++ b/common/webapp/src/components/Menu/MarkerItem.vue @@ -75,7 +75,7 @@ export default { if (this.marker.type === "player") { - if (this.marker.foreign) { + if (this.marker.foreign || this.marker.outOfBounds) { let matchingMap = await this.$bluemap.findPlayerMap(this.marker.playerUuid); if (!matchingMap) return; diff --git a/common/webapp/src/js/BlueMapApp.js b/common/webapp/src/js/BlueMapApp.js index 49beeed46..d86a4e6f5 100644 --- a/common/webapp/src/js/BlueMapApp.js +++ b/common/webapp/src/js/BlueMapApp.js @@ -202,7 +202,7 @@ export class BlueMapApp { let player = this.mapViewer.controlsManager.controls?.data.followingPlayer; if (this.mapViewer.map && player) { - if (player.foreign){ + if (player.foreign || player.outOfBounds) { let matchingMap = await this.findPlayerMap(player.playerUuid) if (matchingMap) { @@ -228,10 +228,20 @@ export class BlueMapApp { for (let map of this.maps) { let playerData = await this.loadPlayerData(map); if (!Array.isArray(playerData.players)) continue; + const [minX, maxX] = map.data?.bounds?.x ?? []; + const [minY, maxY] = map.data?.bounds?.y ?? []; + const [minZ, maxZ] = map.data?.bounds?.z ?? []; for (let p of playerData.players) { if (p.uuid === playerUuid && !p.foreign) { - matchingMap = map; - break; + const pos = p.position || {}; + const { x, y, z } = pos; + // if any coordinate is missing or within its respective map bounds, consider it in bounds + if ((x == null || ((minX == null || x >= minX) && (maxX == null || x <= maxX))) && + (y == null || ((minY == null || y >= minY) && (maxY == null || y <= maxY))) && + (z == null || ((minZ == null || z >= minZ) && (maxZ == null || z <= maxZ)))) { + matchingMap = map; + break; + } } } diff --git a/common/webapp/src/js/map/Map.js b/common/webapp/src/js/map/Map.js index e0fbad7a4..c010d9228 100644 --- a/common/webapp/src/js/map/Map.js +++ b/common/webapp/src/js/map/Map.js @@ -65,6 +65,11 @@ export class Map { texturesUrl: mapDataRoot + "/textures.json", name: id, startPos: {x: 0, z: 0}, + bounds: { + x: null, + y: null, + z: null + }, skyColor: new Color(), voidColor: new Color(0, 0, 0), ambientLight: 0, @@ -169,6 +174,16 @@ export class Map { this.data.startPos = {...this.data.startPos, ...vecArrToObj(worldSettings.startPos, true)}; + if (worldSettings.bounds) { + const currentBounds = this.data.bounds; + ['x', 'y', 'z'].forEach(coordinate => { + const boundsRange = worldSettings.bounds[coordinate]; + if (Array.isArray(boundsRange) && boundsRange.length === 2) { + currentBounds[coordinate] = [...boundsRange]; + } + }); + } + if (worldSettings.skyColor && worldSettings.skyColor.length >= 3) { this.data.skyColor.setRGB( worldSettings.skyColor[0], diff --git a/common/webapp/src/js/markers/PlayerMarker.js b/common/webapp/src/js/markers/PlayerMarker.js index d8d806425..bd87accab 100644 --- a/common/webapp/src/js/markers/PlayerMarker.js +++ b/common/webapp/src/js/markers/PlayerMarker.js @@ -65,6 +65,8 @@ export class PlayerMarker extends Marker { this.playerHeadElement.src = "assets/steve.png"; }, {once: true}); + this.map = window.bluemap.mapViewer.map; + this.add(this.elementObject); } @@ -94,6 +96,7 @@ export class PlayerMarker extends Marker { * uuid: string, * name: string, * foreign: boolean, + * outOfBounds: boolean, * position: {x: number, y: number, z: number}, * rotation: {yaw: number, pitch: number, roll: number} * }} @@ -155,6 +158,22 @@ export class PlayerMarker extends Marker { // update world this.data.foreign = markerData.foreign; + + // update outOfBounds based on current world bounds + if (this.map && this.map.data && this.map.data.bounds) { + const bounds = this.map.data.bounds; + const currentPos = this.position; + this.data.outOfBounds = ( + currentPos.x < bounds.x[0] || + currentPos.x > bounds.x[1] || + currentPos.y < bounds.y[0] || + currentPos.y > bounds.y[1] || + currentPos.z < bounds.z[0] || + currentPos.z > bounds.z[1] + ); + } else { + this.data.outOfBounds = false; + } } dispose() { diff --git a/common/webapp/src/js/markers/PlayerMarkerSet.js b/common/webapp/src/js/markers/PlayerMarkerSet.js index 1883358c3..8a0369942 100644 --- a/common/webapp/src/js/markers/PlayerMarkerSet.js +++ b/common/webapp/src/js/markers/PlayerMarkerSet.js @@ -85,8 +85,8 @@ export class PlayerMarkerSet extends MarkerSet { // update marker.updateFromData(markerData); - // hide if from different world - marker.visible = !markerData.foreign; + // hide if from different world or out of bounds + marker.visible = !markerData.foreign && !marker.data.outOfBounds; return marker; } diff --git a/core/src/main/java/de/bluecolored/bluemap/core/map/MapSettingsSerializer.java b/core/src/main/java/de/bluecolored/bluemap/core/map/MapSettingsSerializer.java index 8e59ed7bb..bc23afc74 100644 --- a/core/src/main/java/de/bluecolored/bluemap/core/map/MapSettingsSerializer.java +++ b/core/src/main/java/de/bluecolored/bluemap/core/map/MapSettingsSerializer.java @@ -25,6 +25,7 @@ package de.bluecolored.bluemap.core.map; import com.flowpowered.math.vector.Vector2i; +import com.flowpowered.math.vector.Vector3i; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; @@ -71,6 +72,15 @@ public JsonElement serialize(BmMap map, Type typeOfSrc, JsonSerializationContext .orElse(map.getWorld().getSpawnPoint().toVector2(true)); root.add("startPos", context.serialize(startPos)); + // bounds + JsonObject bounds = new JsonObject(); + Vector3i min = map.getMapSettings().getMinPos(); + Vector3i max = map.getMapSettings().getMaxPos(); + bounds.add("x", context.serialize(new int[] { min.getX(), max.getX() })); + bounds.add("y", context.serialize(new int[] { min.getY(), max.getY() })); + bounds.add("z", context.serialize(new int[] { min.getZ(), max.getZ() })); + root.add("bounds", bounds); + // skyColor Color skyColor = new Color().parse(map.getMapSettings().getSkyColor()); root.add("skyColor", context.serialize(skyColor));