Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/slow-eagles-jog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@jolly-pixel/voxel.renderer": major
---

Migrate the network sync layer onto `@jolly-pixel/network`'s `NetworkPlugin`/`NetworkChannel` primitives, mirroring `@jolly-pixel/pixel-draw.renderer`'s design: `VoxelSyncServer` now extends `NetworkPlugin`, `VoxelTransport` matches `NetworkChannel`'s shape (`send`/single `onMessage`), and `VoxelSyncClient` is renamed to `VoxelSyncSession` with a two-step `attach(engine)`/`detach()` API that chains onto an existing `onLayerUpdated` handler instead of replacing it. `ConflictResolver`/`ConflictContext` are renamed to `VoxelConflictResolver`/`VoxelConflictContext`. `VoxelSnapshotRequest` and `VoxelTransport.requestSnapshot`/`sendCommand`/`onCommand`/`onSnapshot` are removed in favor of the new `VoxelServerMessage` envelope.
1 change: 1 addition & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ JollyPixel Editor is a monorepo for a collaborative 3D HTML5 game maker. It prov
packages/
engine/ @jolly-pixel/engine – ECS framework on Three.js (public)
runtime/ @jolly-pixel/runtime – Browser/Electron runtime (public)
network/ @jolly-pixel/network – Shared multiplayer sync wire (public)
fs-tree/ @jolly-pixel/fs-tree – Filesystem tree + live sync (public)
fs-tree-backend/ @jolly-pixel/fs-tree-backend – fs-tree socket server backend (private)
resize-handle/ @jolly-pixel/resize-handle – Resizable pane UI element (public)
Expand Down
1 change: 1 addition & 0 deletions packages/editors/voxel-map/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"dependencies": {
"@jolly-pixel/engine": "^3.0.0",
"@jolly-pixel/fs-tree": "^1.0.1",
"@jolly-pixel/network": "*",
"@jolly-pixel/pixel-draw.renderer": "2.0.0",
"@jolly-pixel/resize-handle": "1.0.0",
"@jolly-pixel/runtime": "^3.4.0",
Expand Down
27 changes: 26 additions & 1 deletion packages/editors/voxel-map/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ import {
loadRuntime
} from "@jolly-pixel/runtime";
import { ResizeHandle } from "@jolly-pixel/resize-handle";
import { NetworkClient } from "@jolly-pixel/network";
import type {
PixelNetworkCommand,
PixelServerMessage
} from "@jolly-pixel/pixel-draw.renderer";
import type {
VoxelNetworkCommand,
VoxelServerMessage
} from "@jolly-pixel/voxel.renderer";

// Import Internal Dependencies
import { editorState } from "./EditorState.ts";
Expand All @@ -23,6 +32,19 @@ const runtime = new Runtime(canvas, {
});
const { world } = runtime;

// One shared WebSocket (matching vite.config.ts's createWebSocketNetworkPlugin),
// multiplexing the texture (pixel-draw) and world (voxel) sync namespaces.
const wsProtocol = location.protocol === "https:" ? "wss:" : "ws:";
const networkClient = new NetworkClient({
url: `${wsProtocol}//${location.host}/ws-sync`
});
const textureTransport = networkClient.channel<PixelNetworkCommand, PixelServerMessage>(
"voxel-map:texture"
);
const worldTransport = networkClient.channel<VoxelNetworkCommand, VoxelServerMessage>(
"voxel-map:world"
);

const editorScene = new EditorScene(
editorState,
{
Expand All @@ -31,12 +53,15 @@ const editorScene = new EditorScene(
id: "default",
src: "textures/tileset.png",
tileSize: 32
}
},
voxelTransport: worldTransport
}
);

