Skip to content

Commit

Permalink
Fix/models (#1191)
Browse files Browse the repository at this point in the history
* Load structure models

* Fix explore if no capacity

* Remove biome models if struct on tile

* rebase

* fix knip
  • Loading branch information
bob0005 authored Aug 11, 2024
1 parent 7c80f13 commit 45539a8
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 47 deletions.
26 changes: 26 additions & 0 deletions client/src/dojo/modelManager/ArmyMovementManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ export class ArmyMovementManager {
private positionModel: OverridableComponent<ClientComponents["Position"]["schema"]>;
private armyModel: Component<ClientComponents["Army"]["schema"]>;
private ownerModel: Component<ClientComponents["Owner"]["schema"]>;
private capacityModel: Component<ClientComponents["Capacity"]["schema"]>;
private weightModel: Component<ClientComponents["Weight"]["schema"]>;
private entityOwnerModel: Component<ClientComponents["EntityOwner"]["schema"]>;
private staminaConfigModel: Component<ClientComponents["StaminaConfig"]["schema"]>;
private entity: Entity;
Expand All @@ -91,6 +93,8 @@ export class ArmyMovementManager {
Position,
Army,
Owner,
Capacity,
Weight,
EntityOwner,
StaminaConfig,
Production,
Expand All @@ -102,6 +106,8 @@ export class ArmyMovementManager {
this.positionModel = Position;
this.armyModel = Army;
this.ownerModel = Owner;
this.capacityModel = Capacity;
this.weightModel = Weight;
this.entityOwnerModel = EntityOwner;
this.staminaConfigModel = StaminaConfig;
this.entity = getEntityIdFromKeys([BigInt(entityId)]);
Expand Down Expand Up @@ -189,6 +195,10 @@ export class ArmyMovementManager {
return false;
}

if (this._getArmyRemainingCapacity() < EternumGlobalConfig.exploration.reward) {
return false;
}

return true;
}

Expand Down Expand Up @@ -395,4 +405,20 @@ export class ArmyMovementManager {
this._travelToHex(path);
}
};

private _getArmyRemainingCapacity = () => {
const armyCapacity = getComponentValue(this.capacityModel, this.entity);
const armyWeight = getComponentValue(this.weightModel, this.entity);
const armyEntity = getComponentValue(this.armyModel, this.entity);

const knights = armyEntity?.troops.knight_count || 0n;
const crossbowmen = armyEntity?.troops.crossbowman_count || 0n;
const paladins = armyEntity?.troops.paladin_count || 0n;
const troopQty = (knights + crossbowmen + paladins) / BigInt(EternumGlobalConfig.resources.resourcePrecision);

const capacity = armyCapacity?.weight_gram || 0n;
const weight = (armyWeight?.value || 0n) / BigInt(EternumGlobalConfig.resources.resourcePrecision);

return capacity * troopQty - weight;
};
}
138 changes: 95 additions & 43 deletions client/src/three/components/StructureManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,85 +5,137 @@ import { LabelManager } from "./LabelManager";
import { getWorldPositionForHex } from "@/ui/utils/utils";
import { StructureSystemUpdate } from "../systems/types";
import { FELT_CENTER } from "@/ui/config";
import { ID } from "@bibliothecadao/eternum";
import { ID, StructureType } from "@bibliothecadao/eternum";

const neutralColor = new THREE.Color(0xffffff);
const myColor = new THREE.Color("lime");

const MODEL_PATH = "models/buildings/castle2.glb";
const LABEL_PATH = "textures/realm_label.png";
const StructureModelPaths: Record<StructureType, string> = {
[StructureType.Realm]: "models/buildings/castle2.glb",
[StructureType.Hyperstructure]: "models/buildings/farm.glb", // USING PLACEHOLDER MODEL
// [StructureType.Hyperstructure]: "models/buildings/hyperstructure-half-transformed.glb",
// [StructureType.Hyperstructure]: "models/buildings/hyperstructure.glb",
[StructureType.Bank]: "models/buildings/bank.glb",
[StructureType.FragmentMine]: "models/buildings/mine.glb",
[StructureType.Settlement]: "",
};

const StructureLabelPaths: Record<StructureType, string> = {
[StructureType.Realm]: "textures/realm_label.png",
[StructureType.Hyperstructure]: "textures/hyper_label.png",
[StructureType.FragmentMine]: "textures/shard_label.png",
[StructureType.Bank]: "",
[StructureType.Settlement]: "",
};

const MAX_INSTANCES = 1000;

export class StructureManager {
private scene: THREE.Scene;
private instancedModel: InstancedModel | undefined;
private structureModels: Map<StructureType, InstancedModel> = new Map();
private labelManagers: Map<StructureType, LabelManager> = new Map();
private dummy: THREE.Object3D = new THREE.Object3D();
private isLoaded: boolean = false;
loadPromise: Promise<void>;
modelLoadPromises: Promise<void>[] = [];
structures: Structures = new Structures();
private labelManager: LabelManager;
structuresMap: Map<number, Set<number>> = new Map();
totalStructures: number = 0;

constructor(scene: THREE.Scene) {
this.scene = scene;
this.labelManager = new LabelManager(LABEL_PATH);

this.loadPromise = new Promise<void>((resolve, reject) => {
const loader = new GLTFLoader();
loader.load(
MODEL_PATH,
(gltf) => {
const model = gltf.scene as THREE.Group;
this.instancedModel = new InstancedModel(model, MAX_INSTANCES);
this.instancedModel.setCount(0);
this.scene.add(this.instancedModel.group);
this.isLoaded = true;
resolve();
},
undefined,
(error) => {
console.error("An error occurred while loading the model:", error);
reject(error);
},
);
});
this.loadModels();
}

public async loadModels() {
const loader = new GLTFLoader();

for (const [key, modelPath] of Object.entries(StructureModelPaths)) {
const structureType = StructureType[key as keyof typeof StructureType];

if (structureType === undefined) continue;
if (!modelPath) continue;

const loadPromise = new Promise<void>((resolve, reject) => {
loader.load(
modelPath,
(gltf) => {
const model = gltf.scene as THREE.Group;

const instancedModel = new InstancedModel(model, MAX_INSTANCES);
instancedModel.setCount(0);
this.structureModels.set(structureType, instancedModel);
this.scene.add(instancedModel.group);

const labelManager = new LabelManager(
StructureLabelPaths[StructureType[structureType] as unknown as StructureType],
);
this.labelManagers.set(structureType, labelManager);
resolve();
},
undefined,
(error) => {
console.error(`An error occurred while loading the ${StructureType[structureType as any]} model:`, error);
reject(error);
},
);
});
this.modelLoadPromises.push(loadPromise);
}
}

async onUpdate(update: StructureSystemUpdate) {
await this.loadPromise;
const { entityId, hexCoords, isMine } = update;
await Promise.all(this.modelLoadPromises);

const { entityId, hexCoords, isMine, structureType } = update;
const normalizedCoord = { col: hexCoords.col - FELT_CENTER, row: hexCoords.row - FELT_CENTER };
const position = getWorldPositionForHex(normalizedCoord);
this.dummy.position.copy(position);
this.dummy.updateMatrix();

if (!this.structuresMap.has(normalizedCoord.col)) {
this.structuresMap.set(normalizedCoord.col, new Set());
}
if (!this.structuresMap.get(normalizedCoord.col)!.has(normalizedCoord.row)) {
this.structuresMap.get(normalizedCoord.col)!.add(normalizedCoord.row);
this.totalStructures++;
}

const key = StructureType[structureType] as unknown as StructureType;

// Ensure the structure is added and get its index
const index = this.structures.addStructure(entityId);
const index = this.structures.addStructure(entityId, key);

if (this.instancedModel) {
this.instancedModel.setMatrixAt(index, this.dummy.matrix);
this.instancedModel.setCount(this.structures.counter); // Set the count to the current number of structures
if (this.structureModels) {
const modelType = this.structureModels.get(key);
modelType?.setMatrixAt(index, this.dummy.matrix);
modelType?.setCount(this.structures.getCountForType(key)); // Set the count to the current number of structures

// Add label on top of the structure with appropriate color
const labelColor = isMine ? myColor : neutralColor;
const label = this.labelManager.createLabel(position as any, labelColor);
this.scene.add(label);
const label = this.labelManagers.get(key)?.createLabel(position as any, labelColor);
this.scene.add(label!);
}
}
}

class Structures {
private structures: Map<number, number> = new Map();
counter: number = 0;
private structures: Map<ID, { index: number; structureType: StructureType }> = new Map();
private counters: Map<StructureType, number> = new Map();

addStructure(entityId: ID, structureType: StructureType): number {
const index = this.counters.get(structureType) || 0;

addStructure(entityId: ID): number {
if (!this.structures.has(entityId)) {
this.structures.set(entityId, this.counter);
this.counter++;
this.structures.set(entityId, { index, structureType });
this.counters.set(structureType, index + 1);
}
return this.structures.get(entityId)!;
return this.structures.get(entityId)!.index;
}

getStructureIndex(entityId: ID) {
return this.structures.get(entityId);
return this.structures.get(entityId)?.index;
}

getCountForType(structureType: StructureType): number {
return this.counters.get(structureType) || 0;
}
}
25 changes: 21 additions & 4 deletions client/src/three/scenes/Worldmap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ export default class WorldmapScene extends HexagonScene {
height: 30,
};

private totalStructures: number = 0;

private currentChunk: string = "null";

// Store
Expand All @@ -41,7 +43,6 @@ export default class WorldmapScene extends HexagonScene {
private structureManager: StructureManager;
private battleManager: BattleManager;
private exploredTiles: Map<number, Set<number>> = new Map();
private structures: Map<number, Set<number>> = new Map();
private battles: Map<number, Set<number>> = new Map();

private cachedMatrices: Map<string, Map<string, { matrices: THREE.InstancedBufferAttribute; count: number }>> =
Expand Down Expand Up @@ -75,9 +76,25 @@ export default class WorldmapScene extends HexagonScene {
this.battleManager = new BattleManager(this.scene);

this.systemManager.Army.onUpdate((value) => this.armyManager.onUpdate(value));
this.systemManager.Structure.onUpdate((value) => this.structureManager.onUpdate(value));
this.systemManager.Battle.onUpdate((value) => this.battleManager.onUpdate(value));
this.systemManager.Tile.onUpdate((value) => this.updateExploredHex(value));
this.systemManager.Structure.onUpdate((value) => {
this.structureManager.onUpdate(value);
if (this.totalStructures !== this.structureManager.totalStructures) {
const { col, row } = value.hexCoords;
const { chunkX, chunkZ } = this.worldToChunkCoordinates(
getWorldPositionForHex({ col: col - FELT_CENTER, row: row - FELT_CENTER }).x,
getWorldPositionForHex({ col: col - FELT_CENTER, row: row - FELT_CENTER }).z,
);
const startRow = chunkZ * this.chunkSize;
const startCol = chunkX * this.chunkSize;

this.totalStructures = this.structureManager.totalStructures;

this.removeCachedMatricesForChunk(startRow, startCol);
this.updateHexagonGrid(startRow, startCol, this.renderChunkSize.height, this.renderChunkSize.width);
}
});

this.inputManager.addListener(
"mousemove",
Expand Down Expand Up @@ -176,7 +193,7 @@ export default class WorldmapScene extends HexagonScene {
const pos = getWorldPositionForHex({ row, col });
dummy.position.copy(pos);

const isStructure = this.structures.get(col)?.has(row) || false;
const isStructure = this.structureManager.structuresMap.get(col)?.has(row) || false;

if (isStructure) {
dummy.scale.set(0, 0, 0);
Expand Down Expand Up @@ -291,7 +308,7 @@ export default class WorldmapScene extends HexagonScene {
const pos = getWorldPositionForHex({ row: globalRow, col: globalCol });
dummy.position.copy(pos);

const isStructure = this.structures.get(col)?.has(row) || false;
const isStructure = this.structureManager.structuresMap.get(globalCol)?.has(globalRow) || false;
const isBattle = this.battles.get(globalCol)?.has(globalRow) || false;
const isExplored = this.exploredTiles.get(globalCol)?.has(globalRow) || false;
if (isStructure || !isExplored || !isBattle) {
Expand Down

0 comments on commit 45539a8

Please sign in to comment.