81 lines
2.1 KiB
Svelte
81 lines
2.1 KiB
Svelte
<script lang="ts">
|
|
import { onMount } from 'svelte';
|
|
import { mountWorld, type WorldHandle } from '@idle/render';
|
|
import { connectWorld, type NetStatus } from './net';
|
|
|
|
const STATUS_TEXT: Record<NetStatus, string> = {
|
|
connecting: 'подключение…',
|
|
online: 'онлайн',
|
|
reconnecting: 'переподключение…',
|
|
};
|
|
|
|
let host = $state<HTMLDivElement | undefined>(undefined);
|
|
let status = $state<NetStatus>('connecting');
|
|
|
|
onMount(() => {
|
|
let world: WorldHandle | undefined;
|
|
let disposeNet: (() => void) | undefined;
|
|
|
|
if (host) {
|
|
void mountWorld(host, { backgroundAlpha: 0 }).then((w) => {
|
|
world = w;
|
|
disposeNet = connectWorld({
|
|
onStatus: (s) => {
|
|
status = s;
|
|
},
|
|
onWelcome: (msg) => world?.setWelcome(msg),
|
|
onSnapshot: (msg) => world?.applySnapshot(msg),
|
|
onDelta: (msg) => world?.applyDelta(msg),
|
|
});
|
|
});
|
|
}
|
|
|
|
return () => {
|
|
disposeNet?.();
|
|
world?.destroy();
|
|
};
|
|
});
|
|
</script>
|
|
|
|
<div class="root">
|
|
<div class="world" bind:this={host}></div>
|
|
<div class="badge">{STATUS_TEXT[status]}</div>
|
|
<!-- онбординг — в самом виджете, чат ботом не засоряем -->
|
|
{#if status === 'online'}
|
|
<div class="hint">!рубить · !копать · !рыбачить · !ковать <рецепт> · !готовить <рецепт> · !отдых · !костёр · !стоп</div>
|
|
{/if}
|
|
</div>
|
|
|
|
<style>
|
|
.root {
|
|
position: fixed;
|
|
inset: 0;
|
|
}
|
|
.world {
|
|
position: absolute;
|
|
inset: 0;
|
|
}
|
|
.badge {
|
|
position: absolute;
|
|
top: 8px;
|
|
right: 8px;
|
|
font: 12px/1.4 monospace;
|
|
color: #9fb0c3;
|
|
background: rgba(16, 19, 26, 0.55);
|
|
padding: 2px 8px;
|
|
border-radius: 8px;
|
|
}
|
|
.hint {
|
|
position: absolute;
|
|
bottom: 14px;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
font: 13px/1.4 monospace;
|
|
color: #eef4fa;
|
|
background: rgba(16, 19, 26, 0.6);
|
|
padding: 5px 14px;
|
|
border-radius: 10px;
|
|
white-space: nowrap;
|
|
}
|
|
</style>
|