const sidebar = document.querySelector<EditorSidebar>("#sidebar")!;
if (sidebar) {
sidebar.textureTransport = textureTransport;

// editorScene.vr / gridRenderer are assigned inside awake(), which runs
// after loadScene(). Defer propagating them to the sidebar until the block
// registry is fully populated (dispatched at the end of awake()).
Expand Down
17 changes: 15 additions & 2 deletions packages/editors/voxel-map/src/lib/TextureEditorBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
import type { VoxelRenderer } from "@jolly-pixel/voxel.renderer";
import {
PixelArtCanvas,
type PixelArtCanvasOptions
PixelSyncSession,
type PixelArtCanvasOptions,
type PixelTransport
} from "@jolly-pixel/pixel-draw.renderer";

// CONSTANTS
Expand All @@ -19,6 +21,7 @@ export interface TextureEditorBridgeOptions {
*/
export class TextureEditorBridge {
#manager: PixelArtCanvas | null = null;
#session: PixelSyncSession | null = null;
#threeTexture: { image: unknown; needsUpdate: boolean; } | null = null;
#options: TextureEditorBridgeOptions;
#tilesetId: string | null = null;
Expand All @@ -35,9 +38,12 @@ export class TextureEditorBridge {

mount(
container: HTMLDivElement,
extraOptions?: PixelArtCanvasOptions
extraOptions?: PixelArtCanvasOptions,
transport?: PixelTransport
): void {
if (this.#manager) {
this.#session?.destroy();
this.#session = null;
this.#manager.destroy();
}

Expand All @@ -48,6 +54,11 @@ export class TextureEditorBridge {
};

this.#manager = new PixelArtCanvas(container, managerOptions);

if (transport) {
this.#session = new PixelSyncSession({ transport });
this.#session.attach(this.#manager);
}
}

loadTileset(
Expand Down Expand Up @@ -145,6 +156,8 @@ export class TextureEditorBridge {
}

destroy(): void {
this.#session?.destroy();
this.#session = null;
this.#manager?.destroy();
this.#manager = null;
this.#threeTexture = null;
Expand Down
22 changes: 20 additions & 2 deletions packages/editors/voxel-map/src/scene/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import {
} from "@jolly-pixel/engine";
import {
VoxelRenderer,
VoxelSyncSession,
TilesetLoader,
type TilesetDefinition,
type VoxelWorldJSON
type VoxelWorldJSON,
type VoxelTransport
} from "@jolly-pixel/voxel.renderer";
import * as THREE from "three";

Expand All @@ -30,12 +32,16 @@ export interface EditorSceneOptions {
*/
defaultLayerName?: string;
defaultTileset: TilesetDefinition;
/** Optional transport to synchronize the voxel world over the network. */
voxelTransport?: VoxelTransport;
}

export class EditorScene extends Systems.Scene {
#tilesetLoader!: TilesetLoader;
#defaultLayerName: string;
#defaultTileset: TilesetDefinition;
#voxelTransport: VoxelTransport | undefined;
#voxelSyncSession: VoxelSyncSession | undefined;
#pendingLoad: VoxelWorldJSON | null = null;

editorState: EditorState;
Expand Down Expand Up @@ -66,11 +72,13 @@ export class EditorScene extends Systems.Scene {

const {
defaultLayerName = "Ground",
defaultTileset
defaultTileset,
voxelTransport
} = options;

this.#defaultLayerName = defaultLayerName;
this.#defaultTileset = defaultTileset;
this.#voxelTransport = voxelTransport;
this.editorState = editorState;
}

Expand Down Expand Up @@ -110,6 +118,11 @@ export class EditorScene extends Systems.Scene {
this.vr = vr;
this.editorState.setSelectedLayer(this.#defaultLayerName);

if (this.#voxelTransport) {
this.#voxelSyncSession = new VoxelSyncSession({ transport: this.#voxelTransport });
this.#voxelSyncSession.attach(vr.engine);
}

// Skip default blocks when restoring a saved world — vr.load() will
// register the persisted definitions (which carry user edits).
// Registering defaults first would cause load() to skip saved blocks
Expand Down Expand Up @@ -161,4 +174,9 @@ export class EditorScene extends Systems.Scene {
world.createActor("perf-hud")
.addComponent(PerformanceHUD);
}

override destroy(): void {
this.#voxelSyncSession?.destroy();
this.#voxelSyncSession = undefined;
}
}
8 changes: 7 additions & 1 deletion packages/editors/voxel-map/src/ui/EditorSidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { LitElement, html, css } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import type { VoxelRenderer } from "@jolly-pixel/voxel.renderer";
import type { PixelTransport } from "@jolly-pixel/pixel-draw.renderer";

// Import Internal Dependencies
import { editorState, type SidebarTab } from "../EditorState.ts";
Expand Down Expand Up @@ -102,6 +103,7 @@ export class EditorSidebar extends LitElement {

@property({ attribute: false }) declare vr: VoxelRenderer | undefined;
@property({ attribute: false }) declare gridRenderer: GridRenderer | undefined;
@property({ attribute: false }) declare textureTransport: PixelTransport | undefined;

@state() private declare _tab: SidebarTab;
@state() private declare _selectedLayer: string | null;
Expand Down Expand Up @@ -217,7 +219,11 @@ export class EditorSidebar extends LitElement {
`)}

${this.#section("Texture Editor", html`
<texture-editor .vr=${this.vr} .active=${this._tab === "paint"}></texture-editor>
<texture-editor
.vr=${this.vr}
.active=${this._tab === "paint"}
.transport=${this.textureTransport}
></texture-editor>
`)}
`;
}
Expand Down
5 changes: 3 additions & 2 deletions packages/editors/voxel-map/src/ui/TextureEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { LitElement, html, css } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import Picker from "vanilla-picker";
import type { VoxelRenderer } from "@jolly-pixel/voxel.renderer";
import type { Mode } from "@jolly-pixel/pixel-draw.renderer";
import type { Mode, PixelTransport } from "@jolly-pixel/pixel-draw.renderer";

// Import Internal Dependencies
import { TextureEditorBridge } from "../lib/TextureEditorBridge.ts";
Expand Down Expand Up @@ -99,6 +99,7 @@ export class TextureEditor extends LitElement {
`;

@property({ attribute: false }) declare vr: VoxelRenderer | undefined;
@property({ attribute: false }) declare transport: PixelTransport | undefined;
@property({ type: String }) declare tilesetId: string;
@property({ type: Boolean }) declare active: boolean;

Expand Down Expand Up @@ -147,7 +148,7 @@ export class TextureEditor extends LitElement {
texture: {
maxSize: 512
}
});
}, this.transport);

if (this.vr) {
this.#bridge.loadTileset(this.vr, this.tilesetId || null);
Expand Down
28 changes: 28 additions & 0 deletions packages/editors/voxel-map/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Import Third-party Dependencies
import { defineConfig } from "vite";
import { createWebSocketNetworkPlugin } from "@jolly-pixel/network/plugins/vite.ts";
import { PixelSyncServer } from "@jolly-pixel/pixel-draw.renderer";
import { VoxelSyncServer, VoxelWorld } from "@jolly-pixel/voxel.renderer";

const world = new VoxelWorld(16);
world.addLayer("Ground");

// https://vitejs.dev/config/
export default defineConfig({
server: {
allowedHosts: true
},
plugins: [
createWebSocketNetworkPlugin({
plugins: [
new PixelSyncServer({
namespace: "voxel-map:texture"
}),
new VoxelSyncServer({
namespace: "voxel-map:world",
world
})
]
})
]
});
Loading
Loading