Skip to content

Commit 798c4be

Browse files
authored
feat(voxel-renderer): implement engine Logger (#212)
1 parent cca1c8b commit 798c4be

File tree

4 files changed

+85
-19
lines changed

4 files changed

+85
-19
lines changed

.changeset/wise-cobras-see.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@jolly-pixel/voxel.renderer": minor
3+
---
4+
5+
Implement Logger into VoxelRenderer

packages/voxel-renderer/examples/scripts/demo-physics.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ const runtime = new Runtime(canvas, {
4141
});
4242

4343
const { world } = runtime;
44+
world.logger.setLevel("debug");
45+
world.logger.enableNamespace("*");
4446

4547
const scene = world.sceneManager.getSource();
4648
scene.background = new THREE.Color("#87ceeb");

packages/voxel-renderer/src/VoxelRenderer.ts

Lines changed: 74 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
import * as THREE from "three";
33
import {
44
Actor,
5-
ActorComponent
5+
ActorComponent,
6+
Systems
67
} from "@jolly-pixel/engine";
78

89
// Import Internal Dependencies
@@ -124,6 +125,12 @@ export interface VoxelRendererOptions {
124125
* @default 0.1
125126
*/
126127
alphaTest?: number;
128+
129+
/**
130+
* Optional logger instance for debug output.
131+
* Uses the engine's default logger if not provided.
132+
*/
133+
logger?: Systems.Logger;
127134
}
128135

129136
/**
@@ -156,11 +163,16 @@ export class VoxelRenderer extends ActorComponent {
156163
/**
157164
* One material per tileset ID. Created lazily; disposed on tileset reload or destroy.
158165
*/
159-
#materials = new Map<string, THREE.MeshLambertMaterial | THREE.MeshStandardMaterial>();
166+
#materials = new Map<
167+
string,
168+
THREE.MeshLambertMaterial | THREE.MeshStandardMaterial
169+
>();
160170
#materialCustomizer?: MaterialCustomizerFn;
161171
#materialType: "lambert" | "standard";
162172
#alphaTest: number;
163173

174+
#logger: Systems.Logger;
175+
164176
constructor(
165177
actor: Actor<any>,
166178
options: VoxelRendererOptions = {}
@@ -178,21 +190,28 @@ export class VoxelRenderer extends ActorComponent {
178190
rapier,
179191
blocks = [],
180192
shapes = [],
181-
alphaTest = 0.1
193+
alphaTest = 0.1,
194+
logger = actor.world.logger
182195
} = options;
183196

184197
this.#materialType = material;
185198
this.#materialCustomizer = materialCustomizer;
186199
this.#alphaTest = alphaTest;
200+
this.#logger = logger.child({
201+
namespace: "VoxelRenderer"
202+
});
187203

188204
this.world = new VoxelWorld(chunkSize);
189205
if (layers.length > 0) {
190206
layers.forEach((name) => this.addLayer(name));
191207
}
192208

193209
this.blockRegistry = new BlockRegistry(blocks);
194-
this.shapeRegistry = BlockShapeRegistry.createDefault();
195-
shapes.forEach((shape) => this.shapeRegistry.register(shape));
210+
this.shapeRegistry = BlockShapeRegistry
211+
.createDefault();
212+
shapes.forEach(
213+
(shape) => this.shapeRegistry.register(shape)
214+
);
196215

197216
this.tilesetManager = new TilesetManager();
198217
this.serializer = new VoxelSerializer();
@@ -219,7 +238,7 @@ export class VoxelRenderer extends ActorComponent {
219238
// --- Lifecycle --- //
220239
awake(): void {
221240
// Build initial meshes for all existing chunks (e.g. after deserialize).
222-
this.#rebuildAllChunks();
241+
this.#rebuildAllChunks("awake");
223242
}
224243

225244
update(
@@ -231,12 +250,17 @@ export class VoxelRenderer extends ActorComponent {
231250
continue;
232251
}
233252

253+
this.#logger.debug(
254+
`Layer with name '${layer.name}' is dirty and will be rebuilt.`,
255+
{ source: "update" }
256+
);
234257
this.#rebuildChunk(layer, chunk);
235258
chunk.dirty = false;
236259
}
237260
}
238261

