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/wired-improvements-apr04
This commit is contained in:
@@ -31,7 +31,7 @@ export class RoomMessageHandler
|
|||||||
private _planeParser = new RoomPlaneParser();
|
private _planeParser = new RoomPlaneParser();
|
||||||
private _latestEntryTileEvent: RoomEntryTileMessageEvent = null;
|
private _latestEntryTileEvent: RoomEntryTileMessageEvent = null;
|
||||||
private _messageEvents: IMessageEvent[] = [];
|
private _messageEvents: IMessageEvent[] = [];
|
||||||
private _activeWiredUserMovements = new Map<number, { expiresAt: number, targetX: number, targetY: number, targetZ: number }>();
|
private _activeWiredUserMovements = new Map<number, { expiresAt: number, sourceX: number, sourceY: number, sourceZ: number, targetX: number, targetY: number, targetZ: number }>();
|
||||||
private _activeRoomUserWalks = new Map<number, { startedAt: number, targetX: number, targetY: number, targetZ: number, duration: number }>();
|
private _activeRoomUserWalks = new Map<number, { startedAt: number, targetX: number, targetY: number, targetZ: number, duration: number }>();
|
||||||
private _activeConfInvisHiddenItemIds = new Set<number>();
|
private _activeConfInvisHiddenItemIds = new Set<number>();
|
||||||
private _confInvisReapplyTimeouts: ReturnType<typeof setTimeout>[] = [];
|
private _confInvisReapplyTimeouts: ReturnType<typeof setTimeout>[] = [];
|
||||||
@@ -618,6 +618,9 @@ export class RoomMessageHandler
|
|||||||
{
|
{
|
||||||
this._activeWiredUserMovements.set(movement.id, {
|
this._activeWiredUserMovements.set(movement.id, {
|
||||||
expiresAt: Date.now() + Math.max(movement.duration, 1) + RoomMessageHandler.WIRED_MOVEMENT_STATUS_GRACE,
|
expiresAt: Date.now() + Math.max(movement.duration, 1) + RoomMessageHandler.WIRED_MOVEMENT_STATUS_GRACE,
|
||||||
|
sourceX: movement.location.x,
|
||||||
|
sourceY: movement.location.y,
|
||||||
|
sourceZ: movement.location.z,
|
||||||
targetX: movement.targetLocation.x,
|
targetX: movement.targetLocation.x,
|
||||||
targetY: movement.targetLocation.y,
|
targetY: movement.targetLocation.y,
|
||||||
targetZ: movement.targetLocation.z
|
targetZ: movement.targetLocation.z
|
||||||
@@ -637,7 +640,8 @@ export class RoomMessageHandler
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.shouldReleaseWiredStatusLocation(status, activeMovement))
|
if(this.shouldDiscardWiredStatusLocation(status, activeMovement)
|
||||||
|
|| !!this.getMatchedWiredStatusTargetLocation(status, activeMovement))
|
||||||
{
|
{
|
||||||
this._activeWiredUserMovements.delete(status.id);
|
this._activeWiredUserMovements.delete(status.id);
|
||||||
|
|
||||||
@@ -655,42 +659,74 @@ export class RoomMessageHandler
|
|||||||
|
|
||||||
if(activeMovement.expiresAt <= Date.now()) return null;
|
if(activeMovement.expiresAt <= Date.now()) return null;
|
||||||
|
|
||||||
if(!this.shouldReleaseWiredStatusLocation(status, activeMovement)) return null;
|
if(this.shouldDiscardWiredStatusLocation(status, activeMovement)) return null;
|
||||||
|
|
||||||
return new Vector3d(activeMovement.targetX, activeMovement.targetY, activeMovement.targetZ);
|
return this.getMatchedWiredStatusTargetLocation(status, activeMovement);
|
||||||
}
|
}
|
||||||
|
|
||||||
private shouldReleaseWiredStatusLocation(status: RoomUnitStatusMessage, activeMovement: { expiresAt: number, targetX: number, targetY: number, targetZ: number }): boolean
|
private getMatchedWiredStatusTargetLocation(status: RoomUnitStatusMessage, activeMovement: { expiresAt: number, sourceX: number, sourceY: number, sourceZ: number, targetX: number, targetY: number, targetZ: number }): IVector3D
|
||||||
|
{
|
||||||
|
if(this.matchesWiredMovementTarget(status.x, status.y, (status.z + status.height), activeMovement))
|
||||||
|
{
|
||||||
|
return new Vector3d(activeMovement.targetX, activeMovement.targetY, activeMovement.targetZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(status.didMove && this.matchesWiredMovementTarget(status.targetX, status.targetY, status.targetZ, activeMovement))
|
||||||
|
{
|
||||||
|
return new Vector3d(activeMovement.targetX, activeMovement.targetY, activeMovement.targetZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private shouldDiscardWiredStatusLocation(status: RoomUnitStatusMessage, activeMovement: { expiresAt: number, sourceX: number, sourceY: number, sourceZ: number, targetX: number, targetY: number, targetZ: number }): boolean
|
||||||
{
|
{
|
||||||
if(!status.didMove)
|
if(!status.didMove)
|
||||||
{
|
{
|
||||||
return this.matchesWiredMovementTarget(status.x, status.y, (status.z + status.height), activeMovement);
|
return !this.matchesWiredMovementSource(status.x, status.y, (status.z + status.height), activeMovement)
|
||||||
|
&& !this.matchesWiredMovementTarget(status.x, status.y, (status.z + status.height), activeMovement);
|
||||||
}
|
}
|
||||||
|
|
||||||
return !this.matchesWiredMovementTarget(status.targetX, status.targetY, status.targetZ, activeMovement);
|
return !this.matchesWiredMovementSource(status.x, status.y, (status.z + status.height), activeMovement)
|
||||||
|
&& !this.matchesWiredMovementTarget(status.x, status.y, (status.z + status.height), activeMovement)
|
||||||
|
&& !this.matchesWiredMovementSource(status.targetX, status.targetY, status.targetZ, activeMovement)
|
||||||
|
&& !this.matchesWiredMovementTarget(status.targetX, status.targetY, status.targetZ, activeMovement);
|
||||||
}
|
}
|
||||||
|
|
||||||
private matchesWiredMovementTarget(x: number, y: number, z: number, activeMovement: { expiresAt: number, targetX: number, targetY: number, targetZ: number }): boolean
|
private matchesWiredMovementSource(x: number, y: number, z: number, activeMovement: { expiresAt: number, sourceX: number, sourceY: number, sourceZ: number, targetX: number, targetY: number, targetZ: number }): boolean
|
||||||
{
|
{
|
||||||
if(!activeMovement) return false;
|
if(!activeMovement) return false;
|
||||||
|
|
||||||
return ((x === activeMovement.targetX)
|
return this.matchesWiredMovementLocation(x, y, z, activeMovement.sourceX, activeMovement.sourceY, activeMovement.sourceZ);
|
||||||
&& (y === activeMovement.targetY)
|
}
|
||||||
&& (Math.abs(z - activeMovement.targetZ) <= RoomMessageHandler.WIRED_MOVEMENT_Z_EPSILON));
|
|
||||||
|
private matchesWiredMovementTarget(x: number, y: number, z: number, activeMovement: { expiresAt: number, sourceX: number, sourceY: number, sourceZ: number, targetX: number, targetY: number, targetZ: number }): boolean
|
||||||
|
{
|
||||||
|
if(!activeMovement) return false;
|
||||||
|
|
||||||
|
return this.matchesWiredMovementLocation(x, y, z, activeMovement.targetX, activeMovement.targetY, activeMovement.targetZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
private matchesWiredMovementLocation(x: number, y: number, z: number, movementX: number, movementY: number, movementZ: number): boolean
|
||||||
|
{
|
||||||
|
return ((x === movementX)
|
||||||
|
&& (y === movementY)
|
||||||
|
&& (Math.abs(z - movementZ) <= RoomMessageHandler.WIRED_MOVEMENT_Z_EPSILON));
|
||||||
}
|
}
|
||||||
|
|
||||||
private applyWiredUserDirectionUpdate(update: WiredUserDirectionUpdateData): void
|
private applyWiredUserDirectionUpdate(update: WiredUserDirectionUpdateData): void
|
||||||
{
|
{
|
||||||
this._roomEngine.updateRoomObjectUserLocation(
|
const userObject = this._roomEngine.getRoomObjectUser(this._currentRoomId, update.id);
|
||||||
this._currentRoomId,
|
|
||||||
update.id,
|
if(!userObject) return;
|
||||||
null,
|
|
||||||
null,
|
userObject.setDirection(new Vector3d(update.bodyDirection));
|
||||||
false,
|
|
||||||
0,
|
const model = userObject.model;
|
||||||
new Vector3d(update.bodyDirection),
|
|
||||||
update.headDirection,
|
if(!model) return;
|
||||||
true);
|
|
||||||
|
model.setValue(RoomObjectVariable.HEAD_DIRECTION, update.headDirection);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onObjectsDataUpdateEvent(event: ObjectsDataUpdateEvent): void
|
private onObjectsDataUpdateEvent(event: ObjectsDataUpdateEvent): void
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { RoomObjectLogicBase } from './RoomObjectLogicBase';
|
|||||||
export class MovingObjectLogic extends RoomObjectLogicBase
|
export class MovingObjectLogic extends RoomObjectLogicBase
|
||||||
{
|
{
|
||||||
public static DEFAULT_UPDATE_INTERVAL: number = 500;
|
public static DEFAULT_UPDATE_INTERVAL: number = 500;
|
||||||
|
private static LOCATION_EPSILON: number = 0.01;
|
||||||
private static TEMP_VECTOR: Vector3d = new Vector3d();
|
private static TEMP_VECTOR: Vector3d = new Vector3d();
|
||||||
|
|
||||||
private _liftAmount: number;
|
private _liftAmount: number;
|
||||||
@@ -17,6 +18,7 @@ export class MovingObjectLogic extends RoomObjectLogicBase
|
|||||||
private _lastUpdateTime: number;
|
private _lastUpdateTime: number;
|
||||||
private _changeTime: number;
|
private _changeTime: number;
|
||||||
private _updateInterval: number;
|
private _updateInterval: number;
|
||||||
|
private _queuedMoveMessages: ObjectMoveUpdateMessage[];
|
||||||
|
|
||||||
constructor()
|
constructor()
|
||||||
{
|
{
|
||||||
@@ -31,11 +33,13 @@ export class MovingObjectLogic extends RoomObjectLogicBase
|
|||||||
this._lastUpdateTime = 0;
|
this._lastUpdateTime = 0;
|
||||||
this._changeTime = 0;
|
this._changeTime = 0;
|
||||||
this._updateInterval = MovingObjectLogic.DEFAULT_UPDATE_INTERVAL;
|
this._updateInterval = MovingObjectLogic.DEFAULT_UPDATE_INTERVAL;
|
||||||
|
this._queuedMoveMessages = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public dispose(): void
|
public dispose(): void
|
||||||
{
|
{
|
||||||
this._liftAmount = 0;
|
this._liftAmount = 0;
|
||||||
|
this._queuedMoveMessages = [];
|
||||||
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
@@ -46,6 +50,7 @@ export class MovingObjectLogic extends RoomObjectLogicBase
|
|||||||
|
|
||||||
const locationOffset = this.getLocationOffset();
|
const locationOffset = this.getLocationOffset();
|
||||||
const model = this.object && this.object.model;
|
const model = this.object && this.object.model;
|
||||||
|
let completedInterpolation = false;
|
||||||
|
|
||||||
if(model)
|
if(model)
|
||||||
{
|
{
|
||||||
@@ -111,10 +116,13 @@ export class MovingObjectLogic extends RoomObjectLogicBase
|
|||||||
this._locationDelta.x = 0;
|
this._locationDelta.x = 0;
|
||||||
this._locationDelta.y = 0;
|
this._locationDelta.y = 0;
|
||||||
this._locationDelta.z = 0;
|
this._locationDelta.z = 0;
|
||||||
|
completedInterpolation = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._lastUpdateTime = this.time;
|
this._lastUpdateTime = this.time;
|
||||||
|
|
||||||
|
if(completedInterpolation) this.processQueuedMoveMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
public setObject(object: IRoomObjectController): void
|
public setObject(object: IRoomObjectController): void
|
||||||
@@ -130,6 +138,17 @@ export class MovingObjectLogic extends RoomObjectLogicBase
|
|||||||
|
|
||||||
if(message instanceof ObjectMoveUpdateMessage)
|
if(message instanceof ObjectMoveUpdateMessage)
|
||||||
{
|
{
|
||||||
|
if(this.shouldApplyInstantMoveMessage(message))
|
||||||
|
{
|
||||||
|
super.processUpdateMessage(message);
|
||||||
|
|
||||||
|
if(message.location) this._location.assign(message.location);
|
||||||
|
|
||||||
|
this.resetInterpolationState();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const requiresCustomMoveHandling = !!message.anchorObject || (message.elapsed > 0);
|
const requiresCustomMoveHandling = !!message.anchorObject || (message.elapsed > 0);
|
||||||
|
|
||||||
if(requiresCustomMoveHandling)
|
if(requiresCustomMoveHandling)
|
||||||
@@ -147,15 +166,30 @@ export class MovingObjectLogic extends RoomObjectLogicBase
|
|||||||
if(message instanceof ObjectMoveUpdateMessage) return this.processMoveMessage(message);
|
if(message instanceof ObjectMoveUpdateMessage) return this.processMoveMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private shouldApplyInstantMoveMessage(message: ObjectMoveUpdateMessage): boolean
|
||||||
|
{
|
||||||
|
if(!message || !message.location || message.isSlide || !!message.anchorObject || (message.elapsed > 0)) return false;
|
||||||
|
|
||||||
|
return this.matchesLocation(message.location, message.targetLocation);
|
||||||
|
}
|
||||||
|
|
||||||
private processMoveMessage(message: ObjectMoveUpdateMessage): void
|
private processMoveMessage(message: ObjectMoveUpdateMessage): void
|
||||||
{
|
{
|
||||||
if(!message || !this.object || !message.location) return;
|
if(!message || !this.object || !message.location) return;
|
||||||
|
|
||||||
|
if(this.shouldQueueMoveMessage(message))
|
||||||
|
{
|
||||||
|
this.queueMoveMessage(message);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const hadActiveInterpolation = this.isInterpolating();
|
const hadActiveInterpolation = this.isInterpolating();
|
||||||
|
const duration = ((message.duration > 0) ? message.duration : ObjectMoveUpdateMessage.DEFAULT_DURATION);
|
||||||
const startLocation = hadActiveInterpolation
|
const startLocation = hadActiveInterpolation
|
||||||
? this.object.getLocation()
|
? this.object.getLocation()
|
||||||
: message.location;
|
: message.location;
|
||||||
const elapsed = Math.max(0, Math.min(message.duration, message.elapsed));
|
const elapsed = Math.max(0, Math.min(duration, message.elapsed));
|
||||||
|
|
||||||
this._location.assign(startLocation);
|
this._location.assign(startLocation);
|
||||||
this.object.setLocation(this._location);
|
this.object.setLocation(this._location);
|
||||||
@@ -165,7 +199,7 @@ export class MovingObjectLogic extends RoomObjectLogicBase
|
|||||||
else this._followOffset.assign(new Vector3d());
|
else this._followOffset.assign(new Vector3d());
|
||||||
|
|
||||||
this._changeTime = (this._lastUpdateTime - elapsed);
|
this._changeTime = (this._lastUpdateTime - elapsed);
|
||||||
this.updateInterval = message.duration;
|
this.updateInterval = duration;
|
||||||
|
|
||||||
this._locationDelta.assign(message.targetLocation);
|
this._locationDelta.assign(message.targetLocation);
|
||||||
this._locationDelta.subtract(this._location);
|
this._locationDelta.subtract(this._location);
|
||||||
@@ -203,11 +237,86 @@ export class MovingObjectLogic extends RoomObjectLogicBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private resetInterpolationState(): void
|
||||||
|
{
|
||||||
|
this._locationDelta.x = 0;
|
||||||
|
this._locationDelta.y = 0;
|
||||||
|
this._locationDelta.z = 0;
|
||||||
|
this._followObject = null;
|
||||||
|
this._followOffset.assign(new Vector3d());
|
||||||
|
this._queuedMoveMessages = [];
|
||||||
|
this._changeTime = this._lastUpdateTime;
|
||||||
|
}
|
||||||
|
|
||||||
private isInterpolating(): boolean
|
private isInterpolating(): boolean
|
||||||
{
|
{
|
||||||
return (this._locationDelta.length > 0) && ((this.time - this._changeTime) < this._updateInterval);
|
return (this._locationDelta.length > 0) && ((this.time - this._changeTime) < this._updateInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private shouldQueueMoveMessage(message: ObjectMoveUpdateMessage): boolean
|
||||||
|
{
|
||||||
|
if(!message.isSlide || !!message.anchorObject || !this.isInterpolating() || !message.location || !message.targetLocation) return false;
|
||||||
|
|
||||||
|
const expectedStartLocation = this.getQueuedMovementTailLocation();
|
||||||
|
|
||||||
|
if(!expectedStartLocation) return false;
|
||||||
|
|
||||||
|
return this.matchesLocation(message.location, expectedStartLocation)
|
||||||
|
&& !this.matchesLocation(message.targetLocation, expectedStartLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private queueMoveMessage(message: ObjectMoveUpdateMessage): void
|
||||||
|
{
|
||||||
|
this._queuedMoveMessages.push(new ObjectMoveUpdateMessage(
|
||||||
|
message.location,
|
||||||
|
message.targetLocation,
|
||||||
|
message.direction,
|
||||||
|
message.isSlide,
|
||||||
|
message.duration,
|
||||||
|
message.elapsed,
|
||||||
|
message.anchorObject,
|
||||||
|
message.anchorOffset));
|
||||||
|
}
|
||||||
|
|
||||||
|
private processQueuedMoveMessage(): void
|
||||||
|
{
|
||||||
|
if(!this._queuedMoveMessages.length) return;
|
||||||
|
|
||||||
|
const nextMoveMessage = this._queuedMoveMessages.shift();
|
||||||
|
|
||||||
|
if(!nextMoveMessage) return;
|
||||||
|
|
||||||
|
this.processMoveMessage(nextMoveMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getQueuedMovementTailLocation(): IVector3D
|
||||||
|
{
|
||||||
|
if(this._queuedMoveMessages.length)
|
||||||
|
{
|
||||||
|
const queuedMoveMessage = this._queuedMoveMessages[this._queuedMoveMessages.length - 1];
|
||||||
|
|
||||||
|
if(queuedMoveMessage?.targetLocation) return queuedMoveMessage.targetLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this._locationDelta.length <= 0) return null;
|
||||||
|
|
||||||
|
const targetLocation = new Vector3d();
|
||||||
|
|
||||||
|
targetLocation.assign(this._location);
|
||||||
|
targetLocation.add(this._locationDelta);
|
||||||
|
|
||||||
|
return targetLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private matchesLocation(first: IVector3D, second: IVector3D): boolean
|
||||||
|
{
|
||||||
|
if(!first || !second) return false;
|
||||||
|
|
||||||
|
return (Math.abs(first.x - second.x) <= MovingObjectLogic.LOCATION_EPSILON)
|
||||||
|
&& (Math.abs(first.y - second.y) <= MovingObjectLogic.LOCATION_EPSILON)
|
||||||
|
&& (Math.abs(first.z - second.z) <= MovingObjectLogic.LOCATION_EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
protected getLocationOffset(): IVector3D
|
protected getLocationOffset(): IVector3D
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
Reference in New Issue
Block a user