- Implement camera controls
- Option to resolve object properties when fetching from object store (names, descriptions etc). Can be more efficient - TODO: use FamilyProperties for child prims. - Refactored objectstore to reduce code duplication
This commit is contained in:
6
dist/classes/Agent.d.ts
vendored
6
dist/classes/Agent.d.ts
vendored
@@ -40,7 +40,11 @@ export declare class Agent {
|
||||
uiFlags: {
|
||||
'allowFirstLife'?: boolean;
|
||||
};
|
||||
lookAt: Vector3;
|
||||
cameraLookAt: Vector3;
|
||||
cameraCenter: Vector3;
|
||||
cameraLeftAxis: Vector3;
|
||||
cameraUpAxis: Vector3;
|
||||
cameraFar: number;
|
||||
maxGroups: number;
|
||||
agentFlags: number;
|
||||
startLocation: string;
|
||||
|
||||
15
dist/classes/Agent.js
vendored
15
dist/classes/Agent.js
vendored
@@ -23,6 +23,11 @@ class Agent {
|
||||
this.openID = {};
|
||||
this.buddyList = [];
|
||||
this.uiFlags = {};
|
||||
this.cameraLookAt = new Vector3_1.Vector3([0.979546, 0.105575, -0.171303]);
|
||||
this.cameraCenter = new Vector3_1.Vector3([199.58, 203.95, 24.304]);
|
||||
this.cameraLeftAxis = new Vector3_1.Vector3([-1.0, 0.0, 0]);
|
||||
this.cameraUpAxis = new Vector3_1.Vector3([0.0, 0.0, 1.0]);
|
||||
this.cameraFar = 1;
|
||||
this.home = {};
|
||||
this.gestures = [];
|
||||
this.agentUpdateTimer = null;
|
||||
@@ -89,11 +94,11 @@ class Agent {
|
||||
HeadRotation: Quaternion_1.Quaternion.getIdentity(),
|
||||
BodyRotation: Quaternion_1.Quaternion.getIdentity(),
|
||||
State: AgentState_1.AgentState.None,
|
||||
CameraCenter: new Vector3_1.Vector3([199.58, 203.95, 24.304]),
|
||||
CameraAtAxis: new Vector3_1.Vector3([0.979546, 0.105575, -0.171303]),
|
||||
CameraLeftAxis: new Vector3_1.Vector3([-0.107158, 0.994242, 0]),
|
||||
CameraUpAxis: new Vector3_1.Vector3([0.170316, 0.018357, 0.985218]),
|
||||
Far: 128,
|
||||
CameraCenter: this.cameraCenter,
|
||||
CameraAtAxis: this.cameraLookAt,
|
||||
CameraLeftAxis: this.cameraLeftAxis,
|
||||
CameraUpAxis: this.cameraUpAxis,
|
||||
Far: this.cameraFar,
|
||||
ControlFlags: this.controlFlags,
|
||||
Flags: __1.AgentFlags.None
|
||||
};
|
||||
|
||||
2
dist/classes/Agent.js.map
vendored
2
dist/classes/Agent.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/classes/EventQueueClient.js
vendored
4
dist/classes/EventQueueClient.js
vendored
@@ -136,6 +136,10 @@ class EventQueueClient {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'ObjectPhysicsProperties':
|
||||
{
|
||||
break;
|
||||
}
|
||||
case 'TeleportFinish':
|
||||
{
|
||||
const info = event['body']['Info'][0];
|
||||
|
||||
2
dist/classes/EventQueueClient.js.map
vendored
2
dist/classes/EventQueueClient.js.map
vendored
File diff suppressed because one or more lines are too long
104
dist/classes/GameObject.d.ts
vendored
Normal file
104
dist/classes/GameObject.d.ts
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
/// <reference types="node" />
|
||||
import { Vector3 } from './Vector3';
|
||||
import { UUID } from './UUID';
|
||||
import { Quaternion } from './Quaternion';
|
||||
import { Tree } from '../enums/Tree';
|
||||
import { SoundFlags } from '..';
|
||||
import { Vector4 } from './Vector4';
|
||||
import { TextureEntry } from './TextureEntry';
|
||||
import { Color4 } from './Color4';
|
||||
import { ParticleSystem } from './ParticleSystem';
|
||||
import { ITreeBoundingBox } from './interfaces/ITreeBoundingBox';
|
||||
import { NameValue } from './NameValue';
|
||||
import { PCode } from '../enums/PCode';
|
||||
import * as Long from 'long';
|
||||
export declare class GameObject {
|
||||
creatorID?: UUID;
|
||||
creationDate?: Long;
|
||||
baseMask?: number;
|
||||
ownerMask?: number;
|
||||
groupMask?: number;
|
||||
everyoneMask?: number;
|
||||
nextOwnerMask?: number;
|
||||
ownershipCost?: number;
|
||||
saleType?: number;
|
||||
salePrice?: number;
|
||||
aggregatePerms?: number;
|
||||
aggregatePermTextures?: number;
|
||||
aggregatePermTexturesOwner?: number;
|
||||
category: number;
|
||||
inventorySerial: number;
|
||||
itemID: UUID;
|
||||
folderID: UUID;
|
||||
fromTaskID: UUID;
|
||||
lastOwnerID: UUID;
|
||||
name?: string;
|
||||
description?: string;
|
||||
touchName?: string;
|
||||
sitName?: string;
|
||||
textureID?: string;
|
||||
resolvedAt?: number;
|
||||
totalChildren?: number;
|
||||
children?: GameObject[];
|
||||
rtreeEntry?: ITreeBoundingBox;
|
||||
ID: number;
|
||||
FullID: UUID;
|
||||
ParentID: number;
|
||||
OwnerID: UUID;
|
||||
IsAttachment: boolean;
|
||||
NameValue: {
|
||||
[key: string]: NameValue;
|
||||
};
|
||||
PCode: PCode;
|
||||
State?: number;
|
||||
CRC?: number;
|
||||
Material?: number;
|
||||
ClickAction?: number;
|
||||
Scale?: Vector3;
|
||||
ObjectData?: Buffer;
|
||||
UpdateFlags?: number;
|
||||
Flags?: number;
|
||||
PathCurve?: number;
|
||||
ProfileCurve?: number;
|
||||
PathBegin?: number;
|
||||
PathEnd?: number;
|
||||
PathScaleX?: number;
|
||||
PathScaleY?: number;
|
||||
PathShearX?: number;
|
||||
PathShearY?: number;
|
||||
PathTwist?: number;
|
||||
PathTwistBegin?: number;
|
||||
PathRadiusOffset?: number;
|
||||
PathTaperX?: number;
|
||||
PathTaperY?: number;
|
||||
PathRevolutions?: number;
|
||||
PathSkew?: number;
|
||||
ProfileBegin?: number;
|
||||
ProfileEnd?: number;
|
||||
ProfileHollow?: number;
|
||||
TextureEntry?: TextureEntry;
|
||||
TextureAnim?: Buffer;
|
||||
Data?: Buffer;
|
||||
Text?: string;
|
||||
TextColor?: Color4;
|
||||
MediaURL?: string;
|
||||
PSBlock?: Buffer;
|
||||
JointType?: number;
|
||||
JointPivot?: Vector3;
|
||||
JointAxisOrAnchor?: Vector3;
|
||||
Position?: Vector3;
|
||||
Rotation?: Quaternion;
|
||||
CollisionPlane?: Vector4;
|
||||
Velocity?: Vector3;
|
||||
Acceleration?: Vector3;
|
||||
AngularVelocity?: Vector3;
|
||||
TreeSpecies?: Tree;
|
||||
Sound?: UUID;
|
||||
SoundGain?: number;
|
||||
SoundFlags?: SoundFlags;
|
||||
SoundRadius?: number;
|
||||
Particles?: ParticleSystem;
|
||||
constructor();
|
||||
hasNameValueEntry(key: string): boolean;
|
||||
getNameValueEntry(key: string): string;
|
||||
}
|
||||
36
dist/classes/GameObject.js
vendored
Normal file
36
dist/classes/GameObject.js
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const Vector3_1 = require("./Vector3");
|
||||
const UUID_1 = require("./UUID");
|
||||
const Quaternion_1 = require("./Quaternion");
|
||||
const PCode_1 = require("../enums/PCode");
|
||||
class GameObject {
|
||||
constructor() {
|
||||
this.ID = 0;
|
||||
this.FullID = UUID_1.UUID.random();
|
||||
this.ParentID = 0;
|
||||
this.OwnerID = UUID_1.UUID.zero();
|
||||
this.IsAttachment = false;
|
||||
this.NameValue = {};
|
||||
this.PCode = PCode_1.PCode.None;
|
||||
this.Position = Vector3_1.Vector3.getZero();
|
||||
this.Rotation = Quaternion_1.Quaternion.getIdentity();
|
||||
this.AngularVelocity = Vector3_1.Vector3.getZero();
|
||||
this.TreeSpecies = 0;
|
||||
this.SoundFlags = 0;
|
||||
this.SoundRadius = 1.0;
|
||||
this.SoundGain = 1.0;
|
||||
this.ParentID = 0;
|
||||
}
|
||||
hasNameValueEntry(key) {
|
||||
return this.NameValue[key] !== undefined;
|
||||
}
|
||||
getNameValueEntry(key) {
|
||||
if (this.NameValue[key]) {
|
||||
return this.NameValue[key].value;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
exports.GameObject = GameObject;
|
||||
//# sourceMappingURL=GameObject.js.map
|
||||
1
dist/classes/GameObject.js.map
vendored
Normal file
1
dist/classes/GameObject.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"GameObject.js","sourceRoot":"","sources":["../../lib/classes/GameObject.ts"],"names":[],"mappings":";;AAAA,uCAAkC;AAClC,iCAA4B;AAC5B,6CAAwC;AASxC,0CAAqC;AAIrC,MAAa,UAAU;IAyFnB;QAzDA,OAAE,GAAG,CAAC,CAAC;QACP,WAAM,GAAG,WAAI,CAAC,MAAM,EAAE,CAAC;QACvB,aAAQ,GAAG,CAAC,CAAC;QACb,YAAO,GAAG,WAAI,CAAC,IAAI,EAAE,CAAC;QACtB,iBAAY,GAAG,KAAK,CAAC;QACrB,cAAS,GAA+B,EAAE,CAAC;QAC3C,UAAK,GAAU,aAAK,CAAC,IAAI,CAAC;QAqDtB,IAAI,CAAC,QAAQ,GAAG,iBAAO,CAAC,OAAO,EAAE,CAAC;QAClC,IAAI,CAAC,QAAQ,GAAG,uBAAU,CAAC,WAAW,EAAE,CAAC;QACzC,IAAI,CAAC,eAAe,GAAG,iBAAO,CAAC,OAAO,EAAE,CAAC;QACzC,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;QACrB,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QACpB,IAAI,CAAC,WAAW,GAAG,GAAG,CAAC;QACvB,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;IACtB,CAAC;IAED,iBAAiB,CAAC,GAAW;QAEzB,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC;IAC7C,CAAC;IAED,iBAAiB,CAAC,GAAW;QAEzB,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EACvB;YACI,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;SACpC;QACD,OAAO,EAAE,CAAC;IACd,CAAC;CACJ;AAlHD,gCAkHC"}
|
||||
20
dist/classes/GameObjectBase.d.ts
vendored
Normal file
20
dist/classes/GameObjectBase.d.ts
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
import { UUID } from './UUID';
|
||||
import { NameValue } from './NameValue';
|
||||
import { PCode } from '../enums/PCode';
|
||||
import { ITreeBoundingBox } from './interfaces/ITreeBoundingBox';
|
||||
export declare class GameObjectBase {
|
||||
name?: string;
|
||||
description?: string;
|
||||
rtreeEntry?: ITreeBoundingBox;
|
||||
ID: number;
|
||||
FullID: UUID;
|
||||
ParentID: number;
|
||||
OwnerID: UUID;
|
||||
IsAttachment: boolean;
|
||||
NameValue: {
|
||||
[key: string]: NameValue;
|
||||
};
|
||||
PCode: PCode;
|
||||
hasNameValueEntry(key: string): boolean;
|
||||
getNameValueEntry(key: string): string;
|
||||
}
|
||||
26
dist/classes/GameObjectBase.js
vendored
Normal file
26
dist/classes/GameObjectBase.js
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const UUID_1 = require("./UUID");
|
||||
const PCode_1 = require("../enums/PCode");
|
||||
class GameObjectBase {
|
||||
constructor() {
|
||||
this.ID = 0;
|
||||
this.FullID = UUID_1.UUID.random();
|
||||
this.ParentID = 0;
|
||||
this.OwnerID = UUID_1.UUID.zero();
|
||||
this.IsAttachment = false;
|
||||
this.NameValue = {};
|
||||
this.PCode = PCode_1.PCode.None;
|
||||
}
|
||||
hasNameValueEntry(key) {
|
||||
return this.NameValue[key] !== undefined;
|
||||
}
|
||||
getNameValueEntry(key) {
|
||||
if (this.NameValue[key]) {
|
||||
return this.NameValue[key].value;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
exports.GameObjectBase = GameObjectBase;
|
||||
//# sourceMappingURL=GameObjectBase.js.map
|
||||
1
dist/classes/GameObjectBase.js.map
vendored
Normal file
1
dist/classes/GameObjectBase.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"GameObjectBase.js","sourceRoot":"","sources":["../../lib/classes/GameObjectBase.ts"],"names":[],"mappings":";;AAAA,iCAA4B;AAE5B,0CAAqC;AAGrC,MAAa,cAAc;IAA3B;QAKI,OAAE,GAAG,CAAC,CAAC;QACP,WAAM,GAAG,WAAI,CAAC,MAAM,EAAE,CAAC;QACvB,aAAQ,GAAG,CAAC,CAAC;QACb,YAAO,GAAG,WAAI,CAAC,IAAI,EAAE,CAAC;QACtB,iBAAY,GAAG,KAAK,CAAC;QACrB,cAAS,GAA+B,EAAE,CAAC;QAC3C,UAAK,GAAU,aAAK,CAAC,IAAI,CAAC;IAe9B,CAAC;IAbG,iBAAiB,CAAC,GAAW;QAEzB,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC;IAC7C,CAAC;IAED,iBAAiB,CAAC,GAAW;QAEzB,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EACvB;YACI,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;SACpC;QACD,OAAO,EAAE,CAAC;IACd,CAAC;CACJ;AA1BD,wCA0BC"}
|
||||
2
dist/classes/LoginResponse.js
vendored
2
dist/classes/LoginResponse.js
vendored
@@ -151,7 +151,7 @@ class LoginResponse {
|
||||
});
|
||||
break;
|
||||
case 'look_at':
|
||||
this.agent.lookAt = LoginResponse.parseVector3(val);
|
||||
this.agent.cameraLookAt = LoginResponse.parseVector3(val);
|
||||
break;
|
||||
case 'openid_url':
|
||||
this.agent.openID.url = String(val);
|
||||
|
||||
2
dist/classes/LoginResponse.js.map
vendored
2
dist/classes/LoginResponse.js.map
vendored
File diff suppressed because one or more lines are too long
37
dist/classes/ObjectStoreFull.d.ts
vendored
37
dist/classes/ObjectStoreFull.d.ts
vendored
@@ -1,34 +1,19 @@
|
||||
/// <reference types="node" />
|
||||
import { Circuit } from './Circuit';
|
||||
import { ObjectUpdateMessage } from './messages/ObjectUpdate';
|
||||
import { ObjectUpdateCachedMessage } from './messages/ObjectUpdateCached';
|
||||
import { ObjectUpdateCompressedMessage } from './messages/ObjectUpdateCompressed';
|
||||
import { ImprovedTerseObjectUpdateMessage } from './messages/ImprovedTerseObjectUpdate';
|
||||
import { Agent } from './Agent';
|
||||
import { UUID } from './UUID';
|
||||
import { NameValue } from './NameValue';
|
||||
import { ClientEvents } from './ClientEvents';
|
||||
import { IObjectStore } from './interfaces/IObjectStore';
|
||||
import { GameObjectFull } from './GameObjectFull';
|
||||
import { IGameObject } from './interfaces/IGameObject';
|
||||
import { BotOptionFlags } from '..';
|
||||
import { RBush3D } from 'rbush-3d/dist';
|
||||
export declare class ObjectStoreFull implements IObjectStore {
|
||||
private circuit;
|
||||
private agent;
|
||||
private objects;
|
||||
private objectsByUUID;
|
||||
private objectsByParent;
|
||||
private clientEvents;
|
||||
private options;
|
||||
rtree: RBush3D;
|
||||
import { ObjectStoreLite } from './ObjectStoreLite';
|
||||
export declare class ObjectStoreFull extends ObjectStoreLite implements IObjectStore {
|
||||
rtree?: RBush3D;
|
||||
constructor(circuit: Circuit, agent: Agent, clientEvents: ClientEvents, options: BotOptionFlags);
|
||||
insertIntoRtree(obj: GameObjectFull): void;
|
||||
deleteObject(objectID: number): void;
|
||||
readExtraParams(buf: Buffer, pos: number, o: GameObjectFull): number;
|
||||
getObjectsByParent(parentID: number): IGameObject[];
|
||||
getObjectByUUID(fullID: UUID | string): IGameObject;
|
||||
getObjectByLocalID(localID: number): IGameObject;
|
||||
parseNameValues(str: string): {
|
||||
[key: string]: NameValue;
|
||||
};
|
||||
shutdown(): void;
|
||||
private findParent;
|
||||
getObjectsInArea(minX: number, maxX: number, minY: number, maxY: number, minZ: number, maxZ: number): GameObjectFull[];
|
||||
protected objectUpdate(objectUpdate: ObjectUpdateMessage): void;
|
||||
protected objectUpdateCached(objectUpdateCached: ObjectUpdateCachedMessage): void;
|
||||
protected objectUpdateCompressed(objectUpdateCompressed: ObjectUpdateCompressedMessage): void;
|
||||
protected objectUpdateTerse(objectUpdateTerse: ImprovedTerseObjectUpdateMessage): void;
|
||||
}
|
||||
|
||||
1046
dist/classes/ObjectStoreFull.js
vendored
1046
dist/classes/ObjectStoreFull.js
vendored
File diff suppressed because it is too large
Load Diff
2
dist/classes/ObjectStoreFull.js.map
vendored
2
dist/classes/ObjectStoreFull.js.map
vendored
File diff suppressed because one or more lines are too long
52
dist/classes/ObjectStoreLite.d.ts
vendored
52
dist/classes/ObjectStoreLite.d.ts
vendored
@@ -1,31 +1,53 @@
|
||||
/// <reference types="node" />
|
||||
import { Circuit } from './Circuit';
|
||||
import { ObjectUpdateMessage } from './messages/ObjectUpdate';
|
||||
import { ObjectUpdateCachedMessage } from './messages/ObjectUpdateCached';
|
||||
import { ObjectUpdateCompressedMessage } from './messages/ObjectUpdateCompressed';
|
||||
import { ImprovedTerseObjectUpdateMessage } from './messages/ImprovedTerseObjectUpdate';
|
||||
import { MultipleObjectUpdateMessage } from './messages/MultipleObjectUpdate';
|
||||
import { Agent } from './Agent';
|
||||
import { UUID } from './UUID';
|
||||
import { ClientEvents } from './ClientEvents';
|
||||
import { KillObjectMessage } from './messages/KillObject';
|
||||
import { IObjectStore } from './interfaces/IObjectStore';
|
||||
import { GameObjectLite } from './GameObjectLite';
|
||||
import { NameValue } from './NameValue';
|
||||
import { BotOptionFlags } from '..';
|
||||
import { IGameObject } from './interfaces/IGameObject';
|
||||
import { GameObjectFull } from './GameObjectFull';
|
||||
import { GameObject } from './GameObject';
|
||||
import { RBush3D } from 'rbush-3d/dist';
|
||||
export declare class ObjectStoreLite implements IObjectStore {
|
||||
private circuit;
|
||||
private agent;
|
||||
private objects;
|
||||
private objectsByUUID;
|
||||
private objectsByParent;
|
||||
private clientEvents;
|
||||
private options;
|
||||
protected circuit: Circuit;
|
||||
protected agent: Agent;
|
||||
protected objects: {
|
||||
[key: number]: GameObject;
|
||||
};
|
||||
protected objectsByUUID: {
|
||||
[key: string]: number;
|
||||
};
|
||||
protected objectsByParent: {
|
||||
[key: number]: number[];
|
||||
};
|
||||
protected clientEvents: ClientEvents;
|
||||
protected options: BotOptionFlags;
|
||||
rtree?: RBush3D;
|
||||
constructor(circuit: Circuit, agent: Agent, clientEvents: ClientEvents, options: BotOptionFlags);
|
||||
protected objectUpdate(objectUpdate: ObjectUpdateMessage): void;
|
||||
protected objectUpdateCached(objectUpdateCached: ObjectUpdateCachedMessage): void;
|
||||
protected objectUpdateCompressed(objectUpdateCompressed: ObjectUpdateCompressedMessage): void;
|
||||
protected objectUpdateTerse(objectUpdateTerse: ImprovedTerseObjectUpdateMessage): void;
|
||||
protected objectUpdateMultiple(objectUpdateMultiple: MultipleObjectUpdateMessage): void;
|
||||
protected killObject(killObj: KillObjectMessage): void;
|
||||
deleteObject(objectID: number): void;
|
||||
readExtraParams(buf: Buffer, pos: number, o: GameObjectLite): number;
|
||||
getObjectsByParent(parentID: number): GameObjectLite[];
|
||||
readExtraParams(buf: Buffer, pos: number, o: GameObject): number;
|
||||
getObjectsByParent(parentID: number): GameObject[];
|
||||
parseNameValues(str: string): {
|
||||
[key: string]: NameValue;
|
||||
};
|
||||
shutdown(): void;
|
||||
getObjectsInArea(minX: number, maxX: number, minY: number, maxY: number, minZ: number, maxZ: number): GameObjectFull[];
|
||||
getObjectByUUID(fullID: UUID | string): IGameObject;
|
||||
getObjectByLocalID(localID: number): IGameObject;
|
||||
protected findParent(go: GameObject): GameObject;
|
||||
private populateChildren;
|
||||
getNumberOfObjects(): number;
|
||||
getObjectsInArea(minX: number, maxX: number, minY: number, maxY: number, minZ: number, maxZ: number): GameObject[];
|
||||
getObjectByUUID(fullID: UUID | string): GameObject;
|
||||
getObjectByLocalID(localID: number): GameObject;
|
||||
insertIntoRtree(obj: GameObject): void;
|
||||
}
|
||||
|
||||
494
dist/classes/ObjectStoreLite.js
vendored
494
dist/classes/ObjectStoreLite.js
vendored
@@ -5,9 +5,9 @@ const RequestMultipleObjects_1 = require("./messages/RequestMultipleObjects");
|
||||
const UUID_1 = require("./UUID");
|
||||
const Utils_1 = require("./Utils");
|
||||
const PCode_1 = require("../enums/PCode");
|
||||
const GameObjectLite_1 = require("./GameObjectLite");
|
||||
const NameValue_1 = require("./NameValue");
|
||||
const __1 = require("..");
|
||||
const GameObject_1 = require("./GameObject");
|
||||
class ObjectStoreLite {
|
||||
constructor(circuit, agent, clientEvents, options) {
|
||||
this.objects = {};
|
||||
@@ -29,221 +29,235 @@ class ObjectStoreLite {
|
||||
switch (packet.message.id) {
|
||||
case Message_1.Message.ObjectUpdate:
|
||||
const objectUpdate = packet.message;
|
||||
objectUpdate.ObjectData.forEach((objData) => {
|
||||
const localID = objData.ID;
|
||||
const parentID = objData.ParentID;
|
||||
let addToParentList = true;
|
||||
if (this.objects[localID]) {
|
||||
if (this.objects[localID].ParentID !== parentID && this.objectsByParent[parentID]) {
|
||||
const ind = this.objectsByParent[parentID].indexOf(localID);
|
||||
if (ind !== -1) {
|
||||
this.objectsByParent[parentID].splice(ind, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
addToParentList = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.objects[localID] = new GameObjectLite_1.GameObjectLite();
|
||||
}
|
||||
const obj = this.objects[localID];
|
||||
obj.ID = objData.ID;
|
||||
obj.FullID = objData.FullID;
|
||||
obj.ParentID = objData.ParentID;
|
||||
obj.OwnerID = objData.OwnerID;
|
||||
obj.PCode = objData.PCode;
|
||||
this.objects[localID].NameValue = this.parseNameValues(Utils_1.Utils.BufferToStringSimple(objData.NameValue));
|
||||
if (objData.PCode === PCode_1.PCode.Avatar && this.objects[localID].FullID.toString() === this.agent.agentID.toString()) {
|
||||
this.agent.localID = localID;
|
||||
if (this.options & __1.BotOptionFlags.StoreMyAttachmentsOnly) {
|
||||
Object.keys(this.objectsByParent).forEach((objParentID) => {
|
||||
const parent = parseInt(objParentID, 10);
|
||||
if (parent !== this.agent.localID) {
|
||||
let foundAvatars = false;
|
||||
this.objectsByParent[parent].forEach((objID) => {
|
||||
if (this.objects[objID]) {
|
||||
const o = this.objects[objID];
|
||||
if (o.PCode === PCode_1.PCode.Avatar) {
|
||||
foundAvatars = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (this.objects[parent]) {
|
||||
const o = this.objects[parent];
|
||||
if (o.PCode === PCode_1.PCode.Avatar) {
|
||||
foundAvatars = true;
|
||||
}
|
||||
}
|
||||
if (!foundAvatars) {
|
||||
this.deleteObject(parent);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
this.objectsByUUID[objData.FullID.toString()] = localID;
|
||||
if (!this.objectsByParent[parentID]) {
|
||||
this.objectsByParent[parentID] = [];
|
||||
}
|
||||
if (addToParentList) {
|
||||
this.objectsByParent[parentID].push(localID);
|
||||
}
|
||||
if (objData.PCode !== PCode_1.PCode.Avatar && this.options & __1.BotOptionFlags.StoreMyAttachmentsOnly) {
|
||||
if (this.agent.localID !== 0 && obj.ParentID !== this.agent.localID) {
|
||||
this.deleteObject(localID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
this.objectUpdate(objectUpdate);
|
||||
break;
|
||||
case Message_1.Message.ObjectUpdateCached:
|
||||
const objectUpdateCached = packet.message;
|
||||
const rmo = new RequestMultipleObjects_1.RequestMultipleObjectsMessage();
|
||||
rmo.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: this.circuit.sessionID
|
||||
};
|
||||
rmo.ObjectData = [];
|
||||
objectUpdateCached.ObjectData.forEach((obj) => {
|
||||
rmo.ObjectData.push({
|
||||
CacheMissType: 0,
|
||||
ID: obj.ID
|
||||
});
|
||||
});
|
||||
circuit.sendMessage(rmo, 0);
|
||||
this.objectUpdateCached(objectUpdateCached);
|
||||
break;
|
||||
case Message_1.Message.ObjectUpdateCompressed:
|
||||
{
|
||||
const objectUpdateCompressed = packet.message;
|
||||
for (const obj of objectUpdateCompressed.ObjectData) {
|
||||
const flags = obj.UpdateFlags;
|
||||
const buf = obj.Data;
|
||||
let pos = 0;
|
||||
const fullID = new UUID_1.UUID(buf, pos);
|
||||
pos += 16;
|
||||
const localID = buf.readUInt32LE(pos);
|
||||
pos += 4;
|
||||
const pcode = buf.readUInt8(pos++);
|
||||
let newObj = false;
|
||||
if (!this.objects[localID]) {
|
||||
newObj = true;
|
||||
this.objects[localID] = new GameObjectLite_1.GameObjectLite();
|
||||
}
|
||||
const o = this.objects[localID];
|
||||
o.ID = localID;
|
||||
o.PCode = pcode;
|
||||
this.objectsByUUID[fullID.toString()] = localID;
|
||||
o.FullID = fullID;
|
||||
pos++;
|
||||
pos = pos + 4;
|
||||
pos++;
|
||||
pos++;
|
||||
pos = pos + 12;
|
||||
pos = pos + 12;
|
||||
pos = pos + 12;
|
||||
const compressedflags = buf.readUInt32LE(pos);
|
||||
pos = pos + 4;
|
||||
o.OwnerID = new UUID_1.UUID(buf, pos);
|
||||
pos += 16;
|
||||
if (compressedflags & __1.CompressedFlags.HasAngularVelocity) {
|
||||
pos = pos + 12;
|
||||
}
|
||||
if (compressedflags & __1.CompressedFlags.HasParent) {
|
||||
const newParentID = buf.readUInt32LE(pos);
|
||||
pos += 4;
|
||||
let add = true;
|
||||
if (!newObj) {
|
||||
if (newParentID !== o.ParentID) {
|
||||
const index = this.objectsByParent[o.ParentID].indexOf(localID);
|
||||
if (index !== -1) {
|
||||
this.objectsByParent[o.ParentID].splice(index, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
add = false;
|
||||
}
|
||||
}
|
||||
if (add) {
|
||||
if (!this.objectsByParent[newParentID]) {
|
||||
this.objectsByParent[newParentID] = [];
|
||||
}
|
||||
this.objectsByParent[newParentID].push(localID);
|
||||
}
|
||||
o.ParentID = newParentID;
|
||||
}
|
||||
if (pcode !== PCode_1.PCode.Avatar && newObj && this.options & __1.BotOptionFlags.StoreMyAttachmentsOnly) {
|
||||
if (this.agent.localID !== 0 && o.ParentID !== this.agent.localID) {
|
||||
this.deleteObject(localID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (compressedflags & __1.CompressedFlags.Tree) {
|
||||
pos++;
|
||||
}
|
||||
else if (compressedflags & __1.CompressedFlags.ScratchPad) {
|
||||
const scratchPadSize = buf.readUInt8(pos++);
|
||||
pos = pos + scratchPadSize;
|
||||
}
|
||||
if (compressedflags & __1.CompressedFlags.HasText) {
|
||||
const result = Utils_1.Utils.BufferToString(buf, pos);
|
||||
pos += result.readLength;
|
||||
pos = pos + 4;
|
||||
}
|
||||
if (compressedflags & __1.CompressedFlags.MediaURL) {
|
||||
const result = Utils_1.Utils.BufferToString(buf, pos);
|
||||
pos += result.readLength;
|
||||
}
|
||||
if (compressedflags & __1.CompressedFlags.HasParticles) {
|
||||
pos += 86;
|
||||
}
|
||||
pos = this.readExtraParams(buf, pos, o);
|
||||
if (compressedflags & __1.CompressedFlags.HasSound) {
|
||||
pos = pos + 16;
|
||||
pos += 4;
|
||||
pos++;
|
||||
pos = pos + 4;
|
||||
}
|
||||
if (compressedflags & __1.CompressedFlags.HasNameValues) {
|
||||
const result = Utils_1.Utils.BufferToString(buf, pos);
|
||||
o.NameValue = this.parseNameValues(result.result);
|
||||
pos += result.readLength;
|
||||
}
|
||||
pos++;
|
||||
pos = pos + 2;
|
||||
pos = pos + 2;
|
||||
pos = pos + 12;
|
||||
pos = pos + 2;
|
||||
pos = pos + 2;
|
||||
pos = pos + 2;
|
||||
const textureEntryLength = buf.readUInt32LE(pos);
|
||||
pos = pos + 4;
|
||||
pos = pos + textureEntryLength;
|
||||
if (compressedflags & __1.CompressedFlags.TextureAnimation) {
|
||||
pos = pos + 4;
|
||||
}
|
||||
o.IsAttachment = (compressedflags & __1.CompressedFlags.HasNameValues) !== 0 && o.ParentID !== 0;
|
||||
}
|
||||
;
|
||||
this.objectUpdateCompressed(objectUpdateCompressed);
|
||||
break;
|
||||
}
|
||||
case Message_1.Message.ImprovedTerseObjectUpdate:
|
||||
const objectUpdateTerse = packet.message;
|
||||
this.objectUpdateTerse(objectUpdateTerse);
|
||||
break;
|
||||
case Message_1.Message.MultipleObjectUpdate:
|
||||
const multipleObjectUpdate = packet.message;
|
||||
console.error('TODO: MultipleObjectUpdate');
|
||||
this.objectUpdateMultiple(multipleObjectUpdate);
|
||||
break;
|
||||
case Message_1.Message.KillObject:
|
||||
const killObj = packet.message;
|
||||
killObj.ObjectData.forEach((obj) => {
|
||||
const objectID = obj.ID;
|
||||
this.deleteObject(objectID);
|
||||
});
|
||||
this.killObject(killObj);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
objectUpdate(objectUpdate) {
|
||||
objectUpdate.ObjectData.forEach((objData) => {
|
||||
const localID = objData.ID;
|
||||
const parentID = objData.ParentID;
|
||||
let addToParentList = true;
|
||||
if (this.objects[localID]) {
|
||||
if (this.objects[localID].ParentID !== parentID && this.objectsByParent[parentID]) {
|
||||
const ind = this.objectsByParent[parentID].indexOf(localID);
|
||||
if (ind !== -1) {
|
||||
this.objectsByParent[parentID].splice(ind, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
addToParentList = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.objects[localID] = new GameObject_1.GameObject();
|
||||
}
|
||||
const obj = this.objects[localID];
|
||||
obj.ID = objData.ID;
|
||||
obj.FullID = objData.FullID;
|
||||
obj.ParentID = objData.ParentID;
|
||||
obj.OwnerID = objData.OwnerID;
|
||||
obj.PCode = objData.PCode;
|
||||
this.objects[localID].NameValue = this.parseNameValues(Utils_1.Utils.BufferToStringSimple(objData.NameValue));
|
||||
if (objData.PCode === PCode_1.PCode.Avatar && this.objects[localID].FullID.toString() === this.agent.agentID.toString()) {
|
||||
this.agent.localID = localID;
|
||||
if (this.options & __1.BotOptionFlags.StoreMyAttachmentsOnly) {
|
||||
Object.keys(this.objectsByParent).forEach((objParentID) => {
|
||||
const parent = parseInt(objParentID, 10);
|
||||
if (parent !== this.agent.localID) {
|
||||
let foundAvatars = false;
|
||||
this.objectsByParent[parent].forEach((objID) => {
|
||||
if (this.objects[objID]) {
|
||||
const o = this.objects[objID];
|
||||
if (o.PCode === PCode_1.PCode.Avatar) {
|
||||
foundAvatars = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (this.objects[parent]) {
|
||||
const o = this.objects[parent];
|
||||
if (o.PCode === PCode_1.PCode.Avatar) {
|
||||
foundAvatars = true;
|
||||
}
|
||||
}
|
||||
if (!foundAvatars) {
|
||||
this.deleteObject(parent);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
this.objectsByUUID[objData.FullID.toString()] = localID;
|
||||
if (!this.objectsByParent[parentID]) {
|
||||
this.objectsByParent[parentID] = [];
|
||||
}
|
||||
if (addToParentList) {
|
||||
this.objectsByParent[parentID].push(localID);
|
||||
}
|
||||
if (objData.PCode !== PCode_1.PCode.Avatar && this.options & __1.BotOptionFlags.StoreMyAttachmentsOnly) {
|
||||
if (this.agent.localID !== 0 && obj.ParentID !== this.agent.localID) {
|
||||
this.deleteObject(localID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
objectUpdateCached(objectUpdateCached) {
|
||||
const rmo = new RequestMultipleObjects_1.RequestMultipleObjectsMessage();
|
||||
rmo.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: this.circuit.sessionID
|
||||
};
|
||||
rmo.ObjectData = [];
|
||||
objectUpdateCached.ObjectData.forEach((obj) => {
|
||||
rmo.ObjectData.push({
|
||||
CacheMissType: 0,
|
||||
ID: obj.ID
|
||||
});
|
||||
});
|
||||
this.circuit.sendMessage(rmo, 0);
|
||||
}
|
||||
objectUpdateCompressed(objectUpdateCompressed) {
|
||||
for (const obj of objectUpdateCompressed.ObjectData) {
|
||||
const flags = obj.UpdateFlags;
|
||||
const buf = obj.Data;
|
||||
let pos = 0;
|
||||
const fullID = new UUID_1.UUID(buf, pos);
|
||||
pos += 16;
|
||||
const localID = buf.readUInt32LE(pos);
|
||||
pos += 4;
|
||||
const pcode = buf.readUInt8(pos++);
|
||||
let newObj = false;
|
||||
if (!this.objects[localID]) {
|
||||
newObj = true;
|
||||
this.objects[localID] = new GameObject_1.GameObject();
|
||||
}
|
||||
const o = this.objects[localID];
|
||||
o.ID = localID;
|
||||
o.PCode = pcode;
|
||||
this.objectsByUUID[fullID.toString()] = localID;
|
||||
o.FullID = fullID;
|
||||
pos++;
|
||||
pos = pos + 4;
|
||||
pos++;
|
||||
pos++;
|
||||
pos = pos + 12;
|
||||
pos = pos + 12;
|
||||
pos = pos + 12;
|
||||
const compressedflags = buf.readUInt32LE(pos);
|
||||
pos = pos + 4;
|
||||
o.OwnerID = new UUID_1.UUID(buf, pos);
|
||||
pos += 16;
|
||||
if (compressedflags & __1.CompressedFlags.HasAngularVelocity) {
|
||||
pos = pos + 12;
|
||||
}
|
||||
if (compressedflags & __1.CompressedFlags.HasParent) {
|
||||
const newParentID = buf.readUInt32LE(pos);
|
||||
pos += 4;
|
||||
let add = true;
|
||||
if (!newObj) {
|
||||
if (newParentID !== o.ParentID) {
|
||||
const index = this.objectsByParent[o.ParentID].indexOf(localID);
|
||||
if (index !== -1) {
|
||||
this.objectsByParent[o.ParentID].splice(index, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
add = false;
|
||||
}
|
||||
}
|
||||
if (add) {
|
||||
if (!this.objectsByParent[newParentID]) {
|
||||
this.objectsByParent[newParentID] = [];
|
||||
}
|
||||
this.objectsByParent[newParentID].push(localID);
|
||||
}
|
||||
o.ParentID = newParentID;
|
||||
}
|
||||
if (pcode !== PCode_1.PCode.Avatar && newObj && this.options & __1.BotOptionFlags.StoreMyAttachmentsOnly) {
|
||||
if (this.agent.localID !== 0 && o.ParentID !== this.agent.localID) {
|
||||
this.deleteObject(localID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (compressedflags & __1.CompressedFlags.Tree) {
|
||||
pos++;
|
||||
}
|
||||
else if (compressedflags & __1.CompressedFlags.ScratchPad) {
|
||||
const scratchPadSize = buf.readUInt8(pos++);
|
||||
pos = pos + scratchPadSize;
|
||||
}
|
||||
if (compressedflags & __1.CompressedFlags.HasText) {
|
||||
const result = Utils_1.Utils.BufferToString(buf, pos);
|
||||
pos += result.readLength;
|
||||
pos = pos + 4;
|
||||
}
|
||||
if (compressedflags & __1.CompressedFlags.MediaURL) {
|
||||
const result = Utils_1.Utils.BufferToString(buf, pos);
|
||||
pos += result.readLength;
|
||||
}
|
||||
if (compressedflags & __1.CompressedFlags.HasParticles) {
|
||||
pos += 86;
|
||||
}
|
||||
pos = this.readExtraParams(buf, pos, o);
|
||||
if (compressedflags & __1.CompressedFlags.HasSound) {
|
||||
pos = pos + 16;
|
||||
pos += 4;
|
||||
pos++;
|
||||
pos = pos + 4;
|
||||
}
|
||||
if (compressedflags & __1.CompressedFlags.HasNameValues) {
|
||||
const result = Utils_1.Utils.BufferToString(buf, pos);
|
||||
o.NameValue = this.parseNameValues(result.result);
|
||||
pos += result.readLength;
|
||||
}
|
||||
pos++;
|
||||
pos = pos + 2;
|
||||
pos = pos + 2;
|
||||
pos = pos + 12;
|
||||
pos = pos + 2;
|
||||
pos = pos + 2;
|
||||
pos = pos + 2;
|
||||
const textureEntryLength = buf.readUInt32LE(pos);
|
||||
pos = pos + 4;
|
||||
pos = pos + textureEntryLength;
|
||||
if (compressedflags & __1.CompressedFlags.TextureAnimation) {
|
||||
pos = pos + 4;
|
||||
}
|
||||
o.IsAttachment = (compressedflags & __1.CompressedFlags.HasNameValues) !== 0 && o.ParentID !== 0;
|
||||
}
|
||||
}
|
||||
objectUpdateTerse(objectUpdateTerse) { }
|
||||
objectUpdateMultiple(objectUpdateMultiple) { }
|
||||
killObject(killObj) {
|
||||
killObj.ObjectData.forEach((obj) => {
|
||||
const objectID = obj.ID;
|
||||
this.deleteObject(objectID);
|
||||
});
|
||||
}
|
||||
deleteObject(objectID) {
|
||||
if (this.objects[objectID]) {
|
||||
if (this.objectsByParent[objectID]) {
|
||||
@@ -264,6 +278,9 @@ class ObjectStoreLite {
|
||||
this.objectsByParent[parentID].splice(ind, 1);
|
||||
}
|
||||
}
|
||||
if (this.rtree && this.objects[objectID].rtreeEntry !== undefined) {
|
||||
this.rtree.remove(this.objects[objectID].rtreeEntry);
|
||||
}
|
||||
delete this.objects[objectID];
|
||||
}
|
||||
}
|
||||
@@ -322,11 +339,73 @@ class ObjectStoreLite {
|
||||
}
|
||||
shutdown() {
|
||||
this.objects = {};
|
||||
if (this.rtree) {
|
||||
this.rtree.clear();
|
||||
}
|
||||
this.objectsByUUID = {};
|
||||
this.objectsByParent = {};
|
||||
}
|
||||
findParent(go) {
|
||||
if (go.ParentID !== 0 && this.objects[go.ParentID]) {
|
||||
return this.findParent(this.objects[go.ParentID]);
|
||||
}
|
||||
else {
|
||||
return go;
|
||||
}
|
||||
}
|
||||
populateChildren(obj) {
|
||||
obj.children = [];
|
||||
obj.totalChildren = 0;
|
||||
for (const child of this.getObjectsByParent(obj.ID)) {
|
||||
obj.totalChildren++;
|
||||
this.populateChildren(child);
|
||||
if (child.totalChildren !== undefined) {
|
||||
obj.totalChildren += child.totalChildren;
|
||||
}
|
||||
obj.children.push(child);
|
||||
}
|
||||
}
|
||||
getNumberOfObjects() {
|
||||
return Object.keys(this.objects).length;
|
||||
}
|
||||
getObjectsInArea(minX, maxX, minY, maxY, minZ, maxZ) {
|
||||
throw new Error('GetObjectsInArea not available with the Lite object store.');
|
||||
if (!this.rtree) {
|
||||
throw new Error('GetObjectsInArea not available with the Lite object store');
|
||||
}
|
||||
const result = this.rtree.search({
|
||||
minX: minX,
|
||||
maxX: maxX,
|
||||
minY: minY,
|
||||
maxY: maxY,
|
||||
minZ: minZ,
|
||||
maxZ: maxZ
|
||||
});
|
||||
const found = {};
|
||||
const objs = [];
|
||||
for (const obj of result) {
|
||||
const o = obj;
|
||||
const go = o.gameObject;
|
||||
if (go.PCode !== PCode_1.PCode.Avatar && (go.IsAttachment === undefined || go.IsAttachment === false)) {
|
||||
try {
|
||||
const parent = this.findParent(go);
|
||||
if (parent.PCode !== PCode_1.PCode.Avatar && (parent.IsAttachment === undefined || parent.IsAttachment === false)) {
|
||||
const uuid = parent.FullID.toString();
|
||||
if (found[uuid] === undefined) {
|
||||
found[uuid] = parent;
|
||||
objs.push(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.log('Failed to find parent for ' + go.FullID.toString());
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const obj of objs) {
|
||||
this.populateChildren(obj);
|
||||
}
|
||||
return objs;
|
||||
}
|
||||
getObjectByUUID(fullID) {
|
||||
if (fullID instanceof UUID_1.UUID) {
|
||||
@@ -344,6 +423,29 @@ class ObjectStoreLite {
|
||||
}
|
||||
return this.objects[localID];
|
||||
}
|
||||
insertIntoRtree(obj) {
|
||||
if (!this.rtree) {
|
||||
return;
|
||||
}
|
||||
if (obj.rtreeEntry !== undefined) {
|
||||
this.rtree.remove(obj.rtreeEntry);
|
||||
}
|
||||
if (!obj.Scale || !obj.Position || !obj.Rotation) {
|
||||
return;
|
||||
}
|
||||
const normalizedScale = obj.Scale.multiplyByQuat(obj.Rotation);
|
||||
const bounds = {
|
||||
minX: obj.Position.x - (normalizedScale.x / 2),
|
||||
maxX: obj.Position.x + (normalizedScale.x / 2),
|
||||
minY: obj.Position.y - (normalizedScale.y / 2),
|
||||
maxY: obj.Position.y + (normalizedScale.y / 2),
|
||||
minZ: obj.Position.z - (normalizedScale.z / 2),
|
||||
maxZ: obj.Position.z + (normalizedScale.z / 2),
|
||||
gameObject: obj
|
||||
};
|
||||
obj.rtreeEntry = bounds;
|
||||
this.rtree.insert(bounds);
|
||||
}
|
||||
}
|
||||
exports.ObjectStoreLite = ObjectStoreLite;
|
||||
//# sourceMappingURL=ObjectStoreLite.js.map
|
||||
2
dist/classes/ObjectStoreLite.js.map
vendored
2
dist/classes/ObjectStoreLite.js.map
vendored
File diff suppressed because one or more lines are too long
3
dist/classes/commands/AgentCommands.d.ts
vendored
3
dist/classes/commands/AgentCommands.d.ts
vendored
@@ -1,7 +1,10 @@
|
||||
import { UUID } from '../UUID';
|
||||
import { CommandsBase } from './CommandsBase';
|
||||
import { Vector3 } from '../Vector3';
|
||||
export declare class AgentCommands extends CommandsBase {
|
||||
private animate;
|
||||
startAnimations(anim: UUID[]): Promise<void>;
|
||||
stopAnimations(anim: UUID[]): Promise<void>;
|
||||
setCamera(position: Vector3, lookAt: Vector3, viewDistance?: number, leftAxis?: Vector3, upAxis?: Vector3): void;
|
||||
setViewDistance(viewDistance: number): void;
|
||||
}
|
||||
|
||||
16
dist/classes/commands/AgentCommands.js
vendored
16
dist/classes/commands/AgentCommands.js
vendored
@@ -41,6 +41,22 @@ class AgentCommands extends CommandsBase_1.CommandsBase {
|
||||
return yield this.animate(anim, false);
|
||||
});
|
||||
}
|
||||
setCamera(position, lookAt, viewDistance, leftAxis, upAxis) {
|
||||
this.agent.cameraCenter = position;
|
||||
this.agent.cameraLookAt = lookAt;
|
||||
if (viewDistance !== undefined) {
|
||||
this.agent.cameraFar = viewDistance;
|
||||
}
|
||||
if (leftAxis !== undefined) {
|
||||
this.agent.cameraLeftAxis = leftAxis;
|
||||
}
|
||||
if (upAxis !== undefined) {
|
||||
this.agent.cameraUpAxis = upAxis;
|
||||
}
|
||||
}
|
||||
setViewDistance(viewDistance) {
|
||||
this.agent.cameraFar = viewDistance;
|
||||
}
|
||||
}
|
||||
exports.AgentCommands = AgentCommands;
|
||||
//# sourceMappingURL=AgentCommands.js.map
|
||||
2
dist/classes/commands/AgentCommands.js.map
vendored
2
dist/classes/commands/AgentCommands.js.map
vendored
@@ -1 +1 @@
|
||||
{"version":3,"file":"AgentCommands.js","sourceRoot":"","sources":["../../../lib/classes/commands/AgentCommands.ts"],"names":[],"mappings":";;;;;;;;;;AACA,+DAAiE;AACjE,yDAAoD;AACpD,iDAA4C;AAE5C,MAAa,aAAc,SAAQ,2BAAY;IAE7B,OAAO,CAAC,IAAY,EAAE,GAAY;;YAG5C,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;YAC3C,MAAM,UAAU,GAAG,IAAI,sCAAqB,EAAE,CAAC;YAC/C,UAAU,CAAC,SAAS,GAAG;gBACnB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO;gBAC3B,SAAS,EAAE,OAAO,CAAC,SAAS;aAC/B,CAAC;YACF,UAAU,CAAC,uBAAuB,GAAG,EAAE,CAAC;YACxC,UAAU,CAAC,aAAa,GAAG,EAAE,CAAC;YAC9B,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;gBAEf,UAAU,CAAC,aAAa,CAAC,IAAI,CAAC;oBAC1B,MAAM,EAAE,CAAC;oBACT,SAAS,EAAE,GAAG;iBACjB,CAAC,CAAC;YACP,CAAC,CAAC,CAAC;YAEH,OAAO,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,WAAW,CAAC,UAAU,EAAE,yBAAW,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC;QAClG,CAAC;KAAA;IAEK,eAAe,CAAC,IAAY;;YAE9B,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC1C,CAAC;KAAA;IAEK,cAAc,CAAC,IAAY;;YAE7B,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC3C,CAAC;KAAA;CACJ;AAjCD,sCAiCC"}
|
||||
{"version":3,"file":"AgentCommands.js","sourceRoot":"","sources":["../../../lib/classes/commands/AgentCommands.ts"],"names":[],"mappings":";;;;;;;;;;AACA,+DAAiE;AACjE,yDAAoD;AACpD,iDAA4C;AAG5C,MAAa,aAAc,SAAQ,2BAAY;IAE7B,OAAO,CAAC,IAAY,EAAE,GAAY;;YAG5C,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;YAC3C,MAAM,UAAU,GAAG,IAAI,sCAAqB,EAAE,CAAC;YAC/C,UAAU,CAAC,SAAS,GAAG;gBACnB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO;gBAC3B,SAAS,EAAE,OAAO,CAAC,SAAS;aAC/B,CAAC;YACF,UAAU,CAAC,uBAAuB,GAAG,EAAE,CAAC;YACxC,UAAU,CAAC,aAAa,GAAG,EAAE,CAAC;YAC9B,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;gBAEf,UAAU,CAAC,aAAa,CAAC,IAAI,CAAC;oBAC1B,MAAM,EAAE,CAAC;oBACT,SAAS,EAAE,GAAG;iBACjB,CAAC,CAAC;YACP,CAAC,CAAC,CAAC;YAEH,OAAO,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,WAAW,CAAC,UAAU,EAAE,yBAAW,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC;QAClG,CAAC;KAAA;IAEK,eAAe,CAAC,IAAY;;YAE9B,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC1C,CAAC;KAAA;IAEK,cAAc,CAAC,IAAY;;YAE7B,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC3C,CAAC;KAAA;IAED,SAAS,CAAC,QAAiB,EAAE,MAAe,EAAE,YAAqB,EAAE,QAAkB,EAAE,MAAgB;QAErG,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,QAAQ,CAAC;QACnC,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,MAAM,CAAC;QACjC,IAAI,YAAY,KAAK,SAAS,EAC9B;YACI,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,YAAY,CAAC;SACvC;QACD,IAAI,QAAQ,KAAK,SAAS,EAC1B;YACI,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,QAAQ,CAAC;SACxC;QACD,IAAI,MAAM,KAAK,SAAS,EACxB;YACI,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,MAAM,CAAC;SACpC;IACL,CAAC;IAED,eAAe,CAAC,YAAoB;QAEhC,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,YAAY,CAAC;IACxC,CAAC;CACJ;AAxDD,sCAwDC"}
|
||||
9
dist/classes/commands/RegionCommands.d.ts
vendored
9
dist/classes/commands/RegionCommands.d.ts
vendored
@@ -2,10 +2,15 @@ import { CommandsBase } from './CommandsBase';
|
||||
import { UUID } from '../UUID';
|
||||
import * as Long from 'long';
|
||||
import { Vector3 } from '../..';
|
||||
import { IGameObject } from '../interfaces/IGameObject';
|
||||
import { GameObject } from '../GameObject';
|
||||
import { ObjectPropertiesMessage } from '../messages/ObjectProperties';
|
||||
export declare class RegionCommands extends CommandsBase {
|
||||
getRegionHandle(regionID: UUID): Promise<Long>;
|
||||
getObjectsInArea(minX: number, maxX: number, minY: number, maxY: number, minZ: number, maxZ: number): IGameObject[];
|
||||
deselectObjects(objects: GameObject[]): Promise<void>;
|
||||
countObjects(): number;
|
||||
selectObjects(objects: GameObject[]): Promise<ObjectPropertiesMessage | undefined>;
|
||||
private resolveObjects;
|
||||
getObjectsInArea(minX: number, maxX: number, minY: number, maxY: number, minZ: number, maxZ: number, resolve?: boolean): Promise<GameObject[]>;
|
||||
grabObject(localID: number | UUID, grabOffset?: Vector3, uvCoordinate?: Vector3, stCoordinate?: Vector3, faceIndex?: number, position?: Vector3, normal?: Vector3, binormal?: Vector3): Promise<void>;
|
||||
deGrabObject(localID: number | UUID, grabOffset?: Vector3, uvCoordinate?: Vector3, stCoordinate?: Vector3, faceIndex?: number, position?: Vector3, normal?: Vector3, binormal?: Vector3): Promise<void>;
|
||||
dragGrabbedObject(localID: number | UUID, grabPosition: Vector3, grabOffset?: Vector3, uvCoordinate?: Vector3, stCoordinate?: Vector3, faceIndex?: number, position?: Vector3, normal?: Vector3, binormal?: Vector3): Promise<void>;
|
||||
|
||||
216
dist/classes/commands/RegionCommands.js
vendored
216
dist/classes/commands/RegionCommands.js
vendored
@@ -17,6 +17,10 @@ const __1 = require("../..");
|
||||
const ObjectGrab_1 = require("../messages/ObjectGrab");
|
||||
const ObjectDeGrab_1 = require("../messages/ObjectDeGrab");
|
||||
const ObjectGrabUpdate_1 = require("../messages/ObjectGrabUpdate");
|
||||
const ObjectSelect_1 = require("../messages/ObjectSelect");
|
||||
const Utils_1 = require("../Utils");
|
||||
const ObjectDeselect_1 = require("../messages/ObjectDeselect");
|
||||
const PCode_1 = require("../../enums/PCode");
|
||||
class RegionCommands extends CommandsBase_1.CommandsBase {
|
||||
getRegionHandle(regionID) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
@@ -37,8 +41,216 @@ class RegionCommands extends CommandsBase_1.CommandsBase {
|
||||
return responseMsg.ReplyBlock.RegionHandle;
|
||||
});
|
||||
}
|
||||
getObjectsInArea(minX, maxX, minY, maxY, minZ, maxZ) {
|
||||
return this.currentRegion.objects.getObjectsInArea(minX, maxX, minY, maxY, minZ, maxZ);
|
||||
deselectObjects(objects) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const selectLimit = 255;
|
||||
if (objects.length > selectLimit) {
|
||||
for (let x = 0; x < objects.length; x += selectLimit) {
|
||||
const selectList = [];
|
||||
for (let y = 0; y < selectLimit; y++) {
|
||||
if (y < objects.length) {
|
||||
selectList.push(objects[x + y]);
|
||||
}
|
||||
}
|
||||
yield this.deselectObjects(selectList);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
const deselectObject = new ObjectDeselect_1.ObjectDeselectMessage();
|
||||
deselectObject.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: this.circuit.sessionID
|
||||
};
|
||||
deselectObject.ObjectData = [];
|
||||
const uuidMap = {};
|
||||
for (const obj of objects) {
|
||||
const uuidStr = obj.FullID.toString();
|
||||
if (!uuidMap[uuidStr]) {
|
||||
uuidMap[uuidStr] = obj;
|
||||
deselectObject.ObjectData.push({
|
||||
ObjectLocalID: obj.ID
|
||||
});
|
||||
}
|
||||
}
|
||||
const sequenceID = this.circuit.sendMessage(deselectObject, __1.PacketFlags.Reliable);
|
||||
return yield this.circuit.waitForAck(sequenceID, 10000);
|
||||
}
|
||||
});
|
||||
}
|
||||
countObjects() {
|
||||
return this.currentRegion.objects.getNumberOfObjects();
|
||||
}
|
||||
selectObjects(objects) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const selectLimit = 255;
|
||||
if (objects.length > selectLimit) {
|
||||
for (let x = 0; x < objects.length; x += selectLimit) {
|
||||
const selectList = [];
|
||||
for (let y = 0; y < selectLimit; y++) {
|
||||
if (y < objects.length) {
|
||||
selectList.push(objects[x + y]);
|
||||
}
|
||||
}
|
||||
yield this.selectObjects(selectList);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
const selectObject = new ObjectSelect_1.ObjectSelectMessage();
|
||||
selectObject.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: this.circuit.sessionID
|
||||
};
|
||||
selectObject.ObjectData = [];
|
||||
const uuidMap = {};
|
||||
for (const obj of objects) {
|
||||
const uuidStr = obj.FullID.toString();
|
||||
if (!uuidMap[uuidStr]) {
|
||||
uuidMap[uuidStr] = obj;
|
||||
selectObject.ObjectData.push({
|
||||
ObjectLocalID: obj.ID
|
||||
});
|
||||
}
|
||||
}
|
||||
let resolved = 0;
|
||||
this.circuit.sendMessage(selectObject, __1.PacketFlags.Reliable);
|
||||
return yield this.circuit.waitForMessage(Message_1.Message.ObjectProperties, 10000, (propertiesMessage) => {
|
||||
let found = false;
|
||||
for (const objData of propertiesMessage.ObjectData) {
|
||||
const objDataUUID = objData.ObjectID.toString();
|
||||
if (uuidMap[objDataUUID] !== undefined) {
|
||||
resolved++;
|
||||
const obj = uuidMap[objDataUUID];
|
||||
obj.creatorID = objData.CreatorID;
|
||||
obj.creationDate = objData.CreationDate;
|
||||
obj.baseMask = objData.BaseMask;
|
||||
obj.ownerMask = objData.OwnerMask;
|
||||
obj.groupMask = objData.GroupMask;
|
||||
obj.everyoneMask = objData.EveryoneMask;
|
||||
obj.nextOwnerMask = objData.NextOwnerMask;
|
||||
obj.ownershipCost = objData.OwnershipCost;
|
||||
obj.saleType = objData.SaleType;
|
||||
obj.salePrice = objData.SalePrice;
|
||||
obj.aggregatePerms = objData.AggregatePerms;
|
||||
obj.aggregatePermTextures = objData.AggregatePermTextures;
|
||||
obj.aggregatePermTexturesOwner = objData.AggregatePermTexturesOwner;
|
||||
obj.category = objData.Category;
|
||||
obj.inventorySerial = objData.InventorySerial;
|
||||
obj.itemID = objData.ItemID;
|
||||
obj.folderID = objData.FolderID;
|
||||
obj.fromTaskID = objData.FromTaskID;
|
||||
obj.lastOwnerID = objData.LastOwnerID;
|
||||
obj.name = Utils_1.Utils.BufferToStringSimple(objData.Name);
|
||||
obj.description = Utils_1.Utils.BufferToStringSimple(objData.Description);
|
||||
obj.touchName = Utils_1.Utils.BufferToStringSimple(objData.TouchName);
|
||||
obj.sitName = Utils_1.Utils.BufferToStringSimple(objData.SitName);
|
||||
obj.textureID = Utils_1.Utils.BufferToStringSimple(objData.TextureID);
|
||||
obj.resolvedAt = new Date().getTime() / 1000;
|
||||
delete uuidMap[objDataUUID];
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (Object.keys(uuidMap).length === 0) {
|
||||
return FilterResponse_1.FilterResponse.Finish;
|
||||
}
|
||||
if (!found) {
|
||||
return FilterResponse_1.FilterResponse.NoMatch;
|
||||
}
|
||||
else {
|
||||
return FilterResponse_1.FilterResponse.Match;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
resolveObjects(objects) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const objs = {};
|
||||
const scanObject = function (obj) {
|
||||
const localID = obj.ID;
|
||||
if (!objs[localID]) {
|
||||
objs[localID] = obj;
|
||||
if (obj.children) {
|
||||
for (const child of obj.children) {
|
||||
scanObject(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
for (const obj of objects) {
|
||||
scanObject(obj);
|
||||
}
|
||||
const resolveTime = new Date().getTime() / 1000;
|
||||
let objectList = [];
|
||||
let totalRemaining = 0;
|
||||
try {
|
||||
for (const k of Object.keys(objs)) {
|
||||
const ky = parseInt(k, 10);
|
||||
if (objs[ky] !== undefined) {
|
||||
const o = objs[ky];
|
||||
if (o.resolvedAt === undefined) {
|
||||
o.resolvedAt = 0;
|
||||
}
|
||||
if (o.resolvedAt !== undefined && o.resolvedAt < resolveTime && o.PCode !== PCode_1.PCode.Avatar) {
|
||||
objs[ky].name = undefined;
|
||||
totalRemaining++;
|
||||
objectList.push(objs[ky]);
|
||||
if (objectList.length > 254) {
|
||||
try {
|
||||
yield this.selectObjects(objectList);
|
||||
yield this.deselectObjects(objectList);
|
||||
for (const chk of objectList) {
|
||||
if (chk.resolvedAt !== undefined && chk.resolvedAt >= resolveTime) {
|
||||
totalRemaining--;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ignore) {
|
||||
}
|
||||
finally {
|
||||
objectList = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (objectList.length > 0) {
|
||||
yield this.selectObjects(objectList);
|
||||
yield this.deselectObjects(objectList);
|
||||
for (const chk of objectList) {
|
||||
if (chk.resolvedAt !== undefined && chk.resolvedAt >= resolveTime) {
|
||||
totalRemaining--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ignore) {
|
||||
}
|
||||
finally {
|
||||
if (totalRemaining < 1) {
|
||||
totalRemaining = 0;
|
||||
for (const obj of objectList) {
|
||||
if (obj.resolvedAt === undefined || obj.resolvedAt < resolveTime) {
|
||||
totalRemaining++;
|
||||
}
|
||||
}
|
||||
if (totalRemaining > 0) {
|
||||
console.error(totalRemaining + ' objects could not be resolved');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
getObjectsInArea(minX, maxX, minY, maxY, minZ, maxZ, resolve = false) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const objs = this.currentRegion.objects.getObjectsInArea(minX, maxX, minY, maxY, minZ, maxZ);
|
||||
if (resolve) {
|
||||
console.log('Resolving ' + objs.length + ' objects');
|
||||
yield this.resolveObjects(objs);
|
||||
}
|
||||
return objs;
|
||||
});
|
||||
}
|
||||
grabObject(localID, grabOffset = __1.Vector3.getZero(), uvCoordinate = __1.Vector3.getZero(), stCoordinate = __1.Vector3.getZero(), faceIndex = 0, position = __1.Vector3.getZero(), normal = __1.Vector3.getZero(), binormal = __1.Vector3.getZero()) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
|
||||
2
dist/classes/commands/RegionCommands.js.map
vendored
2
dist/classes/commands/RegionCommands.js.map
vendored
File diff suppressed because one or more lines are too long
12
dist/classes/interfaces/IObjectStore.d.ts
vendored
12
dist/classes/interfaces/IObjectStore.d.ts
vendored
@@ -1,12 +1,12 @@
|
||||
import { IGameObject } from './IGameObject';
|
||||
import { RBush3D } from 'rbush-3d/dist';
|
||||
import { GameObjectFull } from '../GameObjectFull';
|
||||
import { UUID } from '../UUID';
|
||||
import { GameObject } from '../GameObject';
|
||||
export interface IObjectStore {
|
||||
rtree?: RBush3D;
|
||||
getObjectsByParent(parentID: number): IGameObject[];
|
||||
getObjectsByParent(parentID: number): GameObject[];
|
||||
shutdown(): void;
|
||||
getObjectsInArea(minX: number, maxX: number, minY: number, maxY: number, minZ: number, maxZ: number): GameObjectFull[];
|
||||
getObjectByUUID(fullID: UUID): IGameObject;
|
||||
getObjectByLocalID(ID: number): IGameObject;
|
||||
getObjectsInArea(minX: number, maxX: number, minY: number, maxY: number, minZ: number, maxZ: number): GameObject[];
|
||||
getObjectByUUID(fullID: UUID): GameObject;
|
||||
getObjectByLocalID(ID: number): GameObject;
|
||||
getNumberOfObjects(): number;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { BBox } from 'rbush-3d/dist';
|
||||
import { IGameObject } from './IGameObject';
|
||||
import { GameObject } from '../GameObject';
|
||||
export interface ITreeBoundingBox extends BBox {
|
||||
gameObject: IGameObject;
|
||||
gameObject: GameObject;
|
||||
}
|
||||
|
||||
@@ -19,9 +19,9 @@ import {RezSingleAttachmentFromInvMessage} from './messages/RezSingleAttachmentF
|
||||
import {AttachmentPoint} from '../enums/AttachmentPoint';
|
||||
import {Utils} from './Utils';
|
||||
import {ClientEvents} from './ClientEvents';
|
||||
import {IGameObject} from './interfaces/IGameObject';
|
||||
import Timer = NodeJS.Timer;
|
||||
import {ControlFlags, GroupChatSessionAgentListEvent, AgentFlags, PacketFlags, AssetType} from '..';
|
||||
import {GameObject} from './GameObject';
|
||||
|
||||
export class Agent
|
||||
{
|
||||
@@ -53,7 +53,11 @@ export class Agent
|
||||
uiFlags: {
|
||||
'allowFirstLife'?: boolean
|
||||
} = {};
|
||||
lookAt: Vector3;
|
||||
cameraLookAt: Vector3 = new Vector3([0.979546, 0.105575, -0.171303]);
|
||||
cameraCenter: Vector3 = new Vector3([199.58, 203.95, 24.304]);
|
||||
cameraLeftAxis: Vector3 = new Vector3([-1.0, 0.0, 0]);
|
||||
cameraUpAxis: Vector3 = new Vector3([0.0, 0.0, 1.0]);
|
||||
cameraFar = 1;
|
||||
maxGroups: number;
|
||||
agentFlags: number;
|
||||
startLocation: string;
|
||||
@@ -164,11 +168,11 @@ export class Agent
|
||||
HeadRotation: Quaternion.getIdentity(),
|
||||
BodyRotation: Quaternion.getIdentity(),
|
||||
State: AgentState.None,
|
||||
CameraCenter: new Vector3([199.58, 203.95, 24.304]),
|
||||
CameraAtAxis: new Vector3([0.979546, 0.105575, -0.171303]),
|
||||
CameraLeftAxis: new Vector3([-0.107158, 0.994242, 0]),
|
||||
CameraUpAxis: new Vector3([0.170316, 0.018357, 0.985218]),
|
||||
Far: 128,
|
||||
CameraCenter: this.cameraCenter,
|
||||
CameraAtAxis: this.cameraLookAt,
|
||||
CameraLeftAxis: this.cameraLeftAxis,
|
||||
CameraUpAxis: this.cameraUpAxis,
|
||||
Far: this.cameraFar,
|
||||
ControlFlags: this.controlFlags,
|
||||
Flags: AgentFlags.None
|
||||
};
|
||||
@@ -266,7 +270,7 @@ export class Agent
|
||||
if (item.type === 6)
|
||||
{
|
||||
let found = false;
|
||||
wornObjects.forEach((obj: IGameObject) =>
|
||||
wornObjects.forEach((obj: GameObject) =>
|
||||
{
|
||||
if (obj.hasNameValueEntry('AttachItemID'))
|
||||
{
|
||||
|
||||
@@ -366,6 +366,10 @@ export class EventQueueClient
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'ObjectPhysicsProperties':
|
||||
{
|
||||
break;
|
||||
}
|
||||
case 'TeleportFinish':
|
||||
{
|
||||
const info = event['body']['Info'][0];
|
||||
|
||||
130
lib/classes/GameObject.ts
Normal file
130
lib/classes/GameObject.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
import {Vector3} from './Vector3';
|
||||
import {UUID} from './UUID';
|
||||
import {Quaternion} from './Quaternion';
|
||||
import {Tree} from '../enums/Tree';
|
||||
import {SoundFlags} from '..';
|
||||
import {Vector4} from './Vector4';
|
||||
import {TextureEntry} from './TextureEntry';
|
||||
import {Color4} from './Color4';
|
||||
import {ParticleSystem} from './ParticleSystem';
|
||||
import {ITreeBoundingBox} from './interfaces/ITreeBoundingBox';
|
||||
import {NameValue} from './NameValue';
|
||||
import {PCode} from '../enums/PCode';
|
||||
import {Utils} from './Utils';
|
||||
import * as Long from 'long';
|
||||
|
||||
export class GameObject
|
||||
{
|
||||
creatorID?: UUID;
|
||||
creationDate?: Long;
|
||||
baseMask?: number;
|
||||
ownerMask?: number;
|
||||
groupMask?: number;
|
||||
everyoneMask?: number;
|
||||
nextOwnerMask?: number;
|
||||
ownershipCost?: number;
|
||||
saleType?: number;
|
||||
salePrice?: number;
|
||||
aggregatePerms?: number;
|
||||
aggregatePermTextures?: number;
|
||||
aggregatePermTexturesOwner?: number;
|
||||
category: number;
|
||||
inventorySerial: number;
|
||||
itemID: UUID;
|
||||
folderID: UUID;
|
||||
fromTaskID: UUID;
|
||||
lastOwnerID: UUID;
|
||||
name?: string;
|
||||
description?: string;
|
||||
touchName?: string;
|
||||
sitName?: string;
|
||||
textureID?: string;
|
||||
resolvedAt?: number;
|
||||
totalChildren?: number;
|
||||
|
||||
|
||||
children?: GameObject[];
|
||||
rtreeEntry?: ITreeBoundingBox;
|
||||
ID = 0;
|
||||
FullID = UUID.random();
|
||||
ParentID = 0;
|
||||
OwnerID = UUID.zero();
|
||||
IsAttachment = false;
|
||||
NameValue: {[key: string]: NameValue} = {};
|
||||
PCode: PCode = PCode.None;
|
||||
|
||||
State?: number;
|
||||
CRC?: number;
|
||||
Material?: number;
|
||||
ClickAction?: number;
|
||||
Scale?: Vector3;
|
||||
ObjectData?: Buffer;
|
||||
UpdateFlags?: number;
|
||||
Flags?: number;
|
||||
PathCurve?: number;
|
||||
ProfileCurve?: number;
|
||||
PathBegin?: number;
|
||||
PathEnd?: number;
|
||||
PathScaleX?: number;
|
||||
PathScaleY?: number;
|
||||
PathShearX?: number;
|
||||
PathShearY?: number;
|
||||
PathTwist?: number;
|
||||
PathTwistBegin?: number;
|
||||
PathRadiusOffset?: number;
|
||||
PathTaperX?: number;
|
||||
PathTaperY?: number;
|
||||
PathRevolutions?: number;
|
||||
PathSkew?: number;
|
||||
ProfileBegin?: number;
|
||||
ProfileEnd?: number;
|
||||
ProfileHollow?: number;
|
||||
TextureEntry?: TextureEntry;
|
||||
TextureAnim?: Buffer;
|
||||
Data?: Buffer;
|
||||
Text?: string;
|
||||
TextColor?: Color4;
|
||||
MediaURL?: string;
|
||||
PSBlock?: Buffer;
|
||||
JointType?: number;
|
||||
JointPivot?: Vector3;
|
||||
JointAxisOrAnchor?: Vector3;
|
||||
Position?: Vector3;
|
||||
Rotation?: Quaternion;
|
||||
CollisionPlane?: Vector4;
|
||||
Velocity?: Vector3;
|
||||
Acceleration?: Vector3;
|
||||
AngularVelocity?: Vector3;
|
||||
TreeSpecies?: Tree;
|
||||
Sound?: UUID;
|
||||
SoundGain?: number;
|
||||
SoundFlags?: SoundFlags;
|
||||
SoundRadius?: number;
|
||||
Particles?: ParticleSystem;
|
||||
|
||||
constructor()
|
||||
{
|
||||
this.Position = Vector3.getZero();
|
||||
this.Rotation = Quaternion.getIdentity();
|
||||
this.AngularVelocity = Vector3.getZero();
|
||||
this.TreeSpecies = 0;
|
||||
this.SoundFlags = 0;
|
||||
this.SoundRadius = 1.0;
|
||||
this.SoundGain = 1.0;
|
||||
this.ParentID = 0;
|
||||
}
|
||||
|
||||
hasNameValueEntry(key: string): boolean
|
||||
{
|
||||
return this.NameValue[key] !== undefined;
|
||||
}
|
||||
|
||||
getNameValueEntry(key: string): string
|
||||
{
|
||||
if (this.NameValue[key])
|
||||
{
|
||||
return this.NameValue[key].value;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
import {Vector3} from './Vector3';
|
||||
import {UUID} from './UUID';
|
||||
import {PCode} from '../enums/PCode';
|
||||
import {Quaternion} from './Quaternion';
|
||||
import {Tree} from '../enums/Tree';
|
||||
import {NameValue} from './NameValue';
|
||||
import {IGameObject} from './interfaces/IGameObject';
|
||||
import {SoundFlags} from '..';
|
||||
import {ITreeBoundingBox} from './interfaces/ITreeBoundingBox';
|
||||
import {Vector4} from './Vector4';
|
||||
import {TextureEntry} from './TextureEntry';
|
||||
import {Color4} from './Color4';
|
||||
import {ParticleSystem} from './ParticleSystem';
|
||||
|
||||
export class GameObjectFull implements IGameObject
|
||||
{
|
||||
rtreeEntry?: ITreeBoundingBox;
|
||||
ID: number;
|
||||
State: number;
|
||||
FullID: UUID;
|
||||
CRC: number;
|
||||
PCode: PCode;
|
||||
Material: number;
|
||||
ClickAction: number;
|
||||
Scale: Vector3;
|
||||
ObjectData: Buffer;
|
||||
ParentID: number;
|
||||
UpdateFlags: number;
|
||||
Flags: number;
|
||||
PathCurve: number;
|
||||
ProfileCurve: number;
|
||||
PathBegin: number;
|
||||
PathEnd: number;
|
||||
PathScaleX: number;
|
||||
PathScaleY: number;
|
||||
PathShearX: number;
|
||||
PathShearY: number;
|
||||
PathTwist: number;
|
||||
PathTwistBegin: number;
|
||||
PathRadiusOffset: number;
|
||||
PathTaperX: number;
|
||||
PathTaperY: number;
|
||||
PathRevolutions: number;
|
||||
PathSkew: number;
|
||||
ProfileBegin: number;
|
||||
ProfileEnd: number;
|
||||
ProfileHollow: number;
|
||||
TextureEntry: TextureEntry;
|
||||
TextureAnim: Buffer;
|
||||
Data: Buffer;
|
||||
Text: string;
|
||||
TextColor: Color4;
|
||||
MediaURL: string;
|
||||
PSBlock: Buffer;
|
||||
OwnerID: UUID;
|
||||
JointType: number;
|
||||
JointPivot: Vector3;
|
||||
JointAxisOrAnchor: Vector3;
|
||||
Position: Vector3;
|
||||
Rotation: Quaternion;
|
||||
CollisionPlane: Vector4;
|
||||
Velocity: Vector3;
|
||||
Acceleration: Vector3;
|
||||
AngularVelocity: Vector3;
|
||||
TreeSpecies: Tree;
|
||||
Sound: UUID;
|
||||
SoundGain: number;
|
||||
SoundFlags: SoundFlags;
|
||||
SoundRadius: number;
|
||||
IsAttachment: boolean;
|
||||
NameValue: {[key: string]: NameValue};
|
||||
Particles: ParticleSystem;
|
||||
constructor()
|
||||
{
|
||||
this.Position = Vector3.getZero();
|
||||
this.Rotation = Quaternion.getIdentity();
|
||||
this.IsAttachment = false;
|
||||
this.NameValue = {};
|
||||
this.AngularVelocity = Vector3.getZero();
|
||||
this.TreeSpecies = 0;
|
||||
this.SoundFlags = 0;
|
||||
this.SoundRadius = 1.0;
|
||||
this.SoundGain = 1.0;
|
||||
this.ParentID = 0;
|
||||
}
|
||||
|
||||
hasNameValueEntry(key: string): boolean
|
||||
{
|
||||
if (this.NameValue['AttachItemID'])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
getNameValueEntry(key: string): string
|
||||
{
|
||||
if (this.NameValue['AttachItemID'])
|
||||
{
|
||||
return this.NameValue['AttachItemID'].value;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
import {UUID} from './UUID';
|
||||
import {IGameObject} from './interfaces/IGameObject';
|
||||
import {NameValue} from './NameValue';
|
||||
import {PCode} from '../enums/PCode';
|
||||
import {ITreeBoundingBox} from './interfaces/ITreeBoundingBox';
|
||||
|
||||
export class GameObjectLite implements IGameObject
|
||||
{
|
||||
rtreeEntry?: ITreeBoundingBox;
|
||||
ID: number;
|
||||
FullID: UUID;
|
||||
ParentID: number;
|
||||
OwnerID: UUID;
|
||||
IsAttachment: boolean;
|
||||
NameValue: {[key: string]: NameValue};
|
||||
PCode: PCode;
|
||||
constructor()
|
||||
{
|
||||
this.IsAttachment = false;
|
||||
}
|
||||
|
||||
hasNameValueEntry(key: string): boolean
|
||||
{
|
||||
return this.NameValue['AttachItemID'] !== undefined;
|
||||
}
|
||||
|
||||
getNameValueEntry(key: string): string
|
||||
{
|
||||
if (this.NameValue['AttachItemID'])
|
||||
{
|
||||
return this.NameValue['AttachItemID'].value;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -246,7 +246,7 @@ export class LoginResponse
|
||||
});
|
||||
break;
|
||||
case 'look_at':
|
||||
this.agent.lookAt = LoginResponse.parseVector3(val);
|
||||
this.agent.cameraLookAt = LoginResponse.parseVector3(val);
|
||||
break;
|
||||
case 'openid_url':
|
||||
this.agent.openID.url = String(val);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,21 +15,23 @@ import {PCode} from '../enums/PCode';
|
||||
import {ClientEvents} from './ClientEvents';
|
||||
import {KillObjectMessage} from './messages/KillObject';
|
||||
import {IObjectStore} from './interfaces/IObjectStore';
|
||||
import {GameObjectLite} from './GameObjectLite';
|
||||
import {NameValue} from './NameValue';
|
||||
import {BotOptionFlags, CompressedFlags} from '..';
|
||||
import {IGameObject} from './interfaces/IGameObject';
|
||||
import {GameObjectFull} from './GameObjectFull';
|
||||
import {GameObject} from './GameObject';
|
||||
import {RBush3D} from 'rbush-3d/dist';
|
||||
import {ITreeBoundingBox} from './interfaces/ITreeBoundingBox';
|
||||
|
||||
export class ObjectStoreLite implements IObjectStore
|
||||
{
|
||||
private circuit: Circuit;
|
||||
private agent: Agent;
|
||||
private objects: { [key: number]: GameObjectLite } = {};
|
||||
private objectsByUUID: { [key: string]: number } = {};
|
||||
private objectsByParent: { [key: number]: number[] } = {};
|
||||
private clientEvents: ClientEvents;
|
||||
private options: BotOptionFlags;
|
||||
protected circuit: Circuit;
|
||||
protected agent: Agent;
|
||||
protected objects: { [key: number]: GameObject } = {};
|
||||
protected objectsByUUID: { [key: string]: number } = {};
|
||||
protected objectsByParent: { [key: number]: number[] } = {};
|
||||
protected clientEvents: ClientEvents;
|
||||
protected options: BotOptionFlags;
|
||||
|
||||
rtree?: RBush3D;
|
||||
|
||||
constructor(circuit: Circuit, agent: Agent, clientEvents: ClientEvents, options: BotOptionFlags)
|
||||
{
|
||||
@@ -51,295 +53,319 @@ export class ObjectStoreLite implements IObjectStore
|
||||
{
|
||||
case Message.ObjectUpdate:
|
||||
const objectUpdate = packet.message as ObjectUpdateMessage;
|
||||
objectUpdate.ObjectData.forEach((objData) =>
|
||||
{
|
||||
const localID = objData.ID;
|
||||
const parentID = objData.ParentID;
|
||||
let addToParentList = true;
|
||||
|
||||
if (this.objects[localID])
|
||||
{
|
||||
if (this.objects[localID].ParentID !== parentID && this.objectsByParent[parentID])
|
||||
{
|
||||
const ind = this.objectsByParent[parentID].indexOf(localID);
|
||||
if (ind !== -1)
|
||||
{
|
||||
this.objectsByParent[parentID].splice(ind, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
addToParentList = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.objects[localID] = new GameObjectLite();
|
||||
}
|
||||
|
||||
const obj = this.objects[localID];
|
||||
obj.ID = objData.ID;
|
||||
obj.FullID = objData.FullID;
|
||||
obj.ParentID = objData.ParentID;
|
||||
obj.OwnerID = objData.OwnerID;
|
||||
obj.PCode = objData.PCode;
|
||||
|
||||
this.objects[localID].NameValue = this.parseNameValues(Utils.BufferToStringSimple(objData.NameValue));
|
||||
|
||||
if (objData.PCode === PCode.Avatar && this.objects[localID].FullID.toString() === this.agent.agentID.toString())
|
||||
{
|
||||
this.agent.localID = localID;
|
||||
|
||||
if (this.options & BotOptionFlags.StoreMyAttachmentsOnly)
|
||||
{
|
||||
Object.keys(this.objectsByParent).forEach((objParentID: string) =>
|
||||
{
|
||||
const parent = parseInt(objParentID, 10);
|
||||
if (parent !== this.agent.localID)
|
||||
{
|
||||
let foundAvatars = false;
|
||||
this.objectsByParent[parent].forEach((objID) =>
|
||||
{
|
||||
if (this.objects[objID])
|
||||
{
|
||||
const o = this.objects[objID];
|
||||
if (o.PCode === PCode.Avatar)
|
||||
{
|
||||
foundAvatars = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (this.objects[parent])
|
||||
{
|
||||
const o = this.objects[parent];
|
||||
if (o.PCode === PCode.Avatar)
|
||||
{
|
||||
foundAvatars = true;
|
||||
}
|
||||
}
|
||||
if (!foundAvatars)
|
||||
{
|
||||
this.deleteObject(parent);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.objectsByUUID[objData.FullID.toString()] = localID;
|
||||
if (!this.objectsByParent[parentID])
|
||||
{
|
||||
this.objectsByParent[parentID] = [];
|
||||
}
|
||||
if (addToParentList)
|
||||
{
|
||||
this.objectsByParent[parentID].push(localID);
|
||||
}
|
||||
|
||||
if (objData.PCode !== PCode.Avatar && this.options & BotOptionFlags.StoreMyAttachmentsOnly)
|
||||
{
|
||||
if (this.agent.localID !== 0 && obj.ParentID !== this.agent.localID)
|
||||
{
|
||||
// Drop object
|
||||
this.deleteObject(localID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
this.objectUpdate(objectUpdate);
|
||||
break;
|
||||
case Message.ObjectUpdateCached:
|
||||
const objectUpdateCached = packet.message as ObjectUpdateCachedMessage;
|
||||
const rmo = new RequestMultipleObjectsMessage();
|
||||
rmo.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: this.circuit.sessionID
|
||||
};
|
||||
rmo.ObjectData = [];
|
||||
objectUpdateCached.ObjectData.forEach((obj) =>
|
||||
{
|
||||
rmo.ObjectData.push({
|
||||
CacheMissType: 0,
|
||||
ID: obj.ID
|
||||
});
|
||||
});
|
||||
circuit.sendMessage(rmo, 0);
|
||||
this.objectUpdateCached(objectUpdateCached);
|
||||
break;
|
||||
case Message.ObjectUpdateCompressed:
|
||||
{
|
||||
const objectUpdateCompressed = packet.message as ObjectUpdateCompressedMessage;
|
||||
for (const obj of objectUpdateCompressed.ObjectData)
|
||||
{
|
||||
const flags = obj.UpdateFlags;
|
||||
const buf = obj.Data;
|
||||
let pos = 0;
|
||||
|
||||
const fullID = new UUID(buf, pos);
|
||||
pos += 16;
|
||||
const localID = buf.readUInt32LE(pos);
|
||||
pos += 4;
|
||||
const pcode = buf.readUInt8(pos++);
|
||||
let newObj = false;
|
||||
if (!this.objects[localID])
|
||||
{
|
||||
newObj = true;
|
||||
this.objects[localID] = new GameObjectLite();
|
||||
}
|
||||
const o = this.objects[localID];
|
||||
o.ID = localID;
|
||||
o.PCode = pcode;
|
||||
this.objectsByUUID[fullID.toString()] = localID;
|
||||
o.FullID = fullID;
|
||||
|
||||
|
||||
pos++;
|
||||
|
||||
pos = pos + 4;
|
||||
pos++;
|
||||
pos++;
|
||||
|
||||
pos = pos + 12;
|
||||
|
||||
pos = pos + 12;
|
||||
|
||||
pos = pos + 12;
|
||||
const compressedflags: CompressedFlags = buf.readUInt32LE(pos);
|
||||
pos = pos + 4;
|
||||
o.OwnerID = new UUID(buf, pos);
|
||||
pos += 16;
|
||||
|
||||
if (compressedflags & CompressedFlags.HasAngularVelocity)
|
||||
{
|
||||
pos = pos + 12;
|
||||
}
|
||||
if (compressedflags & CompressedFlags.HasParent)
|
||||
{
|
||||
const newParentID = buf.readUInt32LE(pos);
|
||||
pos += 4;
|
||||
let add = true;
|
||||
if (!newObj)
|
||||
{
|
||||
if (newParentID !== o.ParentID)
|
||||
{
|
||||
const index = this.objectsByParent[o.ParentID].indexOf(localID);
|
||||
if (index !== -1)
|
||||
{
|
||||
this.objectsByParent[o.ParentID].splice(index, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
add = false;
|
||||
}
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
if (!this.objectsByParent[newParentID])
|
||||
{
|
||||
this.objectsByParent[newParentID] = [];
|
||||
}
|
||||
this.objectsByParent[newParentID].push(localID);
|
||||
}
|
||||
o.ParentID = newParentID;
|
||||
}
|
||||
if (pcode !== PCode.Avatar && newObj && this.options & BotOptionFlags.StoreMyAttachmentsOnly)
|
||||
{
|
||||
if (this.agent.localID !== 0 && o.ParentID !== this.agent.localID)
|
||||
{
|
||||
// Drop object
|
||||
this.deleteObject(localID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (compressedflags & CompressedFlags.Tree)
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
else if (compressedflags & CompressedFlags.ScratchPad)
|
||||
{
|
||||
const scratchPadSize = buf.readUInt8(pos++);
|
||||
// Ignore this data
|
||||
pos = pos + scratchPadSize;
|
||||
}
|
||||
if (compressedflags & CompressedFlags.HasText)
|
||||
{
|
||||
// Read null terminated string
|
||||
const result = Utils.BufferToString(buf, pos);
|
||||
|
||||
pos += result.readLength;
|
||||
pos = pos + 4;
|
||||
}
|
||||
if (compressedflags & CompressedFlags.MediaURL)
|
||||
{
|
||||
const result = Utils.BufferToString(buf, pos);
|
||||
|
||||
pos += result.readLength;
|
||||
}
|
||||
if (compressedflags & CompressedFlags.HasParticles)
|
||||
{
|
||||
// TODO: Particle system block
|
||||
pos += 86;
|
||||
}
|
||||
|
||||
// Extra params
|
||||
pos = this.readExtraParams(buf, pos, o);
|
||||
|
||||
if (compressedflags & CompressedFlags.HasSound)
|
||||
{
|
||||
pos = pos + 16;
|
||||
pos += 4;
|
||||
pos++;
|
||||
pos = pos + 4;
|
||||
}
|
||||
if (compressedflags & CompressedFlags.HasNameValues)
|
||||
{
|
||||
const result = Utils.BufferToString(buf, pos);
|
||||
o.NameValue = this.parseNameValues(result.result);
|
||||
pos += result.readLength;
|
||||
}
|
||||
pos++;
|
||||
pos = pos + 2;
|
||||
pos = pos + 2;
|
||||
pos = pos + 12;
|
||||
pos = pos + 2;
|
||||
pos = pos + 2;
|
||||
pos = pos + 2;
|
||||
const textureEntryLength = buf.readUInt32LE(pos);
|
||||
pos = pos + 4;
|
||||
// TODO: Properly parse textureentry;
|
||||
pos = pos + textureEntryLength;
|
||||
|
||||
if (compressedflags & CompressedFlags.TextureAnimation)
|
||||
{
|
||||
// TODO: Properly parse textureAnim
|
||||
pos = pos + 4;
|
||||
}
|
||||
|
||||
o.IsAttachment = (compressedflags & CompressedFlags.HasNameValues) !== 0 && o.ParentID !== 0;
|
||||
};
|
||||
|
||||
this.objectUpdateCompressed(objectUpdateCompressed);
|
||||
break;
|
||||
}
|
||||
case Message.ImprovedTerseObjectUpdate:
|
||||
const objectUpdateTerse = packet.message as ImprovedTerseObjectUpdateMessage;
|
||||
// TODO: ImprovedTerseObjectUPdate
|
||||
this.objectUpdateTerse(objectUpdateTerse);
|
||||
break;
|
||||
case Message.MultipleObjectUpdate:
|
||||
const multipleObjectUpdate = packet.message as MultipleObjectUpdateMessage;
|
||||
// TODO: multipleObjectUpdate
|
||||
console.error('TODO: MultipleObjectUpdate');
|
||||
this.objectUpdateMultiple(multipleObjectUpdate);
|
||||
break;
|
||||
case Message.KillObject:
|
||||
const killObj = packet.message as KillObjectMessage;
|
||||
killObj.ObjectData.forEach((obj) =>
|
||||
{
|
||||
const objectID = obj.ID;
|
||||
this.deleteObject(objectID);
|
||||
});
|
||||
this.killObject(killObj);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected objectUpdate(objectUpdate: ObjectUpdateMessage)
|
||||
{
|
||||
objectUpdate.ObjectData.forEach((objData) =>
|
||||
{
|
||||
const localID = objData.ID;
|
||||
const parentID = objData.ParentID;
|
||||
let addToParentList = true;
|
||||
|
||||
if (this.objects[localID])
|
||||
{
|
||||
if (this.objects[localID].ParentID !== parentID && this.objectsByParent[parentID])
|
||||
{
|
||||
const ind = this.objectsByParent[parentID].indexOf(localID);
|
||||
if (ind !== -1)
|
||||
{
|
||||
this.objectsByParent[parentID].splice(ind, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
addToParentList = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.objects[localID] = new GameObject();
|
||||
}
|
||||
|
||||
const obj = this.objects[localID];
|
||||
obj.ID = objData.ID;
|
||||
obj.FullID = objData.FullID;
|
||||
obj.ParentID = objData.ParentID;
|
||||
obj.OwnerID = objData.OwnerID;
|
||||
obj.PCode = objData.PCode;
|
||||
|
||||
this.objects[localID].NameValue = this.parseNameValues(Utils.BufferToStringSimple(objData.NameValue));
|
||||
|
||||
if (objData.PCode === PCode.Avatar && this.objects[localID].FullID.toString() === this.agent.agentID.toString())
|
||||
{
|
||||
this.agent.localID = localID;
|
||||
|
||||
if (this.options & BotOptionFlags.StoreMyAttachmentsOnly)
|
||||
{
|
||||
Object.keys(this.objectsByParent).forEach((objParentID: string) =>
|
||||
{
|
||||
const parent = parseInt(objParentID, 10);
|
||||
if (parent !== this.agent.localID)
|
||||
{
|
||||
let foundAvatars = false;
|
||||
this.objectsByParent[parent].forEach((objID) =>
|
||||
{
|
||||
if (this.objects[objID])
|
||||
{
|
||||
const o = this.objects[objID];
|
||||
if (o.PCode === PCode.Avatar)
|
||||
{
|
||||
foundAvatars = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (this.objects[parent])
|
||||
{
|
||||
const o = this.objects[parent];
|
||||
if (o.PCode === PCode.Avatar)
|
||||
{
|
||||
foundAvatars = true;
|
||||
}
|
||||
}
|
||||
if (!foundAvatars)
|
||||
{
|
||||
this.deleteObject(parent);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.objectsByUUID[objData.FullID.toString()] = localID;
|
||||
if (!this.objectsByParent[parentID])
|
||||
{
|
||||
this.objectsByParent[parentID] = [];
|
||||
}
|
||||
if (addToParentList)
|
||||
{
|
||||
this.objectsByParent[parentID].push(localID);
|
||||
}
|
||||
|
||||
if (objData.PCode !== PCode.Avatar && this.options & BotOptionFlags.StoreMyAttachmentsOnly)
|
||||
{
|
||||
if (this.agent.localID !== 0 && obj.ParentID !== this.agent.localID)
|
||||
{
|
||||
// Drop object
|
||||
this.deleteObject(localID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected objectUpdateCached(objectUpdateCached: ObjectUpdateCachedMessage)
|
||||
{
|
||||
const rmo = new RequestMultipleObjectsMessage();
|
||||
rmo.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: this.circuit.sessionID
|
||||
};
|
||||
rmo.ObjectData = [];
|
||||
objectUpdateCached.ObjectData.forEach((obj) =>
|
||||
{
|
||||
rmo.ObjectData.push({
|
||||
CacheMissType: 0,
|
||||
ID: obj.ID
|
||||
});
|
||||
});
|
||||
this.circuit.sendMessage(rmo, 0);
|
||||
}
|
||||
|
||||
protected objectUpdateCompressed(objectUpdateCompressed: ObjectUpdateCompressedMessage)
|
||||
{
|
||||
for (const obj of objectUpdateCompressed.ObjectData)
|
||||
{
|
||||
const flags = obj.UpdateFlags;
|
||||
const buf = obj.Data;
|
||||
let pos = 0;
|
||||
|
||||
const fullID = new UUID(buf, pos);
|
||||
pos += 16;
|
||||
const localID = buf.readUInt32LE(pos);
|
||||
pos += 4;
|
||||
const pcode = buf.readUInt8(pos++);
|
||||
let newObj = false;
|
||||
if (!this.objects[localID])
|
||||
{
|
||||
newObj = true;
|
||||
this.objects[localID] = new GameObject();
|
||||
}
|
||||
const o = this.objects[localID];
|
||||
o.ID = localID;
|
||||
o.PCode = pcode;
|
||||
this.objectsByUUID[fullID.toString()] = localID;
|
||||
o.FullID = fullID;
|
||||
|
||||
|
||||
pos++;
|
||||
|
||||
pos = pos + 4;
|
||||
pos++;
|
||||
pos++;
|
||||
|
||||
pos = pos + 12;
|
||||
|
||||
pos = pos + 12;
|
||||
|
||||
pos = pos + 12;
|
||||
const compressedflags: CompressedFlags = buf.readUInt32LE(pos);
|
||||
pos = pos + 4;
|
||||
o.OwnerID = new UUID(buf, pos);
|
||||
pos += 16;
|
||||
|
||||
if (compressedflags & CompressedFlags.HasAngularVelocity)
|
||||
{
|
||||
pos = pos + 12;
|
||||
}
|
||||
if (compressedflags & CompressedFlags.HasParent)
|
||||
{
|
||||
const newParentID = buf.readUInt32LE(pos);
|
||||
pos += 4;
|
||||
let add = true;
|
||||
if (!newObj)
|
||||
{
|
||||
if (newParentID !== o.ParentID)
|
||||
{
|
||||
const index = this.objectsByParent[o.ParentID].indexOf(localID);
|
||||
if (index !== -1)
|
||||
{
|
||||
this.objectsByParent[o.ParentID].splice(index, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
add = false;
|
||||
}
|
||||
}
|
||||
if (add)
|
||||
{
|
||||
if (!this.objectsByParent[newParentID])
|
||||
{
|
||||
this.objectsByParent[newParentID] = [];
|
||||
}
|
||||
this.objectsByParent[newParentID].push(localID);
|
||||
}
|
||||
o.ParentID = newParentID;
|
||||
}
|
||||
if (pcode !== PCode.Avatar && newObj && this.options & BotOptionFlags.StoreMyAttachmentsOnly)
|
||||
{
|
||||
if (this.agent.localID !== 0 && o.ParentID !== this.agent.localID)
|
||||
{
|
||||
// Drop object
|
||||
this.deleteObject(localID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (compressedflags & CompressedFlags.Tree)
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
else if (compressedflags & CompressedFlags.ScratchPad)
|
||||
{
|
||||
const scratchPadSize = buf.readUInt8(pos++);
|
||||
// Ignore this data
|
||||
pos = pos + scratchPadSize;
|
||||
}
|
||||
if (compressedflags & CompressedFlags.HasText)
|
||||
{
|
||||
// Read null terminated string
|
||||
const result = Utils.BufferToString(buf, pos);
|
||||
|
||||
pos += result.readLength;
|
||||
pos = pos + 4;
|
||||
}
|
||||
if (compressedflags & CompressedFlags.MediaURL)
|
||||
{
|
||||
const result = Utils.BufferToString(buf, pos);
|
||||
|
||||
pos += result.readLength;
|
||||
}
|
||||
if (compressedflags & CompressedFlags.HasParticles)
|
||||
{
|
||||
// TODO: Particle system block
|
||||
pos += 86;
|
||||
}
|
||||
|
||||
// Extra params
|
||||
pos = this.readExtraParams(buf, pos, o);
|
||||
|
||||
if (compressedflags & CompressedFlags.HasSound)
|
||||
{
|
||||
pos = pos + 16;
|
||||
pos += 4;
|
||||
pos++;
|
||||
pos = pos + 4;
|
||||
}
|
||||
if (compressedflags & CompressedFlags.HasNameValues)
|
||||
{
|
||||
const result = Utils.BufferToString(buf, pos);
|
||||
o.NameValue = this.parseNameValues(result.result);
|
||||
pos += result.readLength;
|
||||
}
|
||||
pos++;
|
||||
pos = pos + 2;
|
||||
pos = pos + 2;
|
||||
pos = pos + 12;
|
||||
pos = pos + 2;
|
||||
pos = pos + 2;
|
||||
pos = pos + 2;
|
||||
const textureEntryLength = buf.readUInt32LE(pos);
|
||||
pos = pos + 4;
|
||||
// TODO: Properly parse textureentry;
|
||||
pos = pos + textureEntryLength;
|
||||
|
||||
if (compressedflags & CompressedFlags.TextureAnimation)
|
||||
{
|
||||
// TODO: Properly parse textureAnim
|
||||
pos = pos + 4;
|
||||
}
|
||||
|
||||
o.IsAttachment = (compressedflags & CompressedFlags.HasNameValues) !== 0 && o.ParentID !== 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected objectUpdateTerse(objectUpdateTerse: ImprovedTerseObjectUpdateMessage)
|
||||
{ }
|
||||
|
||||
protected objectUpdateMultiple(objectUpdateMultiple: MultipleObjectUpdateMessage)
|
||||
{ }
|
||||
|
||||
protected killObject(killObj: KillObjectMessage)
|
||||
{
|
||||
killObj.ObjectData.forEach((obj) =>
|
||||
{
|
||||
const objectID = obj.ID;
|
||||
this.deleteObject(objectID);
|
||||
});
|
||||
}
|
||||
|
||||
deleteObject(objectID: number)
|
||||
{
|
||||
if (this.objects[objectID])
|
||||
@@ -371,11 +397,15 @@ export class ObjectStoreLite implements IObjectStore
|
||||
this.objectsByParent[parentID].splice(ind, 1);
|
||||
}
|
||||
}
|
||||
if (this.rtree && this.objects[objectID].rtreeEntry !== undefined)
|
||||
{
|
||||
this.rtree.remove(this.objects[objectID].rtreeEntry);
|
||||
}
|
||||
delete this.objects[objectID];
|
||||
}
|
||||
}
|
||||
|
||||
readExtraParams(buf: Buffer, pos: number, o: GameObjectLite): number
|
||||
readExtraParams(buf: Buffer, pos: number, o: GameObject): number
|
||||
{
|
||||
if (pos >= buf.length)
|
||||
{
|
||||
@@ -395,14 +425,14 @@ export class ObjectStoreLite implements IObjectStore
|
||||
return pos;
|
||||
}
|
||||
|
||||
getObjectsByParent(parentID: number): GameObjectLite[]
|
||||
getObjectsByParent(parentID: number): GameObject[]
|
||||
{
|
||||
const list = this.objectsByParent[parentID];
|
||||
if (list === undefined)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
const result: GameObjectLite[] = [];
|
||||
const result: GameObject[] = [];
|
||||
list.forEach((localID) =>
|
||||
{
|
||||
result.push(this.objects[localID]);
|
||||
@@ -449,16 +479,102 @@ export class ObjectStoreLite implements IObjectStore
|
||||
shutdown()
|
||||
{
|
||||
this.objects = {};
|
||||
if (this.rtree)
|
||||
{
|
||||
this.rtree.clear();
|
||||
}
|
||||
this.objectsByUUID = {};
|
||||
this.objectsByParent = {};
|
||||
}
|
||||
|
||||
getObjectsInArea(minX: number, maxX: number, minY: number, maxY: number, minZ: number, maxZ: number): GameObjectFull[]
|
||||
protected findParent(go: GameObject): GameObject
|
||||
{
|
||||
throw new Error('GetObjectsInArea not available with the Lite object store.');
|
||||
if (go.ParentID !== 0 && this.objects[go.ParentID])
|
||||
{
|
||||
return this.findParent(this.objects[go.ParentID]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return go;
|
||||
}
|
||||
}
|
||||
|
||||
getObjectByUUID(fullID: UUID | string): IGameObject
|
||||
private populateChildren(obj: GameObject)
|
||||
{
|
||||
obj.children = [];
|
||||
obj.totalChildren = 0;
|
||||
for (const child of this.getObjectsByParent(obj.ID))
|
||||
{
|
||||
obj.totalChildren++;
|
||||
this.populateChildren(child);
|
||||
if (child.totalChildren !== undefined)
|
||||
{
|
||||
obj.totalChildren += child.totalChildren;
|
||||
}
|
||||
obj.children.push(child);
|
||||
}
|
||||
}
|
||||
|
||||
getNumberOfObjects()
|
||||
{
|
||||
return Object.keys(this.objects).length;
|
||||
}
|
||||
|
||||
getObjectsInArea(minX: number, maxX: number, minY: number, maxY: number, minZ: number, maxZ: number): GameObject[]
|
||||
{
|
||||
if (!this.rtree)
|
||||
{
|
||||
throw new Error('GetObjectsInArea not available with the Lite object store');
|
||||
}
|
||||
const result = this.rtree.search({
|
||||
minX: minX,
|
||||
maxX: maxX,
|
||||
minY: minY,
|
||||
maxY: maxY,
|
||||
minZ: minZ,
|
||||
maxZ: maxZ
|
||||
});
|
||||
const found: {[key: string]: GameObject} = {};
|
||||
const objs: GameObject[] = [];
|
||||
for (const obj of result)
|
||||
{
|
||||
const o = obj as ITreeBoundingBox;
|
||||
const go = o.gameObject as GameObject;
|
||||
if (go.PCode !== PCode.Avatar && (go.IsAttachment === undefined || go.IsAttachment === false))
|
||||
{
|
||||
try
|
||||
{
|
||||
const parent = this.findParent(go);
|
||||
if (parent.PCode !== PCode.Avatar && (parent.IsAttachment === undefined || parent.IsAttachment === false))
|
||||
{
|
||||
const uuid = parent.FullID.toString();
|
||||
|
||||
if (found[uuid] === undefined)
|
||||
{
|
||||
found[uuid] = parent;
|
||||
objs.push(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
console.log('Failed to find parent for ' + go.FullID.toString());
|
||||
console.error(error);
|
||||
// Unable to find parent, full object probably not fully loaded yet
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now populate children of each found object
|
||||
for (const obj of objs)
|
||||
{
|
||||
this.populateChildren(obj);
|
||||
}
|
||||
|
||||
return objs;
|
||||
}
|
||||
|
||||
getObjectByUUID(fullID: UUID | string): GameObject
|
||||
{
|
||||
if (fullID instanceof UUID)
|
||||
{
|
||||
@@ -472,7 +588,7 @@ export class ObjectStoreLite implements IObjectStore
|
||||
return this.objects[localID];
|
||||
}
|
||||
|
||||
getObjectByLocalID(localID: number): IGameObject
|
||||
getObjectByLocalID(localID: number): GameObject
|
||||
{
|
||||
if (!this.objects[localID])
|
||||
{
|
||||
@@ -480,4 +596,33 @@ export class ObjectStoreLite implements IObjectStore
|
||||
}
|
||||
return this.objects[localID];
|
||||
}
|
||||
|
||||
insertIntoRtree(obj: GameObject)
|
||||
{
|
||||
if (!this.rtree)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (obj.rtreeEntry !== undefined)
|
||||
{
|
||||
this.rtree.remove(obj.rtreeEntry);
|
||||
}
|
||||
if (!obj.Scale || !obj.Position || !obj.Rotation)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const normalizedScale = obj.Scale.multiplyByQuat(obj.Rotation);
|
||||
const bounds: ITreeBoundingBox = {
|
||||
minX: obj.Position.x - (normalizedScale.x / 2),
|
||||
maxX: obj.Position.x + (normalizedScale.x / 2),
|
||||
minY: obj.Position.y - (normalizedScale.y / 2),
|
||||
maxY: obj.Position.y + (normalizedScale.y / 2),
|
||||
minZ: obj.Position.z - (normalizedScale.z / 2),
|
||||
maxZ: obj.Position.z + (normalizedScale.z / 2),
|
||||
gameObject: obj
|
||||
};
|
||||
|
||||
obj.rtreeEntry = bounds;
|
||||
this.rtree.insert(bounds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import {UUID} from '../UUID';
|
||||
import {AgentAnimationMessage} from '../messages/AgentAnimation';
|
||||
import {PacketFlags} from '../../enums/PacketFlags';
|
||||
import {CommandsBase} from './CommandsBase';
|
||||
import {Vector3} from '../Vector3';
|
||||
|
||||
export class AgentCommands extends CommandsBase
|
||||
{
|
||||
@@ -36,4 +37,27 @@ export class AgentCommands extends CommandsBase
|
||||
{
|
||||
return await this.animate(anim, false);
|
||||
}
|
||||
|
||||
setCamera(position: Vector3, lookAt: Vector3, viewDistance?: number, leftAxis?: Vector3, upAxis?: Vector3)
|
||||
{
|
||||
this.agent.cameraCenter = position;
|
||||
this.agent.cameraLookAt = lookAt;
|
||||
if (viewDistance !== undefined)
|
||||
{
|
||||
this.agent.cameraFar = viewDistance;
|
||||
}
|
||||
if (leftAxis !== undefined)
|
||||
{
|
||||
this.agent.cameraLeftAxis = leftAxis;
|
||||
}
|
||||
if (upAxis !== undefined)
|
||||
{
|
||||
this.agent.cameraUpAxis = upAxis;
|
||||
}
|
||||
}
|
||||
|
||||
setViewDistance(viewDistance: number)
|
||||
{
|
||||
this.agent.cameraFar = viewDistance;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,15 @@ import {Message} from '../../enums/Message';
|
||||
import {FilterResponse} from '../../enums/FilterResponse';
|
||||
import {RegionIDAndHandleReplyMessage} from '../messages/RegionIDAndHandleReply';
|
||||
import {PacketFlags, Vector3} from '../..';
|
||||
import {IGameObject} from '../interfaces/IGameObject';
|
||||
import {ObjectGrabMessage} from '../messages/ObjectGrab';
|
||||
import {ObjectDeGrabMessage} from '../messages/ObjectDeGrab';
|
||||
import {ObjectGrabUpdateMessage} from '../messages/ObjectGrabUpdate';
|
||||
import {GameObject} from '../GameObject';
|
||||
import {ObjectSelectMessage} from '../messages/ObjectSelect';
|
||||
import {ObjectPropertiesMessage} from '../messages/ObjectProperties';
|
||||
import {Utils} from '../Utils';
|
||||
import {ObjectDeselectMessage} from '../messages/ObjectDeselect';
|
||||
import {PCode} from '../../enums/PCode';
|
||||
|
||||
export class RegionCommands extends CommandsBase
|
||||
{
|
||||
@@ -35,9 +40,277 @@ export class RegionCommands extends CommandsBase
|
||||
return responseMsg.ReplyBlock.RegionHandle;
|
||||
}
|
||||
|
||||
getObjectsInArea(minX: number, maxX: number, minY: number, maxY: number, minZ: number, maxZ: number): IGameObject[]
|
||||
async deselectObjects(objects: GameObject[])
|
||||
{
|
||||
return this.currentRegion.objects.getObjectsInArea(minX, maxX, minY, maxY, minZ, maxZ);
|
||||
// Limit to 255 objects at once
|
||||
const selectLimit = 255;
|
||||
if (objects.length > selectLimit)
|
||||
{
|
||||
for (let x = 0; x < objects.length; x += selectLimit)
|
||||
{
|
||||
const selectList: GameObject[] = [];
|
||||
for (let y = 0; y < selectLimit; y++)
|
||||
{
|
||||
if (y < objects.length)
|
||||
{
|
||||
selectList.push(objects[x + y]);
|
||||
}
|
||||
}
|
||||
await this.deselectObjects(selectList);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
const deselectObject = new ObjectDeselectMessage();
|
||||
deselectObject.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: this.circuit.sessionID
|
||||
};
|
||||
deselectObject.ObjectData = [];
|
||||
const uuidMap: {[key: string]: GameObject} = {};
|
||||
for (const obj of objects)
|
||||
{
|
||||
const uuidStr = obj.FullID.toString();
|
||||
if (!uuidMap[uuidStr])
|
||||
{
|
||||
uuidMap[uuidStr] = obj;
|
||||
deselectObject.ObjectData.push({
|
||||
ObjectLocalID: obj.ID
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Create a map of our expected UUIDs
|
||||
|
||||
const sequenceID = this.circuit.sendMessage(deselectObject, PacketFlags.Reliable);
|
||||
return await this.circuit.waitForAck(sequenceID, 10000);
|
||||
}
|
||||
}
|
||||
|
||||
countObjects(): number
|
||||
{
|
||||
return this.currentRegion.objects.getNumberOfObjects();
|
||||
}
|
||||
|
||||
async selectObjects(objects: GameObject[])
|
||||
{
|
||||
// Limit to 255 objects at once
|
||||
const selectLimit = 255;
|
||||
if (objects.length > selectLimit)
|
||||
{
|
||||
for (let x = 0; x < objects.length; x += selectLimit)
|
||||
{
|
||||
const selectList: GameObject[] = [];
|
||||
for (let y = 0; y < selectLimit; y++)
|
||||
{
|
||||
if (y < objects.length)
|
||||
{
|
||||
selectList.push(objects[x + y]);
|
||||
}
|
||||
}
|
||||
await this.selectObjects(selectList);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
const selectObject = new ObjectSelectMessage();
|
||||
selectObject.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: this.circuit.sessionID
|
||||
};
|
||||
selectObject.ObjectData = [];
|
||||
const uuidMap: {[key: string]: GameObject} = {};
|
||||
for (const obj of objects)
|
||||
{
|
||||
const uuidStr = obj.FullID.toString();
|
||||
if (!uuidMap[uuidStr])
|
||||
{
|
||||
uuidMap[uuidStr] = obj;
|
||||
selectObject.ObjectData.push({
|
||||
ObjectLocalID: obj.ID
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Create a map of our expected UUIDs
|
||||
let resolved = 0;
|
||||
|
||||
this.circuit.sendMessage(selectObject, PacketFlags.Reliable);
|
||||
return await this.circuit.waitForMessage<ObjectPropertiesMessage>(Message.ObjectProperties, 10000, (propertiesMessage: ObjectPropertiesMessage): FilterResponse =>
|
||||
{
|
||||
let found = false;
|
||||
for (const objData of propertiesMessage.ObjectData)
|
||||
{
|
||||
const objDataUUID = objData.ObjectID.toString();
|
||||
if (uuidMap[objDataUUID] !== undefined)
|
||||
{
|
||||
resolved++;
|
||||
const obj = uuidMap[objDataUUID];
|
||||
obj.creatorID = objData.CreatorID;
|
||||
obj.creationDate = objData.CreationDate;
|
||||
obj.baseMask = objData.BaseMask;
|
||||
obj.ownerMask = objData.OwnerMask;
|
||||
obj.groupMask = objData.GroupMask;
|
||||
obj.everyoneMask = objData.EveryoneMask;
|
||||
obj.nextOwnerMask = objData.NextOwnerMask;
|
||||
obj.ownershipCost = objData.OwnershipCost;
|
||||
obj.saleType = objData.SaleType;
|
||||
obj.salePrice = objData.SalePrice;
|
||||
obj.aggregatePerms = objData.AggregatePerms;
|
||||
obj.aggregatePermTextures = objData.AggregatePermTextures;
|
||||
obj.aggregatePermTexturesOwner = objData.AggregatePermTexturesOwner;
|
||||
obj.category = objData.Category;
|
||||
obj.inventorySerial = objData.InventorySerial;
|
||||
obj.itemID = objData.ItemID;
|
||||
obj.folderID = objData.FolderID;
|
||||
obj.fromTaskID = objData.FromTaskID;
|
||||
obj.lastOwnerID = objData.LastOwnerID;
|
||||
obj.name = Utils.BufferToStringSimple(objData.Name);
|
||||
obj.description = Utils.BufferToStringSimple(objData.Description);
|
||||
obj.touchName = Utils.BufferToStringSimple(objData.TouchName);
|
||||
obj.sitName = Utils.BufferToStringSimple(objData.SitName);
|
||||
obj.textureID = Utils.BufferToStringSimple(objData.TextureID);
|
||||
obj.resolvedAt = new Date().getTime() / 1000;
|
||||
delete uuidMap[objDataUUID];
|
||||
found = true;
|
||||
|
||||
// console.log(obj.name + ' (' + resolved + ' of ' + objects.length + ')');
|
||||
}
|
||||
}
|
||||
if (Object.keys(uuidMap).length === 0)
|
||||
{
|
||||
return FilterResponse.Finish;
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
return FilterResponse.NoMatch;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FilterResponse.Match;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async resolveObjects(objects: GameObject[])
|
||||
{
|
||||
// First, create a map of all object IDs
|
||||
const objs: {[key: number]: GameObject} = {};
|
||||
const scanObject = function(obj: GameObject)
|
||||
{
|
||||
const localID = obj.ID;
|
||||
if (!objs[localID])
|
||||
{
|
||||
objs[localID] = obj;
|
||||
if (obj.children)
|
||||
{
|
||||
for (const child of obj.children)
|
||||
{
|
||||
scanObject(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
for (const obj of objects)
|
||||
{
|
||||
scanObject(obj);
|
||||
}
|
||||
|
||||
const resolveTime = new Date().getTime() / 1000;
|
||||
let objectList = [];
|
||||
let totalRemaining = 0;
|
||||
try
|
||||
{
|
||||
for (const k of Object.keys(objs))
|
||||
{
|
||||
const ky = parseInt(k, 10);
|
||||
if (objs[ky] !== undefined)
|
||||
{
|
||||
const o = objs[ky];
|
||||
if (o.resolvedAt === undefined)
|
||||
{
|
||||
o.resolvedAt = 0;
|
||||
}
|
||||
if (o.resolvedAt !== undefined && o.resolvedAt < resolveTime && o.PCode !== PCode.Avatar)
|
||||
{
|
||||
objs[ky].name = undefined;
|
||||
totalRemaining++;
|
||||
objectList.push(objs[ky]);
|
||||
if (objectList.length > 254)
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.selectObjects(objectList);
|
||||
await this.deselectObjects(objectList);
|
||||
for (const chk of objectList)
|
||||
{
|
||||
if (chk.resolvedAt !== undefined && chk.resolvedAt >= resolveTime)
|
||||
{
|
||||
totalRemaining--;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ignore)
|
||||
{
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
objectList = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (objectList.length > 0)
|
||||
{
|
||||
await this.selectObjects(objectList);
|
||||
await this.deselectObjects(objectList);
|
||||
for (const chk of objectList)
|
||||
{
|
||||
if (chk.resolvedAt !== undefined && chk.resolvedAt >= resolveTime)
|
||||
{
|
||||
totalRemaining --;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ignore)
|
||||
{
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (totalRemaining < 1)
|
||||
{
|
||||
totalRemaining = 0;
|
||||
for (const obj of objectList)
|
||||
{
|
||||
if (obj.resolvedAt === undefined || obj.resolvedAt < resolveTime)
|
||||
{
|
||||
totalRemaining++;
|
||||
}
|
||||
}
|
||||
if (totalRemaining > 0)
|
||||
{
|
||||
console.error(totalRemaining + ' objects could not be resolved');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async getObjectsInArea(minX: number, maxX: number, minY: number, maxY: number, minZ: number, maxZ: number, resolve: boolean = false): Promise<GameObject[]>
|
||||
{
|
||||
const objs = this.currentRegion.objects.getObjectsInArea(minX, maxX, minY, maxY, minZ, maxZ);
|
||||
if (resolve)
|
||||
{
|
||||
console.log('Resolving ' + objs.length + ' objects');
|
||||
await this.resolveObjects(objs);
|
||||
}
|
||||
return objs;
|
||||
}
|
||||
|
||||
async grabObject(localID: number | UUID,
|
||||
@@ -51,7 +324,7 @@ export class RegionCommands extends CommandsBase
|
||||
{
|
||||
if (localID instanceof UUID)
|
||||
{
|
||||
const obj: IGameObject = this.currentRegion.objects.getObjectByUUID(localID);
|
||||
const obj: GameObject = this.currentRegion.objects.getObjectByUUID(localID);
|
||||
localID = obj.ID;
|
||||
}
|
||||
const msg = new ObjectGrabMessage();
|
||||
@@ -88,7 +361,7 @@ export class RegionCommands extends CommandsBase
|
||||
{
|
||||
if (localID instanceof UUID)
|
||||
{
|
||||
const obj: IGameObject = this.currentRegion.objects.getObjectByUUID(localID);
|
||||
const obj: GameObject = this.currentRegion.objects.getObjectByUUID(localID);
|
||||
localID = obj.ID;
|
||||
}
|
||||
const msg = new ObjectDeGrabMessage();
|
||||
@@ -126,7 +399,7 @@ export class RegionCommands extends CommandsBase
|
||||
// For some reason this message takes a UUID when the others take a LocalID - wtf?
|
||||
if (!(localID instanceof UUID))
|
||||
{
|
||||
const obj: IGameObject = this.currentRegion.objects.getObjectByLocalID(localID);
|
||||
const obj: GameObject = this.currentRegion.objects.getObjectByLocalID(localID);
|
||||
localID = obj.FullID;
|
||||
}
|
||||
const msg = new ObjectGrabUpdateMessage();
|
||||
@@ -165,7 +438,7 @@ export class RegionCommands extends CommandsBase
|
||||
{
|
||||
if (localID instanceof UUID)
|
||||
{
|
||||
const obj: IGameObject = this.currentRegion.objects.getObjectByUUID(localID);
|
||||
const obj: GameObject = this.currentRegion.objects.getObjectByUUID(localID);
|
||||
localID = obj.ID;
|
||||
}
|
||||
await this.grabObject(localID, grabOffset, uvCoordinate, stCoordinate, faceIndex, position, normal, binormal);
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import {ITreeBoundingBox} from './ITreeBoundingBox';
|
||||
import {UUID} from '../UUID';
|
||||
import {PCode} from '../../enums/PCode';
|
||||
|
||||
export interface IGameObject
|
||||
{
|
||||
ID: number;
|
||||
FullID: UUID;
|
||||
ParentID: number;
|
||||
OwnerID: UUID;
|
||||
IsAttachment: boolean;
|
||||
PCode: PCode;
|
||||
rtreeEntry?: ITreeBoundingBox;
|
||||
hasNameValueEntry(key: string): boolean;
|
||||
getNameValueEntry(key: string): string;
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
import {IGameObject} from './IGameObject';
|
||||
import {RBush3D} from 'rbush-3d/dist';
|
||||
import {GameObjectFull} from '../GameObjectFull';
|
||||
import {UUID} from '../UUID';
|
||||
import {GameObject} from '../GameObject';
|
||||
|
||||
export interface IObjectStore
|
||||
{
|
||||
rtree?: RBush3D;
|
||||
getObjectsByParent(parentID: number): IGameObject[];
|
||||
getObjectsByParent(parentID: number): GameObject[];
|
||||
shutdown(): void;
|
||||
getObjectsInArea(minX: number, maxX: number, minY: number, maxY: number, minZ: number, maxZ: number): GameObjectFull[];
|
||||
getObjectByUUID(fullID: UUID): IGameObject;
|
||||
getObjectByLocalID(ID: number): IGameObject;
|
||||
getObjectsInArea(minX: number, maxX: number, minY: number, maxY: number, minZ: number, maxZ: number): GameObject[];
|
||||
getObjectByUUID(fullID: UUID): GameObject;
|
||||
getObjectByLocalID(ID: number): GameObject;
|
||||
getNumberOfObjects(): number;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {BBox} from 'rbush-3d/dist';
|
||||
import {IGameObject} from './IGameObject';
|
||||
import {GameObject} from '../GameObject';
|
||||
|
||||
export interface ITreeBoundingBox extends BBox
|
||||
{
|
||||
gameObject: IGameObject;
|
||||
gameObject: GameObject;
|
||||
}
|
||||
|
||||
22
package-lock.json
generated
22
package-lock.json
generated
@@ -71,6 +71,12 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/tiny-async-pool": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/tiny-async-pool/-/tiny-async-pool-1.0.0.tgz",
|
||||
"integrity": "sha512-d8RK1jg/piCgv5/jD8ta8uJOE10tU8MWExzL1Kf1kOjMaTuL5cW0eZ9ax001SSYa4Ecg6xzZBh/jM4GB7+5OAg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/tough-cookie": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.3.tgz",
|
||||
@@ -167,6 +173,10 @@
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
|
||||
},
|
||||
"assertion": {
|
||||
"version": "github:rxaviers/assertion#ea0449073d2c9e276c447f03df0fa021228de11b",
|
||||
"from": "github:rxaviers/assertion"
|
||||
},
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
@@ -815,8 +825,7 @@
|
||||
"semver": {
|
||||
"version": "5.5.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz",
|
||||
"integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw=="
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
@@ -874,6 +883,15 @@
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"tiny-async-pool": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/tiny-async-pool/-/tiny-async-pool-1.0.1.tgz",
|
||||
"integrity": "sha512-nqqQJ3ZwO/ajCk9hJisYWiW1pKgGZqxQPk2Q/2rzL84GyaFZ3N75sYcvpM+T6OYndgM4UqnezmGURHzQq7D64w==",
|
||||
"requires": {
|
||||
"assertion": "github:rxaviers/assertion#ea0449073d2c9e276c447f03df0fa021228de11b",
|
||||
"semver": "^5.5.0"
|
||||
}
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "2.4.3",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"@types/mocha": "^5.2.5",
|
||||
"@types/node": "^10.11.6",
|
||||
"@types/request": "^2.47.1",
|
||||
"@types/tiny-async-pool": "^1.0.0",
|
||||
"@types/uuid": "^3.4.4",
|
||||
"@types/validator": "^9.4.2",
|
||||
"@types/xml": "^1.0.2",
|
||||
@@ -45,6 +46,7 @@
|
||||
"rbush-3d": "0.0.4",
|
||||
"request": "^2.88.0",
|
||||
"rxjs": "^6.3.3",
|
||||
"tiny-async-pool": "^1.0.1",
|
||||
"uuid": "^3.3.2",
|
||||
"validator": "^10.8.0",
|
||||
"xml": "^1.0.1",
|
||||
|
||||
Reference in New Issue
Block a user