- Add "GET" method to Caps

- New events: ObjectPhysicsDataEvent, ParcelPropertiesEvent, NewObjectEvent, ObjectUpdateEvent, ObjectKilledEvent
- Added getXML function to Color4, Vector2, Vector3, Vector4, GameObject, Region, Quaternion, UUID for opensim-compatible XML export
- Added TextureAnim and ParticleSystem decoding to the "full" ObjectStore
- Object store will automatically request missing "parent" prims
- "setPersist" - When persist is TRUE, the ObjectStore will not forget about "killed" prims - useful for region scanning
- Support for Flexible params, Light params, LightImage params, Mesh data, Sculpt maps
- Fixed object scale being incorrectly calculated
- Add terrain decoding (this was a ballache)
- Add parcel map decoding
- Add support for region windlight settings (region.environment)
- Add support for materials (normal / specular maps)
- Add getBuffer, getLong and bitwiseOr to UUID
- Added a circular-reference-safe JSONStringify to Utils
- Add XferFile capability to Circuit

PUBLIC API:

AssetCommands:
- Rework "downloadAsset" to detect failures
- NEW: downloadInventoryAsset() - uses TransferRequest for prim inventory items
- NEW: getMaterials() - resolves material UUIDs

RegionCommands:
- NEW: getTerrainTextures()
- NEW: exportSettings() - OpenSim XML export of region settings
- NEW: async getTerrain() - Get binary terrain heightmap, 256x256 float32
- resolveObjects() - now fetches task inventory contents too.
- resolveObjects() - fix calculation of land impact
- NEW: getObjectByLocalID(localID: number, timeout: number)
- NEW: getObjectByUUID(uuid: UUID, timeout: number)
- NEW: getParcels();
- NEW: pruneObjects - removes missing GameObjects from a list
- NEW: setPersist - prevent objectstore from forgetting about killed gameobjects
This commit is contained in:
Casper Warden
2018-10-31 11:28:24 +00:00
parent fc2186029b
commit da4cd459f1
61 changed files with 4232 additions and 440 deletions

View File

