You've already forked Nitro_Render_V3
mirror of
https://github.com/duckietm/Nitro_Render_V3.git
synced 2026-06-19 15:06:20 +00:00
feat(session): snapshot getter for UserDataManager room user list
Extends the snapshot pattern to the room's user list. The React client currently has many widgets each calling `getUserDataByIndex(idx)` in a loop (chat, doorbell, room player list, infostand …) — every render walks the underlying Map and rebuilds an array. With `getRoomUserListSnapshot(): ReadonlyArray<IRoomUserData>` consumers can memoize on the array reference and only rebuild when something actually changed. Invalidation fires on every state-changing path: - updateUserData (add/replace) - removeUserData (leave) - updateFigure / updateName / updateMotto / updateNickIcon / updateCustomization / updateBackground / updateAchievementScore / updatePetLevel / updatePetBreedingStatus The inner IRoomUserData objects keep their existing in-place mutation semantics (deep-clone would be too expensive for 30+ avatars on every single status push). Consumers should treat each entry as a snapshot-at-time-of-read and not retain references across an invalidation. New event: NitroEventType.ROOM_USER_LIST_UPDATED. Interface and event additions are backwards-compatible; no existing accessors changed. Also tidied: `updatePetLevel` now uses the explicit `if(!userData) return;` guard pattern matching the rest of the methods (was a one-line inline conditional).
This commit is contained in:
@@ -23,4 +23,20 @@ export interface IUserDataManager
|
||||
updatePetLevel(roomIndex: number, level: number): void;
|
||||
updatePetBreedingStatus(roomIndex: number, canBreed: boolean, canHarvest: boolean, canRevive: boolean, hasBreedingPermission: boolean): void;
|
||||
requestPetInfo(id: number): void;
|
||||
|
||||
/**
|
||||
* Returns the current room's user list as a referentially-stable
|
||||
* ReadonlyArray. The same array reference is returned across reads
|
||||
* until any user is added, removed, or has a tracked field updated
|
||||
* (figure / name / motto / nick icon / customization / background /
|
||||
* achievement score / pet level / breeding status). Mutations
|
||||
* dispatch `NitroEventType.ROOM_USER_LIST_UPDATED` to signal
|
||||
* invalidation.
|
||||
*
|
||||
* The inner IRoomUserData objects keep the existing in-place
|
||||
* mutation semantics — they are NOT deep-cloned. Treat them as
|
||||
* snapshots-at-time-of-read; consumers should not retain individual
|
||||
* entries across invalidations.
|
||||
*/
|
||||
getRoomUserListSnapshot(): ReadonlyArray<IRoomUserData>;
|
||||
}
|
||||
|
||||
@@ -21,4 +21,5 @@ export class NitroEventType
|
||||
public static readonly ROOM_SESSION_UPDATED = 'ROOM_SESSION_UPDATED';
|
||||
public static readonly IGNORED_USERS_UPDATED = 'IGNORED_USERS_UPDATED';
|
||||
public static readonly GROUP_BADGES_UPDATED = 'GROUP_BADGES_UPDATED';
|
||||
public static readonly ROOM_USER_LIST_UPDATED = 'ROOM_USER_LIST_UPDATED';
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { IRoomUserData, IUserDataManager } from '@nitrots/api';
|
||||
import { GetCommunication, RequestPetInfoComposer, UserCurrentBadgesComposer } from '@nitrots/communication';
|
||||
import { GetEventDispatcher, NitroEvent, NitroEventType } from '@nitrots/events';
|
||||
|
||||
export class UserDataManager implements IUserDataManager
|
||||
{
|
||||
@@ -11,6 +12,23 @@ export class UserDataManager implements IUserDataManager
|
||||
private _userDataByType: Map<number, Map<number, IRoomUserData>> = new Map();
|
||||
private _userDataByRoomIndex: Map<number, IRoomUserData> = new Map();
|
||||
private _userBadges: Map<number, string[]> = new Map();
|
||||
private _roomUserListSnapshot: ReadonlyArray<IRoomUserData> | null = null;
|
||||
|
||||
private invalidateRoomUserListSnapshot(): void
|
||||
{
|
||||
this._roomUserListSnapshot = null;
|
||||
|
||||
GetEventDispatcher().dispatchEvent(new NitroEvent(NitroEventType.ROOM_USER_LIST_UPDATED));
|
||||
}
|
||||
|
||||
public getRoomUserListSnapshot(): ReadonlyArray<IRoomUserData>
|
||||
{
|
||||
if(this._roomUserListSnapshot) return this._roomUserListSnapshot;
|
||||
|
||||
this._roomUserListSnapshot = Object.freeze<IRoomUserData[]>([ ...this._userDataByRoomIndex.values() ]) as ReadonlyArray<IRoomUserData>;
|
||||
|
||||
return this._roomUserListSnapshot;
|
||||
}
|
||||
|
||||
public getUserData(webID: number): IRoomUserData
|
||||
{
|
||||
@@ -84,6 +102,8 @@ export class UserDataManager implements IUserDataManager
|
||||
existingType.set(data.webID, data);
|
||||
|
||||
this._userDataByRoomIndex.set(data.roomIndex, data);
|
||||
|
||||
this.invalidateRoomUserListSnapshot();
|
||||
}
|
||||
|
||||
public removeUserData(roomIndex: number): void
|
||||
@@ -97,6 +117,8 @@ export class UserDataManager implements IUserDataManager
|
||||
const existingType = this._userDataByType.get(existing.type);
|
||||
|
||||
if(existingType) existingType.delete(existing.webID);
|
||||
|
||||
this.invalidateRoomUserListSnapshot();
|
||||
}
|
||||
|
||||
public getUserBadges(userId: number): string[]
|
||||
@@ -125,6 +147,8 @@ export class UserDataManager implements IUserDataManager
|
||||
userData.sex = sex;
|
||||
userData.hasSaddle = hasSaddle;
|
||||
userData.isRiding = isRiding;
|
||||
|
||||
this.invalidateRoomUserListSnapshot();
|
||||
}
|
||||
|
||||
public updateName(roomIndex: number, name: string): void
|
||||
@@ -134,6 +158,8 @@ export class UserDataManager implements IUserDataManager
|
||||
if(!userData) return;
|
||||
|
||||
userData.name = name;
|
||||
|
||||
this.invalidateRoomUserListSnapshot();
|
||||
}
|
||||
|
||||
public updateMotto(roomIndex: number, custom: string): void
|
||||
@@ -143,6 +169,8 @@ export class UserDataManager implements IUserDataManager
|
||||
if(!userData) return;
|
||||
|
||||
userData.custom = custom;
|
||||
|
||||
this.invalidateRoomUserListSnapshot();
|
||||
}
|
||||
|
||||
public updateNickIcon(roomIndex: number, nickIcon: string): void
|
||||
@@ -152,6 +180,8 @@ export class UserDataManager implements IUserDataManager
|
||||
if(!userData) return;
|
||||
|
||||
userData.nickIcon = nickIcon;
|
||||
|
||||
this.invalidateRoomUserListSnapshot();
|
||||
}
|
||||
|
||||
public updateCustomization(roomIndex: number, nickIcon: string, prefixText: string, prefixColor: string, prefixIcon: string, prefixEffect: string, prefixFont: string, displayOrder: string): void
|
||||
@@ -167,6 +197,8 @@ export class UserDataManager implements IUserDataManager
|
||||
userData.prefixEffect = prefixEffect;
|
||||
userData.prefixFont = prefixFont;
|
||||
userData.displayOrder = displayOrder;
|
||||
|
||||
this.invalidateRoomUserListSnapshot();
|
||||
}
|
||||
|
||||
public updateBackground(roomIndex: number, background: number, stand: number, overlay: number, cardBackground: number = 0): void
|
||||
@@ -179,6 +211,8 @@ export class UserDataManager implements IUserDataManager
|
||||
userData.stand = stand;
|
||||
userData.overlay = overlay;
|
||||
userData.cardBackground = cardBackground;
|
||||
|
||||
this.invalidateRoomUserListSnapshot();
|
||||
}
|
||||
|
||||
public updateAchievementScore(roomIndex: number, score: number): void
|
||||
@@ -188,13 +222,19 @@ export class UserDataManager implements IUserDataManager
|
||||
if(!userData) return;
|
||||
|
||||
userData.activityPoints = score;
|
||||
|
||||
this.invalidateRoomUserListSnapshot();
|
||||
}
|
||||
|
||||
public updatePetLevel(roomIndex: number, level: number): void
|
||||
{
|
||||
const userData = this.getUserDataByIndex(roomIndex);
|
||||
|
||||
if(userData) userData.petLevel = level;
|
||||
if(!userData) return;
|
||||
|
||||
userData.petLevel = level;
|
||||
|
||||
this.invalidateRoomUserListSnapshot();
|
||||
}
|
||||
|
||||
public updatePetBreedingStatus(roomIndex: number, canBreed: boolean, canHarvest: boolean, canRevive: boolean, hasBreedingPermission: boolean): void
|
||||
@@ -207,6 +247,8 @@ export class UserDataManager implements IUserDataManager
|
||||
userData.canHarvest = canHarvest;
|
||||
userData.canRevive = canRevive;
|
||||
userData.hasBreedingPermission = hasBreedingPermission;
|
||||
|
||||
this.invalidateRoomUserListSnapshot();
|
||||
}
|
||||
|
||||
public requestPetInfo(id: number): void
|
||||
|
||||
Reference in New Issue
Block a user