feat(players): NPC disposition types and launch-with-players session tokens

Add Hostile/Neutral/Friendly ring types with session-only inactive overrides on control, plus launch-with-players flow and live player tokens on the map.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ivan Fontosh
2026-07-30 17:11:01 +08:00
parent 101f595bac
commit cc50e64e21
38 changed files with 1803 additions and 59 deletions
+21 -1
View File
@@ -12,6 +12,7 @@ import type {
NpcId,
NpcRelationId,
NpcGroupId,
NpcDisposition,
NpcsOverlayEvent,
NpcsOverlayState,
Project,
@@ -31,6 +32,8 @@ import type {
SceneNpcToken,
SceneNpcTokensSessionEvent,
SceneNpcTokensSessionState,
ScenePlayerTokensSessionEvent,
ScenePlayerTokensSessionState,
SceneToken,
SceneTokensSessionEvent,
SceneTokensSessionState,
@@ -210,6 +213,11 @@ export const ipcChannels = {
dispatch: 'sceneNpcTokensSession.dispatch',
stateChanged: 'sceneNpcTokensSession.stateChanged',
},
scenePlayerTokensSession: {
getState: 'scenePlayerTokensSession.getState',
dispatch: 'scenePlayerTokensSession.dispatch',
stateChanged: 'scenePlayerTokensSession.stateChanged',
},
video: {
getState: 'video.getState',
dispatch: 'video.dispatch',
@@ -285,6 +293,7 @@ export type IpcEventMap = {
[ipcChannels.players.stateChanged]: { players: AppPlayer[]; teams: AppPlayerTeam[] };
[ipcChannels.players.upsertProgress]: PlayersUpsertProgressEvent;
[ipcChannels.sceneNpcTokensSession.stateChanged]: { state: SceneNpcTokensSessionState };
[ipcChannels.scenePlayerTokensSession.stateChanged]: { state: ScenePlayerTokensSessionState };
[ipcChannels.video.stateChanged]: { state: VideoPlaybackState };
[ipcChannels.license.statusChanged]: { snapshot: LicenseSnapshot };
[ipcChannels.windows.multiWindowStateChanged]: { open: boolean };
@@ -400,6 +409,7 @@ export type IpcInvokeMap = {
filePath?: string;
groupId?: NpcGroupId | null;
ringColor?: string;
disposition?: NpcDisposition;
imageOffset?: PlayerImageOffset;
imageScale?: number;
};
@@ -412,6 +422,7 @@ export type IpcInvokeMap = {
description?: string;
groupId?: NpcGroupId | null;
ringColor?: string;
disposition?: NpcDisposition;
imageOffset?: PlayerImageOffset;
imageScale?: number;
};
@@ -610,7 +621,7 @@ export type IpcInvokeMap = {
res: { ok: true };
};
[ipcChannels.windows.openMultiWindow]: {
req: Record<string, never>;
req: { playerIds?: string[] };
res: { ok: true };
};
[ipcChannels.windows.closeMultiWindow]: {
@@ -801,6 +812,14 @@ export type IpcInvokeMap = {
req: { event: SceneNpcTokensSessionEvent };
res: { ok: true };
};
[ipcChannels.scenePlayerTokensSession.getState]: {
req: Record<string, never>;
res: { state: ScenePlayerTokensSessionState };
};
[ipcChannels.scenePlayerTokensSession.dispatch]: {
req: { event: ScenePlayerTokensSessionEvent };
res: { ok: true };
};
[ipcChannels.video.getState]: {
req: Record<string, never>;
res: { state: VideoPlaybackState };
@@ -845,6 +864,7 @@ export type LegacyIpcEventMap = {
[ipcChannels.players.stateChanged]: { players: AppPlayer[]; teams: AppPlayerTeam[] };
[ipcChannels.players.upsertProgress]: PlayersUpsertProgressEvent;
[ipcChannels.sceneNpcTokensSession.stateChanged]: { state: SceneNpcTokensSessionState };
[ipcChannels.scenePlayerTokensSession.stateChanged]: { state: ScenePlayerTokensSessionState };
[ipcChannels.video.stateChanged]: { state: VideoPlaybackState };
[ipcChannels.license.statusChanged]: Record<string, never>;
};