Merge pull request #39 from duckietm/Dev

Dev
This commit is contained in:
DuckieTM
2026-03-31 16:03:51 +02:00
committed by GitHub
30 changed files with 718 additions and 265 deletions
+3 -3
View File
@@ -24,9 +24,9 @@ export interface IRoomCreator
getRoomObjectUser(roomId: number, objectId: number): IRoomObjectController;
removeRoomObjectUser(roomId: number, objectId: number): void;
getRoomObjectFloor(roomId: number, objectId: number): IRoomObjectController;
addFurnitureFloor(roomId: number, id: number, typeId: number, location: IVector3D, direction: IVector3D, state: number, objectData: IObjectData, extra?: number, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, synchronized?: boolean, realRoomObject?: boolean, sizeZ?: number): boolean;
addFurnitureFloorByTypeName(roomId: number, id: number, typeName: string, location: IVector3D, direction: IVector3D, state: number, objectData: IObjectData, extra?: number, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, synchronized?: boolean, realRoomObject?: boolean, sizeZ?: number): boolean;
addFurnitureWall(roomId: number, id: number, typeId: number, location: IVector3D, direction: IVector3D, state: number, extra: string, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, realRoomObject?: boolean): boolean;
addFurnitureFloor(roomId: number, id: number, typeId: number, location: IVector3D, direction: IVector3D, state: number, objectData: IObjectData, extra?: number, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, synchronized?: boolean, realRoomObject?: boolean, sizeZ?: number, allowStack?: boolean, allowSit?: boolean, allowLay?: boolean, allowWalk?: boolean, dimensionsX?: number, dimensionsY?: number, teleportTargetId?: number): boolean;
addFurnitureFloorByTypeName(roomId: number, id: number, typeName: string, location: IVector3D, direction: IVector3D, state: number, objectData: IObjectData, extra?: number, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, synchronized?: boolean, realRoomObject?: boolean, sizeZ?: number, allowStack?: boolean, allowSit?: boolean, allowLay?: boolean, allowWalk?: boolean, dimensionsX?: number, dimensionsY?: number, teleportTargetId?: number): boolean;
addFurnitureWall(roomId: number, id: number, typeId: number, location: IVector3D, direction: IVector3D, state: number, extra: string, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, realRoomObject?: boolean, allowStack?: boolean, allowSit?: boolean, allowLay?: boolean, allowWalk?: boolean, dimensionsX?: number, dimensionsY?: number, teleportTargetId?: number): boolean;
removeRoomObjectFloor(roomId: number, objectId: number, userId?: number, _arg_4?: boolean): void;
removeRoomObjectWall(roomId: number, objectId: number, userId?: number): void;
updateRoomObjectFloor(roomId: number, objectId: number, location: IVector3D, direction: IVector3D, state: number, data: IObjectData, extra?: number): boolean;
+3 -3
View File
@@ -46,9 +46,9 @@ export interface IRoomEngine
updateRoomObjectWallLocation(roomId: number, objectId: number, location: IVector3D): boolean;
addRoomObjectUser(roomId: number, objectId: number, location: IVector3D, direction: IVector3D, headDirection: number, type: number, figure: string): boolean;
updateRoomObjectUserLocation(roomId: number, objectId: number, location: IVector3D, targetLocation: IVector3D, canStandUp?: boolean, baseY?: number, direction?: IVector3D, headDirection?: number, skipLocationFix?: boolean, isSlide?: boolean, duration?: number): boolean;
addFurnitureFloor(roomId: number, id: number, typeId: number, location: IVector3D, direction: IVector3D, state: number, objectData: IObjectData, extra?: number, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, synchronized?: boolean, realRoomObject?: boolean, sizeZ?: number): boolean;
addFurnitureFloorByTypeName(roomId: number, id: number, typeName: string, location: IVector3D, direction: IVector3D, state: number, objectData: IObjectData, extra?: number, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, synchronized?: boolean, realRoomObject?: boolean, sizeZ?: number): boolean;
addFurnitureWall(roomId: number, id: number, typeId: number, location: IVector3D, direction: IVector3D, state: number, extra: string, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, realRoomObject?: boolean): boolean;
addFurnitureFloor(roomId: number, id: number, typeId: number, location: IVector3D, direction: IVector3D, state: number, objectData: IObjectData, extra?: number, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, synchronized?: boolean, realRoomObject?: boolean, sizeZ?: number, allowStack?: boolean, allowSit?: boolean, allowLay?: boolean, allowWalk?: boolean, dimensionsX?: number, dimensionsY?: number, teleportTargetId?: number): boolean;
addFurnitureFloorByTypeName(roomId: number, id: number, typeName: string, location: IVector3D, direction: IVector3D, state: number, objectData: IObjectData, extra?: number, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, synchronized?: boolean, realRoomObject?: boolean, sizeZ?: number, allowStack?: boolean, allowSit?: boolean, allowLay?: boolean, allowWalk?: boolean, dimensionsX?: number, dimensionsY?: number, teleportTargetId?: number): boolean;
addFurnitureWall(roomId: number, id: number, typeId: number, location: IVector3D, direction: IVector3D, state: number, extra: string, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, realRoomObject?: boolean, allowStack?: boolean, allowSit?: boolean, allowLay?: boolean, allowWalk?: boolean, dimensionsX?: number, dimensionsY?: number, teleportTargetId?: number): boolean;
initalizeTemporaryObjectsByType(type: string, _arg_2: boolean): void;
updateRoomObjectFloor(roomId: number, objectId: number, location: IVector3D, direction: IVector3D, state: number, data: IObjectData, extra?: number): boolean;
updateRoomObjectWall(roomId: number, objectId: number, location: IVector3D, direction: IVector3D, state: number, extra?: string): boolean;
@@ -22,9 +22,9 @@ export interface IRoomEngineServices
getRoomObjectCursor(roomId: number): IRoomObjectController;
getRoomObjectSelectionArrow(roomId: number): IRoomObjectController;
addRoomObjectUser(roomId: number, objectId: number, location: IVector3D, direction: IVector3D, headDirection: number, type: number, figure: string): boolean;
addFurnitureFloor(roomId: number, id: number, typeId: number, location: IVector3D, direction: IVector3D, state: number, objectData: IObjectData, extra?: number, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, synchronized?: boolean, realRoomObject?: boolean, sizeZ?: number): boolean;
addFurnitureFloorByTypeName(roomId: number, id: number, typeName: string, location: IVector3D, direction: IVector3D, state: number, objectData: IObjectData, extra?: number, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, synchronized?: boolean, realRoomObject?: boolean, sizeZ?: number): boolean;
addFurnitureWall(roomId: number, id: number, typeId: number, location: IVector3D, direction: IVector3D, state: number, extra: string, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, realRoomObject?: boolean): boolean;
addFurnitureFloor(roomId: number, id: number, typeId: number, location: IVector3D, direction: IVector3D, state: number, objectData: IObjectData, extra?: number, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, synchronized?: boolean, realRoomObject?: boolean, sizeZ?: number, allowStack?: boolean, allowSit?: boolean, allowLay?: boolean, allowWalk?: boolean, dimensionsX?: number, dimensionsY?: number, teleportTargetId?: number): boolean;
addFurnitureFloorByTypeName(roomId: number, id: number, typeName: string, location: IVector3D, direction: IVector3D, state: number, objectData: IObjectData, extra?: number, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, synchronized?: boolean, realRoomObject?: boolean, sizeZ?: number, allowStack?: boolean, allowSit?: boolean, allowLay?: boolean, allowWalk?: boolean, dimensionsX?: number, dimensionsY?: number, teleportTargetId?: number): boolean;
addFurnitureWall(roomId: number, id: number, typeId: number, location: IVector3D, direction: IVector3D, state: number, extra: string, expires?: number, usagePolicy?: number, ownerId?: number, ownerName?: string, realRoomObject?: boolean, allowStack?: boolean, allowSit?: boolean, allowLay?: boolean, allowWalk?: boolean, dimensionsX?: number, dimensionsY?: number, teleportTargetId?: number): boolean;
removeRoomObjectFloor(roomId: number, objectId: number, userId?: number, _arg_4?: boolean): void;
removeRoomObjectWall(roomId: number, objectId: number, userId?: number): void;
removeRoomObjectUser(roomId: number, objectId: number): void;
@@ -83,6 +83,13 @@ export class RoomObjectVariable
public static FURNITURE_USAGE_POLICY: string = 'furniture_usage_policy';
public static FURNITURE_OWNER_ID: string = 'furniture_owner_id';
public static FURNITURE_OWNER_NAME: string = 'furniture_owner_name';
public static FURNITURE_ALLOW_STACK: string = 'furniture_allow_stack';
public static FURNITURE_ALLOW_SIT: string = 'furniture_allow_sit';
public static FURNITURE_ALLOW_LAY: string = 'furniture_allow_lay';
public static FURNITURE_ALLOW_WALK: string = 'furniture_allow_walk';
public static FURNITURE_DIMENSIONS_X: string = 'furniture_dimensions_x';
public static FURNITURE_DIMENSIONS_Y: string = 'furniture_dimensions_y';
public static FURNITURE_TELEPORT_TARGET_ID: string = 'furniture_teleport_target_id';
public static FURNITURE_ROOM_BACKGROUND_COLOR_HUE: string = 'furniture_room_background_color_hue';
public static FURNITURE_ROOM_BACKGROUND_COLOR_SATURATION: string = 'furniture_room_background_color_saturation';
public static FURNITURE_ROOM_BACKGROUND_COLOR_LIGHTNESS: string = 'furniture_room_background_color_lightness';
@@ -24,6 +24,7 @@ export interface IFurnitureData
purchaseCouldBeUsedForBuyout: boolean;
rentCouldBeUsedForBuyout: boolean;
availableForBuildersClub: boolean;
allowStack: boolean;
canStandOn: boolean;
canSitOn: boolean;
canLayOn: boolean;
@@ -57,6 +57,11 @@ export interface IRoomSession
allowPets: boolean;
controllerLevel: number;
ownRoomIndex: number;
groupId: number;
hotelTimeZone: string;
hotelTimeSnapshotMs: number;
hotelTimeSyncMs: number;
roomItemLimit: number;
isGuildRoom: boolean;
isRoomOwner: boolean;
isDecorating: boolean;
@@ -23,4 +23,6 @@ export interface IRoomUserData
petLevel: number;
botSkills: number[];
isModerator: boolean;
roomEntryMethod: string;
roomEntryTeleportId: number;
}
+2
View File
@@ -285,6 +285,8 @@ export class AvatarImage implements IAvatarImage, IAvatarEffectListener
const container = this.buildAvatarContainer(avatarCanvas, setType);
if(!container) return null;
GetRenderer().render({
target: this._activeTexture,
container: container,
@@ -117,7 +117,12 @@ export class RoomCameraWidgetManager implements IRoomCameraWidgetManager
TextureUtils.writeToTexture(container, renderTexture);
return await TextureUtils.generateImage(renderTexture);
const image = await TextureUtils.generateImage(renderTexture);
container.destroy({ children: true });
renderTexture.destroy(true);
return image;
}
public get effects(): Map<string, IRoomCameraWidgetEffect>
@@ -62,7 +62,8 @@ export class CommunicationManager implements ICommunicationManager
t.shadowColor = 'blue';
t.fillRect(-20, 10, 234, 5);
const i = e.toDataURL();
document.body.appendChild(e);
e.width = 0;
e.height = 0;
let r = 0;
if (i.length === 0) return 'nothing!';
for (let n = 0; n < i.length; n++) {
@@ -11,6 +11,9 @@ export class GetGuestRoomResultMessageParser implements IMessageParser
private _isGroupMember: boolean;
private _moderation: RoomModerationSettings;
private _chat: RoomChatSettings;
private _hotelTimeZoneId: string;
private _hotelCurrentTimeMs: number;
private _roomItemLimit: number;
public flush(): boolean
{
@@ -21,6 +24,9 @@ export class GetGuestRoomResultMessageParser implements IMessageParser
this._isGroupMember = false;
this._moderation = null;
this._chat = null;
this._hotelTimeZoneId = null;
this._hotelCurrentTimeMs = 0;
this._roomItemLimit = 0;
return true;
}
@@ -39,6 +45,13 @@ export class GetGuestRoomResultMessageParser implements IMessageParser
this.data.canMute = wrapper.readBoolean();
this._chat = new RoomChatSettings(wrapper);
if(wrapper.bytesAvailable)
{
this._hotelTimeZoneId = wrapper.readString();
this._hotelCurrentTimeMs = Number(wrapper.readString()) || 0;
if(wrapper.bytesAvailable) this._roomItemLimit = wrapper.readInt();
}
return true;
}
@@ -76,4 +89,19 @@ export class GetGuestRoomResultMessageParser implements IMessageParser
{
return this._chat;
}
public get hotelTimeZoneId(): string
{
return this._hotelTimeZoneId;
}
public get hotelCurrentTimeMs(): number
{
return this._hotelCurrentTimeMs;
}
public get roomItemLimit(): number
{
return this._roomItemLimit;
}
}
@@ -25,6 +25,13 @@ export class FurnitureFloorDataParser
private _usagePolicy: number;
private _userId: number;
private _username: string;
private _allowStack: boolean;
private _allowSit: boolean;
private _allowLay: boolean;
private _allowWalk: boolean;
private _dimensionsX: number;
private _dimensionsY: number;
private _teleportTargetId: number;
constructor(wrapper: IMessageDataWrapper)
{
@@ -51,6 +58,13 @@ export class FurnitureFloorDataParser
this._usagePolicy = 0;
this._userId = 0;
this._username = null;
this._allowStack = false;
this._allowSit = false;
this._allowLay = false;
this._allowWalk = false;
this._dimensionsX = 0;
this._dimensionsY = 0;
this._teleportTargetId = 0;
return true;
}
@@ -72,6 +86,13 @@ export class FurnitureFloorDataParser
this._expires = wrapper.readInt();
this._usagePolicy = wrapper.readInt();
this._userId = wrapper.readInt();
this._allowStack = (wrapper.readInt() === 1);
this._allowSit = (wrapper.readInt() === 1);
this._allowLay = (wrapper.readInt() === 1);
this._allowWalk = (wrapper.readInt() === 1);
this._dimensionsX = wrapper.readInt();
this._dimensionsY = wrapper.readInt();
this._teleportTargetId = wrapper.readInt();
this._username = null;
if(this._spriteId < 0) this._spriteName = wrapper.readString();
@@ -149,6 +170,41 @@ export class FurnitureFloorDataParser
return this._username;
}
public get allowStack(): boolean
{
return this._allowStack;
}
public get allowSit(): boolean
{
return this._allowSit;
}
public get allowLay(): boolean
{
return this._allowLay;
}
public get allowWalk(): boolean
{
return this._allowWalk;
}
public get dimensionsX(): number
{
return this._dimensionsX;
}
public get dimensionsY(): number
{
return this._dimensionsY;
}
public get teleportTargetId(): number
{
return this._teleportTargetId;
}
public set username(username: string)
{
this._username = username;
@@ -11,6 +11,13 @@ export class FurnitureWallDataParser
private _usagePolicy: number;
private _userId: number;
private _username: string;
private _allowStack: boolean;
private _allowSit: boolean;
private _allowLay: boolean;
private _allowWalk: boolean;
private _dimensionsX: number;
private _dimensionsY: number;
private _teleportTargetId: number;
private _width: number;
private _height: number;
@@ -40,6 +47,13 @@ export class FurnitureWallDataParser
this._usagePolicy = -1;
this._userId = 0;
this._username = null;
this._allowStack = false;
this._allowSit = false;
this._allowLay = false;
this._allowWalk = false;
this._dimensionsX = 0;
this._dimensionsY = 0;
this._teleportTargetId = 0;
this._width = 0;
this._height = 0;
@@ -64,6 +78,13 @@ export class FurnitureWallDataParser
this._secondsToExpiration = wrapper.readInt();
this._usagePolicy = wrapper.readInt();
this._userId = wrapper.readInt();
this._allowStack = (wrapper.readInt() === 1);
this._allowSit = (wrapper.readInt() === 1);
this._allowLay = (wrapper.readInt() === 1);
this._allowWalk = (wrapper.readInt() === 1);
this._dimensionsX = wrapper.readInt();
this._dimensionsY = wrapper.readInt();
this._teleportTargetId = wrapper.readInt();
this._username = null;
const state = parseFloat(this._stuffData);
@@ -191,6 +212,41 @@ export class FurnitureWallDataParser
return this._username;
}
public get allowStack(): boolean
{
return this._allowStack;
}
public get allowSit(): boolean
{
return this._allowSit;
}
public get allowLay(): boolean
{
return this._allowLay;
}
public get allowWalk(): boolean
{
return this._allowWalk;
}
public get dimensionsX(): number
{
return this._dimensionsX;
}
public get dimensionsY(): number
{
return this._dimensionsY;
}
public get teleportTargetId(): number
{
return this._teleportTargetId;
}
public set username(username: string)
{
this._username = username;
@@ -135,6 +135,9 @@ export class RoomUnitParser implements IMessageParser
}
}
user.roomEntryMethod = wrapper.readString();
user.roomEntryTeleportId = wrapper.readInt();
i++;
}
@@ -35,6 +35,8 @@ export class UserMessageData
private _petPosture: string = '';
private _botSkills: number[] = [];
private _isModerator: boolean = false;
private _roomEntryMethod: string = 'unknown';
private _roomEntryTeleportId: number = 0;
private _isReadOnly: boolean = false;
constructor(k: number)
@@ -442,4 +444,30 @@ export class UserMessageData
this._isModerator = k;
}
}
public get roomEntryMethod(): string
{
return this._roomEntryMethod;
}
public set roomEntryMethod(k: string)
{
if(!this._isReadOnly)
{
this._roomEntryMethod = k;
}
}
public get roomEntryTeleportId(): number
{
return this._roomEntryTeleportId;
}
public set roomEntryTeleportId(k: number)
{
if(!this._isReadOnly)
{
this._roomEntryTeleportId = k;
}
}
}
+20 -6
View File
@@ -819,6 +819,13 @@ export class RoomEngine implements IRoomEngine, IRoomCreator, IRoomEngineService
model.setValue(RoomObjectVariable.FURNITURE_USAGE_POLICY, data.usagePolicy);
model.setValue(RoomObjectVariable.FURNITURE_OWNER_ID, data.ownerId);
model.setValue(RoomObjectVariable.FURNITURE_OWNER_NAME, data.ownerName);
model.setValue(RoomObjectVariable.FURNITURE_ALLOW_STACK, data.allowStack ? 1 : 0);
model.setValue(RoomObjectVariable.FURNITURE_ALLOW_SIT, data.allowSit ? 1 : 0);
model.setValue(RoomObjectVariable.FURNITURE_ALLOW_LAY, data.allowLay ? 1 : 0);
model.setValue(RoomObjectVariable.FURNITURE_ALLOW_WALK, data.allowWalk ? 1 : 0);
model.setValue(RoomObjectVariable.FURNITURE_DIMENSIONS_X, data.dimensionsX);
model.setValue(RoomObjectVariable.FURNITURE_DIMENSIONS_Y, data.dimensionsY);
model.setValue(RoomObjectVariable.FURNITURE_TELEPORT_TARGET_ID, data.teleportTargetId);
}
if(!this.updateRoomObjectFloor(roomId, id, data.location, data.direction, data.state, data.data, data.extra)) return false;
@@ -879,6 +886,13 @@ export class RoomEngine implements IRoomEngine, IRoomCreator, IRoomEngineService
model.setValue(RoomObjectVariable.FURNITURE_USAGE_POLICY, data.usagePolicy);
model.setValue(RoomObjectVariable.FURNITURE_OWNER_ID, data.ownerId);
model.setValue(RoomObjectVariable.FURNITURE_OWNER_NAME, data.ownerName);
model.setValue(RoomObjectVariable.FURNITURE_ALLOW_STACK, data.allowStack ? 1 : 0);
model.setValue(RoomObjectVariable.FURNITURE_ALLOW_SIT, data.allowSit ? 1 : 0);
model.setValue(RoomObjectVariable.FURNITURE_ALLOW_LAY, data.allowLay ? 1 : 0);
model.setValue(RoomObjectVariable.FURNITURE_ALLOW_WALK, data.allowWalk ? 1 : 0);
model.setValue(RoomObjectVariable.FURNITURE_DIMENSIONS_X, data.dimensionsX);
model.setValue(RoomObjectVariable.FURNITURE_DIMENSIONS_Y, data.dimensionsY);
model.setValue(RoomObjectVariable.FURNITURE_TELEPORT_TARGET_ID, data.teleportTargetId);
}
if(!this.updateRoomObjectWall(roomId, id, data.location, data.direction, data.state, extra)) return false;
@@ -1667,33 +1681,33 @@ export class RoomEngine implements IRoomEngine, IRoomCreator, IRoomEngineService
if(GetEventDispatcher()) GetEventDispatcher().dispatchEvent(new RoomEngineObjectEvent(RoomEngineObjectEvent.REMOVED, roomId, objectId, category));
}
public addFurnitureFloor(roomId: number, id: number, typeId: number, location: IVector3D, direction: IVector3D, state: number, objectData: IObjectData, extra: number = NaN, expires: number = -1, usagePolicy: number = 0, ownerId: number = 0, ownerName: string = '', synchronized: boolean = true, realRoomObject: boolean = true, sizeZ: number = -1): boolean
public addFurnitureFloor(roomId: number, id: number, typeId: number, location: IVector3D, direction: IVector3D, state: number, objectData: IObjectData, extra: number = NaN, expires: number = -1, usagePolicy: number = 0, ownerId: number = 0, ownerName: string = '', synchronized: boolean = true, realRoomObject: boolean = true, sizeZ: number = -1, allowStack: boolean = false, allowSit: boolean = false, allowLay: boolean = false, allowWalk: boolean = false, dimensionsX: number = 0, dimensionsY: number = 0, teleportTargetId: number = 0): boolean
{
const instanceData = this.getRoomInstanceData(roomId);
if(!instanceData) return false;
const furnitureData = new RoomFurnitureData(id, typeId, null, location, direction, state, objectData, extra, expires, usagePolicy, ownerId, ownerName, synchronized, realRoomObject, sizeZ);
const furnitureData = new RoomFurnitureData(id, typeId, null, location, direction, state, objectData, extra, expires, usagePolicy, ownerId, ownerName, synchronized, realRoomObject, sizeZ, allowStack, allowSit, allowLay, allowWalk, dimensionsX, dimensionsY, teleportTargetId);
instanceData.addPendingFurnitureFloor(furnitureData);
return true;
}
public addFurnitureFloorByTypeName(roomId: number, id: number, typeName: string, location: IVector3D, direction: IVector3D, state: number, objectData: IObjectData, extra: number = NaN, expires: number = -1, usagePolicy: number = 0, ownerId: number = 0, ownerName: string = '', synchronized: boolean = true, realRoomObject: boolean = true, sizeZ: number = -1): boolean
public addFurnitureFloorByTypeName(roomId: number, id: number, typeName: string, location: IVector3D, direction: IVector3D, state: number, objectData: IObjectData, extra: number = NaN, expires: number = -1, usagePolicy: number = 0, ownerId: number = 0, ownerName: string = '', synchronized: boolean = true, realRoomObject: boolean = true, sizeZ: number = -1, allowStack: boolean = false, allowSit: boolean = false, allowLay: boolean = false, allowWalk: boolean = false, dimensionsX: number = 0, dimensionsY: number = 0, teleportTargetId: number = 0): boolean
{
const instanceData = this.getRoomInstanceData(roomId);
if(!instanceData) return false;
const furnitureData = new RoomFurnitureData(id, 0, typeName, location, direction, state, objectData, extra, expires, usagePolicy, ownerId, ownerName, synchronized, realRoomObject, sizeZ);
const furnitureData = new RoomFurnitureData(id, 0, typeName, location, direction, state, objectData, extra, expires, usagePolicy, ownerId, ownerName, synchronized, realRoomObject, sizeZ, allowStack, allowSit, allowLay, allowWalk, dimensionsX, dimensionsY, teleportTargetId);
instanceData.addPendingFurnitureFloor(furnitureData);
return true;
}
public addFurnitureWall(roomId: number, id: number, typeId: number, location: IVector3D, direction: IVector3D, state: number, extra: string, expires: number = -1, usagePolicy: number = 0, ownerId: number = 0, ownerName: string = '', realRoomObject: boolean = true): boolean
public addFurnitureWall(roomId: number, id: number, typeId: number, location: IVector3D, direction: IVector3D, state: number, extra: string, expires: number = -1, usagePolicy: number = 0, ownerId: number = 0, ownerName: string = '', realRoomObject: boolean = true, allowStack: boolean = false, allowSit: boolean = false, allowLay: boolean = false, allowWalk: boolean = false, dimensionsX: number = 0, dimensionsY: number = 0, teleportTargetId: number = 0): boolean
{
const instanceData = this.getRoomInstanceData(roomId);
@@ -1703,7 +1717,7 @@ export class RoomEngine implements IRoomEngine, IRoomCreator, IRoomEngineService
objectData.setString(extra);
const furnitureData = new RoomFurnitureData(id, typeId, null, location, direction, state, objectData, NaN, expires, usagePolicy, ownerId, ownerName, true, realRoomObject);
const furnitureData = new RoomFurnitureData(id, typeId, null, location, direction, state, objectData, NaN, expires, usagePolicy, ownerId, ownerName, true, realRoomObject, -1, allowStack, allowSit, allowLay, allowWalk, dimensionsX, dimensionsY, teleportTargetId);
instanceData.addPendingFurnitureWall(furnitureData);
+3 -3
View File
@@ -1167,11 +1167,11 @@ export class RoomMessageHandler
if(data.spriteName)
{
this._roomEngine.addFurnitureFloorByTypeName(roomId, data.itemId, data.spriteName, location, direction, data.state, data.data, data.extra, data.expires, data.usagePolicy, data.userId, data.username, true, true, data.stackHeight);
this._roomEngine.addFurnitureFloorByTypeName(roomId, data.itemId, data.spriteName, location, direction, data.state, data.data, data.extra, data.expires, data.usagePolicy, data.userId, data.username, true, true, data.stackHeight, data.allowStack, data.allowSit, data.allowLay, data.allowWalk, data.dimensionsX, data.dimensionsY, data.teleportTargetId);
}
else
{
this._roomEngine.addFurnitureFloor(roomId, data.itemId, data.spriteId, location, direction, data.state, data.data, data.extra, data.expires, data.usagePolicy, data.userId, data.username, true, true, data.stackHeight);
this._roomEngine.addFurnitureFloor(roomId, data.itemId, data.spriteId, location, direction, data.state, data.data, data.extra, data.expires, data.usagePolicy, data.userId, data.username, true, true, data.stackHeight, data.allowStack, data.allowSit, data.allowLay, data.allowWalk, data.dimensionsX, data.dimensionsY, data.teleportTargetId);
}
}
@@ -1196,7 +1196,7 @@ export class RoomMessageHandler
const direction = new Vector3d(wallGeometry.getDirection(data.direction));
this._roomEngine.addFurnitureWall(roomId, data.itemId, data.spriteId, location, direction, data.state, data.stuffData, data.secondsToExpiration, data.usagePolicy, data.userId, data.username);
this._roomEngine.addFurnitureWall(roomId, data.itemId, data.spriteId, location, direction, data.state, data.stuffData, data.secondsToExpiration, data.usagePolicy, data.userId, data.username, true, data.allowStack, data.allowSit, data.allowLay, data.allowWalk, data.dimensionsX, data.dimensionsY, data.teleportTargetId);
}
private onIgnoreResultEvent(event: IgnoreResultEvent): void
@@ -283,6 +283,8 @@ export class FurnitureBadgeDisplayVisualization extends FurnitureAnimatedVisuali
tempCtx.putImageData(patchData, 0, 0);
accCtx.drawImage(tempCanvas, frame.dims.left, frame.dims.top);
tempCanvas.width = 0;
tempCanvas.height = 0;
// Create a new canvas for this frame and create a texture from it
const frameCanvas = document.createElement('canvas');
@@ -299,6 +301,9 @@ export class FurnitureBadgeDisplayVisualization extends FurnitureAnimatedVisuali
frameDelays.push(frame.delay || 10);
}
accCanvas.width = 0;
accCanvas.height = 0;
// Create AnimatedSprite with frame textures
if(this._frameTextures.length > 1)
{
@@ -340,6 +345,13 @@ export class FurnitureBadgeDisplayVisualization extends FurnitureAnimatedVisuali
ctx.clearRect(0, 0, badgeCanvas.width, badgeCanvas.height);
ctx.drawImage(img, 0, 0, badgeCanvas.width, badgeCanvas.height);
tex.source.update();
img.onload = null;
img.onerror = null;
};
img.onerror = () =>
{
img.onload = null;
img.onerror = null;
};
img.src = badgeUrl;
}
@@ -28,10 +28,19 @@ export class FurnitureDynamicThumbnailVisualization extends IsometricImageFurniV
if (image.complete && image.width > 0 && image.height > 0) {
const texture = Texture.from(image);
texture.source.scaleMode = 'linear';
this.setThumbnailImages(texture, thumbnailUrl); // Pass URL here
this.setThumbnailImages(texture, thumbnailUrl);
} else {
console.error("Image failed to load properly:", thumbnailUrl);
this.setThumbnailImages(null);
}
image.onload = null;
image.onerror = null;
};
image.onerror = () => {
this.setThumbnailImages(null);
image.onload = null;
image.onerror = null;
};
} else {
this.setThumbnailImages(null);
@@ -5,6 +5,13 @@ export class FurnitureYoutubeVisualization extends FurnitureDynamicThumbnailVisu
{
protected static THUMBNAIL_URL: string = 'THUMBNAIL_URL';
constructor()
{
super();
this._hasOutline = false;
}
protected getThumbnailURL(): string
{
if(!this.object) return null;
@@ -1,15 +1,16 @@
import { IGraphicAsset } from '@nitrots/api';
import { GetRenderer, TextureUtils } from '@nitrots/utils';
import { Container, Graphics, Matrix, Sprite, Texture, RenderTexture } from 'pixi.js';
import { GetRenderer } from '@nitrots/utils';
import { Container, Matrix, Sprite, Texture, RenderTexture } from 'pixi.js';
import { FurnitureAnimatedVisualization } from './FurnitureAnimatedVisualization';
export class IsometricImageFurniVisualization extends FurnitureAnimatedVisualization {
protected static THUMBNAIL: string = 'THUMBNAIL';
private _thumbnailAssetNameNormal: string;
private _thumbnailImageNormal: Texture;
private _thumbnailDirection: number;
private _thumbnailChanged: boolean;
private _thumbnailLayerId: number;
private _thumbnailTexture: Texture;
private _uniqueId: string;
private _photoUrl: string;
protected _hasOutline: boolean;
@@ -17,10 +18,11 @@ export class IsometricImageFurniVisualization extends FurnitureAnimatedVisualiza
constructor() {
super();
this._thumbnailAssetNameNormal = null;
this._thumbnailImageNormal = null;
this._thumbnailDirection = -1;
this._thumbnailChanged = false;
this._thumbnailLayerId = -1;
this._thumbnailTexture = null;
this._uniqueId = `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
this._photoUrl = null;
}
@@ -56,13 +58,14 @@ export class IsometricImageFurniVisualization extends FurnitureAnimatedVisualiza
return;
}
const thumbnailAssetName = this.getThumbnailAssetName(64);
if (this._thumbnailImageNormal) {
this.addThumbnailAsset(this._thumbnailImageNormal, 64);
} else {
const layerId = 2;
const sprite = this.getSprite(layerId);
if (this._thumbnailTexture instanceof RenderTexture) {
this._thumbnailTexture.destroy(true);
}
this._thumbnailTexture = null;
this._thumbnailLayerId = -1;
}
this._thumbnailChanged = false;
@@ -76,21 +79,16 @@ export class IsometricImageFurniVisualization extends FurnitureAnimatedVisualiza
const layerTag = this.getLayerTag(scale, this.direction, layerId);
if (layerTag === IsometricImageFurniVisualization.THUMBNAIL) {
this._thumbnailLayerId = layerId;
const assetName = (this.cacheSpriteAssetName(scale, layerId, false) + this.getFrameNumber(scale, layerId));
const asset = this.getAsset(assetName, layerId);
const thumbnailAssetName = `${this.getThumbnailAssetName(scale)}-${this._uniqueId}`;
const transformedTexture = this.generateTransformedThumbnail(k, asset || { width: 64, height: 64 });
// Use the original asset's registered offsets so the thumbnail is drawn at the
// furniture-defined sprite position. Fall back to centering when no asset exists.
const offsetX = asset ? asset.offsetX : -Math.floor(transformedTexture.width / 2);
const offsetY = asset ? asset.offsetY : -Math.floor(transformedTexture.height / 2);
this.asset.addAsset(thumbnailAssetName, transformedTexture, true, offsetX, offsetY, false, false);
const placedSprite = this.getSprite(layerId);
if (placedSprite) {
placedSprite.texture = transformedTexture;
if (asset) {
if (this._thumbnailTexture instanceof RenderTexture) {
this._thumbnailTexture.destroy(true);
}
this._thumbnailTexture = this.generateTransformedThumbnail(k, asset);
}
return;
@@ -100,78 +98,117 @@ export class IsometricImageFurniVisualization extends FurnitureAnimatedVisualiza
}
}
protected generateTransformedThumbnail(texture: Texture, asset: IGraphicAsset): Texture {
const scaleFactor = (asset?.width || 64) / texture.width;
const verticalScale = 1.0265;
const matrix = new Matrix();
const frameThickness = 20;
const frameColor = 0x000000;
protected updateSprite(scale: number, layerId: number): void {
super.updateSprite(scale, layerId);
switch (this.direction) {
if (this._thumbnailTexture && this._thumbnailLayerId === layerId) {
const sprite = this.getSprite(layerId);
if (sprite) {
sprite.texture = this._thumbnailTexture;
}
}
}
protected generateTransformedThumbnail(texture: Texture, asset: IGraphicAsset): Texture {
const assetWidth = asset.width;
const assetHeight = asset.height;
let outlineTexture: RenderTexture = null;
if(this._hasOutline)
{
const borderSize = 20;
const bgWidth = texture.width + borderSize * 2;
const bgHeight = texture.height + borderSize * 2;
const container = new Container();
const background = new Sprite(Texture.WHITE);
background.tint = 0x000000;
background.width = bgWidth;
background.height = bgHeight;
const imageSprite = new Sprite(texture);
imageSprite.position.set(borderSize, borderSize);
container.addChild(background, imageSprite);
outlineTexture = RenderTexture.create({ width: bgWidth, height: bgHeight, resolution: 1 });
GetRenderer().render({ container, target: outlineTexture, clear: true });
texture = outlineTexture;
}
texture.source.scaleMode = 'linear';
const texW = texture.width;
const texH = texture.height;
const scaleX = assetWidth / texW;
const scaleY = assetHeight / texH;
const matrix = new Matrix();
switch(this.direction)
{
case 2:
matrix.a = scaleFactor;
matrix.b = (-0.5 * scaleFactor);
matrix.a = scaleX;
matrix.b = -(0.5 * scaleX);
matrix.c = 0;
matrix.d = (scaleFactor * verticalScale);
matrix.d = (scaleY / 1.6);
matrix.tx = 0;
matrix.ty = (0.5 * scaleFactor * texture.width);
matrix.ty = (0.5 * scaleX * texW);
break;
case 0:
case 4:
matrix.a = scaleFactor;
matrix.b = (0.5 * scaleFactor);
matrix.a = scaleX;
matrix.b = (0.5 * scaleX);
matrix.c = 0;
matrix.d = (scaleFactor * verticalScale);
matrix.d = (scaleY / 1.6);
matrix.tx = 0;
matrix.ty = 0;
break;
default:
matrix.a = scaleFactor;
matrix.a = scaleX;
matrix.b = 0;
matrix.c = 0;
matrix.d = scaleFactor;
matrix.d = scaleY;
matrix.tx = 0;
matrix.ty = 0;
}
const imgWidth = texture.width;
const imgHeight = texture.height;
const flatWidth = imgWidth + frameThickness * 2;
const flatHeight = imgHeight + frameThickness * 2;
const flatRenderTexture = TextureUtils.createAndFillRenderTexture(flatWidth, flatHeight, frameColor);
const imageSprite = new Sprite(texture);
imageSprite.position.set(frameThickness, frameThickness);
TextureUtils.writeToTexture(imageSprite, flatRenderTexture, false);
const flatTexture = flatRenderTexture;
const transformedSprite = new Sprite(flatTexture);
transformedSprite.setFromMatrix(matrix);
const width = 80;
const height = 80;
const finalContainer = new Container();
const posX = (width - transformedSprite.width) / 2;
const posY = (height - transformedSprite.height) / 2;
transformedSprite.position.set(posX, posY);
finalContainer.addChild(transformedSprite);
// Calculate transformed corners manually for accurate bounds
const corners = [
{ x: matrix.tx, y: matrix.ty },
{ x: matrix.a * texW + matrix.tx, y: matrix.b * texW + matrix.ty },
{ x: matrix.c * texH + matrix.tx, y: matrix.d * texH + matrix.ty },
{ x: matrix.a * texW + matrix.c * texH + matrix.tx, y: matrix.b * texW + matrix.d * texH + matrix.ty }
];
const renderTexture = RenderTexture.create({ width, height, resolution: 1 });
GetRenderer().render({ container: finalContainer, target: renderTexture, clear: true });
let minX = corners[0].x, minY = corners[0].y;
let maxX = corners[0].x, maxY = corners[0].y;
for (const corner of corners) {
if (corner.x < minX) minX = corner.x;
if (corner.y < minY) minY = corner.y;
if (corner.x > maxX) maxX = corner.x;
if (corner.y > maxY) maxY = corner.y;
}
const renderWidth = Math.ceil(maxX - minX);
const renderHeight = Math.ceil(maxY - minY);
matrix.tx -= minX;
matrix.ty -= minY;
const transformedSprite = new Sprite(texture);
transformedSprite.setFromMatrix(matrix);
const renderTexture = RenderTexture.create({ width: renderWidth, height: renderHeight, resolution: 1 });
GetRenderer().render({ container: transformedSprite, target: renderTexture, clear: true });
if (outlineTexture) {
outlineTexture.destroy(true);
}
return renderTexture;
}
protected getSpriteAssetName(scale: number, layerId: number): string {
if (this._thumbnailImageNormal && (this.getLayerTag(scale, this.direction, layerId) === IsometricImageFurniVisualization.THUMBNAIL)) {
return `${this.getThumbnailAssetName(scale)}-${this._uniqueId}`;
}
return super.getSpriteAssetName(scale, layerId);
}
protected getThumbnailAssetName(scale: number): string {
return this.cacheSpriteAssetName(scale, 2, false) + this.getFrameNumber(scale, 2);
}
protected getFullThumbnailAssetName(k: number, _arg_2: number): string {
return [this._type, k, 'thumb', _arg_2].join('_');
}
}
}
@@ -867,203 +867,218 @@ export class RoomPlane implements IRoomPlane
}
private renderWindowReflections(): void
{
if(!this._planeTexture || !this._leftSide || !this._rightSide || !this._normal) return;
if(this._leftSide.length <= 0 || this._rightSide.length <= 0) return;
const now = Date.now();
const fadeDurationMs = 150;
const avatars = RoomWindowReflectionState.getAvatars();
const canvasWidth = this._landscapeRenderWidth;
const canvasHeight = this._landscapeRenderHeight;
if(canvasWidth <= 0 || canvasHeight <= 0) return;
const container = new Container();
const visibleAvatarIds = new Set<number>();
const addReflectionSprite = (
texture: Texture,
oppositeTexture: Texture,
location: IVector3D,
alpha: number,
verticalOffset: number = 0,
direction: number = 0,
avatarId: number = -1
): boolean =>
{
if(!this._planeTexture || !this._leftSide || !this._rightSide || !this._normal) return;
if(!texture?.source || texture.source.destroyed || !texture.source.style || !location || alpha < 0)
return false;
if(this._leftSide.length <= 0 || this._rightSide.length <= 0) return;
const relative = Vector3d.dif(location, this._location);
const planeDistance = Math.abs(Vector3d.scalarProjection(relative, this._normal));
const now = Date.now();
const fadeDurationMs = 150;
const avatars = RoomWindowReflectionState.getAvatars();
const canvasWidth = this._landscapeRenderWidth;
const canvasHeight = this._landscapeRenderHeight;
if(planeDistance > 0.8) return false;
if(canvasWidth <= 0 || canvasHeight <= 0) return;
const leftSideLoc = Vector3d.scalarProjection(relative, this._leftSide);
const rightSideLoc = Vector3d.scalarProjection(relative, this._rightSide);
const container = new Container();
const visibleAvatarIds = new Set<number>();
const addReflectionSprite = (texture: Texture, oppositeTexture: Texture, location: IVector3D, alpha: number, verticalOffset: number = 0, direction: number = 0, avatarId: number = -1): boolean => {
if(!texture?.source || texture.source.destroyed || !texture.source.style || !location || alpha < 0) return false;
const relative = Vector3d.dif(location, this._location);
const planeDistance = Math.abs(Vector3d.scalarProjection(relative, this._normal));
if(planeDistance > 0.8) return false;
const leftSideLoc = Vector3d.scalarProjection(relative, this._leftSide);
const rightSideLoc = Vector3d.scalarProjection(relative, this._rightSide);
const closestMask = this._windowMasks.reduce((best, mask) => {
const score = Math.abs(mask.leftSideLoc - leftSideLoc) + Math.abs(mask.rightSideLoc - rightSideLoc);
if(!best || (score < best.score)) return { mask, score };
return best;
}, null as { mask: { leftSideLoc: number; rightSideLoc: number }; score: number } | null);
if(!closestMask || (closestMask.score > 3)) return false;
const x = (canvasWidth - ((canvasWidth * leftSideLoc) / this._leftSide.length));
const y = (canvasHeight - ((canvasHeight * rightSideLoc) / this._rightSide.length)) + verticalOffset;
const toPlaneX = (this._location.x - location.x);
const toPlaneY = (this._location.y - location.y);
const toPlaneLength = Math.hypot(toPlaneX, toPlaneY);
const facingRadians = ((((direction - 90) % 360) + 360) % 360) * (Math.PI / 180);
const facingX = Math.cos(facingRadians);
const facingY = Math.sin(facingRadians);
const facingWindow = (toPlaneLength > 0.001)
? (((facingX * toPlaneX) + (facingY * toPlaneY)) / toPlaneLength) > 0.5
: false;
const deltaLeft = Math.abs(closestMask.mask.leftSideLoc - leftSideLoc);
const deltaRight = Math.abs(closestMask.mask.rightSideLoc - rightSideLoc);
const isInFrontOfWindow = ((closestMask.score <= 2) && ((deltaLeft <= 0.9) || (deltaRight <= 0.9)));
const shouldMirror = isInFrontOfWindow;
const normal2DLength = Math.hypot(this._normal.x, this._normal.y);
const normalX = (normal2DLength > 0.0001) ? (this._normal.x / normal2DLength) : 0;
const normalY = (normal2DLength > 0.0001) ? (this._normal.y / normal2DLength) : 0;
const normalFacingDot = Math.abs((facingX * normalX) + (facingY * normalY));
const transitionLow = 0.6;
const transitionHigh = 0.8;
let oppositeWeight = 0;
if(shouldMirror && oppositeTexture)
{
if(normalFacingDot >= transitionHigh) oppositeWeight = 1;
else if(normalFacingDot > transitionLow) oppositeWeight = (normalFacingDot - transitionLow) / (transitionHigh - transitionLow);
}
if(oppositeWeight < 1)
{
const sprite = new Sprite(texture);
sprite.anchor.set(0.5, 1);
sprite.position.set(Math.trunc(x), Math.trunc(y));
sprite.scale.set(1, 1);
sprite.tint = 0xCFE3FF;
sprite.alpha = alpha * (1 - oppositeWeight);
container.addChild(sprite);
}
if(oppositeWeight > 0 && oppositeTexture)
{
const sprite = new Sprite(oppositeTexture);
sprite.anchor.set(0.5, 1);
sprite.position.set(Math.trunc(x), Math.trunc(y));
sprite.scale.set(1, 1);
sprite.tint = 0xCFE3FF;
sprite.alpha = alpha * oppositeWeight;
container.addChild(sprite);
}
return true;
};
for(const avatar of avatars)
const closestMask = this._windowMasks.reduce((best, mask) =>
{
if(!avatar?.texture?.source || avatar.texture.source.destroyed || !avatar.texture.source.style || !avatar.location) continue;
const score = Math.abs(mask.leftSideLoc - leftSideLoc) + Math.abs(mask.rightSideLoc - rightSideLoc);
let firstSeenAt = this._windowReflectionFirstSeenAt.get(avatar.id);
if(!best || (score < best.score)) return { mask, score };
if(firstSeenAt === undefined)
{
firstSeenAt = now;
}
return best;
}, null as { mask: { leftSideLoc: number; rightSideLoc: number }; score: number } | null);
const elapsed = Math.min(fadeDurationMs, Math.max(0, (now - firstSeenAt)));
const progress = (elapsed / fadeDurationMs);
const alpha = (0.4 * progress);
if(!closestMask || (closestMask.score > 3)) return false;
if(!addReflectionSprite(avatar.texture, avatar.oppositeTexture, avatar.location, alpha, avatar.verticalOffset || 0, avatar.direction || 0, avatar.id)) continue;
const x = (canvasWidth - ((canvasWidth * leftSideLoc) / this._leftSide.length));
const y = (canvasHeight - ((canvasHeight * rightSideLoc) / this._rightSide.length)) + verticalOffset;
if(!this._windowReflectionFirstSeenAt.has(avatar.id)) this._windowReflectionFirstSeenAt.set(avatar.id, firstSeenAt);
const toPlaneX = (this._location.x - location.x);
const toPlaneY = (this._location.y - location.y);
const toPlaneLength = Math.hypot(toPlaneX, toPlaneY);
visibleAvatarIds.add(avatar.id);
this._windowReflectionFadeOut.delete(avatar.id);
const facingRadians = ((((direction - 90) % 360) + 360) % 360) * (Math.PI / 180);
const facingX = Math.cos(facingRadians);
const facingY = Math.sin(facingRadians);
const facingWindow = (toPlaneLength > 0.001)
? (((facingX * toPlaneX) + (facingY * toPlaneY)) / toPlaneLength) > 0.5
: false;
const storedLocation = new Vector3d();
storedLocation.assign(avatar.location);
const deltaLeft = Math.abs(closestMask.mask.leftSideLoc - leftSideLoc);
const deltaRight = Math.abs(closestMask.mask.rightSideLoc - rightSideLoc);
this._windowReflectionLastVisible.set(avatar.id, {
texture: avatar.texture,
oppositeTexture: avatar.oppositeTexture,
location: storedLocation,
verticalOffset: avatar.verticalOffset || 0,
direction: avatar.direction || 0
});
const isInFrontOfWindow = ((closestMask.score <= 2) && ((deltaLeft <= 0.9) || (deltaRight <= 0.9)));
const shouldMirror = isInFrontOfWindow;
const normal2DLength = Math.hypot(this._normal.x, this._normal.y);
const normalX = (normal2DLength > 0.0001) ? (this._normal.x / normal2DLength) : 0;
const normalY = (normal2DLength > 0.0001) ? (this._normal.y / normal2DLength) : 0;
const normalFacingDot = Math.abs((facingX * normalX) + (facingY * normalY));
const transitionLow = 0.6;
const transitionHigh = 0.8;
let oppositeWeight = 0;
if(shouldMirror && oppositeTexture)
{
if(normalFacingDot >= transitionHigh) oppositeWeight = 1;
else if(normalFacingDot > transitionLow)
oppositeWeight = (normalFacingDot - transitionLow) / (transitionHigh - transitionLow);
}
for(const [id, lastVisible] of this._windowReflectionLastVisible)
if(oppositeWeight < 1)
{
if(visibleAvatarIds.has(id) || this._windowReflectionFadeOut.has(id)) continue;
if(!lastVisible.texture?.source || lastVisible.texture.source.destroyed || !lastVisible.texture.source.style)
{
this._windowReflectionLastVisible.delete(id);
this._windowReflectionFirstSeenAt.delete(id);
continue;
}
this._windowReflectionFadeOut.set(id, {
texture: lastVisible.texture,
oppositeTexture: lastVisible.oppositeTexture,
location: lastVisible.location,
verticalOffset: lastVisible.verticalOffset,
direction: lastVisible.direction,
startedAt: now
});
this._windowReflectionLastVisible.delete(id);
this._windowReflectionFirstSeenAt.delete(id);
const sprite = new Sprite(texture);
sprite.anchor.set(0.5, 1);
sprite.position.set(Math.trunc(x), Math.trunc(y));
sprite.tint = 0xCFE3FF;
sprite.alpha = alpha * (1 - oppositeWeight);
container.addChild(sprite);
}
for(const [id, fadeOut] of this._windowReflectionFadeOut)
if(oppositeWeight > 0 && oppositeTexture)
{
const elapsed = (now - fadeOut.startedAt);
if(elapsed >= fadeDurationMs)
{
this._windowReflectionFadeOut.delete(id);
continue;
}
const alpha = (0.4 * (1 - (elapsed / fadeDurationMs)));
if(!addReflectionSprite(fadeOut.texture, fadeOut.oppositeTexture, fadeOut.location, alpha, fadeOut.verticalOffset, fadeOut.direction, id)) this._windowReflectionFadeOut.delete(id);
const sprite = new Sprite(oppositeTexture);
sprite.anchor.set(0.5, 1);
sprite.position.set(Math.trunc(x), Math.trunc(y));
sprite.tint = 0xCFE3FF;
sprite.alpha = alpha * oppositeWeight;
container.addChild(sprite);
}
if(!container.children.length)
{
container.destroy({ children: true });
return true;
};
if(!avatars.length)
{
this._windowReflectionFirstSeenAt.clear();
this._windowReflectionLastVisible.clear();
}
for(const avatar of avatars)
{
if(!avatar?.texture?.source || avatar.texture.source.destroyed || !avatar.texture.source.style || !avatar.location)
continue;
return;
}
let firstSeenAt = this._windowReflectionFirstSeenAt.get(avatar.id);
if(this._maskFilter) container.filters = [this._maskFilter];
if(firstSeenAt === undefined) firstSeenAt = now;
GetRenderer().render({
target: this._planeTexture,
container,
transform: this.getMatrixForDimensions(canvasWidth, canvasHeight),
clear: false
const elapsed = Math.min(fadeDurationMs, Math.max(0, (now - firstSeenAt)));
const alpha = (0.4 * (elapsed / fadeDurationMs));
if(!addReflectionSprite(
avatar.texture,
avatar.oppositeTexture,
avatar.location,
alpha,
avatar.verticalOffset || 0,
avatar.direction || 0,
avatar.id))
continue;
if(!this._windowReflectionFirstSeenAt.has(avatar.id))
this._windowReflectionFirstSeenAt.set(avatar.id, firstSeenAt);
visibleAvatarIds.add(avatar.id);
this._windowReflectionFadeOut.delete(avatar.id);
const storedLocation = new Vector3d();
storedLocation.assign(avatar.location);
this._windowReflectionLastVisible.set(avatar.id, {
texture: avatar.texture,
oppositeTexture: avatar.oppositeTexture,
location: storedLocation,
verticalOffset: avatar.verticalOffset || 0,
direction: avatar.direction || 0
});
}
// move to fade-out (NO destruction)
for(const [id, lastVisible] of this._windowReflectionLastVisible)
{
if(visibleAvatarIds.has(id) || this._windowReflectionFadeOut.has(id)) continue;
this._windowReflectionFadeOut.set(id, {
...lastVisible,
startedAt: now
});
container.destroy({ children: true });
this._windowReflectionLastVisible.delete(id);
this._windowReflectionFirstSeenAt.delete(id);
}
// fade-out rendering (NO destruction)
for(const [id, fadeOut] of this._windowReflectionFadeOut)
{
const elapsed = (now - fadeOut.startedAt);
if(elapsed >= fadeDurationMs)
{
this._windowReflectionFadeOut.delete(id);
continue;
}
const alpha = (0.4 * (1 - (elapsed / fadeDurationMs)));
if(!addReflectionSprite(
fadeOut.texture,
fadeOut.oppositeTexture,
fadeOut.location,
alpha,
fadeOut.verticalOffset,
fadeOut.direction,
id))
{
this._windowReflectionFadeOut.delete(id);
}
}
if(!container.children.length)
{
container.destroy({ children: true });
if(!avatars.length)
{
this._windowReflectionFirstSeenAt.clear();
this._windowReflectionLastVisible.clear();
}
return;
}
if(this._maskFilter) container.filters = [this._maskFilter];
GetRenderer().render({
target: this._planeTexture,
container,
transform: this.getMatrixForDimensions(canvasWidth, canvasHeight),
clear: false
});
container.destroy({ children: true });
}
private updateCorners(geometry: IRoomGeometry): void
{
this._cornerA.assign(geometry.getScreenPosition(this._location));
+50 -1
View File
@@ -18,8 +18,15 @@ export class RoomFurnitureData
private _synchronized: boolean;
private _realRoomObject: boolean;
private _sizeZ: number;
private _allowStack: boolean;
private _allowSit: boolean;
private _allowLay: boolean;
private _allowWalk: boolean;
private _dimensionsX: number;
private _dimensionsY: number;
private _teleportTargetId: number;
constructor(id: number, typeId: number, type: string, location: IVector3D, direction: IVector3D, state: number, objectData: IObjectData, extra: number = NaN, expires: number = -1, usagePolicy: number = 0, ownerId: number = 0, ownerName: string = '', synchronized: boolean = true, realRoomObject: boolean = true, sizeZ: number = -1)
constructor(id: number, typeId: number, type: string, location: IVector3D, direction: IVector3D, state: number, objectData: IObjectData, extra: number = NaN, expires: number = -1, usagePolicy: number = 0, ownerId: number = 0, ownerName: string = '', synchronized: boolean = true, realRoomObject: boolean = true, sizeZ: number = -1, allowStack: boolean = false, allowSit: boolean = false, allowLay: boolean = false, allowWalk: boolean = false, dimensionsX: number = 0, dimensionsY: number = 0, teleportTargetId: number = 0)
{
this._id = id;
this._typeId = typeId;
@@ -34,6 +41,13 @@ export class RoomFurnitureData
this._synchronized = synchronized;
this._realRoomObject = realRoomObject;
this._sizeZ = sizeZ;
this._allowStack = allowStack;
this._allowSit = allowSit;
this._allowLay = allowLay;
this._allowWalk = allowWalk;
this._dimensionsX = dimensionsX;
this._dimensionsY = dimensionsY;
this._teleportTargetId = teleportTargetId;
this._location = new Vector3d();
this._direction = new Vector3d();
@@ -116,4 +130,39 @@ export class RoomFurnitureData
{
return this._sizeZ;
}
public get allowStack(): boolean
{
return this._allowStack;
}
public get allowSit(): boolean
{
return this._allowSit;
}
public get allowLay(): boolean
{
return this._allowLay;
}
public get allowWalk(): boolean
{
return this._allowWalk;
}
public get dimensionsX(): number
{
return this._dimensionsX;
}
public get dimensionsY(): number
{
return this._dimensionsY;
}
public get teleportTargetId(): number
{
return this._teleportTargetId;
}
}
+55
View File
@@ -17,6 +17,11 @@ export class RoomSession implements IRoomSession
private _allowPets: boolean = false;
private _controllerLevel: number = RoomControllerLevel.NONE;
private _ownRoomIndex: number = -1;
private _groupId: number = 0;
private _hotelTimeZone: string = 'UTC';
private _hotelTimeSnapshotMs: number = 0;
private _hotelTimeSyncMs: number = 0;
private _roomItemLimit: number = 0;
private _isGuildRoom: boolean = false;
private _isRoomOwner: boolean = false;
private _isDecorating: boolean = false;
@@ -398,6 +403,56 @@ export class RoomSession implements IRoomSession
return this._ownRoomIndex;
}
public get groupId(): number
{
return this._groupId;
}
public set groupId(groupId: number)
{
this._groupId = groupId;
}
public get hotelTimeZone(): string
{
return this._hotelTimeZone;
}
public set hotelTimeZone(timeZone: string)
{
this._hotelTimeZone = (timeZone || 'UTC');
}
public get hotelTimeSnapshotMs(): number
{
return this._hotelTimeSnapshotMs;
}
public set hotelTimeSnapshotMs(value: number)
{
this._hotelTimeSnapshotMs = value;
}
public get hotelTimeSyncMs(): number
{
return this._hotelTimeSyncMs;
}
public set hotelTimeSyncMs(value: number)
{
this._hotelTimeSyncMs = value;
}
public get roomItemLimit(): number
{
return this._roomItemLimit;
}
public set roomItemLimit(value: number)
{
this._roomItemLimit = value;
}
public get isGuildRoom(): boolean
{
return this._isGuildRoom;
+22
View File
@@ -28,6 +28,8 @@ export class RoomUserData implements IRoomUserData
private _hasBreedingPermission: boolean;
private _botSkills: number[];
private _isModerator: boolean;
private _roomEntryMethod: string = 'unknown';
private _roomEntryTeleportId: number = 0;
constructor(k: number)
{
@@ -288,4 +290,24 @@ export class RoomUserData implements IRoomUserData
{
this._isModerator = k;
}
public get roomEntryMethod(): string
{
return this._roomEntryMethod;
}
public set roomEntryMethod(k: string)
{
this._roomEntryMethod = k;
}
public get roomEntryTeleportId(): number
{
return this._roomEntryTeleportId;
}
public set roomEntryTeleportId(k: number)
{
this._roomEntryTeleportId = k;
}
}
@@ -248,6 +248,7 @@ export class BadgeImageManager
if(!renderedLayers) return false;
const texture = TextureUtils.generateTexture(container);
container.destroy({ children: true });
GetAssetManager().setTexture(groupBadge.code, texture);
GetEventDispatcher().dispatchEvent(new BadgeImageReadyEvent(groupBadge.code, texture));
@@ -24,6 +24,7 @@ export class FurnitureData implements IFurnitureData
private _purchaseCouldBeUsedForBuyout: boolean;
private _rentCouldBeUsedForBuyout: boolean;
private _availableForBuildersClub: boolean;
private _allowStack: boolean;
private _canStandOn: boolean;
private _canSitOn: boolean;
private _canLayOn: boolean;
@@ -32,7 +33,7 @@ export class FurnitureData implements IFurnitureData
private _environment: string;
private _rare: boolean;
constructor(type: FurnitureType, id: number, fullName: string, className: string, category: string, localizedName: string, description: string, revision: number, tileSizeX: number, tileSizeY: number, tileSizeZ: number, colors: number[], hadIndexedColor: boolean, colorIndex: number, adUrl: string, purchaseOfferId: number, purchaseCouldBeUsedForBuyout: boolean, rentOfferId: number, rentCouldBeUsedForBuyout: boolean, availableForBuildersClub: boolean, customParams: string, specialType: number, canStandOn: boolean, canSitOn: boolean, canLayOn: boolean, excludedfromDynamic: boolean, furniLine: string, environment: string, rare: boolean)
constructor(type: FurnitureType, id: number, fullName: string, className: string, category: string, localizedName: string, description: string, revision: number, tileSizeX: number, tileSizeY: number, tileSizeZ: number, colors: number[], hadIndexedColor: boolean, colorIndex: number, adUrl: string, purchaseOfferId: number, purchaseCouldBeUsedForBuyout: boolean, rentOfferId: number, rentCouldBeUsedForBuyout: boolean, availableForBuildersClub: boolean, customParams: string, specialType: number, allowStack: boolean, canStandOn: boolean, canSitOn: boolean, canLayOn: boolean, excludedfromDynamic: boolean, furniLine: string, environment: string, rare: boolean)
{
this._type = type;
this._id = id;
@@ -56,6 +57,7 @@ export class FurnitureData implements IFurnitureData
this._customParams = customParams;
this._specialType = specialType;
this._availableForBuildersClub = availableForBuildersClub;
this._allowStack = allowStack;
this._canStandOn = canStandOn;
this._canSitOn = canSitOn;
this._canLayOn = canLayOn;
@@ -180,6 +182,11 @@ export class FurnitureData implements IFurnitureData
return this._availableForBuildersClub;
}
public get allowStack(): boolean
{
return this._allowStack;
}
public get canStandOn(): boolean
{
return this._canStandOn;
@@ -82,8 +82,9 @@ export class FurnitureDataLoader
const className = classSplit[0];
const colorIndex = ((classSplit.length > 1) ? parseInt(classSplit[1]) : 0);
const hasColorIndex = (classSplit.length > 1);
const allowStack = this.resolveBooleanFlag(furniture.allowstack, furniture.allow_stack, furniture.allowStack);
const furnitureData = new FurnitureData(FurnitureType.FLOOR, furniture.id, furniture.classname, className, furniture.category, furniture.name, furniture.description, furniture.revision, furniture.xdim, furniture.ydim, 0, colors, hasColorIndex, colorIndex, furniture.adurl, furniture.offerid, furniture.buyout, furniture.rentofferid, furniture.rentbuyout, furniture.bc, furniture.customparams, furniture.specialtype, furniture.canstandon, furniture.cansiton, furniture.canlayon, furniture.excludeddynamic, furniture.furniline, furniture.environment, furniture.rare);
const furnitureData = new FurnitureData(FurnitureType.FLOOR, furniture.id, furniture.classname, className, furniture.category, furniture.name, furniture.description, furniture.revision, furniture.xdim, furniture.ydim, 0, colors, hasColorIndex, colorIndex, furniture.adurl, furniture.offerid, furniture.buyout, furniture.rentofferid, furniture.rentbuyout, furniture.bc, furniture.customparams, furniture.specialtype, allowStack, furniture.canstandon, furniture.cansiton, furniture.canlayon, furniture.excludeddynamic, furniture.furniline, furniture.environment, furniture.rare);
this._floorItems.set(furnitureData.id, furnitureData);
@@ -99,7 +100,8 @@ export class FurnitureDataLoader
{
if(!furniture) continue;
const furnitureData = new FurnitureData(FurnitureType.WALL, furniture.id, furniture.classname, furniture.classname, furniture.category, furniture.name, furniture.description, furniture.revision, 0, 0, 0, null, false, 0, furniture.adurl, furniture.offerid, furniture.buyout, furniture.rentofferid, furniture.rentbuyout, furniture.bc, null, furniture.specialtype, false, false, false, furniture.excludeddynamic, furniture.furniline, furniture.environment, furniture.rare);
const allowStack = this.resolveBooleanFlag(furniture.allowstack, furniture.allow_stack, furniture.allowStack);
const furnitureData = new FurnitureData(FurnitureType.WALL, furniture.id, furniture.classname, furniture.classname, furniture.category, furniture.name, furniture.description, furniture.revision, 0, 0, 0, null, false, 0, furniture.adurl, furniture.offerid, furniture.buyout, furniture.rentofferid, furniture.rentbuyout, furniture.bc, null, furniture.specialtype, allowStack, false, false, false, furniture.excludeddynamic, furniture.furniline, furniture.environment, furniture.rare);
this._wallItems.set(furnitureData.id, furnitureData);
@@ -121,4 +123,26 @@ export class FurnitureDataLoader
return;
}
}
private resolveBooleanFlag(...values: any[]): boolean
{
for(const value of values)
{
if(value === undefined || value === null) continue;
if(typeof value === 'string')
{
const normalized = value.trim().toLowerCase();
if(!normalized.length) continue;
if([ '1', 'true', 'yes' ].includes(normalized)) return true;
if([ '0', 'false', 'no' ].includes(normalized)) return false;
}
return !!value;
}
return false;
}
}
@@ -29,6 +29,11 @@ export class RoomDataHandler extends BaseHandler
const roomData = parser.data;
roomSession.tradeMode = roomData.tradeMode;
roomSession.groupId = roomData.habboGroupId;
roomSession.hotelTimeZone = (parser.hotelTimeZoneId || 'UTC');
roomSession.hotelTimeSnapshotMs = parser.hotelCurrentTimeMs;
roomSession.hotelTimeSyncMs = Date.now();
roomSession.roomItemLimit = parser.roomItemLimit;
roomSession.isGuildRoom = (roomData.habboGroupId !== 0);
roomSession.doorMode = roomData.doorMode;
roomSession.allowPets = roomData.allowPets;
@@ -78,6 +78,8 @@ export class RoomUsersHandler extends BaseHandler
userData.petLevel = user.petLevel;
userData.botSkills = user.botSkills;
userData.isModerator = user.isModerator;
userData.roomEntryMethod = user.roomEntryMethod;
userData.roomEntryTeleportId = user.roomEntryTeleportId;
if(!session.userDataManager.getUserData(user.roomIndex)) usersToAdd.push(userData);