Ping / circuit latency, break out commands, add typing function for IM, add thinkingTime and charactersPerSecond parameters to typing functions
This commit is contained in:
@@ -150,39 +150,6 @@ export class Agent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private animate(anim: UUID[], run: boolean): Promise<void>
|
||||
{
|
||||
|
||||
const circuit = this.currentRegion.circuit;
|
||||
const animPacket = new AgentAnimationMessage();
|
||||
animPacket.AgentData = {
|
||||
AgentID: this.agentID,
|
||||
SessionID: circuit.sessionID
|
||||
};
|
||||
animPacket.PhysicalAvatarEventList = [];
|
||||
animPacket.AnimationList = [];
|
||||
anim.forEach((a) =>
|
||||
{
|
||||
animPacket.AnimationList.push({
|
||||
AnimID: a,
|
||||
StartAnim: run
|
||||
});
|
||||
});
|
||||
|
||||
return circuit.waitForAck(circuit.sendMessage(animPacket, PacketFlags.Reliable), 10000);
|
||||
}
|
||||
|
||||
startAnimations(anim: UUID[]): Promise<void>
|
||||
{
|
||||
return this.animate(anim, true);
|
||||
}
|
||||
|
||||
stopAnimations(anim: UUID[]): Promise<void>
|
||||
{
|
||||
return this.animate(anim, false);
|
||||
}
|
||||
|
||||
setInitialAppearance()
|
||||
{
|
||||
const circuit = this.currentRegion.circuit;
|
||||
@@ -280,5 +247,4 @@ export class Agent
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
export class Assets
|
||||
{
|
||||
|
||||
}
|
||||
@@ -29,7 +29,8 @@ export class Circuit
|
||||
awaitingAck: {
|
||||
[key: number]: {
|
||||
packet: Packet,
|
||||
timeout: number
|
||||
timeout: number,
|
||||
sent: number
|
||||
}
|
||||
} = {};
|
||||
receivedPackets: {
|
||||
@@ -216,7 +217,8 @@ export class Circuit
|
||||
this.awaitingAck[packet.sequenceNumber] =
|
||||
{
|
||||
packet: packet,
|
||||
timeout: setTimeout(this.resend.bind(this, packet.sequenceNumber), 1000)
|
||||
timeout: setTimeout(this.resend.bind(this, packet.sequenceNumber), 1000),
|
||||
sent: new Date().getTime()
|
||||
};
|
||||
}
|
||||
let dataToSend: Buffer = Buffer.allocUnsafe(packet.getSize());
|
||||
@@ -261,6 +263,26 @@ export class Circuit
|
||||
this.sendMessage(msg, 0);
|
||||
}
|
||||
|
||||
getOldestUnacked(): number
|
||||
{
|
||||
let result = 0;
|
||||
let oldest = -1;
|
||||
|
||||
const keys: string[] = Object.keys(this.awaitingAck);
|
||||
|
||||
keys.forEach((seqID: string) =>
|
||||
{
|
||||
const nSeq = parseInt(seqID, 10);
|
||||
if (oldest === -1 || this.awaitingAck[nSeq].sent < oldest)
|
||||
{
|
||||
result = nSeq;
|
||||
oldest = this.awaitingAck[nSeq].sent;
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
expireReceivedPacket(sequenceNumber: number)
|
||||
{
|
||||
// Enough time has elapsed that we can forget about this packet
|
||||
|
||||
35
lib/classes/ClientCommands.ts
Normal file
35
lib/classes/ClientCommands.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import {Region} from './Region';
|
||||
import {Agent} from './Agent';
|
||||
import {Bot} from '../Bot';
|
||||
import {NetworkCommands} from './commands/NetworkCommands';
|
||||
import {AssetCommands} from './commands/AssetCommands';
|
||||
import {TeleportCommands} from './commands/TeleportCommands';
|
||||
import {RegionCommands} from './commands/RegionCommands';
|
||||
import {GridCommands} from './commands/GridCommands';
|
||||
import {CommunicationsCommands} from './commands/CommunicationsCommands';
|
||||
import {AgentCommands} from './commands/AgentCommands';
|
||||
import {GroupCommands} from './commands/GroupCommands';
|
||||
|
||||
export class ClientCommands
|
||||
{
|
||||
public network: NetworkCommands;
|
||||
public asset: AssetCommands;
|
||||
public teleport: TeleportCommands;
|
||||
public region: RegionCommands;
|
||||
public grid: GridCommands;
|
||||
public comms: CommunicationsCommands;
|
||||
public agent: AgentCommands;
|
||||
public group: GroupCommands;
|
||||
|
||||
constructor(region: Region, agent: Agent, bot: Bot)
|
||||
{
|
||||
this.network = new NetworkCommands(region, agent, bot);
|
||||
this.asset = new AssetCommands(region, agent, bot);
|
||||
this.teleport = new TeleportCommands(region, agent, bot);
|
||||
this.region = new RegionCommands(region, agent, bot);
|
||||
this.grid = new GridCommands(region, agent, bot);
|
||||
this.comms = new CommunicationsCommands(region, agent, bot);
|
||||
this.agent = new AgentCommands(region, agent, bot);
|
||||
this.group = new GroupCommands(region, agent, bot);
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,19 @@ import {LureEvent} from '../events/LureEvent';
|
||||
import {ChatEvent} from '../events/ChatEvent';
|
||||
import {TeleportEvent} from '../events/TeleportEvent';
|
||||
import {Subject} from 'rxjs/Subject';
|
||||
import {InstantMessageEvent} from '../events/InstantMessageEvent';
|
||||
import {GroupInviteEvent} from '../events/GroupInviteEvent';
|
||||
import {FriendRequestEvent} from '../events/FriendRequestEvent';
|
||||
import {DisconnectEvent} from '../events/DisconnectEvent';
|
||||
|
||||
export class ClientEvents
|
||||
{
|
||||
onNearbyChat: Subject<ChatEvent> = new Subject<ChatEvent>();
|
||||
onInstantMessage: Subject<InstantMessageEvent> = new Subject<InstantMessageEvent>();
|
||||
onGroupInvite: Subject<GroupInviteEvent> = new Subject<GroupInviteEvent>();
|
||||
onFriendRequest: Subject<FriendRequestEvent> = new Subject<FriendRequestEvent>();
|
||||
onLure: Subject<LureEvent> = new Subject<LureEvent>();
|
||||
onTeleportEvent: Subject<TeleportEvent> = new Subject<TeleportEvent>();
|
||||
onDisconnected: Subject<DisconnectEvent> = new Subject<DisconnectEvent>();
|
||||
onCircuitLatency: Subject<number> = new Subject<number>();
|
||||
}
|
||||
|
||||
@@ -4,17 +4,15 @@ import {Packet} from './Packet';
|
||||
import {Message} from '../enums/Message';
|
||||
import {ChatFromSimulatorMessage} from './messages/ChatFromSimulator';
|
||||
import {ImprovedInstantMessageMessage} from './messages/ImprovedInstantMessage';
|
||||
import {ChatType} from '../enums/ChatType';
|
||||
import {Utils} from './Utils';
|
||||
import {ChatFromViewerMessage} from './messages/ChatFromViewer';
|
||||
import {PacketFlags} from '../enums/PacketFlags';
|
||||
import {ChatEvent} from '../events/ChatEvent';
|
||||
import {UUID} from './UUID';
|
||||
import {InstantMessageDialog} from '../enums/InstantMessageDialog';
|
||||
import {LureEvent} from '../events/LureEvent';
|
||||
import {AlertMessageMessage} from './messages/AlertMessage';
|
||||
import {ClientEvents} from './ClientEvents';
|
||||
import {Vector3} from './Vector3';
|
||||
import {InstantMessageEvent} from '../events/InstantMessageEvent';
|
||||
import {ChatSourceType} from '../enums/ChatSourceType';
|
||||
import {InstantMessageEventFlags} from '../enums/InstantMessageEventFlags';
|
||||
|
||||
export class Comms
|
||||
{
|
||||
@@ -29,10 +27,10 @@ export class Comms
|
||||
this.agent = agent;
|
||||
|
||||
this.circuit.subscribeToMessages([
|
||||
Message.ImprovedInstantMessage,
|
||||
Message.ChatFromSimulator,
|
||||
Message.AlertMessage
|
||||
], (packet: Packet) =>
|
||||
Message.ImprovedInstantMessage,
|
||||
Message.ChatFromSimulator,
|
||||
Message.AlertMessage
|
||||
], (packet: Packet) =>
|
||||
{
|
||||
switch (packet.message.id)
|
||||
{
|
||||
@@ -41,7 +39,18 @@ export class Comms
|
||||
switch (im.MessageBlock.Dialog)
|
||||
{
|
||||
case InstantMessageDialog.MessageFromAgent:
|
||||
{
|
||||
console.log(im);
|
||||
const imEvent = new InstantMessageEvent();
|
||||
imEvent.source = ChatSourceType.Agent;
|
||||
imEvent.from = im.AgentData.AgentID;
|
||||
imEvent.owner = im.AgentData.AgentID;
|
||||
imEvent.fromName = Utils.BufferToStringSimple(im.MessageBlock.FromAgentName);
|
||||
imEvent.message = Utils.BufferToStringSimple(im.MessageBlock.Message);
|
||||
imEvent.flags = InstantMessageEventFlags.normal;
|
||||
this.clientEvents.onInstantMessage.next(imEvent);
|
||||
break;
|
||||
}
|
||||
case InstantMessageDialog.MessageBox:
|
||||
break;
|
||||
case InstantMessageDialog.GroupInvitation:
|
||||
@@ -59,15 +68,37 @@ export class Comms
|
||||
case InstantMessageDialog.TaskInventoryDeclined:
|
||||
break;
|
||||
case InstantMessageDialog.MessageFromObject:
|
||||
{
|
||||
console.log(im);
|
||||
const imEvent = new InstantMessageEvent();
|
||||
imEvent.source = ChatSourceType.Object;
|
||||
imEvent.owner = im.AgentData.AgentID;
|
||||
imEvent.from = im.MessageBlock.ID;
|
||||
imEvent.fromName = Utils.BufferToStringSimple(im.MessageBlock.FromAgentName);
|
||||
imEvent.message = Utils.BufferToStringSimple(im.MessageBlock.Message);
|
||||
imEvent.flags = InstantMessageEventFlags.normal;
|
||||
this.clientEvents.onInstantMessage.next(imEvent);
|
||||
break;
|
||||
}
|
||||
case InstantMessageDialog.BusyAutoResponse:
|
||||
{
|
||||
const imEvent = new InstantMessageEvent();
|
||||
imEvent.source = ChatSourceType.Agent;
|
||||
imEvent.from = im.AgentData.AgentID;
|
||||
imEvent.owner = im.AgentData.AgentID;
|
||||
imEvent.fromName = Utils.BufferToStringSimple(im.MessageBlock.FromAgentName);
|
||||
imEvent.message = Utils.BufferToStringSimple(im.MessageBlock.Message);
|
||||
imEvent.flags = InstantMessageEventFlags.busyResponse;
|
||||
this.clientEvents.onInstantMessage.next(imEvent);
|
||||
break;
|
||||
}
|
||||
case InstantMessageDialog.ConsoleAndChatHistory:
|
||||
break;
|
||||
case InstantMessageDialog.RequestTeleport:
|
||||
const lureEvent = new LureEvent();
|
||||
const extraData = Utils.BufferToStringSimple(im.MessageBlock.BinaryBucket).split('|');
|
||||
lureEvent.fromName = Utils.BufferToStringSimple(im.MessageBlock.FromAgentName);
|
||||
lureEvent.from = im.AgentData.AgentID;
|
||||
lureEvent.fromName = Utils.BufferToStringSimple(im.MessageBlock.FromAgentName);
|
||||
lureEvent.lureMessage = Utils.BufferToStringSimple(im.MessageBlock.Message);
|
||||
lureEvent.regionID = im.MessageBlock.RegionID;
|
||||
lureEvent.position = im.MessageBlock.Position;
|
||||
@@ -105,9 +136,29 @@ export class Comms
|
||||
case InstantMessageDialog.FriendshipDeclined:
|
||||
break;
|
||||
case InstantMessageDialog.StartTyping:
|
||||
{
|
||||
const imEvent = new InstantMessageEvent();
|
||||
imEvent.source = ChatSourceType.Agent;
|
||||
imEvent.from = im.AgentData.AgentID;
|
||||
imEvent.owner = im.AgentData.AgentID;
|
||||
imEvent.fromName = Utils.BufferToStringSimple(im.MessageBlock.FromAgentName);
|
||||
imEvent.message = '';
|
||||
imEvent.flags = InstantMessageEventFlags.startTyping;
|
||||
this.clientEvents.onInstantMessage.next(imEvent);
|
||||
break;
|
||||
}
|
||||
case InstantMessageDialog.StopTyping:
|
||||
{
|
||||
const imEvent = new InstantMessageEvent();
|
||||
imEvent.source = ChatSourceType.Agent;
|
||||
imEvent.from = im.AgentData.AgentID;
|
||||
imEvent.owner = im.AgentData.AgentID;
|
||||
imEvent.fromName = Utils.BufferToStringSimple(im.MessageBlock.FromAgentName);
|
||||
imEvent.message = '';
|
||||
imEvent.flags = InstantMessageEventFlags.finishTyping;
|
||||
this.clientEvents.onInstantMessage.next(imEvent);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
@@ -130,128 +181,21 @@ export class Comms
|
||||
case Message.AlertMessage:
|
||||
const alertm = packet.message as AlertMessageMessage;
|
||||
|
||||
let alertMessage = Utils.BufferToStringSimple(alertm.AlertData.Message);
|
||||
const alertMessage = Utils.BufferToStringSimple(alertm.AlertData.Message);
|
||||
|
||||
console.log('Alert message: ' + alertMessage);
|
||||
alertm.AlertInfo.forEach((info) => {
|
||||
let alertInfoMessage = Utils.BufferToStringSimple(info.Message);
|
||||
alertm.AlertInfo.forEach((info) =>
|
||||
{
|
||||
const alertInfoMessage = Utils.BufferToStringSimple(info.Message);
|
||||
console.log('Alert info message: ' + alertInfoMessage);
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
nearbyChat(message: string, type: ChatType, channel?: number)
|
||||
{
|
||||
if (channel === undefined)
|
||||
{
|
||||
channel = 0;
|
||||
}
|
||||
const cfv = new ChatFromViewerMessage();
|
||||
cfv.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: this.circuit.sessionID
|
||||
};
|
||||
cfv.ChatData = {
|
||||
Message: Utils.StringToBuffer(message),
|
||||
Type: type,
|
||||
Channel: channel
|
||||
};
|
||||
this.circuit.sendMessage(cfv, PacketFlags.Reliable);
|
||||
}
|
||||
say(message: string, channel?: number)
|
||||
{
|
||||
this.nearbyChat(message, ChatType.Normal, channel);
|
||||
}
|
||||
whisper(message: string, channel?: number)
|
||||
{
|
||||
this.nearbyChat(message, ChatType.Whisper, channel);
|
||||
}
|
||||
shout(message: string, channel?: number)
|
||||
{
|
||||
this.nearbyChat(message, ChatType.Shout, channel);
|
||||
}
|
||||
startTypingLocal()
|
||||
{
|
||||
const cfv = new ChatFromViewerMessage();
|
||||
cfv.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: this.circuit.sessionID
|
||||
};
|
||||
cfv.ChatData = {
|
||||
Message: Buffer.allocUnsafe(0),
|
||||
Type: ChatType.StartTyping,
|
||||
Channel: 0
|
||||
};
|
||||
this.circuit.sendMessage(cfv, PacketFlags.Reliable);
|
||||
}
|
||||
stopTypingLocal()
|
||||
{
|
||||
const cfv = new ChatFromViewerMessage();
|
||||
cfv.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: this.circuit.sessionID
|
||||
};
|
||||
cfv.ChatData = {
|
||||
Message: Buffer.allocUnsafe(0),
|
||||
Type: ChatType.StopTyping,
|
||||
Channel: 0
|
||||
};
|
||||
this.circuit.sendMessage(cfv, PacketFlags.Reliable);
|
||||
}
|
||||
typeMessage(message: string)
|
||||
{
|
||||
this.startTypingLocal();
|
||||
this.agent.startAnimations([new UUID('c541c47f-e0c0-058b-ad1a-d6ae3a4584d9')]).then(() =>
|
||||
{
|
||||
// Average four characters per second i guess?
|
||||
const timeToWait = (message.length / 5) * 1000;
|
||||
setTimeout(() =>
|
||||
{
|
||||
this.stopTypingLocal();
|
||||
this.agent.stopAnimations([new UUID('c541c47f-e0c0-058b-ad1a-d6ae3a4584d9')]).then(() =>
|
||||
{
|
||||
this.say(message);
|
||||
});
|
||||
}, timeToWait);
|
||||
});
|
||||
}
|
||||
|
||||
shutdown()
|
||||
{
|
||||
|
||||
}
|
||||
sendInstantMessage(to: UUID | string, message: string): Promise<void>
|
||||
{
|
||||
const circuit = this.circuit;
|
||||
if (typeof to === 'string')
|
||||
{
|
||||
to = new UUID(to);
|
||||
}
|
||||
message += '\0';
|
||||
const agentName = this.agent.firstName + ' ' + this.agent.lastName;
|
||||
const im: ImprovedInstantMessageMessage = new ImprovedInstantMessageMessage();
|
||||
im.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: circuit.sessionID
|
||||
};
|
||||
im.MessageBlock = {
|
||||
FromGroup: false,
|
||||
ToAgentID: to,
|
||||
ParentEstateID: 0,
|
||||
RegionID: UUID.zero(),
|
||||
Position: Vector3.getZero(),
|
||||
Offline: 0,
|
||||
Dialog: 0,
|
||||
ID: UUID.zero(),
|
||||
Timestamp: 0,
|
||||
FromAgentName: Utils.StringToBuffer(agentName),
|
||||
Message: Utils.StringToBuffer(message),
|
||||
BinaryBucket: Buffer.allocUnsafe(0)
|
||||
};
|
||||
im.EstateBlock = {
|
||||
EstateID: 0
|
||||
};
|
||||
const sequenceNo = circuit.sendMessage(im, PacketFlags.Reliable);
|
||||
return circuit.waitForAck(sequenceNo, 10000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,25 +10,39 @@ export class IPAddress
|
||||
}
|
||||
public toString = (): string =>
|
||||
{
|
||||
return this.ip.toString();
|
||||
try
|
||||
{
|
||||
return this.ip.toString();
|
||||
}
|
||||
catch (ignore)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
};
|
||||
constructor(buf?: Buffer | string, pos?: number)
|
||||
{
|
||||
if (buf !== undefined && buf instanceof Buffer)
|
||||
try
|
||||
{
|
||||
if (pos !== undefined)
|
||||
if (buf !== undefined && buf instanceof Buffer)
|
||||
{
|
||||
const bytes = buf.slice(pos, 4);
|
||||
this.ip = ipaddr.fromByteArray(bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ipaddr.isValid(buf))
|
||||
if (pos !== undefined)
|
||||
{
|
||||
this.ip = ipaddr.parse(buf);
|
||||
const bytes = buf.slice(pos, 4);
|
||||
this.ip = ipaddr.fromByteArray(bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ipaddr.isValid(buf))
|
||||
{
|
||||
this.ip = ipaddr.parse(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ignore)
|
||||
{
|
||||
this.ip = ipaddr.parse('0.0.0.0');
|
||||
}
|
||||
}
|
||||
writeToBuffer(buf: Buffer, pos: number)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as Long from 'long';
|
||||
import {HTTPAssets} from "../enums/HTTPAssets";
|
||||
import {HTTPAssets} from '../enums/HTTPAssets';
|
||||
|
||||
export class Utils
|
||||
{
|
||||
|
||||
39
lib/classes/commands/AgentCommands.ts
Normal file
39
lib/classes/commands/AgentCommands.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import {UUID} from '../UUID';
|
||||
import {AgentAnimationMessage} from '../messages/AgentAnimation';
|
||||
import {PacketFlags} from '../../enums/PacketFlags';
|
||||
import {CommandsBase} from './CommandsBase';
|
||||
|
||||
export class AgentCommands extends CommandsBase
|
||||
{
|
||||
private animate(anim: UUID[], run: boolean): Promise<void>
|
||||
{
|
||||
|
||||
const circuit = this.currentRegion.circuit;
|
||||
const animPacket = new AgentAnimationMessage();
|
||||
animPacket.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: circuit.sessionID
|
||||
};
|
||||
animPacket.PhysicalAvatarEventList = [];
|
||||
animPacket.AnimationList = [];
|
||||
anim.forEach((a) =>
|
||||
{
|
||||
animPacket.AnimationList.push({
|
||||
AnimID: a,
|
||||
StartAnim: run
|
||||
});
|
||||
});
|
||||
|
||||
return circuit.waitForAck(circuit.sendMessage(animPacket, PacketFlags.Reliable), 10000);
|
||||
}
|
||||
|
||||
startAnimations(anim: UUID[]): Promise<void>
|
||||
{
|
||||
return this.animate(anim, true);
|
||||
}
|
||||
|
||||
stopAnimations(anim: UUID[]): Promise<void>
|
||||
{
|
||||
return this.animate(anim, false);
|
||||
}
|
||||
}
|
||||
50
lib/classes/commands/AssetCommands.ts
Normal file
50
lib/classes/commands/AssetCommands.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import {CommandsBase} from './CommandsBase';
|
||||
import {HTTPAssets} from '../../enums/HTTPAssets';
|
||||
import {UUID} from '../UUID';
|
||||
import * as LLSD from 'llsd';
|
||||
import {Utils} from '../Utils';
|
||||
|
||||
export class AssetCommands extends CommandsBase
|
||||
{
|
||||
downloadAsset(type: HTTPAssets, uuid: UUID)
|
||||
{
|
||||
return this.currentRegion.caps.downloadAsset(uuid, type);
|
||||
}
|
||||
|
||||
uploadAsset(type: HTTPAssets, data: Buffer, name: string, description: string): Promise<UUID>
|
||||
{
|
||||
return new Promise<UUID>((resolve, reject) =>
|
||||
{
|
||||
if (this.agent && this.agent.inventory && this.agent.inventory.main && this.agent.inventory.main.root)
|
||||
{
|
||||
this.currentRegion.caps.capsRequestXML('NewFileAgentInventory', {
|
||||
'folder_id': new LLSD.UUID(this.agent.inventory.main.root.toString()),
|
||||
'asset_type': type,
|
||||
'inventory_type': Utils.HTTPAssetTypeToInventoryType(type),
|
||||
'name': name,
|
||||
'description': description,
|
||||
'everyone_mask': (1 << 13) | (1 << 14) | (1 << 15) | (1 << 19),
|
||||
'group_mask': (1 << 13) | (1 << 14) | (1 << 15) | (1 << 19),
|
||||
'next_owner_mask': (1 << 13) | (1 << 14) | (1 << 15) | (1 << 19),
|
||||
'expected_upload_cost': 0
|
||||
}).then((response: any) =>
|
||||
{
|
||||
if (response['state'] === 'upload')
|
||||
{
|
||||
const uploadURL = response['uploader'];
|
||||
this.currentRegion.caps.capsRequestUpload(uploadURL, data).then((responseUpload: any) =>
|
||||
{
|
||||
resolve(new UUID(responseUpload['new_asset'].toString()));
|
||||
}).catch((err) =>
|
||||
{
|
||||
reject(err);
|
||||
});
|
||||
}
|
||||
}).catch((err) =>
|
||||
{
|
||||
console.log(err);
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
20
lib/classes/commands/CommandsBase.ts
Normal file
20
lib/classes/commands/CommandsBase.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import {Region} from '../Region';
|
||||
import {Bot} from '../../Bot';
|
||||
import {Agent} from '../Agent';
|
||||
import {Circuit} from '../Circuit';
|
||||
|
||||
export class CommandsBase
|
||||
{
|
||||
protected currentRegion: Region;
|
||||
protected agent: Agent;
|
||||
protected bot: Bot;
|
||||
protected circuit: Circuit;
|
||||
|
||||
constructor(region: Region, agent: Agent, bot: Bot)
|
||||
{
|
||||
this.currentRegion = region;
|
||||
this.agent = agent;
|
||||
this.bot = bot;
|
||||
this.circuit = this.currentRegion.circuit;
|
||||
}
|
||||
}
|
||||
296
lib/classes/commands/CommunicationsCommands.ts
Normal file
296
lib/classes/commands/CommunicationsCommands.ts
Normal file
@@ -0,0 +1,296 @@
|
||||
import {CommandsBase} from './CommandsBase';
|
||||
import {UUID} from '../UUID';
|
||||
import {Utils} from '../Utils';
|
||||
import {PacketFlags} from '../../enums/PacketFlags';
|
||||
import {ImprovedInstantMessageMessage} from '../messages/ImprovedInstantMessage';
|
||||
import {Vector3} from '../Vector3';
|
||||
import {ChatFromViewerMessage} from '../messages/ChatFromViewer';
|
||||
import {ChatType} from '../../enums/ChatType';
|
||||
import {InstantMessageDialog} from '../../enums/InstantMessageDialog';
|
||||
import Timer = NodeJS.Timer;
|
||||
|
||||
export class CommunicationsCommands extends CommandsBase
|
||||
{
|
||||
sendInstantMessage(to: UUID | string, message: string): Promise<void>
|
||||
{
|
||||
const circuit = this.circuit;
|
||||
if (typeof to === 'string')
|
||||
{
|
||||
to = new UUID(to);
|
||||
}
|
||||
const agentName = this.agent.firstName + ' ' + this.agent.lastName;
|
||||
const im: ImprovedInstantMessageMessage = new ImprovedInstantMessageMessage();
|
||||
im.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: circuit.sessionID
|
||||
};
|
||||
im.MessageBlock = {
|
||||
FromGroup: false,
|
||||
ToAgentID: to,
|
||||
ParentEstateID: 0,
|
||||
RegionID: UUID.zero(),
|
||||
Position: Vector3.getZero(),
|
||||
Offline: 1,
|
||||
Dialog: 0,
|
||||
ID: UUID.zero(),
|
||||
Timestamp: 0,
|
||||
FromAgentName: Utils.StringToBuffer(agentName),
|
||||
Message: Utils.StringToBuffer(message),
|
||||
BinaryBucket: Buffer.allocUnsafe(0)
|
||||
};
|
||||
im.EstateBlock = {
|
||||
EstateID: 0
|
||||
};
|
||||
const sequenceNo = circuit.sendMessage(im, PacketFlags.Reliable);
|
||||
return circuit.waitForAck(sequenceNo, 10000);
|
||||
}
|
||||
|
||||
nearbyChat(message: string, type: ChatType, channel?: number): Promise<void>
|
||||
{
|
||||
if (channel === undefined)
|
||||
{
|
||||
channel = 0;
|
||||
}
|
||||
const cfv = new ChatFromViewerMessage();
|
||||
cfv.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: this.circuit.sessionID
|
||||
};
|
||||
cfv.ChatData = {
|
||||
Message: Utils.StringToBuffer(message),
|
||||
Type: type,
|
||||
Channel: channel
|
||||
};
|
||||
const sequenceNo = this.circuit.sendMessage(cfv, PacketFlags.Reliable);
|
||||
return this.circuit.waitForAck(sequenceNo, 10000);
|
||||
}
|
||||
|
||||
say(message: string, channel?: number): Promise<void>
|
||||
{
|
||||
return this.nearbyChat(message, ChatType.Normal, channel);
|
||||
}
|
||||
|
||||
whisper(message: string, channel?: number): Promise<void>
|
||||
{
|
||||
return this.nearbyChat(message, ChatType.Whisper, channel);
|
||||
}
|
||||
|
||||
shout(message: string, channel?: number): Promise<void>
|
||||
{
|
||||
return this.nearbyChat(message, ChatType.Shout, channel);
|
||||
}
|
||||
|
||||
startTypingLocal(): Promise<void>
|
||||
{
|
||||
const cfv = new ChatFromViewerMessage();
|
||||
cfv.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: this.circuit.sessionID
|
||||
};
|
||||
cfv.ChatData = {
|
||||
Message: Buffer.allocUnsafe(0),
|
||||
Type: ChatType.StartTyping,
|
||||
Channel: 0
|
||||
};
|
||||
const sequenceNo = this.circuit.sendMessage(cfv, PacketFlags.Reliable);
|
||||
return this.circuit.waitForAck(sequenceNo, 10000);
|
||||
}
|
||||
|
||||
stopTypingLocal(): Promise<void>
|
||||
{
|
||||
const cfv = new ChatFromViewerMessage();
|
||||
cfv.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: this.circuit.sessionID
|
||||
};
|
||||
cfv.ChatData = {
|
||||
Message: Buffer.allocUnsafe(0),
|
||||
Type: ChatType.StopTyping,
|
||||
Channel: 0
|
||||
};
|
||||
const sequenceNo = this.circuit.sendMessage(cfv, PacketFlags.Reliable);
|
||||
return this.circuit.waitForAck(sequenceNo, 10000);
|
||||
}
|
||||
|
||||
startTypingIM(to: UUID | string): Promise<void>
|
||||
{
|
||||
if (typeof to === 'string')
|
||||
{
|
||||
to = new UUID(to);
|
||||
}
|
||||
const circuit = this.circuit;
|
||||
const agentName = this.agent.firstName + ' ' + this.agent.lastName;
|
||||
const im: ImprovedInstantMessageMessage = new ImprovedInstantMessageMessage();
|
||||
im.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: circuit.sessionID
|
||||
};
|
||||
im.MessageBlock = {
|
||||
FromGroup: false,
|
||||
ToAgentID: to,
|
||||
ParentEstateID: 0,
|
||||
RegionID: UUID.zero(),
|
||||
Position: Vector3.getZero(),
|
||||
Offline: 0,
|
||||
Dialog: InstantMessageDialog.StartTyping,
|
||||
ID: UUID.zero(),
|
||||
Timestamp: 0,
|
||||
FromAgentName: Utils.StringToBuffer(agentName),
|
||||
Message: Utils.StringToBuffer(''),
|
||||
BinaryBucket: Buffer.allocUnsafe(0)
|
||||
};
|
||||
im.EstateBlock = {
|
||||
EstateID: 0
|
||||
};
|
||||
const sequenceNo = circuit.sendMessage(im, PacketFlags.Reliable);
|
||||
return circuit.waitForAck(sequenceNo, 10000);
|
||||
}
|
||||
|
||||
stopTypingIM(to: UUID | string): Promise<void>
|
||||
{
|
||||
if (typeof to === 'string')
|
||||
{
|
||||
to = new UUID(to);
|
||||
}
|
||||
const circuit = this.circuit;
|
||||
const agentName = this.agent.firstName + ' ' + this.agent.lastName;
|
||||
const im: ImprovedInstantMessageMessage = new ImprovedInstantMessageMessage();
|
||||
im.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: circuit.sessionID
|
||||
};
|
||||
im.MessageBlock = {
|
||||
FromGroup: false,
|
||||
ToAgentID: to,
|
||||
ParentEstateID: 0,
|
||||
RegionID: UUID.zero(),
|
||||
Position: Vector3.getZero(),
|
||||
Offline: 0,
|
||||
Dialog: InstantMessageDialog.StopTyping,
|
||||
ID: UUID.zero(),
|
||||
Timestamp: 0,
|
||||
FromAgentName: Utils.StringToBuffer(agentName),
|
||||
Message: Utils.StringToBuffer(''),
|
||||
BinaryBucket: Buffer.allocUnsafe(0)
|
||||
};
|
||||
im.EstateBlock = {
|
||||
EstateID: 0
|
||||
};
|
||||
const sequenceNo = circuit.sendMessage(im, PacketFlags.Reliable);
|
||||
return circuit.waitForAck(sequenceNo, 10000);
|
||||
}
|
||||
|
||||
typeInstantMessage(to: UUID | string, message: string, thinkingTime?: number, charactersPerSecond?: number): Promise<void>
|
||||
{
|
||||
return new Promise<void>((resolve, reject) =>
|
||||
{
|
||||
if (thinkingTime === undefined)
|
||||
{
|
||||
thinkingTime = 2000;
|
||||
}
|
||||
setTimeout(() =>
|
||||
{
|
||||
if (typeof to === 'string')
|
||||
{
|
||||
to = new UUID(to);
|
||||
}
|
||||
let typeTimer: Timer | null = null;
|
||||
this.startTypingIM(to).then(() =>
|
||||
{
|
||||
typeTimer = setInterval(() =>
|
||||
{
|
||||
this.startTypingIM(to).catch(() =>
|
||||
{
|
||||
// ignore
|
||||
});
|
||||
}, 5000);
|
||||
if (charactersPerSecond === undefined)
|
||||
{
|
||||
charactersPerSecond = 5;
|
||||
}
|
||||
|
||||
const timeToWait = (message.length / charactersPerSecond) * 1000;
|
||||
setTimeout(() =>
|
||||
{
|
||||
if (typeTimer !== null)
|
||||
{
|
||||
clearInterval(typeTimer);
|
||||
typeTimer = null;
|
||||
}
|
||||
this.stopTypingIM(to).then(() =>
|
||||
{
|
||||
this.sendInstantMessage(to, message).then(() =>
|
||||
{
|
||||
resolve();
|
||||
}).catch((err) =>
|
||||
{
|
||||
reject(err);
|
||||
});
|
||||
}).catch((err) =>
|
||||
{
|
||||
reject(err);
|
||||
});
|
||||
}, timeToWait);
|
||||
}).catch((err) =>
|
||||
{
|
||||
if (typeTimer !== null)
|
||||
{
|
||||
clearInterval(typeTimer);
|
||||
typeTimer = null;
|
||||
}
|
||||
reject(err);
|
||||
});
|
||||
}, thinkingTime);
|
||||
});
|
||||
}
|
||||
|
||||
typeLocalMessage(message: string, thinkingTime?: number, charactersPerSecond?: number): Promise<void>
|
||||
{
|
||||
return new Promise<void>((resolve, reject) =>
|
||||
{
|
||||
if (thinkingTime === undefined)
|
||||
{
|
||||
thinkingTime = 0;
|
||||
}
|
||||
setTimeout(() =>
|
||||
{
|
||||
this.startTypingLocal().then(() =>
|
||||
{
|
||||
this.bot.clientCommands.agent.startAnimations([new UUID('c541c47f-e0c0-058b-ad1a-d6ae3a4584d9')]).then(() =>
|
||||
{
|
||||
if (charactersPerSecond === undefined)
|
||||
{
|
||||
charactersPerSecond = 5;
|
||||
}
|
||||
|
||||
const timeToWait = (message.length / charactersPerSecond) * 1000;
|
||||
setTimeout(() =>
|
||||
{
|
||||
this.stopTypingLocal().then(() =>
|
||||
{
|
||||
this.bot.clientCommands.agent.stopAnimations([new UUID('c541c47f-e0c0-058b-ad1a-d6ae3a4584d9')]).then(() =>
|
||||
{
|
||||
this.say(message).then(() =>
|
||||
{
|
||||
resolve();
|
||||
}).catch((err) =>
|
||||
{
|
||||
reject(err);
|
||||
});
|
||||
}).catch((err) => {
|
||||
reject(err);
|
||||
});
|
||||
}).catch((err) => {
|
||||
reject(err);
|
||||
});
|
||||
}, timeToWait);
|
||||
}).catch((err) => {
|
||||
reject(err);
|
||||
});
|
||||
}).catch((err) => {
|
||||
reject(err);
|
||||
});
|
||||
}, thinkingTime);
|
||||
});
|
||||
}
|
||||
}
|
||||
141
lib/classes/commands/GridCommands.ts
Normal file
141
lib/classes/commands/GridCommands.ts
Normal file
@@ -0,0 +1,141 @@
|
||||
import {MapInfoReply} from '../../events/MapInfoReply';
|
||||
import {Packet} from '../Packet';
|
||||
import * as Long from 'long';
|
||||
import {RegionHandleRequestMessage} from '../messages/RegionHandleRequest';
|
||||
import {MapItemReplyMessage} from '../messages/MapItemReply';
|
||||
import {Message} from '../../enums/Message';
|
||||
import {MapBlockReplyMessage} from '../messages/MapBlockReply';
|
||||
import {MapBlockRequestMessage} from '../messages/MapBlockRequest';
|
||||
import {UUID} from '../UUID';
|
||||
import {MapItemRequestMessage} from '../messages/MapItemRequest';
|
||||
import {Utils} from '../Utils';
|
||||
import {PacketFlags} from '../../enums/PacketFlags';
|
||||
import {GridItemType} from '../../enums/GridItemType';
|
||||
import {RegionIDAndHandleReplyMessage} from '../messages/RegionIDAndHandleReply';
|
||||
import {CommandsBase} from './CommandsBase';
|
||||
export class GridCommands extends CommandsBase
|
||||
{
|
||||
getRegionHandle(regionID: UUID): Promise<Long>
|
||||
{
|
||||
return new Promise<Long>((resolve, reject) =>
|
||||
{
|
||||
const circuit = this.currentRegion.circuit;
|
||||
const msg: RegionHandleRequestMessage = new RegionHandleRequestMessage();
|
||||
msg.RequestBlock = {
|
||||
RegionID: regionID,
|
||||
};
|
||||
circuit.sendMessage(msg, PacketFlags.Reliable);
|
||||
circuit.waitForMessage(Message.RegionIDAndHandleReply, 10000, (packet: Packet) =>
|
||||
{
|
||||
const filterMsg = packet.message as RegionIDAndHandleReplyMessage;
|
||||
return (filterMsg.ReplyBlock.RegionID.toString() === regionID.toString());
|
||||
}).then((packet: Packet) =>
|
||||
{
|
||||
const responseMsg = packet.message as RegionIDAndHandleReplyMessage;
|
||||
resolve(responseMsg.ReplyBlock.RegionHandle);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getRegionMapInfo(gridX: number, gridY: number): Promise<MapInfoReply>
|
||||
{
|
||||
return new Promise<MapInfoReply>((resolve, reject) =>
|
||||
{
|
||||
const circuit = this.currentRegion.circuit;
|
||||
const response = new MapInfoReply();
|
||||
const msg: MapBlockRequestMessage = new MapBlockRequestMessage();
|
||||
msg.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: circuit.sessionID,
|
||||
Flags: 65536,
|
||||
EstateID: 0,
|
||||
Godlike: true
|
||||
};
|
||||
msg.PositionData = {
|
||||
MinX: (gridX / 256),
|
||||
MaxX: (gridX / 256),
|
||||
MinY: (gridY / 256),
|
||||
MaxY: (gridY / 256)
|
||||
};
|
||||
circuit.sendMessage(msg, PacketFlags.Reliable);
|
||||
circuit.waitForMessage(Message.MapBlockReply, 10000, (packet: Packet) =>
|
||||
{
|
||||
const filterMsg = packet.message as MapBlockReplyMessage;
|
||||
let found = false;
|
||||
filterMsg.Data.forEach((data) =>
|
||||
{
|
||||
if (data.X === (gridX / 256) && data.Y === (gridY / 256))
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
});
|
||||
return found;
|
||||
}).then((packet: Packet) =>
|
||||
{
|
||||
const responseMsg = packet.message as MapBlockReplyMessage;
|
||||
responseMsg.Data.forEach((data) =>
|
||||
{
|
||||
if (data.X === (gridX / 256) && data.Y === (gridY / 256))
|
||||
{
|
||||
response.name = Utils.BufferToStringSimple(data.Name);
|
||||
response.accessFlags = data.Access;
|
||||
response.mapImage = data.MapImageID;
|
||||
}
|
||||
});
|
||||
|
||||
// Now get the region handle
|
||||
const regionHandle: Long = Utils.RegionCoordinatesToHandle(gridX, gridY);
|
||||
|
||||
const mi = new MapItemRequestMessage();
|
||||
mi.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: circuit.sessionID,
|
||||
Flags: 2,
|
||||
EstateID: 0,
|
||||
Godlike: false
|
||||
};
|
||||
mi.RequestData = {
|
||||
ItemType: GridItemType.AgentLocations,
|
||||
RegionHandle: regionHandle
|
||||
};
|
||||
circuit.sendMessage(mi, PacketFlags.Reliable);
|
||||
const minX = Math.floor(gridX / 256) * 256;
|
||||
const maxX = minX + 256;
|
||||
const minY = Math.floor(gridY / 256) * 256;
|
||||
const maxY = minY + 256;
|
||||
response.avatars = [];
|
||||
circuit.waitForMessage(Message.MapItemReply, 10000, (packet: Packet) =>
|
||||
{
|
||||
const filterMsg = packet.message as MapItemReplyMessage;
|
||||
let found = false;
|
||||
filterMsg.Data.forEach((data) =>
|
||||
{
|
||||
// Check if avatar is within our bounds
|
||||
if (data.X >= minX && data.X <= maxX && data.Y >= minY && data.Y <= maxY)
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
});
|
||||
return found;
|
||||
}).then((packet2: Packet) =>
|
||||
{
|
||||
const responseMsg2 = packet2.message as MapItemReplyMessage;
|
||||
responseMsg2.Data.forEach((data) =>
|
||||
{
|
||||
response.avatars.push({
|
||||
X: data.X,
|
||||
Y: data.Y
|
||||
});
|
||||
});
|
||||
resolve(response);
|
||||
}).catch((err) =>
|
||||
{
|
||||
reject(err);
|
||||
});
|
||||
}).catch((err) =>
|
||||
{
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
44
lib/classes/commands/GroupCommands.ts
Normal file
44
lib/classes/commands/GroupCommands.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import {CommandsBase} from './CommandsBase';
|
||||
import {UUID} from '../UUID';
|
||||
import {InstantMessageDialog} from '../../enums/InstantMessageDialog';
|
||||
import {Utils} from '../Utils';
|
||||
import {PacketFlags} from '../../enums/PacketFlags';
|
||||
import {ImprovedInstantMessageMessage} from '../messages/ImprovedInstantMessage';
|
||||
import {Vector3} from '../Vector3';
|
||||
|
||||
export class GroupCommands extends CommandsBase
|
||||
{
|
||||
sendGroupNotice(group: UUID | string, subject: string, message: string)
|
||||
{
|
||||
if (typeof group === 'string')
|
||||
{
|
||||
group = new UUID(group);
|
||||
}
|
||||
const circuit = this.circuit;
|
||||
const agentName = this.agent.firstName + ' ' + this.agent.lastName;
|
||||
const im: ImprovedInstantMessageMessage = new ImprovedInstantMessageMessage();
|
||||
im.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: circuit.sessionID
|
||||
};
|
||||
im.MessageBlock = {
|
||||
FromGroup: false,
|
||||
ToAgentID: group,
|
||||
ParentEstateID: 0,
|
||||
RegionID: UUID.zero(),
|
||||
Position: Vector3.getZero(),
|
||||
Offline: 0,
|
||||
Dialog: InstantMessageDialog.GroupNotice,
|
||||
ID: UUID.zero(),
|
||||
Timestamp: 0,
|
||||
FromAgentName: Utils.StringToBuffer(agentName),
|
||||
Message: Utils.StringToBuffer(subject + '|' + message),
|
||||
BinaryBucket: Buffer.allocUnsafe(0)
|
||||
};
|
||||
im.EstateBlock = {
|
||||
EstateID: 0
|
||||
};
|
||||
const sequenceNo = circuit.sendMessage(im, PacketFlags.Reliable);
|
||||
return circuit.waitForAck(sequenceNo, 10000);
|
||||
}
|
||||
}
|
||||
50
lib/classes/commands/NetworkCommands.ts
Normal file
50
lib/classes/commands/NetworkCommands.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import {CommandsBase} from './CommandsBase';
|
||||
import {PacketFlags} from '../../enums/PacketFlags';
|
||||
import {AgentThrottleMessage} from '../messages/AgentThrottle';
|
||||
|
||||
export class NetworkCommands extends CommandsBase
|
||||
{
|
||||
private throttleGenCounter = 0;
|
||||
|
||||
setBandwidth(total: number)
|
||||
{
|
||||
const agentThrottle: AgentThrottleMessage = new AgentThrottleMessage();
|
||||
agentThrottle.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: this.circuit.sessionID,
|
||||
CircuitCode: this.circuit.circuitCode
|
||||
};
|
||||
|
||||
const throttleData = Buffer.allocUnsafe(28);
|
||||
let pos = 0;
|
||||
|
||||
const resendThrottle = total * 0.1;
|
||||
const landThrottle = total * 0.172;
|
||||
const windThrottle = total * 0.05;
|
||||
const cloudThrottle = total * 0.05;
|
||||
const taskThrottle = total * 0.234;
|
||||
const textureThrottle = total * 0.234;
|
||||
const assetThrottle = total * 0.160;
|
||||
|
||||
|
||||
throttleData.writeFloatLE(resendThrottle, pos);
|
||||
pos += 4;
|
||||
throttleData.writeFloatLE(landThrottle, pos);
|
||||
pos += 4;
|
||||
throttleData.writeFloatLE(windThrottle, pos);
|
||||
pos += 4;
|
||||
throttleData.writeFloatLE(cloudThrottle, pos);
|
||||
pos += 4;
|
||||
throttleData.writeFloatLE(taskThrottle, pos);
|
||||
pos += 4;
|
||||
throttleData.writeFloatLE(textureThrottle, pos);
|
||||
pos += 4;
|
||||
throttleData.writeFloatLE(assetThrottle, pos);
|
||||
|
||||
agentThrottle.Throttle = {
|
||||
GenCounter: this.throttleGenCounter++,
|
||||
Throttles: throttleData
|
||||
};
|
||||
this.circuit.sendMessage(agentThrottle, PacketFlags.Reliable);
|
||||
}
|
||||
}
|
||||
6
lib/classes/commands/RegionCommands.ts
Normal file
6
lib/classes/commands/RegionCommands.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import {CommandsBase} from './CommandsBase';
|
||||
|
||||
export class RegionCommands extends CommandsBase
|
||||
{
|
||||
|
||||
}
|
||||
82
lib/classes/commands/TeleportCommands.ts
Normal file
82
lib/classes/commands/TeleportCommands.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import {CommandsBase} from './CommandsBase';
|
||||
import {Region} from '../Region';
|
||||
import {LureEvent} from '../../events/LureEvent';
|
||||
import {TeleportEventType} from '../../enums/TeleportEventType';
|
||||
import {TeleportEvent} from '../../events/TeleportEvent';
|
||||
import {PacketFlags} from '../../enums/PacketFlags';
|
||||
import {TeleportLureRequestMessage} from '../messages/TeleportLureRequest';
|
||||
import {TeleportFlags} from '../../enums/TeleportFlags';
|
||||
|
||||
export class TeleportCommands extends CommandsBase
|
||||
{
|
||||
acceptTeleport(lure: LureEvent): Promise<TeleportEvent>
|
||||
{
|
||||
return new Promise<TeleportEvent>((resolve, reject) =>
|
||||
{
|
||||
const circuit = this.currentRegion.circuit;
|
||||
const tlr = new TeleportLureRequestMessage();
|
||||
tlr.Info = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: circuit.sessionID,
|
||||
LureID: lure.lureID,
|
||||
TeleportFlags: TeleportFlags.ViaLure
|
||||
};
|
||||
circuit.sendMessage(tlr, PacketFlags.Reliable);
|
||||
if (this.currentRegion.caps.eventQueueClient)
|
||||
{
|
||||
if (this.bot.clientEvents === null)
|
||||
{
|
||||
reject(new Error('ClientEvents is null'));
|
||||
return;
|
||||
}
|
||||
const subscription = this.bot.clientEvents.onTeleportEvent.subscribe((e: TeleportEvent) =>
|
||||
{
|
||||
if (e.eventType === TeleportEventType.TeleportFailed || e.eventType === TeleportEventType.TeleportCompleted)
|
||||
{
|
||||
subscription.unsubscribe();
|
||||
}
|
||||
if (e.eventType === TeleportEventType.TeleportFailed)
|
||||
{
|
||||
reject(e);
|
||||
}
|
||||
else if (e.eventType === TeleportEventType.TeleportCompleted)
|
||||
{
|
||||
if (e.simIP === 'local')
|
||||
{
|
||||
// Local TP - no need for any other shindiggery
|
||||
resolve(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.bot.clientEvents === null)
|
||||
{
|
||||
reject(new Error('ClientEvents is null'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Successful teleport! First, rip apart circuit
|
||||
this.currentRegion.shutdown();
|
||||
const region: Region = new Region(this.agent, this.bot.clientEvents);
|
||||
region.circuit.circuitCode = this.currentRegion.circuit.circuitCode;
|
||||
region.circuit.secureSessionID = this.currentRegion.circuit.secureSessionID;
|
||||
region.circuit.sessionID = this.currentRegion.circuit.sessionID;
|
||||
region.circuit.udpBlacklist = this.currentRegion.circuit.udpBlacklist;
|
||||
region.circuit.ipAddress = e.simIP;
|
||||
region.circuit.port = e.simPort;
|
||||
this.agent.setCurrentRegion(region);
|
||||
this.currentRegion = region;
|
||||
this.currentRegion.activateCaps(e.seedCapability);
|
||||
|
||||
this.bot.changeRegion(this.currentRegion).then(() =>
|
||||
{
|
||||
resolve(e);
|
||||
}).catch((error) =>
|
||||
{
|
||||
reject(error);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user