@@ -9,16 +9,15 @@ import {UUID} from './UUID';
import {Quaternion} from './Quaternion';
import {Vector3} from './Vector3';
import {Utils} from './Utils';
import {PCode} from '../enums/PCode';
import {ClientEvents} from './ClientEvents';
import {IObjectStore} from './interfaces/IObjectStore';
import {BotOptionFlags, CompressedFlags} from '..';
import {BotOptionFlags, CompressedFlags, PacketFlags, PCode} from '..';
import {RBush3D} from 'rbush-3d/dist';
import {Vector4} from './Vector4';
import {TextureEntry} from './TextureEntry';
import {Color4} from './Color4';
import {ParticleSystem} from './ParticleSystem';
import {GameObject} from './GameObject';
import {GameObject} from './public/GameObject';
import {ObjectStoreLite} from './ObjectStoreLite';
export class ObjectStoreFull extends ObjectStoreLite implements IObjectStore
@@ -38,7 +37,7 @@ export class ObjectStoreFull extends ObjectStoreLite implements IObjectStore
const localID = objData.ID;
const parentID = objData.ParentID;
let addToParentList = true;
let newObject = false;
if (this.objects[localID])
{
if (this.objects[localID].ParentID !== parentID && this.objectsByParent[parentID])
@@ -49,15 +48,18 @@ export class ObjectStoreFull extends ObjectStoreLite implements IObjectStore
this.objectsByParent[parentID].splice(ind, 1);
}
}
else
else if (this.objectsByParent[parentID])
{
addToParentList = false;
}
}
else
{
newObject = true;
this.objects[localID] = new GameObject();
this.objects[localID].region = this.agent.currentRegion;
}
this.objects[localID].deleted = false;
const obj = this.objects[localID];
obj.ID = objData.ID;
@@ -67,6 +69,7 @@ export class ObjectStoreFull extends ObjectStoreLite implements IObjectStore
obj.PCode = objData.PCode;
obj.Material = objData.Material;
obj.ClickAction = objData.ClickAction;
obj.Scale = objData.Scale;
obj.ObjectData = objData.ObjectData;
const data: Buffer = objData.ObjectData;
@@ -158,6 +161,7 @@ export class ObjectStoreFull extends ObjectStoreLite implements IObjectStore
break;
}
obj.ParentID = objData.ParentID;
obj.Flags = objData.UpdateFlags;
obj.PathCurve = objData.PathCurve;
obj.ProfileCurve = objData.ProfileCurve;
@@ -179,11 +183,21 @@ export class ObjectStoreFull extends ObjectStoreLite implements IObjectStore
obj.ProfileHollow = objData.ProfileHollow;
obj.TextureEntry = new TextureEntry(objData.TextureEntry);
obj.TextureAnim = objData.TextureAnim;
if (obj.TextureAnim.length >= 16)
{
this.readTextureAnim(obj);
}
const pcodeData = objData.Data;
obj.Text = Utils.BufferToStringSimple(objData.Text);
obj.TextColor = new Color4(objData.TextColor, 0, false, true);
obj.MediaURL = Utils.BufferToStringSimple(objData.MediaURL);
obj.PSBlock = objData.PSBlock;
if (obj.PSBlock.length > 0)
{
obj.Particles = new ParticleSystem(obj.PSBlock, 0);
}
obj.Sound = objData.Sound;
obj.OwnerID = objData.OwnerID;
obj.SoundGain = objData.Gain;
@@ -202,6 +216,9 @@ export class ObjectStoreFull extends ObjectStoreLite implements IObjectStore
{
obj.TreeSpecies = pcodeData[0];
}
break;
case PCode.Prim:
break;
}
@@ -248,14 +265,7 @@ export class ObjectStoreFull extends ObjectStoreLite implements IObjectStore
this.readExtraParams(objData.ExtraParams, 0, this.objects[localID]);
this.objects[localID].NameValue = this.parseNameValues(Utils.BufferToStringSimple(objData.NameValue));
if (this.objects[localID].NameValue['AttachItemID'])
{
this.objects[localID].IsAttachment = true;
}
else
{
this.objects[localID].IsAttachment = false;
}
this.objects[localID].IsAttachment = this.objects[localID].NameValue['AttachItemID'] !== undefined;
this.objectsByUUID[objData.FullID.toString()] = localID;
if (!this.objectsByParent[parentID])
@@ -275,6 +285,14 @@ export class ObjectStoreFull extends ObjectStoreLite implements IObjectStore
else
{
this.insertIntoRtree(obj);
if (objData.ParentID !== undefined && objData.ParentID !== 0 && !this.objects[objData.ParentID])
{
this.requestMissingObject(objData.ParentID);
}
if (obj.ParentID === 0)
{
this.notifyObjectUpdate(newObject, obj);
}
}
}
}
@@ -303,7 +321,24 @@ export class ObjectStoreFull extends ObjectStoreLite implements IObjectStore
}
}
protected objectUpdateCompressed(objectUpdateCompressed: ObjectUpdateCompressedMessage)
private readTextureAnim(obj: GameObject)
{
let animPos = 0;
if (obj.TextureAnim !== undefined)
{
obj.TextureAnimFlags = obj.TextureAnim.readUInt8(animPos++);
obj.TextureAnimFace = obj.TextureAnim.readUInt8(animPos++);
obj.TextureAnimSizeX = obj.TextureAnim.readUInt8(animPos++);
obj.TextureAnimSizeY = obj.TextureAnim.readUInt8(animPos++);
obj.TextureAnimStart = obj.TextureAnim.readFloatLE(animPos);
animPos = animPos + 4;
obj.TextureAnimLength = obj.TextureAnim.readFloatLE(animPos);
animPos = animPos + 4;
obj.TextureAnimRate = obj.TextureAnim.readFloatLE(animPos);
}
}
protected async objectUpdateCompressed(objectUpdateCompressed: ObjectUpdateCompressedMessage)
{
for (const obj of objectUpdateCompressed.ObjectData)
{
@@ -321,6 +356,7 @@ export class ObjectStoreFull extends ObjectStoreLite implements IObjectStore
{
newObj = true;
this.objects[localID] = new GameObject();
this.objects[localID].region = this.agent.currentRegion;
}
const o = this.objects[localID];
o.ID = localID;
@@ -328,6 +364,7 @@ export class ObjectStoreFull extends ObjectStoreLite implements IObjectStore
o.FullID = fullID;
o.Flags = flags;
o.PCode = pcode;
o.deleted = false;
o.State = buf.readUInt8(pos++);
o.CRC = buf.readUInt32LE(pos);
pos = pos + 4;
@@ -349,36 +386,38 @@ export class ObjectStoreFull extends ObjectStoreLite implements IObjectStore
o.AngularVelocity = new Vector3(buf, pos, false);
pos = pos + 12;
}
let newParentID = 0;
if (compressedflags & CompressedFlags.HasParent)
{
const newParentID = buf.readUInt32LE(pos);
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;
}
o.ParentID = newParentID;
let add = true;
if (!newObj && o.ParentID !== undefined)
{
if (newParentID !== o.ParentID)
{
const index = this.objectsByParent[o.ParentID].indexOf(localID);
if (index !== -1)
{
this.objectsByParent[o.ParentID].splice(index, 1);
}
}
else if (this.objectsByParent[o.ParentID])
{
add = false;
}
}
if (add)
{
if (!this.objectsByParent[newParentID])
{
this.objectsByParent[newParentID] = [];
}
this.objectsByParent[newParentID].push(localID);
}
if (pcode !== PCode.Avatar && newObj && this.options & BotOptionFlags.StoreMyAttachmentsOnly && (this.agent.localID !== 0 && o.ParentID !== this.agent.localID))
{
// Drop object
@@ -387,6 +426,10 @@ export class ObjectStoreFull extends ObjectStoreLite implements IObjectStore
}
else
{
if (o.ParentID !== undefined && o.ParentID !== 0 && !this.objects[o.ParentID])
{
this.requestMissingObject(o.ParentID);
}
if (compressedflags & CompressedFlags.Tree)
{
o.TreeSpecies = buf.readUInt8(pos++);
@@ -421,7 +464,8 @@ export class ObjectStoreFull extends ObjectStoreLite implements IObjectStore
}
if (compressedflags & CompressedFlags.HasParticles)
{
o.Particles = new ParticleSystem(buf.slice(pos, pos + 86), 0);
o.PSBlock = buf.slice(pos, pos + 86);
o.Particles = new ParticleSystem(o.PSBlock, 0);
pos += 86;
}
@@ -474,13 +518,23 @@ export class ObjectStoreFull extends ObjectStoreLite implements IObjectStore
if (compressedflags & CompressedFlags.TextureAnimation)
{
// TODO: Properly parse textureAnim
const textureAnimLength = buf.readUInt32LE(pos);
pos = pos + 4;
o.TextureAnim = buf.slice(pos, pos + textureAnimLength);
if (o.TextureAnim.length >= 16)
{
this.readTextureAnim(o);
}
}
o.IsAttachment = (compressedflags & CompressedFlags.HasNameValues) !== 0 && o.ParentID !== 0;
this.insertIntoRtree(o);
if (o.ParentID === 0)
{
this.notifyObjectUpdate(newObj, o);
}
}
}
}
@@ -543,19 +597,8 @@ export class ObjectStoreFull extends ObjectStoreLite implements IObjectStore
}
else
{
console.log('Received terse update for object ' + localID + ' which is not in the store, so requesting the object');
// We don't know about this object, so request it
const rmo = new RequestMultipleObjectsMessage();
rmo.AgentData = {
AgentID: this.agent.agentID,
SessionID: this.circuit.sessionID
};
rmo.ObjectData = [];
rmo.ObjectData.push({
CacheMissType: 0,
ID: localID
});
this.circuit.sendMessage(rmo, 0);
this.requestMissingObject(localID);
}
}
}