added friends' neko to scene page

This commit is contained in:
2026-03-10 12:59:06 +08:00
parent a4d8601297
commit e38697faa9
13 changed files with 239 additions and 18 deletions

View File

@@ -0,0 +1,36 @@
import { writable } from "svelte/store";
import {
commands,
events,
type FriendActiveDollSpritesDto,
} from "$lib/bindings";
import { createEventSource } from "./listener-utils";
export const friendActiveDollSpriteUrls = writable<Record<string, string>>({});
function toSpriteUrls(
spriteBase64ByFriendId: FriendActiveDollSpritesDto,
): Record<string, string> {
return Object.fromEntries(
Object.entries(spriteBase64ByFriendId)
.filter((entry): entry is [string, string] => entry[1] !== undefined)
.map(([friendId, spriteBase64]) => [
friendId,
`data:image/gif;base64,${spriteBase64}`,
]),
);
}
export const {
start: startFriendActiveDollSprite,
stop: stopFriendActiveDollSprite,
} = createEventSource(async (addEventListener) => {
const initialSprites = await commands.getFriendActiveDollSpritesBase64();
friendActiveDollSpriteUrls.set(toSpriteUrls(initialSprites));
addEventListener(
await events.friendActiveDollSpritesUpdated.listen((event) => {
friendActiveDollSpriteUrls.set(toSpriteUrls(event.payload));
}),
);
});

View File

@@ -11,6 +11,9 @@ async getAppData() : Promise<UserData> {
async getActiveDollSpriteBase64() : Promise<string | null> {
return await TAURI_INVOKE("get_active_doll_sprite_base64");
},
async getFriendActiveDollSpritesBase64() : Promise<FriendActiveDollSpritesDto> {
return await TAURI_INVOKE("get_friend_active_doll_sprites_base64");
},
async refreshAppData() : Promise<UserData> {
return await TAURI_INVOKE("refresh_app_data");
},
@@ -134,6 +137,7 @@ createDoll: CreateDoll,
cursorMoved: CursorMoved,
editDoll: EditDoll,
friendActiveDollChanged: FriendActiveDollChanged,
friendActiveDollSpritesUpdated: FriendActiveDollSpritesUpdated,
friendCursorPositionsUpdated: FriendCursorPositionsUpdated,
friendDisconnected: FriendDisconnected,
friendRequestAccepted: FriendRequestAccepted,
@@ -153,6 +157,7 @@ createDoll: "create-doll",
cursorMoved: "cursor-moved",
editDoll: "edit-doll",
friendActiveDollChanged: "friend-active-doll-changed",
friendActiveDollSpritesUpdated: "friend-active-doll-sprites-updated",
friendCursorPositionsUpdated: "friend-cursor-positions-updated",
friendDisconnected: "friend-disconnected",
friendRequestAccepted: "friend-request-accepted",
@@ -188,6 +193,8 @@ export type DollDto = { id: string; name: string; configuration: DollConfigurati
export type EditDoll = string
export type FriendActiveDollChanged = FriendActiveDollChangedPayload
export type FriendActiveDollChangedPayload = { friendId: string; doll: DollDto | null }
export type FriendActiveDollSpritesDto = Partial<{ [key in string]: string }>
export type FriendActiveDollSpritesUpdated = FriendActiveDollSpritesDto
export type FriendCursorPositionsDto = Partial<{ [key in string]: CursorPositions }>
export type FriendCursorPositionsUpdated = FriendCursorPositionsDto
export type FriendDisconnected = FriendDisconnectedPayload

View File

@@ -10,6 +10,10 @@
startActiveDollSprite,
stopActiveDollSprite,
} from "../events/active-doll-sprite";
import {
startFriendActiveDollSprite,
stopFriendActiveDollSprite,
} from "../events/friend-active-doll-sprite";
import { startAppData } from "../events/app-data";
import { startInteraction, stopInteraction } from "../events/interaction";
import {
@@ -24,6 +28,7 @@
try {
await startAppData();
await startActiveDollSprite();
await startFriendActiveDollSprite();
await startCursorTracking();
await startFriendCursorTracking();
await startSceneInteractive();
@@ -38,6 +43,7 @@
stopCursorTracking();
stopFriendCursorTracking();
stopActiveDollSprite();
stopFriendActiveDollSprite();
stopSceneInteractive();
stopInteraction();
stopUserStatus();

View File

@@ -3,6 +3,7 @@
import { friendsCursorPositions } from "../../events/friend-cursor";
import { appData } from "../../events/app-data";
import { activeDollSpriteUrl } from "../../events/active-doll-sprite";
import { friendActiveDollSpriteUrls } from "../../events/friend-active-doll-sprite";
import { sceneInteractive } from "../../events/scene-interactive";
import {
friendsPresenceStates,
@@ -26,6 +27,17 @@
targetY={$cursorPositionOnScreen.raw.y}
spriteUrl={$activeDollSpriteUrl}
/>
{#each Object.entries($friendsCursorPositions) as [friendId, position] (friendId)}
{#if $friendActiveDollSpriteUrls[friendId]}
<Neko
targetX={position.raw.x}
targetY={position.raw.y}
spriteUrl={$friendActiveDollSpriteUrls[friendId]}
initialX={position.raw.x}
initialY={position.raw.y}
/>
{/if}
{/each}
<div id="debug-bar">
<DebugBar
isInteractive={$sceneInteractive}

View File

@@ -8,14 +8,17 @@
targetX: number;
targetY: number;
spriteUrl: string;
initialX?: number;
initialY?: number;
}
let { targetX, targetY, spriteUrl }: Props = $props();
let { targetX, targetY, spriteUrl, initialX = 32, initialY = 32 }: Props =
$props();
let nekoEl: HTMLDivElement;
let animationFrameId: number;
let nekoPos = $state({ x: 32, y: 32 });
let nekoPos = $state({ x: initialX, y: initialY });
let frameCount = 0;
let idleTime = 0;
let idleAnimation: string | null = $state(null);