moving
diff --git a/src/lib/world-editor/Instance.svelte b/src/lib/world-editor/Instance.svelte
index 3701811..beb41a1 100644
--- a/src/lib/world-editor/Instance.svelte
+++ b/src/lib/world-editor/Instance.svelte
@@ -8,8 +8,8 @@
+
+{#if editingState.selectedInstance}
+
+
+
{
+ return selectedTool;
+ },
+ (value) => {
+ selectedTool = value;
+ }
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{/if}
diff --git a/src/lib/world-editor/ModelSelection.svelte b/src/lib/world-editor/ModelSelection.svelte
index 0bc8ffa..41833cc 100644
--- a/src/lib/world-editor/ModelSelection.svelte
+++ b/src/lib/world-editor/ModelSelection.svelte
@@ -2,7 +2,6 @@
import ModalModelPicker from '$lib/model-picker/modal/ModalModelPicker.svelte';
import { derivePromise } from '$lib/utils.svelte';
import type { EntityIdStr } from '@muni-town/leaf';
- import { Button } from 'fuchs';
import { onMount } from 'svelte';
import { applyTransform, editingState } from './state.svelte';
import { g, initRoomy } from '$lib/roomy.svelte';
@@ -16,14 +15,19 @@
);
let worldModelList = derivePromise([], async () => {
- if (!g.roomy) return [];
- const models = await g.world?.instances.items();
+ if (!g.world || !g.roomy) {
+ return [];
+ }
+
+ const models = await g.world.instances.items();
const groups = new Set
();
for (const model of models ?? []) {
groups.add(model.group);
}
return Promise.all(
- Array.from(groups).map(async (group) => await g.roomy?.open(VoxelGroup, group))
+ Array.from(groups)
+ .filter((group) => group)
+ .map(async (group) => await g.roomy?.open(VoxelGroup, group))
);
});
@@ -47,7 +51,7 @@
function getItems() {
let items: { voxels: VoxelGroup; label: string }[] = [];
if (editingState.modelPickerType === 'public') {
- items= globalModelList.value.map((model) => ({ voxels: model, label: model.name }));
+ items = globalModelList.value.map((model) => ({ voxels: model, label: model.name }));
}
if (editingState.modelPickerType === 'private') {
@@ -55,7 +59,10 @@
}
if (editingState.modelPickerType === 'world') {
- items = worldModelList.value.map((model) => ({ voxels: model, label: model?.name })) as { voxels: VoxelGroup; label: string }[];
+ items = worldModelList.value.map((model) => ({ voxels: model, label: model?.name })) as {
+ voxels: VoxelGroup;
+ label: string;
+ }[];
}
// filter all items that have no voxels
diff --git a/src/lib/world-editor/WorldEditorScene.svelte b/src/lib/world-editor/WorldEditorScene.svelte
index 28fdddd..79523ab 100644
--- a/src/lib/world-editor/WorldEditorScene.svelte
+++ b/src/lib/world-editor/WorldEditorScene.svelte
@@ -21,7 +21,11 @@
let instances = derivePromise([], async () => (g.world ? await g.world.instances.items() : []));
- let camera = $state('first');
+ let terrainGradient = derivePromise([], async () =>
+ g.world ? (await g.world.loadTerrainGradient()).stops.items() : []
+ );
+
+ $inspect(terrainGradient.value);
const { renderer } = useThrelte();
@@ -29,18 +33,25 @@
window.addEventListener('keydown', (e) => {
// on c switch camera
if (e.key === 'c') {
- camera = camera === 'first' ? 'third' : 'first';
+ editingState.camera = editingState.camera === 'first' ? 'third' : 'first';
}
});
renderer.toneMapping = ACESFilmicToneMapping;
});
+
+ $effect(() => {
+ if (g.world && g.world.settings.version > editingState.worldSettings.version) {
+ editingState.worldSettings = g.world.settings;
+ console.log('settings', editingState.worldSettings);
+ }
+ });
-{#if camera === 'first'}
+{#if editingState.camera === 'third'}
{
ref.lookAt(0, 1, 0);
}}
@@ -53,19 +64,22 @@
-{#key editingState.worldSettings.version}
+{#key editingState.worldSettings.version + editingState.worldSettings.waterPercentage + editingState.worldSettings.size}
{
if (editingState.selectedModelId) {
addInstance(editingState.selectedModelId, e.point);
}
}}
+ settings={editingState.worldSettings}
/>
-
+ {#if editingState.worldSettings.waterPercentage > 0}
+
+ {/if}
{/key}
-
+
diff --git a/src/lib/world-editor/WorldEditorUI.svelte b/src/lib/world-editor/WorldEditorUI.svelte
index 5d0819c..e060b70 100644
--- a/src/lib/world-editor/WorldEditorUI.svelte
+++ b/src/lib/world-editor/WorldEditorUI.svelte
@@ -1,12 +1,19 @@
+
+
+
+
+
+
diff --git a/src/lib/world-editor/WorldSettingsUI.svelte b/src/lib/world-editor/WorldSettingsUI.svelte
index 1322646..2ae12cc 100644
--- a/src/lib/world-editor/WorldSettingsUI.svelte
+++ b/src/lib/world-editor/WorldSettingsUI.svelte
@@ -1,50 +1,89 @@
-
-
-
-
-
-
-
{
- editingState.worldSettings.version += 1;
- }}
- />
-
+{#if g.world}
+
+ Size
+
- {
- editingState.worldSettings.version += 1;
- }}
- />
-
-
-
-
-
\ No newline at end of file
+ }}>
+ Update
+
+
+
+{/if}
diff --git a/src/lib/world-editor/state.svelte.ts b/src/lib/world-editor/state.svelte.ts
index fce36a0..8746ac6 100644
--- a/src/lib/world-editor/state.svelte.ts
+++ b/src/lib/world-editor/state.svelte.ts
@@ -1,4 +1,4 @@
-import { TransformedGroup } from '$lib/roomy';
+import { TransformedGroup, type WorldSettings } from '$lib/roomy';
import { g, initRoomy } from '$lib/roomy.svelte';
import type { EntityIdStr } from '@muni-town/leaf';
import { Quaternion, Vector3 } from 'three';
@@ -11,13 +11,17 @@ export const editingState = $state({
showModelEditor: false,
showWorldSettings: false,
showModelPicker: false,
+ camera: 'third' as 'first' | 'third',
modelPickerType: 'public' as 'private' | 'world' | 'public',
+
+ tool: 'move' as 'move' | 'rotate' | 'scale',
+
worldSettings: {
- seed: Math.floor(Math.random() * 1000000),
- size: 100,
+ seed: Math.floor(Math.random() * 1000000).toString(),
+ size: 0,
terrainGradient: [
- { rgb: { r: 0, g: 0.05, b: 0 }, position: 0 },
- { rgb: { r: 0, g: 0.35, b: 0 }, position: 1 }
+ { rgb: { r: 0, g: 0, b: 0 }, position: 0 },
+ { rgb: { r: 0, g: 0, b: 0 }, position: 1 }
] as {
rgb: {
r: number;
@@ -28,7 +32,7 @@ export const editingState = $state({
}[],
waterGradient: [
{ rgb: { r: 0, g: 0, b: 0 }, position: 0 },
- { rgb: { r: 0, g: 0, b: 1 }, position: 1 }
+ { rgb: { r: 0, g: 0, b: 0 }, position: 1 }
] as {
rgb: {
r: number;
@@ -38,8 +42,8 @@ export const editingState = $state({
position: number;
}[],
waterPercentage: 35,
- version: 0
- }
+ version: -1
+ } as WorldSettings
});
export type AddInstanceFunction = (id: EntityIdStr, position: Vector3) => void;
@@ -87,3 +91,14 @@ export async function addInstance(id: EntityIdStr, position: Vector3) {
g.world?.instances.push(instance);
g.world?.commit();
}
+
+export async function deleteInstance(id: string) {
+ const instances = await g.world?.instances.items();
+ // find voxel by id
+ const instance = instances?.findIndex((v) => v.id === id);
+ console.log(instance);
+ if (instance === undefined || instance < 0) return;
+
+ g.world?.instances.remove(instance);
+ g.world?.commit();
+}
diff --git a/src/lib/world/Terrain.svelte b/src/lib/world/Terrain.svelte
index b6c26d5..eedb074 100644
--- a/src/lib/world/Terrain.svelte
+++ b/src/lib/world/Terrain.svelte
@@ -7,9 +7,24 @@
import type { IntersectionEvent } from '@threlte/extras';
import { shuffle } from '$lib/utils.svelte';
import { ColorGradient } from './colorgradient';
- import { editingState } from '$lib/world-editor/state.svelte';
+ import type { WorldSettings } from '$lib/roomy';
+ import { applyTransform, editingState } from '$lib/world-editor/state.svelte';
- const size = editingState.worldSettings.size;
+ let {
+ clickedTerrain,
+ collider = true,
+ animate = false,
+ animationTime = 3,
+ settings
+ }: {
+ clickedTerrain?: (e: IntersectionEvent) => void;
+ collider?: boolean;
+ animate?: boolean;
+ animationTime?: number;
+ settings: WorldSettings;
+ } = $props();
+
+ const size = settings.size;
const voxelSize = 1;
@@ -28,18 +43,22 @@
const dummy = new THREE.Object3D();
const color = new THREE.Color(0x00ff00);
+ console.log('seed', settings.seed);
const heightfield: number[] = [];
- const upperNoise = new UberNoise({
- seed: editingState.worldSettings.seed,
+ const options = settings.terrainNoise ?? {
octaves: 6,
scale: 0.03,
min: 0,
max: 3,
warp: 1
- });
+ };
+
+ options.seed = settings.seed;
+
+ const upperNoise = new UberNoise(options);
const lowerNoise = new UberNoise({
- seed: editingState.worldSettings.seed + 10,
+ seed: settings.seed + 10,
octaves: 6,
scale: 0.05,
min: 0,
@@ -51,7 +70,7 @@
const gradient = new ColorGradient({
- stops: editingState.worldSettings.terrainGradient.map(({ rgb, position }) => ({
+ stops: settings.terrainGradient.map(({ rgb, position }) => ({
position: (position - 0.5) * 2,
value: new THREE.Color(rgb.r, rgb.g, rgb.b)
}))
@@ -69,7 +88,7 @@
continue;
}
- const height = noiseHeight + Math.pow(distance / (size / 2), 2) * -5;
+ const height = noiseHeight// + Math.pow(distance / (size / 2), 2) * -5;
const noise = upperNoise.normalized(x, z);
dummy.position.set(x, height, z);
dummy.scale.set(1, 3, 1);
@@ -110,17 +129,6 @@
let heightfieldData = new Float32Array(heightfield);
- let {
- clickedTerrain,
- collider = true,
- animate = false,
- animationTime = 3
- }: {
- clickedTerrain?: (e: IntersectionEvent) => void;
- collider?: boolean;
- animate?: boolean;
- animationTime?: number;
- } = $props();
let i = 0;
const addPerSecond = totalVoxels / animationTime;
@@ -148,6 +156,11 @@
clickedTerrain(e);
}
: undefined}
+
+ ondblclick={() => {
+ applyTransform();
+ editingState.selectedInstance = null;
+ }}
/>
{#if collider}
diff --git a/src/lib/world/Water.svelte b/src/lib/world/Water.svelte
index 153a173..83f6659 100644
--- a/src/lib/world/Water.svelte
+++ b/src/lib/world/Water.svelte
@@ -5,8 +5,21 @@
import { shuffle } from '$lib/utils.svelte';
import { ColorGradient } from './colorgradient';
import { editingState } from '$lib/world-editor/state.svelte';
+ import type { WorldSettings } from '$lib/roomy';
- const size = editingState.worldSettings.size;
+ let {
+ animate = true,
+ animateIn = false,
+ animationTime = 3,
+ settings
+ }: {
+ animate?: boolean;
+ animateIn?: boolean;
+ animationTime?: number;
+ settings: WorldSettings;
+ } = $props();
+
+ const size = settings.size;
const voxelSize = 1;
@@ -25,7 +38,7 @@
const dummy = new THREE.Object3D();
const waterNoise = new UberNoise({
- seed: editingState.worldSettings.seed + 10,
+ seed: settings.seed + 10,
octaves: 3,
scale: 0.01,
min: 0,
@@ -34,17 +47,20 @@
});
- const terrainNoise = new UberNoise({
- seed: editingState.worldSettings.seed,
+ const options = settings.terrainNoise ?? {
octaves: 6,
scale: 0.03,
min: 0,
max: 3,
warp: 1
- });
+ };
+
+ options.seed = settings.seed;
+
+ const terrainNoise = new UberNoise(options);
const waterGradient = new ColorGradient({
- stops: editingState.worldSettings.waterGradient.map(({ rgb, position }) => ({
+ stops: settings.waterGradient.map(({ rgb, position }) => ({
position: (position - 1),
value: new THREE.Color(rgb.r, rgb.g, rgb.b)
}))
@@ -76,8 +92,7 @@
const isEdge = surrounding.some(s => s > size / 2);
-
- const height = noiseHeight + Math.pow(distance / (size / 2), 2) * -5;
+ const height = noiseHeight// + Math.pow(distance / (size / 2), 2) * -5;
if(water > (editingState.worldSettings.waterPercentage / 100 * 2 - 1)) continue;
@@ -103,17 +118,6 @@
instancedMesh.instanceColor.needsUpdate = true;
}
-
- let {
- animate = true,
- animateIn = false,
- animationTime = 3
- }: {
- animate?: boolean;
- animateIn?: boolean;
- animationTime?: number;
- } = $props();
-
let totalTime = 0;
const addPerSecond = totalVoxels / animationTime;
diff --git a/src/routes/world/+layout.svelte b/src/routes/world/+layout.svelte
index 61621ed..00110fa 100644
--- a/src/routes/world/+layout.svelte
+++ b/src/routes/world/+layout.svelte
@@ -12,9 +12,6 @@
let showWorld = $state(false);
$effect(() => {
- console.log('hello');
- //const worldId = page.params.id;
- // TODO: we should use search params here
const worldId = page.url.searchParams.get('id');
if (!worldId) return;
@@ -28,7 +25,6 @@
return;
}
}
- console.log('loading', worldId);
g.roomy
.open(World, worldId as EntityIdStr)
diff --git a/src/routes/world/+page.svelte b/src/routes/world/+page.svelte
index c09f0f2..58d5943 100644
--- a/src/routes/world/+page.svelte
+++ b/src/routes/world/+page.svelte
@@ -12,13 +12,14 @@
import WorldSettingsUi from '$lib/world-editor/WorldSettingsUI.svelte';
import HudUi from '$lib/world-editor/HudUI.svelte';
import WorldEditorUi from '$lib/world-editor/WorldEditorUI.svelte';
+ import { g } from '$lib/roomy.svelte';
let showPerfMonitor = $state(false);
- {:else}
-
+ {#if g.world?.settings}
+
+ {/if}
+
{/if}
+
+
+
{:else}
{/if}
-
-
\ No newline at end of file