Files
node-metaverse/lib/classes/Agent.ts

324 lines
12 KiB
TypeScript
Raw Normal View History

import { UUID } from './UUID';
import { Vector3 } from './Vector3';
import { Inventory } from './Inventory';
import { Wearable } from './Wearable';
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 { BuiltInAnimations } from '../enums/BuiltInAnimations';
import * as LLSD from '@caspertech/llsd';
import { AgentWearablesRequestMessage } from './messages/AgentWearablesRequest';
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 { ClientEvents } from './ClientEvents';
import { GameObject } from './public/GameObject';
import * as Long from 'long';
2018-10-10 10:12:20 +01:00
import Timer = NodeJS.Timer;
import { GroupChatSessionAgentListEvent } from '../events/GroupChatSessionAgentListEvent';
import { AgentFlags } from '../enums/AgentFlags';
import { ControlFlags } from '../enums/ControlFlags';
import { PacketFlags } from '../enums/PacketFlags';
import { FolderType } from '../enums/FolderType';
import { Subject, Subscription } from 'rxjs';
2017-11-24 01:00:56 +00:00
export class Agent
{
firstName: string;
lastName: string;
localID = 0;
2017-11-24 01:00:56 +00:00
agentID: UUID;
accessMax: string;
regionAccess: string;
agentAccess: string;
currentRegion: Region;
2017-12-19 17:58:25 +00:00
chatSessions: {[key: string]: {
[key: string]: {
hasVoice: boolean,
isModerator: boolean
}
}} = {};
controlFlags: ControlFlags = 0;
2017-11-24 01:00:56 +00:00
openID: {
'token'?: string,
'url'?: string
} = {};
AOTransition: boolean;
buddyList: {
'buddyRightsGiven': boolean,
'buddyID': UUID,
'buddyRightsHas': boolean
}[] = [];
uiFlags: {
'allowFirstLife'?: boolean
} = {};
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;
2017-11-24 01:00:56 +00:00
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
};
2018-10-10 10:12:20 +01:00
agentUpdateTimer: Timer | null = null;
estateManager = false;
appearanceSet = false;
appearanceSetEvent: Subject<void> = new Subject<void>();
private clientEvents: ClientEvents;
2017-11-24 01:00:56 +00:00
constructor(clientEvents: ClientEvents)
2017-11-24 01:00:56 +00:00
{
this.inventory = new Inventory(clientEvents, this);
this.clientEvents = clientEvents;
2017-12-19 17:58:25 +00:00
this.clientEvents.onGroupChatAgentListUpdate.subscribe((event: GroupChatSessionAgentListEvent) =>
{
const str = event.groupID.toString();
if (this.chatSessions[str] === undefined)
{
this.chatSessions[str] = {};
}
const agent = event.agentID.toString();
if (event.entered)
{
this.chatSessions[str][agent] = {
hasVoice: event.canVoiceChat,
isModerator: event.isModerator
}
}
else
{
delete this.chatSessions[str][agent];
}
});
}
setIsEstateManager(is: boolean): void
{
this.estateManager = is;
}
2017-12-19 17:58:25 +00:00
getSessionAgentCount(uuid: UUID): number
{
const str = uuid.toString();
if (this.chatSessions[str] === undefined)
{
return 0;
}
else
{
return Object.keys(this.chatSessions[str]).length;
}
2017-11-24 01:00:56 +00:00
}
addChatSession(uuid: UUID)
{
const str = uuid.toString();
2017-12-19 17:58:25 +00:00
if (this.chatSessions[str] === undefined)
{
2017-12-19 17:58:25 +00:00
this.chatSessions[str] = {};
}
}
hasChatSession(uuid: UUID): boolean
{
const str = uuid.toString();
2018-10-10 10:12:20 +01:00
return !(this.chatSessions[str] === undefined);
}
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: this.cameraCenter,
CameraAtAxis: this.cameraLookAt,
CameraLeftAxis: this.cameraLeftAxis,
CameraUpAxis: this.cameraUpAxis,
Far: this.cameraFar,
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;
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<AgentWearablesUpdateMessage>(Message.AgentWearablesUpdate, 10000).then((wearables: 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
});
}
});
}
2017-12-19 23:43:00 +00:00
Object.keys(this.inventory.main.skeleton).forEach((uuid) =>
{
2017-12-19 23:43:00 +00:00
const folder = this.inventory.main.skeleton[uuid];
if (folder.typeDefault === FolderType.CurrentOutfit)
{
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.capsPostXML('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: GameObject) =>
{
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);
}
}
});
});
}
});
this.appearanceSet = true;
this.appearanceSetEvent.next();
});
}
2017-11-24 01:00:56 +00:00
}