diff --git a/client/apps/game/src/three/managers/army-manager.ts b/client/apps/game/src/three/managers/army-manager.ts index a60ff8d80..1d166b952 100644 --- a/client/apps/game/src/three/managers/army-manager.ts +++ b/client/apps/game/src/three/managers/army-manager.ts @@ -5,11 +5,11 @@ import { ArmyModel } from "@/three/managers/army-model"; import { Biome } from "@/three/managers/biome"; import { LabelManager } from "@/three/managers/label-manager"; import { ArmyData, MovingArmyData, MovingLabelData, RenderChunkSize } from "@/types"; -import { calculateOffset, getHexForWorldPosition, getWorldPositionForHex } from "@/ui/utils/utils"; import { BiomeType, ContractAddress, FELT_CENTER, ID, orders } from "@bibliothecadao/eternum"; import { ArmySystemUpdate, Position, useAccountStore } from "@bibliothecadao/react"; import * as THREE from "three"; import { CSS2DObject } from "three/examples/jsm/renderers/CSS2DRenderer"; +import { calculateOffset, getHexForWorldPosition, getWorldPositionForHex } from "../utils"; const myColor = new THREE.Color(0, 1.5, 0); const neutralColor = new THREE.Color(0xffffff); diff --git a/client/apps/game/src/three/managers/battle-manager.ts b/client/apps/game/src/three/managers/battle-manager.ts index 932a9c35a..3abbc465c 100644 --- a/client/apps/game/src/three/managers/battle-manager.ts +++ b/client/apps/game/src/three/managers/battle-manager.ts @@ -1,10 +1,10 @@ import { GUIManager } from "@/three/helpers/gui-manager"; import { BattleModel } from "@/three/managers/battle-model"; import { LabelManager } from "@/three/managers/label-manager"; -import { getWorldPositionForHex } from "@/ui/utils/utils"; import { ID } from "@bibliothecadao/eternum"; import { BattleSystemUpdate, Position } from "@bibliothecadao/react"; import * as THREE from "three"; +import { getWorldPositionForHex } from "../utils"; const LABEL_PATH = "textures/battle_label.png"; diff --git a/client/apps/game/src/three/managers/highlight-hex-manager.ts b/client/apps/game/src/three/managers/highlight-hex-manager.ts index 5aecb6395..9bb8b971b 100644 --- a/client/apps/game/src/three/managers/highlight-hex-manager.ts +++ b/client/apps/game/src/three/managers/highlight-hex-manager.ts @@ -1,9 +1,9 @@ import { createHexagonShape } from "@/three/geometry/hexagon-geometry"; import { HEX_SIZE } from "@/three/scenes/constants"; import { highlightHexMaterial } from "@/three/shaders/highlight-hex-material"; -import { getWorldPositionForHex } from "@/ui/utils/utils"; import { HexPosition } from "@bibliothecadao/eternum"; import * as THREE from "three"; +import { getWorldPositionForHex } from "../utils"; export class HighlightHexManager { private highlightedHexes: THREE.Mesh[] = []; diff --git a/client/apps/game/src/three/managers/interactive-hex-manager.ts b/client/apps/game/src/three/managers/interactive-hex-manager.ts index a2609f0b2..c762adce8 100644 --- a/client/apps/game/src/three/managers/interactive-hex-manager.ts +++ b/client/apps/game/src/three/managers/interactive-hex-manager.ts @@ -2,8 +2,8 @@ import { createHexagonShape } from "@/three/geometry/hexagon-geometry"; import { Aura } from "@/three/managers/aura"; import { HEX_SIZE } from "@/three/scenes/constants"; import { interactiveHexMaterial } from "@/three/shaders/border-hex-material"; -import { getHexagonCoordinates, getWorldPositionForHex } from "@/ui/utils/utils"; import * as THREE from "three"; +import { getHexagonCoordinates, getWorldPositionForHex } from "../utils"; export class InteractiveHexManager { private scene: THREE.Scene; diff --git a/client/apps/game/src/three/managers/minimap.ts b/client/apps/game/src/three/managers/minimap.ts index f352a22e9..e3c89b570 100644 --- a/client/apps/game/src/three/managers/minimap.ts +++ b/client/apps/game/src/three/managers/minimap.ts @@ -4,11 +4,11 @@ import { type Biome, BIOME_COLORS } from "@/three/managers/biome"; import { type StructureManager } from "@/three/managers/structure-manager"; import type WorldmapScene from "@/three/scenes/worldmap"; import { FELT_CENTER } from "@/ui/config"; -import { getHexForWorldPosition } from "@/ui/utils/utils"; import { StructureType } from "@bibliothecadao/eternum"; import { useUIStore } from "@bibliothecadao/react"; import throttle from "lodash/throttle"; import type * as THREE from "three"; +import { getHexForWorldPosition } from "../utils"; const LABELS = { ARMY: "/textures/army_label.png", diff --git a/client/apps/game/src/three/managers/navigator.ts b/client/apps/game/src/three/managers/navigator.ts index de630da86..7485fed44 100644 --- a/client/apps/game/src/three/managers/navigator.ts +++ b/client/apps/game/src/three/managers/navigator.ts @@ -1,10 +1,10 @@ import { gltfLoader } from "@/three/helpers/utils"; -import { calculateDistanceInHexes, getWorldPositionForHex } from "@/ui/utils/utils"; import { type HexPosition } from "@bibliothecadao/eternum"; import throttle from "lodash/throttle"; import * as THREE from "three"; import { CSS2DObject } from "three-stdlib"; import { type MapControls } from "three/examples/jsm/controls/MapControls"; +import { calculateDistanceInHexes, getWorldPositionForHex } from "../utils"; const dummyObject = new THREE.Object3D(); const arrowOffset = new THREE.Vector3(0, 3, 0); diff --git a/client/apps/game/src/three/managers/structure-manager.ts b/client/apps/game/src/three/managers/structure-manager.ts index 665b639ee..ec2b7bac5 100644 --- a/client/apps/game/src/three/managers/structure-manager.ts +++ b/client/apps/game/src/three/managers/structure-manager.ts @@ -4,10 +4,10 @@ import { LabelManager } from "@/three/managers/label-manager"; import { StructureLabelPaths, StructureModelPaths } from "@/three/scenes/constants"; import { RenderChunkSize, StructureInfo } from "@/types"; import { FELT_CENTER } from "@/ui/config"; -import { getWorldPositionForHex } from "@/ui/utils/utils"; import { ID, StructureType } from "@bibliothecadao/eternum"; import { StructureSystemUpdate, useAccountStore } from "@bibliothecadao/react"; import * as THREE from "three"; +import { getWorldPositionForHex } from "../utils"; const neutralColor = new THREE.Color(0xffffff); const myColor = new THREE.Color("lime"); diff --git a/client/apps/game/src/three/scenes/hexagon-scene.ts b/client/apps/game/src/three/scenes/hexagon-scene.ts index f3eaed4d5..61082cf13 100644 --- a/client/apps/game/src/three/scenes/hexagon-scene.ts +++ b/client/apps/game/src/three/scenes/hexagon-scene.ts @@ -11,7 +11,6 @@ import { HEX_SIZE, biomeModelPaths } from "@/three/scenes/constants"; import { SystemManager } from "@/three/systems/system-manager"; import { type SceneName } from "@/types"; import { GRAPHICS_SETTING, GraphicsSettings, IS_FLAT_MODE } from "@/ui/config"; -import { getWorldPositionForHex } from "@/ui/utils/utils"; import { type HexPosition } from "@bibliothecadao/eternum"; import { LeftView, RightView, useUIStore, type AppStore, type SetupResult } from "@bibliothecadao/react"; import gsap from "gsap"; @@ -19,6 +18,7 @@ import throttle from "lodash/throttle"; import * as THREE from "three"; import { type MapControls } from "three/examples/jsm/controls/MapControls"; import { env } from "../../../env"; +import { getWorldPositionForHex } from "../utils"; export abstract class HexagonScene { protected scene!: THREE.Scene; protected camera!: THREE.PerspectiveCamera; diff --git a/client/apps/game/src/three/scenes/hexception.tsx b/client/apps/game/src/three/scenes/hexception.tsx index 4e488b6d6..3467eeb1e 100644 --- a/client/apps/game/src/three/scenes/hexception.tsx +++ b/client/apps/game/src/three/scenes/hexception.tsx @@ -9,7 +9,6 @@ import { playBuildingSound } from "@/three/sound/utils"; import { SceneName } from "@/types"; import { IS_FLAT_MODE } from "@/ui/config"; import { ResourceIcon } from "@/ui/elements/resource-icon"; -import { getEntityIdFromKeys, getHexForWorldPosition, getWorldPositionForHex } from "@/ui/utils/utils"; import { BUILDINGS_CENTER, BuildingType, @@ -21,6 +20,7 @@ import { StructureType, TileManager, findResourceById, + getEntityIdFromKeys, getNeighborHexes, } from "@bibliothecadao/eternum"; import { @@ -38,6 +38,7 @@ import clsx from "clsx"; import * as THREE from "three"; import { CSS2DObject } from "three-stdlib"; import { MapControls } from "three/examples/jsm/controls/MapControls"; +import { getHexForWorldPosition, getWorldPositionForHex } from "../utils"; import { HEX_SIZE, MinesMaterialsParams, diff --git a/client/apps/game/src/three/scenes/worldmap.ts b/client/apps/game/src/three/scenes/worldmap.ts index de3dc07cb..65cdec9a2 100644 --- a/client/apps/game/src/three/scenes/worldmap.ts +++ b/client/apps/game/src/three/scenes/worldmap.ts @@ -9,11 +9,9 @@ import { SceneManager } from "@/three/scene-manager"; import { HEX_SIZE, PREVIEW_BUILD_COLOR_INVALID } from "@/three/scenes/constants"; import { HexagonScene } from "@/three/scenes/hexagon-scene"; import { playSound } from "@/three/sound/utils"; -import { ArmySystemUpdate, TileSystemUpdate } from "@bibliothecadao/react"; import { SceneName } from "@/types"; import { FELT_CENTER, IS_FLAT_MODE, IS_MOBILE } from "@/ui/config"; import { UNDEFINED_STRUCTURE_ENTITY_ID } from "@/ui/constants"; -import { getWorldPositionForHex } from "@/ui/utils/utils"; import { ArmyMovementManager, BiomeType, @@ -25,10 +23,12 @@ import { getNeighborOffsets, } from "@bibliothecadao/eternum"; import { + ArmySystemUpdate, LeftView, LoadingStateKey, Position, SetupResult, + TileSystemUpdate, soundSelector, useAccountStore, useUIStore, @@ -39,6 +39,7 @@ import throttle from "lodash/throttle"; import * as THREE from "three"; import { Raycaster } from "three"; import { MapControls } from "three/examples/jsm/controls/MapControls"; +import { getWorldPositionForHex } from "../utils"; export default class WorldmapScene extends HexagonScene { private biome!: Biome; diff --git a/client/apps/game/src/three/utils.ts b/client/apps/game/src/three/utils.ts new file mode 100644 index 000000000..ca2bd5a26 --- /dev/null +++ b/client/apps/game/src/three/utils.ts @@ -0,0 +1,83 @@ +import { calculateDistance, HexPosition, Position } from "@bibliothecadao/eternum"; +import * as THREE from "three"; +import { HEX_SIZE } from "./scenes/constants"; + +export const getHexagonCoordinates = ( + instancedMesh: THREE.InstancedMesh, + instanceId: number, +): { hexCoords: HexPosition; position: THREE.Vector3 } => { + const matrix = new THREE.Matrix4(); + instancedMesh.getMatrixAt(instanceId, matrix); + const position = new THREE.Vector3(); + matrix.decompose(position, new THREE.Quaternion(), new THREE.Vector3()); + + const hexCoords = getHexForWorldPosition(position); + + return { hexCoords, position }; +}; + +export const getWorldPositionForHex = (hexCoords: HexPosition, flat: boolean = true) => { + const hexRadius = HEX_SIZE; + const hexHeight = hexRadius * 2; + const hexWidth = Math.sqrt(3) * hexRadius; + const vertDist = hexHeight * 0.75; + const horizDist = hexWidth; + + const col = hexCoords.col; + const row = hexCoords.row; + const rowOffset = ((row % 2) * Math.sign(row) * horizDist) / 2; + const x = col * horizDist - rowOffset; + const z = row * vertDist; + const y = flat ? 0 : pseudoRandom(x, z) * 2; + return new THREE.Vector3(x, y, z); +}; + +export const getHexForWorldPosition = (worldPosition: { x: number; y: number; z: number }): HexPosition => { + const hexRadius = HEX_SIZE; + const hexHeight = hexRadius * 2; + const hexWidth = Math.sqrt(3) * hexRadius; + const vertDist = hexHeight * 0.75; + const horizDist = hexWidth; + + const row = Math.round(worldPosition.z / vertDist); + // hexception offsets hack + const rowOffset = ((row % 2) * Math.sign(row) * horizDist) / 2; + const col = Math.round((worldPosition.x + rowOffset) / horizDist); + + return { + col, + row, + }; +}; + +export const calculateDistanceInHexes = (start: Position, destination: Position): number | undefined => { + const distance = calculateDistance(start, destination); + if (distance) { + return Math.round(distance / HEX_SIZE / 2); + } + return undefined; +}; + +export const calculateOffset = (index: number, total: number, radius: number) => { + if (total === 1) return { x: 0, y: 0 }; + + const angleIncrement = (2 * Math.PI) / 6; // Maximum 6 points on the circumference for the first layer + let angle = angleIncrement * (index % 6); + let offsetRadius = radius; + + if (index >= 6) { + // Adjustments for more than 6 armies, placing them in another layer + offsetRadius += 0.5; // Increase radius for each new layer + angle += angleIncrement / 2; // Offset angle to interleave with previous layer + } + + return { + x: offsetRadius * Math.cos(angle), + z: offsetRadius * Math.sin(angle), + }; +}; + +const pseudoRandom = (x: number, y: number) => { + const n = Math.sin(x * 12.9898 + y * 78.233) * 43758.5453123; + return n - Math.floor(n); +}; diff --git a/client/apps/game/src/ui/utils/utils.ts b/client/apps/game/src/ui/utils/utils.ts index 6007602c6..73204cd23 100644 --- a/client/apps/game/src/ui/utils/utils.ts +++ b/client/apps/game/src/ui/utils/utils.ts @@ -1,18 +1,13 @@ -import { HEX_SIZE } from "@/three/scenes/constants"; import { SortInterface } from "@/ui/elements/sort-button"; import { - calculateDistance, ContractAddress, EternumGlobalConfig, ResourceCost, ResourcesIds, toHexString, - type HexPosition, - type Position, type Resource, } from "@bibliothecadao/eternum"; import { getEntityIdFromKeys } from "@dojoengine/utils"; -import * as THREE from "three"; import { env } from "../../../env"; export { getEntityIdFromKeys }; @@ -88,86 +83,6 @@ export function addressToNumber(address: string) { return result < 10 ? `0${result}` : result.toString(); } -export const getHexagonCoordinates = ( - instancedMesh: THREE.InstancedMesh, - instanceId: number, -): { hexCoords: HexPosition; position: THREE.Vector3 } => { - const matrix = new THREE.Matrix4(); - instancedMesh.getMatrixAt(instanceId, matrix); - const position = new THREE.Vector3(); - matrix.decompose(position, new THREE.Quaternion(), new THREE.Vector3()); - - const hexCoords = getHexForWorldPosition(position); - - return { hexCoords, position }; -}; - -export const getWorldPositionForHex = (hexCoords: HexPosition, flat: boolean = true) => { - const hexRadius = HEX_SIZE; - const hexHeight = hexRadius * 2; - const hexWidth = Math.sqrt(3) * hexRadius; - const vertDist = hexHeight * 0.75; - const horizDist = hexWidth; - - const col = hexCoords.col; - const row = hexCoords.row; - const rowOffset = ((row % 2) * Math.sign(row) * horizDist) / 2; - const x = col * horizDist - rowOffset; - const z = row * vertDist; - const y = flat ? 0 : pseudoRandom(x, z) * 2; - return new THREE.Vector3(x, y, z); -}; - -export const getHexForWorldPosition = (worldPosition: { x: number; y: number; z: number }): HexPosition => { - const hexRadius = HEX_SIZE; - const hexHeight = hexRadius * 2; - const hexWidth = Math.sqrt(3) * hexRadius; - const vertDist = hexHeight * 0.75; - const horizDist = hexWidth; - - const row = Math.round(worldPosition.z / vertDist); - // hexception offsets hack - const rowOffset = ((row % 2) * Math.sign(row) * horizDist) / 2; - const col = Math.round((worldPosition.x + rowOffset) / horizDist); - - return { - col, - row, - }; -}; - -export const calculateDistanceInHexes = (start: Position, destination: Position): number | undefined => { - const distance = calculateDistance(start, destination); - if (distance) { - return Math.round(distance / HEX_SIZE / 2); - } - return undefined; -}; - -export const calculateOffset = (index: number, total: number, radius: number) => { - if (total === 1) return { x: 0, y: 0 }; - - const angleIncrement = (2 * Math.PI) / 6; // Maximum 6 points on the circumference for the first layer - let angle = angleIncrement * (index % 6); - let offsetRadius = radius; - - if (index >= 6) { - // Adjustments for more than 6 armies, placing them in another layer - offsetRadius += 0.5; // Increase radius for each new layer - angle += angleIncrement / 2; // Offset angle to interleave with previous layer - } - - return { - x: offsetRadius * Math.cos(angle), - z: offsetRadius * Math.sin(angle), - }; -}; - -const pseudoRandom = (x: number, y: number) => { - const n = Math.sin(x * 12.9898 + y * 78.233) * 43758.5453123; - return n - Math.floor(n); -}; - export const copyPlayerAddressToClipboard = (address: ContractAddress, name: string, hex: boolean = false) => { navigator.clipboard .writeText(hex ? toHexString(address) : address.toString())