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(room): RoomMessageHandler.applyFloorModelLocally for live floor preview
Adds a public method that rebuilds the active room's floor geometry from an in-memory model string + wallHeight without touching the server. Same pipeline as the wire-driven onRoomModelEvent (FloorHeightMapMessageParser -> _planeParser -> wallGeometry), but instead of going through RoomEngine.createRoomInstance (which is a no-op on a room that already exists) it routes the resulting RoomMapData through the room object's ObjectRoomMapUpdateMessage channel - the same mechanism RoomPreviewer.updateRoomPlanes uses for its iso preview. Result: the visualization rebuilds in place and existing furniture/avatars are preserved. Refactor: extracted the parser->planeParser->wallGeometry- >RoomMapData work from onRoomModelEvent into a private _rebuildFloorGeometry(parser) helper so the wire handler and the new public method share an implementation. Intended use: tools that need a live in-room preview of a floor edit before committing it server-side (e.g. the React floor-plan editor's live-preview mode). The wire UpdateFloorPropertiesMessageComposer remains the source of truth - call applyFloorModelLocally only for transient client-side preview.
This commit is contained in:
@@ -2,11 +2,17 @@ import { AvatarGuideStatus, IConnection, IMessageEvent, IRoomCreator, IRoomObjec
|
|||||||
import { AreaHideMessageEvent, ConfInvisStateMessageEvent, DiceValueMessageEvent, FloorHeightMapEvent, FurnitureAliasesComposer, FurnitureAliasesEvent, FurnitureDataEvent, FurnitureFloorAddEvent, FurnitureFloorDataParser, FurnitureFloorEvent, FurnitureFloorRemoveEvent, FurnitureFloorUpdateEvent, FurnitureWallAddEvent, FurnitureWallDataParser, FurnitureWallEvent, FurnitureWallRemoveEvent, FurnitureWallUpdateEvent, GetCommunication, GetRoomEntryDataMessageComposer, GuideSessionEndedMessageEvent, GuideSessionErrorMessageEvent, GuideSessionStartedMessageEvent, IgnoreResultEvent, ItemDataUpdateMessageEvent, ObjectsDataUpdateEvent, ObjectsRollingEvent, OneWayDoorStatusMessageEvent, PetExperienceEvent, PetFigureUpdateEvent, RoomEntryTileMessageEvent, RoomEntryTileMessageParser, RoomHeightMapEvent, RoomHeightMapUpdateEvent, RoomPaintEvent, RoomReadyMessageEvent, RoomUnitChatEvent, RoomUnitChatShoutEvent, RoomUnitChatWhisperEvent, RoomUnitDanceEvent, RoomUnitEffectEvent, RoomUnitEvent, RoomUnitExpressionEvent, RoomUnitHandItemEvent, RoomUnitIdleEvent, RoomUnitInfoEvent, RoomUnitNumberEvent, RoomUnitRemoveEvent, RoomUnitStatusEvent, RoomUnitStatusMessage, RoomUnitTypingEvent, RoomVisualizationSettingsEvent, UserInfoEvent, WiredFurniMovementData, WiredMovementsEvent, WiredUserDirectionUpdateData, WiredUserMovementData, YouArePlayingGameEvent } from '@nitrots/communication';
|
import { AreaHideMessageEvent, ConfInvisStateMessageEvent, DiceValueMessageEvent, FloorHeightMapEvent, FurnitureAliasesComposer, FurnitureAliasesEvent, FurnitureDataEvent, FurnitureFloorAddEvent, FurnitureFloorDataParser, FurnitureFloorEvent, FurnitureFloorRemoveEvent, FurnitureFloorUpdateEvent, FurnitureWallAddEvent, FurnitureWallDataParser, FurnitureWallEvent, FurnitureWallRemoveEvent, FurnitureWallUpdateEvent, GetCommunication, GetRoomEntryDataMessageComposer, GuideSessionEndedMessageEvent, GuideSessionErrorMessageEvent, GuideSessionStartedMessageEvent, IgnoreResultEvent, ItemDataUpdateMessageEvent, ObjectsDataUpdateEvent, ObjectsRollingEvent, OneWayDoorStatusMessageEvent, PetExperienceEvent, PetFigureUpdateEvent, RoomEntryTileMessageEvent, RoomEntryTileMessageParser, RoomHeightMapEvent, RoomHeightMapUpdateEvent, RoomPaintEvent, RoomReadyMessageEvent, RoomUnitChatEvent, RoomUnitChatShoutEvent, RoomUnitChatWhisperEvent, RoomUnitDanceEvent, RoomUnitEffectEvent, RoomUnitEvent, RoomUnitExpressionEvent, RoomUnitHandItemEvent, RoomUnitIdleEvent, RoomUnitInfoEvent, RoomUnitNumberEvent, RoomUnitRemoveEvent, RoomUnitStatusEvent, RoomUnitStatusMessage, RoomUnitTypingEvent, RoomVisualizationSettingsEvent, UserInfoEvent, WiredFurniMovementData, WiredMovementsEvent, WiredUserDirectionUpdateData, WiredUserMovementData, YouArePlayingGameEvent } from '@nitrots/communication';
|
||||||
import { GetRoomSessionManager, GetSessionDataManager } from '@nitrots/session';
|
import { GetRoomSessionManager, GetSessionDataManager } from '@nitrots/session';
|
||||||
import { Vector3d } from '@nitrots/utils';
|
import { Vector3d } from '@nitrots/utils';
|
||||||
|
import { FloorHeightMapMessageParser } from '@nitrots/communication';
|
||||||
import { GetRoomEngine } from './GetRoomEngine';
|
import { GetRoomEngine } from './GetRoomEngine';
|
||||||
import { RoomVariableEnum } from './RoomVariableEnum';
|
import { RoomVariableEnum } from './RoomVariableEnum';
|
||||||
|
import { ObjectRoomMapUpdateMessage } from './messages';
|
||||||
import { RoomPlaneParser } from './object/RoomPlaneParser';
|
import { RoomPlaneParser } from './object/RoomPlaneParser';
|
||||||
import { FurnitureStackingHeightMap, LegacyWallGeometry } from './utils';
|
import { FurnitureStackingHeightMap, LegacyWallGeometry } from './utils';
|
||||||
|
|
||||||
|
// Local mirror of `RoomEngine.ROOM_OBJECT_ID` to avoid a circular
|
||||||
|
// import between this handler and the engine that owns it.
|
||||||
|
const ROOM_OWN_OBJECT_ID = -1;
|
||||||
|
|
||||||
type AreaHideControllerState = {
|
type AreaHideControllerState = {
|
||||||
rootX: number;
|
rootX: number;
|
||||||
rootY: number;
|
rootY: number;
|
||||||
@@ -232,9 +238,75 @@ export class RoomMessageHandler
|
|||||||
|
|
||||||
if(!parser) return;
|
if(!parser) return;
|
||||||
|
|
||||||
|
const roomMap = this._rebuildFloorGeometry(parser);
|
||||||
|
|
||||||
|
if(!roomMap) return;
|
||||||
|
|
||||||
|
// Initial server-driven load: create the instance from
|
||||||
|
// scratch. RoomEngine.createRoomInstance is a no-op when
|
||||||
|
// the room already exists, so we never accidentally wipe
|
||||||
|
// furniture/avatars on a re-enter.
|
||||||
|
this._roomEngine.createRoomInstance(this._currentRoomId, roomMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a floor model to the ACTIVE room locally, without
|
||||||
|
* touching the server. Drives the same `wallGeometry` +
|
||||||
|
* `RoomPlaneParser` pipeline as the wire-driven path, then
|
||||||
|
* routes the resulting `RoomMapData` through the room object's
|
||||||
|
* `ObjectRoomMapUpdateMessage` channel — the same mechanism
|
||||||
|
* `RoomPreviewer.updateRoomPlanes` uses. The visualization
|
||||||
|
* rebuilds in place, so existing furniture and avatars are
|
||||||
|
* preserved.
|
||||||
|
*
|
||||||
|
* Intended for tools that need a live in-room preview of a
|
||||||
|
* floor edit before the user commits to a server save (e.g.
|
||||||
|
* the React floor-plan editor's live-preview mode). The wire
|
||||||
|
* `UpdateFloorPropertiesMessageComposer` is still the source
|
||||||
|
* of truth — call this purely for transient client-side
|
||||||
|
* preview, then send the composer separately when the user
|
||||||
|
* confirms.
|
||||||
|
*
|
||||||
|
* @returns `true` if the floor was rebuilt; `false` if no
|
||||||
|
* active room is bound, the engine isn't ready, or the
|
||||||
|
* model string failed to parse.
|
||||||
|
*/
|
||||||
|
public applyFloorModelLocally(modelString: string, wallHeight: number, scale: boolean = true): boolean
|
||||||
|
{
|
||||||
|
if(!this._roomEngine || this._currentRoomId <= 0 || !modelString) return false;
|
||||||
|
|
||||||
|
const parser = new FloorHeightMapMessageParser();
|
||||||
|
|
||||||
|
parser.flush();
|
||||||
|
|
||||||
|
if(!parser.parseModel(modelString, wallHeight, scale)) return false;
|
||||||
|
|
||||||
|
const roomMap = this._rebuildFloorGeometry(parser);
|
||||||
|
|
||||||
|
if(!roomMap) return false;
|
||||||
|
|
||||||
|
const roomObject = this._roomEngine.getRoomObject(this._currentRoomId, ROOM_OWN_OBJECT_ID, RoomObjectCategory.ROOM);
|
||||||
|
|
||||||
|
if(!roomObject) return false;
|
||||||
|
|
||||||
|
roomObject.processUpdateMessage(new ObjectRoomMapUpdateMessage(roomMap));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shared body of `onRoomModelEvent` and
|
||||||
|
* `applyFloorModelLocally`. Feeds the floor heightmap into
|
||||||
|
* `_planeParser`, refreshes `wallGeometry`, and returns the
|
||||||
|
* resulting `RoomMapData` (doors included). The caller decides
|
||||||
|
* whether to seed a fresh room (initial enter) or update an
|
||||||
|
* existing one (live preview).
|
||||||
|
*/
|
||||||
|
private _rebuildFloorGeometry(parser: FloorHeightMapMessageParser)
|
||||||
|
{
|
||||||
const wallGeometry = this._roomEngine.getLegacyWallGeometry(this._currentRoomId);
|
const wallGeometry = this._roomEngine.getLegacyWallGeometry(this._currentRoomId);
|
||||||
|
|
||||||
if(!wallGeometry) return;
|
if(!wallGeometry) return null;
|
||||||
|
|
||||||
this._planeParser.reset();
|
this._planeParser.reset();
|
||||||
|
|
||||||
@@ -320,7 +392,7 @@ export class RoomMessageHandler
|
|||||||
dir: doorDirection
|
dir: doorDirection
|
||||||
});
|
});
|
||||||
|
|
||||||
this._roomEngine.createRoomInstance(this._currentRoomId, roomMap);
|
return roomMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private onRoomHeightMapEvent(event: RoomHeightMapEvent): void
|
private onRoomHeightMapEvent(event: RoomHeightMapEvent): void
|
||||||
|
|||||||
Reference in New Issue
Block a user