useRoom.ts 13.5 Ko
Télécharger le fichier
import {
ColorConverter,
GetDesiredResolution,
GetRenderer,
GetRoomEngine,
GetStage,
IRoomSession,
OctaneAdjustmentFilter,
OctaneSprite,
OctaneTexture,
RoomBackgroundColorEvent,
RoomEngineEvent,
RoomEngineObjectEvent,
RoomGeometry,
RoomId,
RoomObjectCategory,
RoomObjectHSLColorEnabledEvent,
RoomObjectOperationType,
RoomSessionEvent,
WiredClickSettingsEvent,
RoomVariableEnum,
Vector3d
} from '@octane/renderer';
import { useEffect, useRef, useState } from 'react';
import { registerSharedHook, useSharedHook } from '@/state/useSharedHook';
import {
CanManipulateFurniture,
DispatchUiEvent,
GetRoomSession,
IsFurnitureSelectionDisabled,
ProcessRoomObjectOperation,
RoomWidgetUpdateBackgroundColorPreviewEvent,
RoomWidgetUpdateRoomObjectEvent,
SetActiveRoomId,
StartRoomSession
} from '../../api';
import { useMessageEvent, useOctaneEvent, useUiEvent } from '../events';
import { RoomTintTarget, updateRoomTint } from './updateRoomTint';
import { useWiredFurniOpacity } from './useWiredFurniOpacity';
const getViewportSize = () => {
const viewport = window.visualViewport;
return {
width: Math.max(1, Math.floor(viewport?.width ?? window.innerWidth)),
height: Math.max(1, Math.floor(viewport?.height ?? window.innerHeight))
};
};
const useRoomState = () => {
const [roomSession, setRoomSession] = useState<IRoomSession>(null);
const [roomBackground, setRoomBackground] = useState<OctaneSprite>(null);
const [roomFilter, setRoomFilter] = useState<OctaneAdjustmentFilter>(null);
const roomMasterRef = useRef<RoomTintTarget>(null);
const [originalRoomBackgroundColor, setOriginalRoomBackgroundColor] = useState(0);
useWiredFurniOpacity(roomSession?.roomId ?? 0);
const updateRoomBackgroundColor = (hue: number, saturation: number, lightness: number, original: boolean = false) => {
if (!roomBackground) return;
const newColor = ColorConverter.hslToRGB(((hue & 0xff) << 16) + ((saturation & 0xff) << 8) + (lightness & 0xff));
if (original) setOriginalRoomBackgroundColor(newColor);
if (!hue && !saturation && !lightness) {
roomBackground.tint = 0;
} else {
roomBackground.tint = newColor;
}
};
const updateRoomFilter = (color: number) => {
if (!roomFilter) return;
updateRoomTint(roomMasterRef.current, roomFilter, color);
};
useUiEvent<RoomWidgetUpdateBackgroundColorPreviewEvent>(RoomWidgetUpdateBackgroundColorPreviewEvent.PREVIEW, (event) =>
updateRoomBackgroundColor(event.hue, event.saturation, event.lightness)
);
useUiEvent<RoomWidgetUpdateBackgroundColorPreviewEvent>(RoomWidgetUpdateBackgroundColorPreviewEvent.CLEAR_PREVIEW, (event) => {
if (!roomBackground) return;
roomBackground.tint = originalRoomBackgroundColor;
});
useOctaneEvent<RoomObjectHSLColorEnabledEvent>(RoomObjectHSLColorEnabledEvent.ROOM_BACKGROUND_COLOR, (event) => {
if (RoomId.isRoomPreviewerId(event.roomId)) return;
if (event.enable) updateRoomBackgroundColor(event.hue, event.saturation, event.lightness, true);
else updateRoomBackgroundColor(0, 0, 0, true);
});
useOctaneEvent<RoomBackgroundColorEvent>(RoomBackgroundColorEvent.ROOM_COLOR, (event) => {
if (RoomId.isRoomPreviewerId(event.roomId)) return;
let color = 0x000000;
let brightness = 0xff;
if (!event.bgOnly) {
color = event.color;
brightness = event.brightness;
}
updateRoomFilter(ColorConverter.hslToRGB((ColorConverter.rgbToHSL(color) & 0xffff00) + brightness));
});
useOctaneEvent<RoomEngineEvent>([RoomEngineEvent.INITIALIZED, RoomEngineEvent.DISPOSED], (event) => {
if (RoomId.isRoomPreviewerId(event.roomId)) return;
const session = GetRoomSession();
if (!session) return;
switch (event.type) {
case RoomEngineEvent.INITIALIZED:
SetActiveRoomId(event.roomId);
setRoomSession(session);
return;
case RoomEngineEvent.DISPOSED:
setRoomSession(null);
return;
}
});
useOctaneEvent<RoomSessionEvent>([RoomSessionEvent.CREATED, RoomSessionEvent.ENDED], (event) => {
switch (event.type) {
case RoomSessionEvent.CREATED:
StartRoomSession(event.session);
return;
case RoomSessionEvent.ENDED:
setRoomSession(null);
// A wired click setting belongs to the room that sent it.
GetRoomEngine().setWiredClickSettings(0, 0);
return;
}
});
// The room's wired click-settings box: what this player's clicks on avatars and furni do
// (walk behind, pass through). The renderer applies it and forgets it with the room.
useMessageEvent<WiredClickSettingsEvent>(WiredClickSettingsEvent, (event) => {
const parser = event.getParser();
if (!parser) return;
GetRoomEngine().setWiredClickSettings(parser.userOption, parser.furniOption);
});
useOctaneEvent<RoomEngineObjectEvent>(
[
RoomEngineObjectEvent.SELECTED,
RoomEngineObjectEvent.DESELECTED,
RoomEngineObjectEvent.ADDED,
RoomEngineObjectEvent.REMOVED,
RoomEngineObjectEvent.PLACED,
RoomEngineObjectEvent.REQUEST_MOVE,
RoomEngineObjectEvent.REQUEST_ROTATE,
RoomEngineObjectEvent.MOUSE_ENTER,
RoomEngineObjectEvent.MOUSE_LEAVE,
RoomEngineObjectEvent.DOUBLE_CLICK
],
(event) => {
if (RoomId.isRoomPreviewerId(event.roomId)) return;
let updateEvent: RoomWidgetUpdateRoomObjectEvent = null;
switch (event.type) {
case RoomEngineObjectEvent.SELECTED:
if (!IsFurnitureSelectionDisabled(event))
updateEvent = new RoomWidgetUpdateRoomObjectEvent(
RoomWidgetUpdateRoomObjectEvent.OBJECT_SELECTED,
event.objectId,
event.category,
event.roomId
);
break;
case RoomEngineObjectEvent.DESELECTED:
updateEvent = new RoomWidgetUpdateRoomObjectEvent(
RoomWidgetUpdateRoomObjectEvent.OBJECT_DESELECTED,
event.objectId,
event.category,
event.roomId
);
break;
case RoomEngineObjectEvent.ADDED: {
let addedEventType: string = null;
switch (event.category) {
case RoomObjectCategory.FLOOR:
case RoomObjectCategory.WALL:
addedEventType = RoomWidgetUpdateRoomObjectEvent.FURNI_ADDED;
break;
case RoomObjectCategory.UNIT:
addedEventType = RoomWidgetUpdateRoomObjectEvent.USER_ADDED;
break;
}
if (addedEventType) updateEvent = new RoomWidgetUpdateRoomObjectEvent(addedEventType, event.objectId, event.category, event.roomId);
break;
}
case RoomEngineObjectEvent.REMOVED: {
let removedEventType: string = null;
switch (event.category) {
case RoomObjectCategory.FLOOR:
case RoomObjectCategory.WALL:
removedEventType = RoomWidgetUpdateRoomObjectEvent.FURNI_REMOVED;
break;
case RoomObjectCategory.UNIT:
removedEventType = RoomWidgetUpdateRoomObjectEvent.USER_REMOVED;
break;
}
if (removedEventType) updateEvent = new RoomWidgetUpdateRoomObjectEvent(removedEventType, event.objectId, event.category, event.roomId);
break;
}
case RoomEngineObjectEvent.REQUEST_MOVE:
if (CanManipulateFurniture(roomSession, event.objectId, event.category))
ProcessRoomObjectOperation(event.objectId, event.category, RoomObjectOperationType.OBJECT_MOVE);
break;
case RoomEngineObjectEvent.REQUEST_ROTATE:
if (CanManipulateFurniture(roomSession, event.objectId, event.category))
ProcessRoomObjectOperation(event.objectId, event.category, RoomObjectOperationType.OBJECT_ROTATE_POSITIVE);
break;
case RoomEngineObjectEvent.MOUSE_ENTER:
updateEvent = new RoomWidgetUpdateRoomObjectEvent(
RoomWidgetUpdateRoomObjectEvent.OBJECT_ROLL_OVER,
event.objectId,
event.category,
event.roomId
);
break;
case RoomEngineObjectEvent.MOUSE_LEAVE:
updateEvent = new RoomWidgetUpdateRoomObjectEvent(
RoomWidgetUpdateRoomObjectEvent.OBJECT_ROLL_OUT,
event.objectId,
event.category,
event.roomId
);
break;
case RoomEngineObjectEvent.DOUBLE_CLICK:
updateEvent = new RoomWidgetUpdateRoomObjectEvent(
RoomWidgetUpdateRoomObjectEvent.OBJECT_DOUBLE_CLICKED,
event.objectId,
event.category,
event.roomId
);
break;
}
if (updateEvent) DispatchUiEvent(updateEvent);
}
);
useEffect(() => {
if (!roomSession) return;
const roomEngine = GetRoomEngine();
const roomId = roomSession.roomId;
const canvasId = 1;
const { width, height } = getViewportSize();
const renderer = GetRenderer();
if (renderer) renderer.resize(width, height);
const displayObject = roomEngine.getRoomInstanceDisplay(roomId, canvasId, width, height, RoomGeometry.SCALE_ZOOMED_IN);
const canvas = GetRoomEngine().getRoomInstanceRenderingCanvas(roomId, canvasId);
if (!displayObject || !canvas) return;
const background = new OctaneSprite(OctaneTexture.WHITE);
const filter = new OctaneAdjustmentFilter();
const master = canvas.master;
background.tint = 0;
background.width = width;
background.height = height;
master.addChildAt(background, 0);
// A white tint is an identity; the filter is attached only while the mood light changes it.
roomMasterRef.current = master;
setRoomBackground(background);
setRoomFilter(filter);
const geometry = roomEngine.getRoomInstanceGeometry(roomId, canvasId) as RoomGeometry;
if (geometry) {
const minX = roomEngine.getRoomInstanceVariable<number>(roomId, RoomVariableEnum.ROOM_MIN_X) || 0;
const maxX = roomEngine.getRoomInstanceVariable<number>(roomId, RoomVariableEnum.ROOM_MAX_X) || 0;
const minY = roomEngine.getRoomInstanceVariable<number>(roomId, RoomVariableEnum.ROOM_MIN_Y) || 0;
const maxY = roomEngine.getRoomInstanceVariable<number>(roomId, RoomVariableEnum.ROOM_MAX_Y) || 0;
let x = (minX + maxX) / 2;
let y = (minY + maxY) / 2;
const offset = 20;
x = x + (offset - 1);
y = y + (offset - 1);
const z = Math.sqrt(offset * offset + offset * offset) * Math.tan((30 / 180) * Math.PI);
geometry.location = new Vector3d(x, y, z);
}
GetStage().addChild(displayObject);
SetActiveRoomId(roomSession.roomId);
const resize = () => {
const { width: newWidth, height: newHeight } = getViewportSize();
const offsetX = canvas.screenOffsetX - (newWidth - canvas.width) / 2;
const offsetY = canvas.screenOffsetY - (newHeight - canvas.height) / 2;
renderer.resize(newWidth, newHeight, GetDesiredResolution());
background.width = newWidth;
background.height = newHeight;
canvas.initialize(newWidth, newHeight);
canvas.screenOffsetX = ~~offsetX;
canvas.screenOffsetY = ~~offsetY;
};
const viewport = window.visualViewport;
window.addEventListener('resize', resize);
viewport?.addEventListener('resize', resize);
viewport?.addEventListener('scroll', resize);
return () => {
setRoomBackground(null);
setRoomFilter(null);
updateRoomTint(master, filter, 0xffffff);
roomMasterRef.current = null;
filter.destroy();
setOriginalRoomBackgroundColor(0);
window.removeEventListener('resize', resize);
viewport?.removeEventListener('resize', resize);
viewport?.removeEventListener('scroll', resize);
};
}, [roomSession]);
// roomBackgroundColor: the room background colour (AIR roomDesktop.roomBackgroundColor), used by the camera scene.
return { roomSession, roomBackgroundColor: originalRoomBackgroundColor };
};
export const useRoom = () => useSharedHook(useRoomState);
registerSharedHook(useRoomState);
