271 lines
10 KiB
TypeScript
271 lines
10 KiB
TypeScript
import {UUID} from './UUID';
|
|
import {Vector3} from './Vector3';
|
|
import {Inventory} from './Inventory';
|
|
import Long = require('long');
|
|
import {Wearable} from './Wearable';
|
|
import {ControlFlags} from '../enums/ControlFlags';
|
|
import {Region} from './Region';
|
|
import {Message} from '../enums/Message';
|
|
import {Packet} from './Packet';
|
|
import {AvatarAnimationMessage} from './messages/AvatarAnimation';
|
|
import {AgentUpdateMessage} from './messages/AgentUpdate';
|
|
import {Quaternion} from './Quaternion';
|
|
import {AgentState} from '../enums/AgentState';
|
|
import {AgentFlags} from '../enums/AgentFlags';
|
|
import {BuiltInAnimations} from '../enums/BuiltInAnimations';
|
|
import * as LLSD from 'llsd';
|
|
import {AssetType} from '../enums/AssetType';
|
|
import {AgentWearablesRequestMessage} from './messages/AgentWearablesRequest';
|
|
import {PacketFlags} from '../enums/PacketFlags';
|
|
import {AgentWearablesUpdateMessage} from './messages/AgentWearablesUpdate';
|
|
import {InventorySortOrder} from '../enums/InventorySortOrder';
|
|
import {RezSingleAttachmentFromInvMessage} from './messages/RezSingleAttachmentFromInv';
|
|
import {AttachmentPoint} from '../enums/AttachmentPoint';
|
|
import {Utils} from './Utils';
|
|
import {AgentAnimationMessage} from './messages/AgentAnimation';
|
|
import {ClientEvents} from './ClientEvents';
|
|
import {IGameObject} from './interfaces/IGameObject';
|
|
|
|
export class Agent
|
|
{
|
|
firstName: string;
|
|
lastName: string;
|
|
localID = 0;
|
|
agentID: UUID;
|
|
accessMax: string;
|
|
regionAccess: string;
|
|
agentAccess: string;
|
|
currentRegion: Region;
|
|
chatSessions: string[] = [];
|
|
controlFlags: ControlFlags = 0;
|
|
openID: {
|
|
'token'?: string,
|
|
'url'?: string
|
|
} = {};
|
|
AOTransition: boolean;
|
|
buddyList: {
|
|
'buddyRightsGiven': boolean,
|
|
'buddyID': UUID,
|
|
'buddyRightsHas': boolean
|
|
}[] = [];
|
|
uiFlags: {
|
|
'allowFirstLife'?: boolean
|
|
} = {};
|
|
lookAt: Vector3;
|
|
maxGroups: number;
|
|
agentFlags: number;
|
|
startLocation: string;
|
|
cofVersion: number;
|
|
home: {
|
|
'regionHandle'?: Long,
|
|
'position'?: Vector3,
|
|
'lookAt'?: Vector3
|
|
} = {};
|
|
snapshotConfigURL: string;
|
|
inventory: Inventory;
|
|
gestures: {
|
|
assetID: UUID,
|
|
itemID: UUID
|
|
}[] = [];
|
|
agentAppearanceService: string;
|
|
wearables?: {
|
|
attachments: Wearable[];
|
|
serialNumber: number
|
|
};
|
|
agentUpdateTimer: number | null = null;
|
|
private clientEvents: ClientEvents;
|
|
|
|
constructor(clientEvents: ClientEvents)
|
|
{
|
|
this.inventory = new Inventory(clientEvents);
|
|
this.clientEvents = clientEvents;
|
|
}
|
|
|
|
addChatSession(uuid: UUID)
|
|
{
|
|
const str = uuid.toString();
|
|
if (this.chatSessions.indexOf(str) === -1)
|
|
{
|
|
this.chatSessions.push(str);
|
|
}
|
|
}
|
|
|
|
hasChatSession(uuid: UUID): boolean
|
|
{
|
|
const str = uuid.toString();
|
|
if (this.chatSessions.indexOf(str) === -1)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
setCurrentRegion(region: Region)
|
|
{
|
|
this.currentRegion = region;
|
|
this.currentRegion.circuit.subscribeToMessages([
|
|
Message.AvatarAnimation
|
|
], this.onAnimState.bind(this));
|
|
}
|
|
circuitActive()
|
|
{
|
|
this.agentUpdateTimer = setInterval(this.sendAgentUpdate.bind(this), 1000);
|
|
}
|
|
sendAgentUpdate()
|
|
{
|
|
if (!this.currentRegion)
|
|
{
|
|
return;
|
|
}
|
|
const circuit = this.currentRegion.circuit;
|
|
const agentUpdate: AgentUpdateMessage = new AgentUpdateMessage();
|
|
agentUpdate.AgentData = {
|
|
AgentID: this.agentID,
|
|
SessionID: circuit.sessionID,
|
|
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,
|
|
ControlFlags: this.controlFlags,
|
|
Flags: AgentFlags.None
|
|
};
|
|
circuit.sendMessage(agentUpdate, 0);
|
|
}
|
|
shutdown()
|
|
{
|
|
if (this.agentUpdateTimer !== null)
|
|
{
|
|
clearInterval(this.agentUpdateTimer);
|
|
this.agentUpdateTimer = null;
|
|
}
|
|
}
|
|
onAnimState(packet: Packet)
|
|
{
|
|
if (packet.message.id === Message.AvatarAnimation)
|
|
{
|
|
const animMsg = packet.message as AvatarAnimationMessage;
|
|
if (animMsg.Sender.ID.toString() === this.agentID.toString())
|
|
{
|
|
animMsg.AnimationList.forEach((anim) =>
|
|
{
|
|
const a = anim.AnimID.toString();
|
|
if (a === BuiltInAnimations.STANDUP ||
|
|
a === BuiltInAnimations.PRE_JUMP ||
|
|
a === BuiltInAnimations.LAND ||
|
|
a === BuiltInAnimations.MEDIUM_LAND ||
|
|
a === BuiltInAnimations.WALK ||
|
|
a === BuiltInAnimations.RUN)
|
|
{
|
|
// TODO: Pretty sure this isn't the best way to do this
|
|
this.controlFlags = ControlFlags.AGENT_CONTROL_FINISH_ANIM;
|
|
console.log('Stopping animation ' + a);
|
|
this.sendAgentUpdate();
|
|
this.controlFlags = 0;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
setInitialAppearance()
|
|
{
|
|
const circuit = this.currentRegion.circuit;
|
|
const wearablesRequest: AgentWearablesRequestMessage = new AgentWearablesRequestMessage();
|
|
wearablesRequest.AgentData = {
|
|
AgentID: this.agentID,
|
|
SessionID: circuit.sessionID
|
|
};
|
|
circuit.sendMessage(wearablesRequest, PacketFlags.Reliable);
|
|
circuit.waitForMessage(Message.AgentWearablesUpdate, 10000).then((packet: Packet) =>
|
|
{
|
|
const wearables = packet.message as AgentWearablesUpdateMessage;
|
|
if (!this.wearables || wearables.AgentData.SerialNum > this.wearables.serialNumber)
|
|
{
|
|
this.wearables = {
|
|
serialNumber: wearables.AgentData.SerialNum,
|
|
attachments: []
|
|
};
|
|
wearables.WearableData.forEach((wearable) =>
|
|
{
|
|
if (this.wearables && this.wearables.attachments)
|
|
{
|
|
this.wearables.attachments.push({
|
|
itemID: wearable.ItemID,
|
|
assetID: wearable.AssetID,
|
|
wearableType: wearable.WearableType
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
this.inventory.main.skeleton.forEach((folder) =>
|
|
{
|
|
if (folder.typeDefault === AssetType.CurrentOutfitFolder)
|
|
{
|
|
const folderID = folder.folderID;
|
|
|
|
const requestFolder = {
|
|
folder_id: new LLSD.UUID(folderID),
|
|
owner_id: new LLSD.UUID(this.agentID),
|
|
fetch_folders: true,
|
|
fetch_items: true,
|
|
sort_order: InventorySortOrder.ByName
|
|
};
|
|
const requestedFolders = {
|
|
'folders': [
|
|
requestFolder
|
|
]
|
|
};
|
|
this.currentRegion.caps.capsRequestXML('FetchInventoryDescendents2', requestedFolders).then((folderContents: any) =>
|
|
{
|
|
const currentOutfitFolderContents = folderContents['folders'][0]['items'];
|
|
const wornObjects = this.currentRegion.objects.getObjectsByParent(this.localID);
|
|
currentOutfitFolderContents.forEach((item: any) =>
|
|
{
|
|
if (item.type === 6)
|
|
{
|
|
let found = false;
|
|
wornObjects.forEach((obj: IGameObject) =>
|
|
{
|
|
if (obj.hasNameValueEntry('AttachItemID'))
|
|
{
|
|
if (item['item_id'].toString() === obj.getNameValueEntry('AttachItemID'))
|
|
{
|
|
found = true;
|
|
}
|
|
}
|
|
});
|
|
|
|
if (!found)
|
|
{
|
|
const rsafi = new RezSingleAttachmentFromInvMessage();
|
|
rsafi.AgentData = {
|
|
AgentID: this.agentID,
|
|
SessionID: circuit.sessionID
|
|
};
|
|
rsafi.ObjectData = {
|
|
ItemID: new UUID(item['item_id'].toString()),
|
|
OwnerID: this.agentID,
|
|
AttachmentPt: 0x80 | AttachmentPoint.Default,
|
|
ItemFlags: item['flags'],
|
|
GroupMask: item['permissions']['group_mask'],
|
|
EveryoneMask: item['permissions']['everyone_mask'],
|
|
NextOwnerMask: item['permissions']['next_owner_mask'],
|
|
Name: Utils.StringToBuffer(item['name']),
|
|
Description: Utils.StringToBuffer(item['desc'])
|
|
};
|
|
circuit.sendMessage(rsafi, PacketFlags.Reliable);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}
|