- 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:
Casper Warden
2018-10-19 16:30:09 +01:00
parent ff0a5fa58b
commit 2852c76cb0
42 changed files with 2651 additions and 2121 deletions

View File

@@ -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
View File

@@ -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
};

File diff suppressed because one or more lines are too long

View File

@@ -136,6 +136,10 @@ class EventQueueClient {
}
break;
}
case 'ObjectPhysicsProperties':
{
break;
}
case 'TeleportFinish':
{
const info = event['body']['Info'][0];

File diff suppressed because one or more lines are too long

104
dist/classes/GameObject.d.ts vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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"}

View File

@@ -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);

File diff suppressed because one or more lines are too long

View File

@@ -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;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -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;
}

View File

@@ -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

File diff suppressed because one or more lines are too long

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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"}

View File

@@ -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>;

View File

@@ -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* () {

File diff suppressed because one or more lines are too long

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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'))
{

View File

@@ -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
View 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 '';
}
}

View File

@@ -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 '';
}
}

View File

@@ -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 '';
}
}

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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
View File

@@ -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",

View File

@@ -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",