239262
override destroy(): void {
263+
this.#logger.debug("Destroying VoxelRenderer.");
240264
// Remove and dispose all chunk meshes individually (we own the geometries
241265
// but share materials per tileset, so we must NOT call removeChildren).
242266
for (const mesh of this.#chunkMeshes.values()) {
@@ -369,6 +393,7 @@ export class VoxelRenderer extends ActorComponent {
369393
);
370394

371395
this.tilesetManager.registerTexture(def, texture);
396+
this.#logger.debug(`Loaded tileset '${def.id}' from '${def.src}'`);
372397

373398
// Invalidate the cached material for this tileset so it is recreated
374399
// with the new texture.
@@ -377,11 +402,13 @@ export class VoxelRenderer extends ActorComponent {
377402
this.#materials.delete(def.id);
378403

379404
// Force all chunks to rebuild geometry (UV offsets may have changed).
380-
this.#markAllChunksDirty();
405+
this.#markAllChunksDirty("loadTileset");
381406
}
382407

383408
// --- Serialization --- //
384409
save(): VoxelWorldJSON {
410+
this.#logger.debug("Serializing world to JSON...");
411+
385412
return this.serializer.serialize(
386413
this.world,
387414
this.tilesetManager
@@ -397,6 +424,7 @@ export class VoxelRenderer extends ActorComponent {
397424
mesh.geometry.dispose();
398425
}
399426
this.#chunkMeshes.clear();
427+
this.#logger.debug("Cleared existing chunk meshes while loading new world.");
400428

401429
// Register block definitions embedded by a converter, if present.
402430
// Skips IDs already registered so callers can pre-register overrides.
@@ -426,12 +454,15 @@ export class VoxelRenderer extends ActorComponent {
426454
mat.dispose();
427455
}
428456
this.#materials.clear();
429-
this.#rebuildAllChunks();
457+
458+
this.#rebuildAllChunks("load");
430459
}
431460

432461
#getMaterial(
433462
tilesetId: string
434463
): THREE.MeshLambertMaterial | THREE.MeshStandardMaterial {
464+
this.#logger.debug(`Getting material for tileset '${tilesetId}'`);
465+
435466
let material = this.#materials.get(tilesetId);
436467
if (material) {
437468
return material;
@@ -466,16 +497,17 @@ export class VoxelRenderer extends ActorComponent {
466497
layer: VoxelLayer,
467498
chunk: VoxelChunk
468499
): void {
469-
const chunkKeyBase = `${layer.id}:${chunk.cx},${chunk.cy},${chunk.cz}`;
500+
const chunkKeyBase = `${layer.id}:${chunk.toString()}`;
501+
this.#logger.debug(
502+
`Rebuilding chunk '${chunkKeyBase}' with layer name '${layer.name}'`
503+
);
470504

471505
// Remove all existing meshes for this chunk (rebuilt per tileset below).
472-
const keysToRemove: string[] = [];
473506
for (const key of this.#chunkMeshes.keys()) {
474-
if (key.startsWith(`${chunkKeyBase}:`)) {
475-
keysToRemove.push(key);
507+
if (!key.startsWith(`${chunkKeyBase}:`)) {
508+
continue;
476509
}
477-
}
478-
for (const key of keysToRemove) {
510+
479511
const mesh = this.#chunkMeshes.get(key)!;
480512
this.actor.object3D.remove(mesh);
481513
mesh.geometry.dispose();
@@ -502,8 +534,18 @@ export class VoxelRenderer extends ActorComponent {
502534

503535
// Rebuild collision collider if physics is enabled.
504536
if (this.#colliderBuilder) {
505-
const collider = this.#buildColliderFromGeometries(chunk, geometries, layer.offset);
537+
const offset = layer.offset;
538+
this.#logger.debug(
539+
`Rebuilding chunk geometries collider '${chunkKeyBase}' with layer name '${layer.name}'`,
540+
{
541+
offset
542+
}
543+
);
544+
545+
const collider = this.#buildColliderFromGeometries(chunk, geometries, offset);
506546
if (collider) {
547+
this.#logger.debug(`Successfully built collider for chunk '${chunkKeyBase}'`);
548+
507549
this.#chunkColliders.set(chunkKeyBase, collider);
508550
}
509551
}
@@ -518,11 +560,16 @@ export class VoxelRenderer extends ActorComponent {
518560
geometries: Map<string, THREE.BufferGeometry>,
519561
layerOffset: { x: number; y: number; z: number; }
520562
): RapierCollider | null {
563+
const colliderBuilder = this.#colliderBuilder;
564+
if (!colliderBuilder) {
565+
return null;
566+
}
567+
521568
if (geometries.size === 1) {
522569
// Fast path: single tileset — pass the geometry directly.
523570
const [geometry] = geometries.values();
524571

525-
return this.#colliderBuilder!.buildChunkCollider(chunk, geometry, layerOffset);
572+
return colliderBuilder.buildChunkCollider(chunk, geometry, layerOffset);
526573
}
527574

528575
// Merge position/index arrays from all tileset geometries.
@@ -557,20 +604,28 @@ export class VoxelRenderer extends ActorComponent {
557604
);
558605
combinedGeo.setIndex(combinedIndices);
559606

560-
const collider = this.#colliderBuilder!.buildChunkCollider(chunk, combinedGeo, layerOffset);
607+
const collider = colliderBuilder.buildChunkCollider(chunk, combinedGeo, layerOffset);
561608
combinedGeo.dispose();
562609

563610
return collider;
564611
}
565612

566-
#rebuildAllChunks(): void {
613+
#rebuildAllChunks(
614+
source?: string
615+
): void {
616+
this.#logger.debug("Rebuilding all chunks...", { source });
617+
567618
for (const { layer, chunk } of this.world.getAllChunks()) {
568619
this.#rebuildChunk(layer, chunk);
569620
chunk.dirty = false;
570621
}
571622
}
572623

573-
#markAllChunksDirty(): void {
624+
#markAllChunksDirty(
625+
source?: string
626+
): void {
627+
this.#logger.debug("Marking all chunks dirty...", { source });
628+
574629
for (const { chunk } of this.world.getAllChunks()) {
575630
chunk.dirty = true;
576631
}

packages/voxel-renderer/src/world/VoxelChunk.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,8 @@ export class VoxelChunk {
102102
get voxelCount(): number {
103103
return this.#data.size;
104104
}
105+
106+
toString(): string {
107+
return `${this.cx},${this.cy},${this.cz}`;
108+
}
105109
}

0 commit comments

Comments
 (0)