Ping / circuit latency, break out commands, add typing function for IM, add thinkingTime and charactersPerSecond parameters to typing functions

This commit is contained in:
Casper Warden
2017-12-13 19:55:08 +00:00
parent af71aa597e
commit 4e8feb181f
96 changed files with 2151 additions and 935 deletions

25
dist/Bot.d.ts vendored
View File

@@ -1,26 +1,19 @@
/// <reference types="long" />
/// <reference types="node" />
import { LoginParameters } from './classes/LoginParameters';
import { UUID } from './classes/UUID';
import * as Long from 'long';
import { MapInfoReply } from './events/MapInfoReply';
import { LureEvent } from './events/LureEvent';
import { HTTPAssets } from './enums/HTTPAssets';
import { TeleportEvent } from './events/TeleportEvent';
import { Region } from './classes/Region';
import { ClientEvents } from './classes/ClientEvents';
import { ClientCommands } from './classes/ClientCommands';
export declare class Bot {
private loginParams;
private currentRegion;
private agent;
private throttleGenCounter;
private clientEvents;
private ping;
private pingNumber;
private lastSuccessfulPing;
clientEvents: ClientEvents | null;
clientCommands: ClientCommands;
constructor(login: LoginParameters);
login(): Promise<{}>;
changeRegion(region: Region): Promise<{}>;
close(): Promise<{}>;
setBandwidth(total: number): void;
acceptTeleport(lure: LureEvent): Promise<TeleportEvent>;
getRegionHandle(regionID: UUID): Promise<Long>;
getRegionMapInfo(gridX: number, gridY: number): Promise<MapInfoReply>;
connectToSim(): Promise<{}>;
downloadAsset(type: HTTPAssets, uuid: UUID): Promise<Buffer>;
uploadAsset(type: HTTPAssets, data: Buffer, name: string, description: string): Promise<UUID>;
}

344
dist/Bot.js vendored
View File

@@ -1,31 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const LoginHandler_1 = require("./LoginHandler");
const UUID_1 = require("./classes/UUID");
const PacketFlags_1 = require("./enums/PacketFlags");
const UseCircuitCode_1 = require("./classes/messages/UseCircuitCode");
const CompleteAgentMovement_1 = require("./classes/messages/CompleteAgentMovement");
const Message_1 = require("./enums/Message");
const Region_1 = require("./classes/Region");
const LogoutRequest_1 = require("./classes/messages/LogoutRequest");
const Utils_1 = require("./classes/Utils");
const RegionHandshakeReply_1 = require("./classes/messages/RegionHandshakeReply");
const RegionProtocolFlags_1 = require("./enums/RegionProtocolFlags");
const AgentThrottle_1 = require("./classes/messages/AgentThrottle");
const AgentDataUpdateRequest_1 = require("./classes/messages/AgentDataUpdateRequest");
const RegionHandleRequest_1 = require("./classes/messages/RegionHandleRequest");
const MapItemRequest_1 = require("./classes/messages/MapItemRequest");
const GridItemType_1 = require("./enums/GridItemType");
const MapBlockRequest_1 = require("./classes/messages/MapBlockRequest");
const MapInfoReply_1 = require("./events/MapInfoReply");
const TeleportLureRequest_1 = require("./classes/messages/TeleportLureRequest");
const TeleportFlags_1 = require("./enums/TeleportFlags");
const LLSD = require("llsd");
const TeleportEvent_1 = require("./events/TeleportEvent");
const TeleportEventType_1 = require("./enums/TeleportEventType");
const ClientCommands_1 = require("./classes/ClientCommands");
const DisconnectEvent_1 = require("./events/DisconnectEvent");
const StartPingCheck_1 = require("./classes/messages/StartPingCheck");
class Bot {
constructor(login) {
this.throttleGenCounter = 0;
this.ping = null;
this.pingNumber = 0;
this.lastSuccessfulPing = 0;
this.clientEvents = null;
this.loginParams = login;
}
@@ -36,12 +30,24 @@ class Bot {
this.clientEvents = response.clientEvents;
this.currentRegion = response.region;
this.agent = response.agent;
this.clientCommands = new ClientCommands_1.ClientCommands(response.region, response.agent, this);
resolve(response);
}).catch((error) => {
reject(error);
});
});
}
changeRegion(region) {
return new Promise((resolve, reject) => {
this.currentRegion = region;
this.clientCommands = new ClientCommands_1.ClientCommands(this.currentRegion, this.agent, this);
this.connectToSim().then(() => {
resolve();
}).catch((error) => {
reject(error);
});
});
}
close() {
return new Promise((resolve, reject) => {
const circuit = this.currentRegion.circuit;
@@ -59,195 +65,18 @@ class Bot {
this.currentRegion.shutdown();
delete this.currentRegion;
delete this.agent;
resolve();
});
});
}
setBandwidth(total) {
const circuit = this.currentRegion.circuit;
const agentThrottle = new AgentThrottle_1.AgentThrottleMessage();
agentThrottle.AgentData = {
AgentID: this.agent.agentID,
SessionID: circuit.sessionID,
CircuitCode: 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
};
circuit.sendMessage(agentThrottle, PacketFlags_1.PacketFlags.Reliable);
}
acceptTeleport(lure) {
return new Promise((resolve, reject) => {
const circuit = this.currentRegion.circuit;
const tlr = new TeleportLureRequest_1.TeleportLureRequestMessage();
tlr.Info = {
AgentID: this.agent.agentID,
SessionID: circuit.sessionID,
LureID: lure.lureID,
TeleportFlags: TeleportFlags_1.TeleportFlags.ViaLure
};
circuit.sendMessage(tlr, PacketFlags_1.PacketFlags.Reliable);
if (this.currentRegion.caps.eventQueueClient) {
if (this.clientEvents === null) {
reject(new Error('ClientEvents is null'));
return;
delete this.clientCommands;
if (this.ping !== null) {
clearInterval(this.ping);
this.ping = null;
}
const subscription = this.clientEvents.onTeleportEvent.subscribe((e) => {
if (e.eventType === TeleportEventType_1.TeleportEventType.TeleportFailed || e.eventType === TeleportEventType_1.TeleportEventType.TeleportCompleted) {
subscription.unsubscribe();
}
if (e.eventType === TeleportEventType_1.TeleportEventType.TeleportFailed) {
reject(e);
}
else if (e.eventType === TeleportEventType_1.TeleportEventType.TeleportCompleted) {
if (e.simIP === 'local') {
resolve(e);
return;
}
if (this.clientEvents === null) {
reject(new Error('ClientEvents is null'));
return;
}
this.currentRegion.shutdown();
const region = new Region_1.Region(this.agent, this.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.connectToSim().then(() => {
resolve(e);
}).catch((error) => {
reject(e);
});
}
});
}
});
}
getRegionHandle(regionID) {
return new Promise((resolve, reject) => {
const circuit = this.currentRegion.circuit;
const msg = new RegionHandleRequest_1.RegionHandleRequestMessage();
msg.RequestBlock = {
RegionID: regionID,
};
circuit.sendMessage(msg, PacketFlags_1.PacketFlags.Reliable);
circuit.waitForMessage(Message_1.Message.RegionIDAndHandleReply, 10000, (packet) => {
const filterMsg = packet.message;
return (filterMsg.ReplyBlock.RegionID.toString() === regionID.toString());
}).then((packet) => {
const responseMsg = packet.message;
resolve(responseMsg.ReplyBlock.RegionHandle);
});
});
}
getRegionMapInfo(gridX, gridY) {
return new Promise((resolve, reject) => {
const circuit = this.currentRegion.circuit;
const response = new MapInfoReply_1.MapInfoReply();
const msg = new MapBlockRequest_1.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_1.PacketFlags.Reliable);
circuit.waitForMessage(Message_1.Message.MapBlockReply, 10000, (packet) => {
const filterMsg = packet.message;
let found = false;
filterMsg.Data.forEach((data) => {
if (data.X === (gridX / 256) && data.Y === (gridY / 256)) {
found = true;
}
});
return found;
}).then((packet) => {
const responseMsg = packet.message;
responseMsg.Data.forEach((data) => {
if (data.X === (gridX / 256) && data.Y === (gridY / 256)) {
response.name = Utils_1.Utils.BufferToStringSimple(data.Name);
response.accessFlags = data.Access;
response.mapImage = data.MapImageID;
}
});
const regionHandle = Utils_1.Utils.RegionCoordinatesToHandle(gridX, gridY);
const mi = new MapItemRequest_1.MapItemRequestMessage();
mi.AgentData = {
AgentID: this.agent.agentID,
SessionID: circuit.sessionID,
Flags: 2,
EstateID: 0,
Godlike: false
};
mi.RequestData = {
ItemType: GridItemType_1.GridItemType.AgentLocations,
RegionHandle: regionHandle
};
circuit.sendMessage(mi, PacketFlags_1.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_1.Message.MapItemReply, 10000, (packet) => {
const filterMsg = packet.message;
let found = false;
filterMsg.Data.forEach((data) => {
if (data.X >= minX && data.X <= maxX && data.Y >= minY && data.Y <= maxY) {
found = true;
}
});
return found;
}).then((packet2) => {
const responseMsg2 = packet2.message;
responseMsg2.Data.forEach((data) => {
response.avatars.push({
X: data.X,
Y: data.Y
});
});
resolve(response);
}).catch((err) => {
reject(err);
});
}).catch((err) => {
reject(err);
const disconnectEvent = new DisconnectEvent_1.DisconnectEvent();
disconnectEvent.requested = true;
disconnectEvent.message = 'Logout completed';
if (this.clientEvents) {
this.clientEvents.onDisconnected.next(disconnectEvent);
}
resolve();
});
});
}
@@ -281,7 +110,9 @@ class Bot {
};
return circuit.waitForAck(circuit.sendMessage(handshakeReply, PacketFlags_1.PacketFlags.Reliable), 10000);
}).then(() => {
this.setBandwidth(1536000);
if (this.clientCommands !== null) {
this.clientCommands.network.setBandwidth(1536000);
}
const agentRequest = new AgentDataUpdateRequest_1.AgentDataUpdateRequestMessage();
agentRequest.AgentData = {
AgentID: this.agent.agentID,
@@ -290,6 +121,51 @@ class Bot {
circuit.sendMessage(agentRequest, PacketFlags_1.PacketFlags.Reliable);
this.agent.setInitialAppearance();
this.agent.circuitActive();
this.lastSuccessfulPing = new Date().getTime();
this.ping = setInterval(() => {
this.pingNumber++;
if (this.pingNumber > 255) {
this.pingNumber = 0;
}
const ping = new StartPingCheck_1.StartPingCheckMessage();
ping.PingID = {
PingID: this.pingNumber,
OldestUnacked: this.currentRegion.circuit.getOldestUnacked()
};
circuit.sendMessage(ping, PacketFlags_1.PacketFlags.Reliable);
circuit.waitForMessage(Message_1.Message.CompletePingCheck, 10000, ((pingData, packet) => {
const cpc = packet.message;
if (cpc.PingID.PingID === pingData.pingID) {
this.lastSuccessfulPing = new Date().getTime();
const pingTime = this.lastSuccessfulPing - pingData.timeSent;
if (this.clientEvents !== null) {
this.clientEvents.onCircuitLatency.next(pingTime);
}
return true;
}
return false;
}).bind(this, {
pingID: this.pingNumber,
timeSent: new Date().getTime()
}));
if ((new Date().getTime() - this.lastSuccessfulPing) > 60000) {
this.agent.shutdown();
this.currentRegion.shutdown();
delete this.currentRegion;
delete this.agent;
delete this.clientCommands;
if (this.ping !== null) {
clearInterval(this.ping);
this.ping = null;
}
const disconnectEvent = new DisconnectEvent_1.DisconnectEvent();
disconnectEvent.requested = false;
disconnectEvent.message = 'Circuit timeout';
if (this.clientEvents) {
this.clientEvents.onDisconnected.next(disconnectEvent);
}
}
}, 5000);
circuit.subscribeToMessages([
Message_1.Message.TeleportFailed,
Message_1.Message.TeleportFinish,
@@ -297,9 +173,7 @@ class Bot {
Message_1.Message.TeleportStart,
Message_1.Message.TeleportProgress,
Message_1.Message.TeleportCancel,
Message_1.Message.SoundTrigger,
Message_1.Message.AttachedSound,
Message_1.Message.AvatarAnimation
Message_1.Message.KickUser
], (packet) => {
switch (packet.message.id) {
case Message_1.Message.TeleportLocal:
@@ -350,21 +224,24 @@ class Bot {
this.clientEvents.onTeleportEvent.next(tpEvent);
break;
}
case Message_1.Message.SoundTrigger:
case Message_1.Message.KickUser:
{
const soundTrigger = packet.message;
const soundID = soundTrigger.SoundData.SoundID;
break;
}
case Message_1.Message.AttachedSound:
{
const attachedSound = packet.message;
const soundID = attachedSound.DataBlock.SoundID;
break;
}
case Message_1.Message.AvatarAnimation:
{
const avatarAnimation = packet.message;
const kickUser = packet.message;
this.agent.shutdown();
this.currentRegion.shutdown();
delete this.currentRegion;
delete this.agent;
delete this.clientCommands;
if (this.ping !== null) {
clearInterval(this.ping);
this.ping = null;
}
const disconnectEvent = new DisconnectEvent_1.DisconnectEvent();
disconnectEvent.requested = false;
disconnectEvent.message = Utils_1.Utils.BufferToStringSimple(kickUser.UserInfo.Reason);
if (this.clientEvents) {
this.clientEvents.onDisconnected.next(disconnectEvent);
}
break;
}
}
@@ -375,37 +252,6 @@ class Bot {
});
});
}
downloadAsset(type, uuid) {
return this.currentRegion.caps.downloadAsset(uuid, type);
}
uploadAsset(type, data, name, description) {
return new Promise((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_1.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) => {
if (response['state'] === 'upload') {
const uploadURL = response['uploader'];
this.currentRegion.caps.capsRequestUpload(uploadURL, data).then((responseUpload) => {
resolve(new UUID_1.UUID(responseUpload['new_asset'].toString()));
}).catch((err) => {
reject(err);
});
}
}).catch((err) => {
console.log(err);
});
}
});
}
}
exports.Bot = Bot;
//# sourceMappingURL=Bot.js.map

2
dist/Bot.js.map vendored

File diff suppressed because one or more lines are too long

View File

@@ -60,8 +60,5 @@ export declare class Agent {
sendAgentUpdate(): void;
shutdown(): void;
onAnimState(packet: Packet): void;
private animate(anim, run);
startAnimations(anim: UUID[]): Promise<void>;
stopAnimations(anim: UUID[]): Promise<void>;
setInitialAppearance(): void;
}

24
dist/classes/Agent.js vendored
View File

@@ -18,7 +18,6 @@ const InventorySortOrder_1 = require("../enums/InventorySortOrder");
const RezSingleAttachmentFromInv_1 = require("./messages/RezSingleAttachmentFromInv");
const AttachmentPoint_1 = require("../enums/AttachmentPoint");
const Utils_1 = require("./Utils");
const AgentAnimation_1 = require("./messages/AgentAnimation");
class Agent {
constructor(clientEvents) {
this.localID = 0;
@@ -90,29 +89,6 @@ class Agent {
}
}
}
animate(anim, run) {
const circuit = this.currentRegion.circuit;
const animPacket = new AgentAnimation_1.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_1.PacketFlags.Reliable), 10000);
}
startAnimations(anim) {
return this.animate(anim, true);
}
stopAnimations(anim) {
return this.animate(anim, false);
}
setInitialAppearance() {
const circuit = this.currentRegion.circuit;
const wearablesRequest = new AgentWearablesRequest_1.AgentWearablesRequestMessage();

File diff suppressed because one or more lines are too long

View File

@@ -22,6 +22,7 @@ export declare class Circuit {
[key: number]: {
packet: Packet;
timeout: number;
sent: number;
};
};
receivedPackets: {
@@ -41,6 +42,7 @@ export declare class Circuit {
sendPacket(packet: Packet): void;
ackReceived(sequenceNumber: number): void;
sendAck(sequenceNumber: number): void;
getOldestUnacked(): number;
expireReceivedPacket(sequenceNumber: number): void;
receivedPacket(bytes: Buffer): void;
}

View File

@@ -133,7 +133,8 @@ 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.allocUnsafe(packet.getSize());
@@ -162,6 +163,19 @@ class Circuit {
];
this.sendMessage(msg, 0);
}
getOldestUnacked() {
let result = 0;
let oldest = -1;
const keys = Object.keys(this.awaitingAck);
keys.forEach((seqID) => {
const nSeq = parseInt(seqID, 10);
if (oldest === -1 || this.awaitingAck[nSeq].sent < oldest) {
result = nSeq;
oldest = this.awaitingAck[nSeq].sent;
}
});
return result;
}
expireReceivedPacket(sequenceNumber) {
if (this.receivedPackets[sequenceNumber]) {
delete this.receivedPackets[sequenceNumber];

File diff suppressed because one or more lines are too long

22
dist/classes/ClientCommands.d.ts vendored Normal file
View File

@@ -0,0 +1,22 @@
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 declare class ClientCommands {
network: NetworkCommands;
asset: AssetCommands;
teleport: TeleportCommands;
region: RegionCommands;
grid: GridCommands;
comms: CommunicationsCommands;
agent: AgentCommands;
group: GroupCommands;
constructor(region: Region, agent: Agent, bot: Bot);
}

24
dist/classes/ClientCommands.js vendored Normal file
View File

@@ -0,0 +1,24 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const NetworkCommands_1 = require("./commands/NetworkCommands");
const AssetCommands_1 = require("./commands/AssetCommands");
const TeleportCommands_1 = require("./commands/TeleportCommands");
const RegionCommands_1 = require("./commands/RegionCommands");
const GridCommands_1 = require("./commands/GridCommands");
const CommunicationsCommands_1 = require("./commands/CommunicationsCommands");
const AgentCommands_1 = require("./commands/AgentCommands");
const GroupCommands_1 = require("./commands/GroupCommands");
class ClientCommands {
constructor(region, agent, bot) {
this.network = new NetworkCommands_1.NetworkCommands(region, agent, bot);
this.asset = new AssetCommands_1.AssetCommands(region, agent, bot);
this.teleport = new TeleportCommands_1.TeleportCommands(region, agent, bot);
this.region = new RegionCommands_1.RegionCommands(region, agent, bot);
this.grid = new GridCommands_1.GridCommands(region, agent, bot);
this.comms = new CommunicationsCommands_1.CommunicationsCommands(region, agent, bot);
this.agent = new AgentCommands_1.AgentCommands(region, agent, bot);
this.group = new GroupCommands_1.GroupCommands(region, agent, bot);
}
}
exports.ClientCommands = ClientCommands;
//# sourceMappingURL=ClientCommands.js.map

1
dist/classes/ClientCommands.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"ClientCommands.js","sourceRoot":"","sources":["../../lib/classes/ClientCommands.ts"],"names":[],"mappings":";;AAGA,gEAA2D;AAC3D,4DAAuD;AACvD,kEAA6D;AAC7D,8DAAyD;AACzD,0DAAqD;AACrD,8EAAyE;AACzE,4DAAuD;AACvD,4DAAuD;AAEvD;IAWI,YAAY,MAAc,EAAE,KAAY,EAAE,GAAQ;QAE9C,IAAI,CAAC,OAAO,GAAG,IAAI,iCAAe,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;QACvD,IAAI,CAAC,KAAK,GAAG,IAAI,6BAAa,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;QACnD,IAAI,CAAC,QAAQ,GAAG,IAAI,mCAAgB,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM,GAAG,IAAI,+BAAc,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;QACrD,IAAI,CAAC,IAAI,GAAG,IAAI,2BAAY,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;QACjD,IAAI,CAAC,KAAK,GAAG,IAAI,+CAAsB,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;QAC5D,IAAI,CAAC,KAAK,GAAG,IAAI,6BAAa,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;QACnD,IAAI,CAAC,KAAK,GAAG,IAAI,6BAAa,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IACvD,CAAC;CACJ;AAtBD,wCAsBC"}

View File

@@ -2,8 +2,17 @@ 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 declare class ClientEvents {
onNearbyChat: Subject<ChatEvent>;
onInstantMessage: Subject<InstantMessageEvent>;
onGroupInvite: Subject<GroupInviteEvent>;
onFriendRequest: Subject<FriendRequestEvent>;
onLure: Subject<LureEvent>;
onTeleportEvent: Subject<TeleportEvent>;
onDisconnected: Subject<DisconnectEvent>;
onCircuitLatency: Subject<number>;
}

View File

@@ -4,8 +4,13 @@ const Subject_1 = require("rxjs/Subject");
class ClientEvents {
constructor() {
this.onNearbyChat = new Subject_1.Subject();
this.onInstantMessage = new Subject_1.Subject();
this.onGroupInvite = new Subject_1.Subject();
this.onFriendRequest = new Subject_1.Subject();
this.onLure = new Subject_1.Subject();
this.onTeleportEvent = new Subject_1.Subject();
this.onDisconnected = new Subject_1.Subject();
this.onCircuitLatency = new Subject_1.Subject();
}
}
exports.ClientEvents = ClientEvents;

View File

@@ -1 +1 @@
{"version":3,"file":"ClientEvents.js","sourceRoot":"","sources":["../../lib/classes/ClientEvents.ts"],"names":[],"mappings":";;AAGA,0CAAqC;AAErC;IAAA;QAEI,iBAAY,GAAuB,IAAI,iBAAO,EAAa,CAAC;QAC5D,WAAM,GAAuB,IAAI,iBAAO,EAAa,CAAC;QACtD,oBAAe,GAA2B,IAAI,iBAAO,EAAiB,CAAC;IAC3E,CAAC;CAAA;AALD,oCAKC"}
{"version":3,"file":"ClientEvents.js","sourceRoot":"","sources":["../../lib/classes/ClientEvents.ts"],"names":[],"mappings":";;AAGA,0CAAqC;AAMrC;IAAA;QAEI,iBAAY,GAAuB,IAAI,iBAAO,EAAa,CAAC;QAC5D,qBAAgB,GAAiC,IAAI,iBAAO,EAAuB,CAAC;QACpF,kBAAa,GAA8B,IAAI,iBAAO,EAAoB,CAAC;QAC3E,oBAAe,GAAgC,IAAI,iBAAO,EAAsB,CAAC;QACjF,WAAM,GAAuB,IAAI,iBAAO,EAAa,CAAC;QACtD,oBAAe,GAA2B,IAAI,iBAAO,EAAiB,CAAC;QACvE,mBAAc,GAA8B,IAAI,iBAAO,EAAmB,CAAC;QAC3E,qBAAgB,GAAoB,IAAI,iBAAO,EAAU,CAAC;IAC9D,CAAC;CAAA;AAVD,oCAUC"}

View File

@@ -1,20 +1,10 @@
import { Circuit } from './Circuit';
import { Agent } from './Agent';
import { ChatType } from '../enums/ChatType';
import { UUID } from './UUID';
import { ClientEvents } from './ClientEvents';
export declare class Comms {
private circuit;
private agent;
private clientEvents;
constructor(circuit: Circuit, agent: Agent, clientEvents: ClientEvents);
nearbyChat(message: string, type: ChatType, channel?: number): void;
say(message: string, channel?: number): void;
whisper(message: string, channel?: number): void;
shout(message: string, channel?: number): void;
startTypingLocal(): void;
stopTypingLocal(): void;
typeMessage(message: string): void;
shutdown(): void;
sendInstantMessage(to: UUID | string, message: string): Promise<void>;
}

171
dist/classes/Comms.js vendored
View File

@@ -1,16 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const Message_1 = require("../enums/Message");
const ImprovedInstantMessage_1 = require("./messages/ImprovedInstantMessage");
const ChatType_1 = require("../enums/ChatType");
const Utils_1 = require("./Utils");
const ChatFromViewer_1 = require("./messages/ChatFromViewer");
const PacketFlags_1 = require("../enums/PacketFlags");
const ChatEvent_1 = require("../events/ChatEvent");
const UUID_1 = require("./UUID");
const InstantMessageDialog_1 = require("../enums/InstantMessageDialog");
const LureEvent_1 = require("../events/LureEvent");
const Vector3_1 = require("./Vector3");
const InstantMessageEvent_1 = require("../events/InstantMessageEvent");
const ChatSourceType_1 = require("../enums/ChatSourceType");
const InstantMessageEventFlags_1 = require("../enums/InstantMessageEventFlags");
class Comms {
constructor(circuit, agent, clientEvents) {
this.clientEvents = clientEvents;
@@ -26,7 +23,18 @@ class Comms {
const im = packet.message;
switch (im.MessageBlock.Dialog) {
case InstantMessageDialog_1.InstantMessageDialog.MessageFromAgent:
break;
{
console.log(im);
const imEvent = new InstantMessageEvent_1.InstantMessageEvent();
imEvent.source = ChatSourceType_1.ChatSourceType.Agent;
imEvent.from = im.AgentData.AgentID;
imEvent.owner = im.AgentData.AgentID;
imEvent.fromName = Utils_1.Utils.BufferToStringSimple(im.MessageBlock.FromAgentName);
imEvent.message = Utils_1.Utils.BufferToStringSimple(im.MessageBlock.Message);
imEvent.flags = InstantMessageEventFlags_1.InstantMessageEventFlags.normal;
this.clientEvents.onInstantMessage.next(imEvent);
break;
}
case InstantMessageDialog_1.InstantMessageDialog.MessageBox:
break;
case InstantMessageDialog_1.InstantMessageDialog.GroupInvitation:
@@ -44,14 +52,36 @@ class Comms {
case InstantMessageDialog_1.InstantMessageDialog.TaskInventoryDeclined:
break;
case InstantMessageDialog_1.InstantMessageDialog.MessageFromObject:
break;
{
console.log(im);
const imEvent = new InstantMessageEvent_1.InstantMessageEvent();
imEvent.source = ChatSourceType_1.ChatSourceType.Object;
imEvent.owner = im.AgentData.AgentID;
imEvent.from = im.MessageBlock.ID;
imEvent.fromName = Utils_1.Utils.BufferToStringSimple(im.MessageBlock.FromAgentName);
imEvent.message = Utils_1.Utils.BufferToStringSimple(im.MessageBlock.Message);
imEvent.flags = InstantMessageEventFlags_1.InstantMessageEventFlags.normal;
this.clientEvents.onInstantMessage.next(imEvent);
break;
}
case InstantMessageDialog_1.InstantMessageDialog.BusyAutoResponse:
break;
{
const imEvent = new InstantMessageEvent_1.InstantMessageEvent();
imEvent.source = ChatSourceType_1.ChatSourceType.Agent;
imEvent.from = im.AgentData.AgentID;
imEvent.owner = im.AgentData.AgentID;
imEvent.fromName = Utils_1.Utils.BufferToStringSimple(im.MessageBlock.FromAgentName);
imEvent.message = Utils_1.Utils.BufferToStringSimple(im.MessageBlock.Message);
imEvent.flags = InstantMessageEventFlags_1.InstantMessageEventFlags.busyResponse;
this.clientEvents.onInstantMessage.next(imEvent);
break;
}
case InstantMessageDialog_1.InstantMessageDialog.ConsoleAndChatHistory:
break;
case InstantMessageDialog_1.InstantMessageDialog.RequestTeleport:
const lureEvent = new LureEvent_1.LureEvent();
const extraData = Utils_1.Utils.BufferToStringSimple(im.MessageBlock.BinaryBucket).split('|');
lureEvent.from = im.AgentData.AgentID;
lureEvent.fromName = Utils_1.Utils.BufferToStringSimple(im.MessageBlock.FromAgentName);
lureEvent.lureMessage = Utils_1.Utils.BufferToStringSimple(im.MessageBlock.Message);
lureEvent.regionID = im.MessageBlock.RegionID;
@@ -90,9 +120,29 @@ class Comms {
case InstantMessageDialog_1.InstantMessageDialog.FriendshipDeclined:
break;
case InstantMessageDialog_1.InstantMessageDialog.StartTyping:
break;
{
const imEvent = new InstantMessageEvent_1.InstantMessageEvent();
imEvent.source = ChatSourceType_1.ChatSourceType.Agent;
imEvent.from = im.AgentData.AgentID;
imEvent.owner = im.AgentData.AgentID;
imEvent.fromName = Utils_1.Utils.BufferToStringSimple(im.MessageBlock.FromAgentName);
imEvent.message = '';
imEvent.flags = InstantMessageEventFlags_1.InstantMessageEventFlags.startTyping;
this.clientEvents.onInstantMessage.next(imEvent);
break;
}
case InstantMessageDialog_1.InstantMessageDialog.StopTyping:
break;
{
const imEvent = new InstantMessageEvent_1.InstantMessageEvent();
imEvent.source = ChatSourceType_1.ChatSourceType.Agent;
imEvent.from = im.AgentData.AgentID;
imEvent.owner = im.AgentData.AgentID;
imEvent.fromName = Utils_1.Utils.BufferToStringSimple(im.MessageBlock.FromAgentName);
imEvent.message = '';
imEvent.flags = InstantMessageEventFlags_1.InstantMessageEventFlags.finishTyping;
this.clientEvents.onInstantMessage.next(imEvent);
break;
}
}
break;
case Message_1.Message.ChatFromSimulator:
@@ -110,113 +160,18 @@ class Comms {
break;
case Message_1.Message.AlertMessage:
const alertm = packet.message;
let alertMessage = Utils_1.Utils.BufferToStringSimple(alertm.AlertData.Message);
const alertMessage = Utils_1.Utils.BufferToStringSimple(alertm.AlertData.Message);
console.log('Alert message: ' + alertMessage);
alertm.AlertInfo.forEach((info) => {
let alertInfoMessage = Utils_1.Utils.BufferToStringSimple(info.Message);
const alertInfoMessage = Utils_1.Utils.BufferToStringSimple(info.Message);
console.log('Alert info message: ' + alertInfoMessage);
});
break;
}
});
}
nearbyChat(message, type, channel) {
if (channel === undefined) {
channel = 0;
}
const cfv = new ChatFromViewer_1.ChatFromViewerMessage();
cfv.AgentData = {
AgentID: this.agent.agentID,
SessionID: this.circuit.sessionID
};
cfv.ChatData = {
Message: Utils_1.Utils.StringToBuffer(message),
Type: type,
Channel: channel
};
this.circuit.sendMessage(cfv, PacketFlags_1.PacketFlags.Reliable);
}
say(message, channel) {
this.nearbyChat(message, ChatType_1.ChatType.Normal, channel);
}
whisper(message, channel) {
this.nearbyChat(message, ChatType_1.ChatType.Whisper, channel);
}
shout(message, channel) {
this.nearbyChat(message, ChatType_1.ChatType.Shout, channel);
}
startTypingLocal() {
const cfv = new ChatFromViewer_1.ChatFromViewerMessage();
cfv.AgentData = {
AgentID: this.agent.agentID,
SessionID: this.circuit.sessionID
};
cfv.ChatData = {
Message: Buffer.allocUnsafe(0),
Type: ChatType_1.ChatType.StartTyping,
Channel: 0
};
this.circuit.sendMessage(cfv, PacketFlags_1.PacketFlags.Reliable);
}
stopTypingLocal() {
const cfv = new ChatFromViewer_1.ChatFromViewerMessage();
cfv.AgentData = {
AgentID: this.agent.agentID,
SessionID: this.circuit.sessionID
};
cfv.ChatData = {
Message: Buffer.allocUnsafe(0),
Type: ChatType_1.ChatType.StopTyping,
Channel: 0
};
this.circuit.sendMessage(cfv, PacketFlags_1.PacketFlags.Reliable);
}
typeMessage(message) {
this.startTypingLocal();
this.agent.startAnimations([new UUID_1.UUID('c541c47f-e0c0-058b-ad1a-d6ae3a4584d9')]).then(() => {
const timeToWait = (message.length / 5) * 1000;
setTimeout(() => {
this.stopTypingLocal();
this.agent.stopAnimations([new UUID_1.UUID('c541c47f-e0c0-058b-ad1a-d6ae3a4584d9')]).then(() => {
this.say(message);
});
}, timeToWait);
});
}
shutdown() {
}
sendInstantMessage(to, message) {
const circuit = this.circuit;
if (typeof to === 'string') {
to = new UUID_1.UUID(to);
}
message += '\0';
const agentName = this.agent.firstName + ' ' + this.agent.lastName;
const im = new ImprovedInstantMessage_1.ImprovedInstantMessageMessage();
im.AgentData = {
AgentID: this.agent.agentID,
SessionID: circuit.sessionID
};
im.MessageBlock = {
FromGroup: false,
ToAgentID: to,
ParentEstateID: 0,
RegionID: UUID_1.UUID.zero(),
Position: Vector3_1.Vector3.getZero(),
Offline: 0,
Dialog: 0,
ID: UUID_1.UUID.zero(),
Timestamp: 0,
FromAgentName: Utils_1.Utils.StringToBuffer(agentName),
Message: Utils_1.Utils.StringToBuffer(message),
BinaryBucket: Buffer.allocUnsafe(0)
};
im.EstateBlock = {
EstateID: 0
};
const sequenceNo = circuit.sendMessage(im, PacketFlags_1.PacketFlags.Reliable);
return circuit.waitForAck(sequenceNo, 10000);
}
}
exports.Comms = Comms;
//# sourceMappingURL=Comms.js.map

File diff suppressed because one or more lines are too long

View File

@@ -5,19 +5,29 @@ class IPAddress {
constructor(buf, pos) {
this.ip = null;
this.toString = () => {
return this.ip.toString();
};
if (buf !== undefined && buf instanceof Buffer) {
if (pos !== undefined) {
const bytes = buf.slice(pos, 4);
this.ip = ipaddr.fromByteArray(bytes);
try {
return this.ip.toString();
}
else {
if (ipaddr.isValid(buf)) {
this.ip = ipaddr.parse(buf);
catch (ignore) {
return '';
}
};
try {
if (buf !== undefined && buf instanceof Buffer) {
if (pos !== undefined) {
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');
}
}
static zero() {
return new IPAddress('0.0.0.0');

View File

@@ -1 +1 @@
{"version":3,"file":"IPAddress.js","sourceRoot":"","sources":["../../lib/classes/IPAddress.ts"],"names":[],"mappings":";;AAAA,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;AAEpC;IAYI,YAAY,GAAqB,EAAE,GAAY;QAV/C,OAAE,GAAQ,IAAI,CAAC;QAMR,aAAQ,GAAG,GAAW,EAAE;YAE3B,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC;QAC9B,CAAC,CAAC;QAGE,EAAE,CAAC,CAAC,GAAG,KAAK,SAAS,IAAI,GAAG,YAAY,MAAM,CAAC,CAC/C,CAAC;YACG,EAAE,CAAC,CAAC,GAAG,KAAK,SAAS,CAAC,CACtB,CAAC;gBACG,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;gBAChC,IAAI,CAAC,EAAE,GAAG,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAC1C,CAAC;YACD,IAAI,CACJ,CAAC;gBACG,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CACxB,CAAC;oBACG,IAAI,CAAC,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAChC,CAAC;YACL,CAAC;QACL,CAAC;IACL,CAAC;IAzBD,MAAM,CAAC,IAAI;QAEP,MAAM,CAAC,IAAI,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC,CAAC;IAuBD,aAAa,CAAC,GAAW,EAAE,GAAW;QAElC,MAAM,KAAK,GAAe,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC;QAChD,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAChC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAChC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAChC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAClC,CAAC;CACJ;AAtCD,8BAsCC"}
{"version":3,"file":"IPAddress.js","sourceRoot":"","sources":["../../lib/classes/IPAddress.ts"],"names":[],"mappings":";;AAAA,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;AAEpC;IAmBI,YAAY,GAAqB,EAAE,GAAY;QAjB/C,OAAE,GAAQ,IAAI,CAAC;QAMR,aAAQ,GAAG,GAAW,EAAE;YAE3B,IACA,CAAC;gBACG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC;YAC9B,CAAC;YACD,KAAK,CAAC,CAAC,MAAM,CAAC,CACd,CAAC;gBACG,MAAM,CAAC,EAAE,CAAC;YACd,CAAC;QACL,CAAC,CAAC;QAGE,IACA,CAAC;YACG,EAAE,CAAC,CAAC,GAAG,KAAK,SAAS,IAAI,GAAG,YAAY,MAAM,CAAC,CAC/C,CAAC;gBACG,EAAE,CAAC,CAAC,GAAG,KAAK,SAAS,CAAC,CACtB,CAAC;oBACG,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;oBAChC,IAAI,CAAC,EAAE,GAAG,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;gBAC1C,CAAC;gBACD,IAAI,CACJ,CAAC;oBACG,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CACxB,CAAC;wBACG,IAAI,CAAC,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;oBAChC,CAAC;gBACL,CAAC;YACL,CAAC;QACL,CAAC;QACD,KAAK,CAAC,CAAC,MAAM,CAAC,CACd,CAAC;YACG,IAAI,CAAC,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACtC,CAAC;IACL,CAAC;IAvCD,MAAM,CAAC,IAAI;QAEP,MAAM,CAAC,IAAI,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC,CAAC;IAqCD,aAAa,CAAC,GAAW,EAAE,GAAW;QAElC,MAAM,KAAK,GAAe,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC;QAChD,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAChC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAChC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAChC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAClC,CAAC;CACJ;AApDD,8BAoDC"}

View File

@@ -0,0 +1,7 @@
import { UUID } from '../UUID';
import { CommandsBase } from './CommandsBase';
export declare class AgentCommands extends CommandsBase {
private animate(anim, run);
startAnimations(anim: UUID[]): Promise<void>;
stopAnimations(anim: UUID[]): Promise<void>;
}

32
dist/classes/commands/AgentCommands.js vendored Normal file
View File

@@ -0,0 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const AgentAnimation_1 = require("../messages/AgentAnimation");
const PacketFlags_1 = require("../../enums/PacketFlags");
const CommandsBase_1 = require("./CommandsBase");
class AgentCommands extends CommandsBase_1.CommandsBase {
animate(anim, run) {
const circuit = this.currentRegion.circuit;
const animPacket = new AgentAnimation_1.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_1.PacketFlags.Reliable), 10000);
}
startAnimations(anim) {
return this.animate(anim, true);
}
stopAnimations(anim) {
return this.animate(anim, false);
}
}
exports.AgentCommands = AgentCommands;
//# sourceMappingURL=AgentCommands.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"AgentCommands.js","sourceRoot":"","sources":["../../../lib/classes/commands/AgentCommands.ts"],"names":[],"mappings":";;AACA,+DAAiE;AACjE,yDAAoD;AACpD,iDAA4C;AAE5C,mBAA2B,SAAQ,2BAAY;IAEnC,OAAO,CAAC,IAAY,EAAE,GAAY;QAGtC,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;QAC3C,MAAM,UAAU,GAAG,IAAI,sCAAqB,EAAE,CAAC;QAC/C,UAAU,CAAC,SAAS,GAAG;YACnB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO;YAC3B,SAAS,EAAE,OAAO,CAAC,SAAS;SAC/B,CAAC;QACF,UAAU,CAAC,uBAAuB,GAAG,EAAE,CAAC;QACxC,UAAU,CAAC,aAAa,GAAG,EAAE,CAAC;QAC9B,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;YAEf,UAAU,CAAC,aAAa,CAAC,IAAI,CAAC;gBAC1B,MAAM,EAAE,CAAC;gBACT,SAAS,EAAE,GAAG;aACjB,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,WAAW,CAAC,UAAU,EAAE,yBAAW,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC;IAC5F,CAAC;IAED,eAAe,CAAC,IAAY;QAExB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACpC,CAAC;IAED,cAAc,CAAC,IAAY;QAEvB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACrC,CAAC;CACJ;AAjCD,sCAiCC"}

View File

@@ -0,0 +1,8 @@
/// <reference types="node" />
import { CommandsBase } from './CommandsBase';
import { HTTPAssets } from '../../enums/HTTPAssets';
import { UUID } from '../UUID';
export declare class AssetCommands extends CommandsBase {
downloadAsset(type: HTTPAssets, uuid: UUID): Promise<Buffer>;
uploadAsset(type: HTTPAssets, data: Buffer, name: string, description: string): Promise<UUID>;
}

41
dist/classes/commands/AssetCommands.js vendored Normal file
View File

@@ -0,0 +1,41 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const CommandsBase_1 = require("./CommandsBase");
const UUID_1 = require("../UUID");
const LLSD = require("llsd");
const Utils_1 = require("../Utils");
class AssetCommands extends CommandsBase_1.CommandsBase {
downloadAsset(type, uuid) {
return this.currentRegion.caps.downloadAsset(uuid, type);
}
uploadAsset(type, data, name, description) {
return new Promise((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_1.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) => {
if (response['state'] === 'upload') {
const uploadURL = response['uploader'];
this.currentRegion.caps.capsRequestUpload(uploadURL, data).then((responseUpload) => {
resolve(new UUID_1.UUID(responseUpload['new_asset'].toString()));
}).catch((err) => {
reject(err);
});
}
}).catch((err) => {
console.log(err);
});
}
});
}
}
exports.AssetCommands = AssetCommands;
//# sourceMappingURL=AssetCommands.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"AssetCommands.js","sourceRoot":"","sources":["../../../lib/classes/commands/AssetCommands.ts"],"names":[],"mappings":";;AAAA,iDAA4C;AAE5C,kCAA6B;AAC7B,6BAA6B;AAC7B,oCAA+B;AAE/B,mBAA2B,SAAQ,2BAAY;IAE3C,aAAa,CAAC,IAAgB,EAAE,IAAU;QAEtC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC7D,CAAC;IAED,WAAW,CAAC,IAAgB,EAAE,IAAY,EAAE,IAAY,EAAE,WAAmB;QAEzE,MAAM,CAAC,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAEzC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CACtG,CAAC;gBACG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,cAAc,CAAC,uBAAuB,EAAE;oBAC5D,WAAW,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACrE,YAAY,EAAE,IAAI;oBAClB,gBAAgB,EAAE,aAAK,CAAC,4BAA4B,CAAC,IAAI,CAAC;oBAC1D,MAAM,EAAE,IAAI;oBACZ,aAAa,EAAE,WAAW;oBAC1B,eAAe,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;oBAC9D,YAAY,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;oBAC3D,iBAAiB,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;oBAChE,sBAAsB,EAAE,CAAC;iBAC5B,CAAC,CAAC,IAAI,CAAC,CAAC,QAAa,EAAE,EAAE;oBAEtB,EAAE,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CACnC,CAAC;wBACG,MAAM,SAAS,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;wBACvC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,iBAAiB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,cAAmB,EAAE,EAAE;4BAEpF,OAAO,CAAC,IAAI,WAAI,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;wBAC9D,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;4BAEb,MAAM,CAAC,GAAG,CAAC,CAAC;wBAChB,CAAC,CAAC,CAAC;oBACP,CAAC;gBACL,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;oBAEb,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACrB,CAAC,CAAC,CAAA;YACN,CAAC;QACL,CAAC,CAAC,CAAC;IACP,CAAC;CACJ;AA3CD,sCA2CC"}

11
dist/classes/commands/CommandsBase.d.ts vendored Normal file
View File

@@ -0,0 +1,11 @@
import { Region } from '../Region';
import { Bot } from '../../Bot';
import { Agent } from '../Agent';
import { Circuit } from '../Circuit';
export declare class CommandsBase {
protected currentRegion: Region;
protected agent: Agent;
protected bot: Bot;
protected circuit: Circuit;
constructor(region: Region, agent: Agent, bot: Bot);
}

12
dist/classes/commands/CommandsBase.js vendored Normal file
View File

@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class CommandsBase {
constructor(region, agent, bot) {
this.currentRegion = region;
this.agent = agent;
this.bot = bot;
this.circuit = this.currentRegion.circuit;
}
}
exports.CommandsBase = CommandsBase;
//# sourceMappingURL=CommandsBase.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"CommandsBase.js","sourceRoot":"","sources":["../../../lib/classes/commands/CommandsBase.ts"],"names":[],"mappings":";;AAKA;IAOI,YAAY,MAAc,EAAE,KAAY,EAAE,GAAQ;QAE9C,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC;QAC5B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;IAC9C,CAAC;CACJ;AAdD,oCAcC"}

View File

@@ -0,0 +1,16 @@
import { CommandsBase } from './CommandsBase';
import { UUID } from '../UUID';
import { ChatType } from '../../enums/ChatType';
export declare class CommunicationsCommands extends CommandsBase {
sendInstantMessage(to: UUID | string, message: string): Promise<void>;
nearbyChat(message: string, type: ChatType, channel?: number): Promise<void>;
say(message: string, channel?: number): Promise<void>;
whisper(message: string, channel?: number): Promise<void>;
shout(message: string, channel?: number): Promise<void>;
startTypingLocal(): Promise<void>;
stopTypingLocal(): Promise<void>;
startTypingIM(to: UUID | string): Promise<void>;
stopTypingIM(to: UUID | string): Promise<void>;
typeInstantMessage(to: UUID | string, message: string, thinkingTime?: number, charactersPerSecond?: number): Promise<void>;
typeLocalMessage(message: string, thinkingTime?: number, charactersPerSecond?: number): Promise<void>;
}

View File

@@ -0,0 +1,242 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const CommandsBase_1 = require("./CommandsBase");
const UUID_1 = require("../UUID");
const Utils_1 = require("../Utils");
const PacketFlags_1 = require("../../enums/PacketFlags");
const ImprovedInstantMessage_1 = require("../messages/ImprovedInstantMessage");
const Vector3_1 = require("../Vector3");
const ChatFromViewer_1 = require("../messages/ChatFromViewer");
const ChatType_1 = require("../../enums/ChatType");
const InstantMessageDialog_1 = require("../../enums/InstantMessageDialog");
class CommunicationsCommands extends CommandsBase_1.CommandsBase {
sendInstantMessage(to, message) {
const circuit = this.circuit;
if (typeof to === 'string') {
to = new UUID_1.UUID(to);
}
const agentName = this.agent.firstName + ' ' + this.agent.lastName;
const im = new ImprovedInstantMessage_1.ImprovedInstantMessageMessage();
im.AgentData = {
AgentID: this.agent.agentID,
SessionID: circuit.sessionID
};
im.MessageBlock = {
FromGroup: false,
ToAgentID: to,
ParentEstateID: 0,
RegionID: UUID_1.UUID.zero(),
Position: Vector3_1.Vector3.getZero(),
Offline: 1,
Dialog: 0,
ID: UUID_1.UUID.zero(),
Timestamp: 0,
FromAgentName: Utils_1.Utils.StringToBuffer(agentName),
Message: Utils_1.Utils.StringToBuffer(message),
BinaryBucket: Buffer.allocUnsafe(0)
};
im.EstateBlock = {
EstateID: 0
};
const sequenceNo = circuit.sendMessage(im, PacketFlags_1.PacketFlags.Reliable);
return circuit.waitForAck(sequenceNo, 10000);
}
nearbyChat(message, type, channel) {
if (channel === undefined) {
channel = 0;
}
const cfv = new ChatFromViewer_1.ChatFromViewerMessage();
cfv.AgentData = {
AgentID: this.agent.agentID,
SessionID: this.circuit.sessionID
};
cfv.ChatData = {
Message: Utils_1.Utils.StringToBuffer(message),
Type: type,
Channel: channel
};
const sequenceNo = this.circuit.sendMessage(cfv, PacketFlags_1.PacketFlags.Reliable);
return this.circuit.waitForAck(sequenceNo, 10000);
}
say(message, channel) {
return this.nearbyChat(message, ChatType_1.ChatType.Normal, channel);
}
whisper(message, channel) {
return this.nearbyChat(message, ChatType_1.ChatType.Whisper, channel);
}
shout(message, channel) {
return this.nearbyChat(message, ChatType_1.ChatType.Shout, channel);
}
startTypingLocal() {
const cfv = new ChatFromViewer_1.ChatFromViewerMessage();
cfv.AgentData = {
AgentID: this.agent.agentID,
SessionID: this.circuit.sessionID
};
cfv.ChatData = {
Message: Buffer.allocUnsafe(0),
Type: ChatType_1.ChatType.StartTyping,
Channel: 0
};
const sequenceNo = this.circuit.sendMessage(cfv, PacketFlags_1.PacketFlags.Reliable);
return this.circuit.waitForAck(sequenceNo, 10000);
}
stopTypingLocal() {
const cfv = new ChatFromViewer_1.ChatFromViewerMessage();
cfv.AgentData = {
AgentID: this.agent.agentID,
SessionID: this.circuit.sessionID
};
cfv.ChatData = {
Message: Buffer.allocUnsafe(0),
Type: ChatType_1.ChatType.StopTyping,
Channel: 0
};
const sequenceNo = this.circuit.sendMessage(cfv, PacketFlags_1.PacketFlags.Reliable);
return this.circuit.waitForAck(sequenceNo, 10000);
}
startTypingIM(to) {
if (typeof to === 'string') {
to = new UUID_1.UUID(to);
}
const circuit = this.circuit;
const agentName = this.agent.firstName + ' ' + this.agent.lastName;
const im = new ImprovedInstantMessage_1.ImprovedInstantMessageMessage();
im.AgentData = {
AgentID: this.agent.agentID,
SessionID: circuit.sessionID
};
im.MessageBlock = {
FromGroup: false,
ToAgentID: to,
ParentEstateID: 0,
RegionID: UUID_1.UUID.zero(),
Position: Vector3_1.Vector3.getZero(),
Offline: 0,
Dialog: InstantMessageDialog_1.InstantMessageDialog.StartTyping,
ID: UUID_1.UUID.zero(),
Timestamp: 0,
FromAgentName: Utils_1.Utils.StringToBuffer(agentName),
Message: Utils_1.Utils.StringToBuffer(''),
BinaryBucket: Buffer.allocUnsafe(0)
};
im.EstateBlock = {
EstateID: 0
};
const sequenceNo = circuit.sendMessage(im, PacketFlags_1.PacketFlags.Reliable);
return circuit.waitForAck(sequenceNo, 10000);
}
stopTypingIM(to) {
if (typeof to === 'string') {
to = new UUID_1.UUID(to);
}
const circuit = this.circuit;
const agentName = this.agent.firstName + ' ' + this.agent.lastName;
const im = new ImprovedInstantMessage_1.ImprovedInstantMessageMessage();
im.AgentData = {
AgentID: this.agent.agentID,
SessionID: circuit.sessionID
};
im.MessageBlock = {
FromGroup: false,
ToAgentID: to,
ParentEstateID: 0,
RegionID: UUID_1.UUID.zero(),
Position: Vector3_1.Vector3.getZero(),
Offline: 0,
Dialog: InstantMessageDialog_1.InstantMessageDialog.StopTyping,
ID: UUID_1.UUID.zero(),
Timestamp: 0,
FromAgentName: Utils_1.Utils.StringToBuffer(agentName),
Message: Utils_1.Utils.StringToBuffer(''),
BinaryBucket: Buffer.allocUnsafe(0)
};
im.EstateBlock = {
EstateID: 0
};
const sequenceNo = circuit.sendMessage(im, PacketFlags_1.PacketFlags.Reliable);
return circuit.waitForAck(sequenceNo, 10000);
}
typeInstantMessage(to, message, thinkingTime, charactersPerSecond) {
return new Promise((resolve, reject) => {
if (thinkingTime === undefined) {
thinkingTime = 2000;
}
setTimeout(() => {
if (typeof to === 'string') {
to = new UUID_1.UUID(to);
}
let typeTimer = null;
this.startTypingIM(to).then(() => {
typeTimer = setInterval(() => {
this.startTypingIM(to).catch(() => {
});
}, 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, thinkingTime, charactersPerSecond) {
return new Promise((resolve, reject) => {
if (thinkingTime === undefined) {
thinkingTime = 0;
}
setTimeout(() => {
this.startTypingLocal().then(() => {
this.bot.clientCommands.agent.startAnimations([new UUID_1.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_1.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);
});
}
}
exports.CommunicationsCommands = CommunicationsCommands;
//# sourceMappingURL=CommunicationsCommands.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,9 @@
/// <reference types="long" />
import { MapInfoReply } from '../../events/MapInfoReply';
import * as Long from 'long';
import { UUID } from '../UUID';
import { CommandsBase } from './CommandsBase';
export declare class GridCommands extends CommandsBase {
getRegionHandle(regionID: UUID): Promise<Long>;
getRegionMapInfo(gridX: number, gridY: number): Promise<MapInfoReply>;
}

114
dist/classes/commands/GridCommands.js vendored Normal file
View File

@@ -0,0 +1,114 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const MapInfoReply_1 = require("../../events/MapInfoReply");
const RegionHandleRequest_1 = require("../messages/RegionHandleRequest");
const Message_1 = require("../../enums/Message");
const MapBlockRequest_1 = require("../messages/MapBlockRequest");
const MapItemRequest_1 = require("../messages/MapItemRequest");
const Utils_1 = require("../Utils");
const PacketFlags_1 = require("../../enums/PacketFlags");
const GridItemType_1 = require("../../enums/GridItemType");
const CommandsBase_1 = require("./CommandsBase");
class GridCommands extends CommandsBase_1.CommandsBase {
getRegionHandle(regionID) {
return new Promise((resolve, reject) => {
const circuit = this.currentRegion.circuit;
const msg = new RegionHandleRequest_1.RegionHandleRequestMessage();
msg.RequestBlock = {
RegionID: regionID,
};
circuit.sendMessage(msg, PacketFlags_1.PacketFlags.Reliable);
circuit.waitForMessage(Message_1.Message.RegionIDAndHandleReply, 10000, (packet) => {
const filterMsg = packet.message;
return (filterMsg.ReplyBlock.RegionID.toString() === regionID.toString());
}).then((packet) => {
const responseMsg = packet.message;
resolve(responseMsg.ReplyBlock.RegionHandle);
});
});
}
getRegionMapInfo(gridX, gridY) {
return new Promise((resolve, reject) => {
const circuit = this.currentRegion.circuit;
const response = new MapInfoReply_1.MapInfoReply();
const msg = new MapBlockRequest_1.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_1.PacketFlags.Reliable);
circuit.waitForMessage(Message_1.Message.MapBlockReply, 10000, (packet) => {
const filterMsg = packet.message;
let found = false;
filterMsg.Data.forEach((data) => {
if (data.X === (gridX / 256) && data.Y === (gridY / 256)) {
found = true;
}
});
return found;
}).then((packet) => {
const responseMsg = packet.message;
responseMsg.Data.forEach((data) => {
if (data.X === (gridX / 256) && data.Y === (gridY / 256)) {
response.name = Utils_1.Utils.BufferToStringSimple(data.Name);
response.accessFlags = data.Access;
response.mapImage = data.MapImageID;
}
});
const regionHandle = Utils_1.Utils.RegionCoordinatesToHandle(gridX, gridY);
const mi = new MapItemRequest_1.MapItemRequestMessage();
mi.AgentData = {
AgentID: this.agent.agentID,
SessionID: circuit.sessionID,
Flags: 2,
EstateID: 0,
Godlike: false
};
mi.RequestData = {
ItemType: GridItemType_1.GridItemType.AgentLocations,
RegionHandle: regionHandle
};
circuit.sendMessage(mi, PacketFlags_1.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_1.Message.MapItemReply, 10000, (packet) => {
const filterMsg = packet.message;
let found = false;
filterMsg.Data.forEach((data) => {
if (data.X >= minX && data.X <= maxX && data.Y >= minY && data.Y <= maxY) {
found = true;
}
});
return found;
}).then((packet2) => {
const responseMsg2 = packet2.message;
responseMsg2.Data.forEach((data) => {
response.avatars.push({
X: data.X,
Y: data.Y
});
});
resolve(response);
}).catch((err) => {
reject(err);
});
}).catch((err) => {
reject(err);
});
});
}
}
exports.GridCommands = GridCommands;
//# sourceMappingURL=GridCommands.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"GridCommands.js","sourceRoot":"","sources":["../../../lib/classes/commands/GridCommands.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,5 @@
import { CommandsBase } from './CommandsBase';
import { UUID } from '../UUID';
export declare class GroupCommands extends CommandsBase {
sendGroupNotice(group: UUID | string, subject: string, message: string): Promise<void>;
}

44
dist/classes/commands/GroupCommands.js vendored Normal file
View File

@@ -0,0 +1,44 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const CommandsBase_1 = require("./CommandsBase");
const UUID_1 = require("../UUID");
const InstantMessageDialog_1 = require("../../enums/InstantMessageDialog");
const Utils_1 = require("../Utils");
const PacketFlags_1 = require("../../enums/PacketFlags");
const ImprovedInstantMessage_1 = require("../messages/ImprovedInstantMessage");
const Vector3_1 = require("../Vector3");
class GroupCommands extends CommandsBase_1.CommandsBase {
sendGroupNotice(group, subject, message) {
if (typeof group === 'string') {
group = new UUID_1.UUID(group);
}
const circuit = this.circuit;
const agentName = this.agent.firstName + ' ' + this.agent.lastName;
const im = new ImprovedInstantMessage_1.ImprovedInstantMessageMessage();
im.AgentData = {
AgentID: this.agent.agentID,
SessionID: circuit.sessionID
};
im.MessageBlock = {
FromGroup: false,
ToAgentID: group,
ParentEstateID: 0,
RegionID: UUID_1.UUID.zero(),
Position: Vector3_1.Vector3.getZero(),
Offline: 0,
Dialog: InstantMessageDialog_1.InstantMessageDialog.GroupNotice,
ID: UUID_1.UUID.zero(),
Timestamp: 0,
FromAgentName: Utils_1.Utils.StringToBuffer(agentName),
Message: Utils_1.Utils.StringToBuffer(subject + '|' + message),
BinaryBucket: Buffer.allocUnsafe(0)
};
im.EstateBlock = {
EstateID: 0
};
const sequenceNo = circuit.sendMessage(im, PacketFlags_1.PacketFlags.Reliable);
return circuit.waitForAck(sequenceNo, 10000);
}
}
exports.GroupCommands = GroupCommands;
//# sourceMappingURL=GroupCommands.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"GroupCommands.js","sourceRoot":"","sources":["../../../lib/classes/commands/GroupCommands.ts"],"names":[],"mappings":";;AAAA,iDAA4C;AAC5C,kCAA6B;AAC7B,2EAAsE;AACtE,oCAA+B;AAC/B,yDAAoD;AACpD,+EAAiF;AACjF,wCAAmC;AAEnC,mBAA2B,SAAQ,2BAAY;IAE3C,eAAe,CAAC,KAAoB,EAAE,OAAe,EAAE,OAAe;QAElE,EAAE,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAC9B,CAAC;YACG,KAAK,GAAG,IAAI,WAAI,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;QACnE,MAAM,EAAE,GAAkC,IAAI,sDAA6B,EAAE,CAAC;QAC9E,EAAE,CAAC,SAAS,GAAG;YACX,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO;YAC3B,SAAS,EAAE,OAAO,CAAC,SAAS;SAC/B,CAAC;QACF,EAAE,CAAC,YAAY,GAAG;YACd,SAAS,EAAE,KAAK;YAChB,SAAS,EAAE,KAAK;YAChB,cAAc,EAAE,CAAC;YACjB,QAAQ,EAAE,WAAI,CAAC,IAAI,EAAE;YACrB,QAAQ,EAAE,iBAAO,CAAC,OAAO,EAAE;YAC3B,OAAO,EAAE,CAAC;YACV,MAAM,EAAE,2CAAoB,CAAC,WAAW;YACxC,EAAE,EAAE,WAAI,CAAC,IAAI,EAAE;YACf,SAAS,EAAE,CAAC;YACZ,aAAa,EAAE,aAAK,CAAC,cAAc,CAAC,SAAS,CAAC;YAC9C,OAAO,EAAE,aAAK,CAAC,cAAc,CAAC,OAAO,GAAG,GAAG,GAAG,OAAO,CAAC;YACtD,YAAY,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;SACtC,CAAC;QACF,EAAE,CAAC,WAAW,GAAG;YACb,QAAQ,EAAE,CAAC;SACd,CAAC;QACF,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,yBAAW,CAAC,QAAQ,CAAC,CAAC;QACjE,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACjD,CAAC;CACJ;AAnCD,sCAmCC"}

View File

@@ -0,0 +1,5 @@
import { CommandsBase } from './CommandsBase';
export declare class NetworkCommands extends CommandsBase {
private throttleGenCounter;
setBandwidth(total: number): void;
}

View File

@@ -0,0 +1,48 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const CommandsBase_1 = require("./CommandsBase");
const PacketFlags_1 = require("../../enums/PacketFlags");
const AgentThrottle_1 = require("../messages/AgentThrottle");
class NetworkCommands extends CommandsBase_1.CommandsBase {
constructor() {
super(...arguments);
this.throttleGenCounter = 0;
}
setBandwidth(total) {
const agentThrottle = new AgentThrottle_1.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_1.PacketFlags.Reliable);
}
}
exports.NetworkCommands = NetworkCommands;
//# sourceMappingURL=NetworkCommands.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"NetworkCommands.js","sourceRoot":"","sources":["../../../lib/classes/commands/NetworkCommands.ts"],"names":[],"mappings":";;AAAA,iDAA4C;AAC5C,yDAAoD;AACpD,6DAA+D;AAE/D,qBAA6B,SAAQ,2BAAY;IAAjD;;QAEY,uBAAkB,GAAG,CAAC,CAAC;IA2CnC,CAAC;IAzCG,YAAY,CAAC,KAAa;QAEtB,MAAM,aAAa,GAAyB,IAAI,oCAAoB,EAAE,CAAC;QACvE,aAAa,CAAC,SAAS,GAAG;YACtB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO;YAC3B,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS;YACjC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW;SACxC,CAAC;QAEF,MAAM,YAAY,GAAG,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAC5C,IAAI,GAAG,GAAG,CAAC,CAAC;QAEZ,MAAM,cAAc,GAAG,KAAK,GAAG,GAAG,CAAC;QACnC,MAAM,YAAY,GAAG,KAAK,GAAG,KAAK,CAAC;QACnC,MAAM,YAAY,GAAG,KAAK,GAAG,IAAI,CAAC;QAClC,MAAM,aAAa,GAAG,KAAK,GAAG,IAAI,CAAC;QACnC,MAAM,YAAY,GAAG,KAAK,GAAG,KAAK,CAAC;QACnC,MAAM,eAAe,GAAG,KAAK,GAAG,KAAK,CAAC;QACtC,MAAM,aAAa,GAAG,KAAK,GAAG,KAAK,CAAC;QAGpC,YAAY,CAAC,YAAY,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;QAC/C,GAAG,IAAI,CAAC,CAAC;QACT,YAAY,CAAC,YAAY,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;QAC7C,GAAG,IAAI,CAAC,CAAC;QACT,YAAY,CAAC,YAAY,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;QAC7C,GAAG,IAAI,CAAC,CAAC;QACT,YAAY,CAAC,YAAY,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;QAC9C,GAAG,IAAI,CAAC,CAAC;QACT,YAAY,CAAC,YAAY,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;QAC7C,GAAG,IAAI,CAAC,CAAC;QACT,YAAY,CAAC,YAAY,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC;QAChD,GAAG,IAAI,CAAC,CAAC;QACT,YAAY,CAAC,YAAY,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;QAE9C,aAAa,CAAC,QAAQ,GAAG;YACrB,UAAU,EAAE,IAAI,CAAC,kBAAkB,EAAE;YACrC,SAAS,EAAE,YAAY;SAC1B,CAAC;QACF,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,aAAa,EAAE,yBAAW,CAAC,QAAQ,CAAC,CAAC;IAClE,CAAC;CACJ;AA7CD,0CA6CC"}

View File

@@ -0,0 +1,3 @@
import { CommandsBase } from './CommandsBase';
export declare class RegionCommands extends CommandsBase {
}

View File

@@ -0,0 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const CommandsBase_1 = require("./CommandsBase");
class RegionCommands extends CommandsBase_1.CommandsBase {
}
exports.RegionCommands = RegionCommands;
//# sourceMappingURL=RegionCommands.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"RegionCommands.js","sourceRoot":"","sources":["../../../lib/classes/commands/RegionCommands.ts"],"names":[],"mappings":";;AAAA,iDAA4C;AAE5C,oBAA4B,SAAQ,2BAAY;CAG/C;AAHD,wCAGC"}

View File

@@ -0,0 +1,6 @@
import { CommandsBase } from './CommandsBase';
import { LureEvent } from '../../events/LureEvent';
import { TeleportEvent } from '../../events/TeleportEvent';
export declare class TeleportCommands extends CommandsBase {
acceptTeleport(lure: LureEvent): Promise<TeleportEvent>;
}

View File

@@ -0,0 +1,65 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const CommandsBase_1 = require("./CommandsBase");
const Region_1 = require("../Region");
const TeleportEventType_1 = require("../../enums/TeleportEventType");
const PacketFlags_1 = require("../../enums/PacketFlags");
const TeleportLureRequest_1 = require("../messages/TeleportLureRequest");
const TeleportFlags_1 = require("../../enums/TeleportFlags");
class TeleportCommands extends CommandsBase_1.CommandsBase {
acceptTeleport(lure) {
return new Promise((resolve, reject) => {
const circuit = this.currentRegion.circuit;
const tlr = new TeleportLureRequest_1.TeleportLureRequestMessage();
tlr.Info = {
AgentID: this.agent.agentID,
SessionID: circuit.sessionID,
LureID: lure.lureID,
TeleportFlags: TeleportFlags_1.TeleportFlags.ViaLure
};
circuit.sendMessage(tlr, PacketFlags_1.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) => {
if (e.eventType === TeleportEventType_1.TeleportEventType.TeleportFailed || e.eventType === TeleportEventType_1.TeleportEventType.TeleportCompleted) {
subscription.unsubscribe();
}
if (e.eventType === TeleportEventType_1.TeleportEventType.TeleportFailed) {
reject(e);
}
else if (e.eventType === TeleportEventType_1.TeleportEventType.TeleportCompleted) {
if (e.simIP === 'local') {
resolve(e);
return;
}
if (this.bot.clientEvents === null) {
reject(new Error('ClientEvents is null'));
return;
}
this.currentRegion.shutdown();
const region = new Region_1.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);
});
}
});
}
});
}
}
exports.TeleportCommands = TeleportCommands;
//# sourceMappingURL=TeleportCommands.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"TeleportCommands.js","sourceRoot":"","sources":["../../../lib/classes/commands/TeleportCommands.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,6 @@
export declare enum InstantMessageEventFlags {
normal = 0,
busyResponse = 1,
startTyping = 2,
finishTyping = 4,
}

10
dist/enums/InstantMessageEventFlags.js vendored Normal file
View File

@@ -0,0 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var InstantMessageEventFlags;
(function (InstantMessageEventFlags) {
InstantMessageEventFlags[InstantMessageEventFlags["normal"] = 0] = "normal";
InstantMessageEventFlags[InstantMessageEventFlags["busyResponse"] = 1] = "busyResponse";
InstantMessageEventFlags[InstantMessageEventFlags["startTyping"] = 2] = "startTyping";
InstantMessageEventFlags[InstantMessageEventFlags["finishTyping"] = 4] = "finishTyping";
})(InstantMessageEventFlags = exports.InstantMessageEventFlags || (exports.InstantMessageEventFlags = {}));
//# sourceMappingURL=InstantMessageEventFlags.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"InstantMessageEventFlags.js","sourceRoot":"","sources":["../../lib/enums/InstantMessageEventFlags.ts"],"names":[],"mappings":";;AAAA,IAAY,wBAMX;AAND,WAAY,wBAAwB;IAEhC,2EAAU,CAAA;IACV,uFAAgB,CAAA;IAChB,qFAAe,CAAA;IACf,uFAAgB,CAAA;AACpB,CAAC,EANW,wBAAwB,GAAxB,gCAAwB,KAAxB,gCAAwB,QAMnC"}

4
dist/enums/InstantMessageFlags.d.ts vendored Normal file
View File

@@ -0,0 +1,4 @@
export declare enum InstantMessageFlags {
normal = 0,
busyResponse = 1,
}

8
dist/enums/InstantMessageFlags.js vendored Normal file
View File

@@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var InstantMessageFlags;
(function (InstantMessageFlags) {
InstantMessageFlags[InstantMessageFlags["normal"] = 0] = "normal";
InstantMessageFlags[InstantMessageFlags["busyResponse"] = 1] = "busyResponse";
})(InstantMessageFlags = exports.InstantMessageFlags || (exports.InstantMessageFlags = {}));
//# sourceMappingURL=InstantMessageFlags.js.map

1
dist/enums/InstantMessageFlags.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"InstantMessageFlags.js","sourceRoot":"","sources":["../../lib/enums/InstantMessageFlags.ts"],"names":[],"mappings":";;AAAA,IAAY,mBAIX;AAJD,WAAY,mBAAmB;IAE3B,iEAAU,CAAA;IACV,6EAAgB,CAAA;AACpB,CAAC,EAJW,mBAAmB,GAAnB,2BAAmB,KAAnB,2BAAmB,QAI9B"}

4
dist/events/DisconnectEvent.d.ts vendored Normal file
View File

@@ -0,0 +1,4 @@
export declare class DisconnectEvent {
requested: boolean;
message: string;
}

6
dist/events/DisconnectEvent.js vendored Normal file
View File

@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class DisconnectEvent {
}
exports.DisconnectEvent = DisconnectEvent;
//# sourceMappingURL=DisconnectEvent.js.map

1
dist/events/DisconnectEvent.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"DisconnectEvent.js","sourceRoot":"","sources":["../../lib/events/DisconnectEvent.ts"],"names":[],"mappings":";;AAAA;CAIC;AAJD,0CAIC"}

2
dist/events/FriendRequestEvent.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
export declare class FriendRequestEvent {
}

6
dist/events/FriendRequestEvent.js vendored Normal file
View File

@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class FriendRequestEvent {
}
exports.FriendRequestEvent = FriendRequestEvent;
//# sourceMappingURL=FriendRequestEvent.js.map

1
dist/events/FriendRequestEvent.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"FriendRequestEvent.js","sourceRoot":"","sources":["../../lib/events/FriendRequestEvent.ts"],"names":[],"mappings":";;AAAA;CAGC;AAHD,gDAGC"}

2
dist/events/GroupInviteEvent.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
export declare class GroupInviteEvent {
}

6
dist/events/GroupInviteEvent.js vendored Normal file
View File

@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class GroupInviteEvent {
}
exports.GroupInviteEvent = GroupInviteEvent;
//# sourceMappingURL=GroupInviteEvent.js.map

1
dist/events/GroupInviteEvent.js.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"GroupInviteEvent.js","sourceRoot":"","sources":["../../lib/events/GroupInviteEvent.ts"],"names":[],"mappings":";;AAAA;CAGC;AAHD,4CAGC"}

11
dist/events/InstantMessageEvent.d.ts vendored Normal file
View File

@@ -0,0 +1,11 @@
import { ChatSourceType } from '../enums/ChatSourceType';
import { UUID } from '../classes/UUID';
import { InstantMessageEventFlags } from '../enums/InstantMessageEventFlags';
export declare class InstantMessageEvent {
source: ChatSourceType;
fromName: string;
from: UUID;
owner: UUID;
message: string;
flags: InstantMessageEventFlags;
}

6
dist/events/InstantMessageEvent.js vendored Normal file
View File

@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class InstantMessageEvent {
}
exports.InstantMessageEvent = InstantMessageEvent;
//# sourceMappingURL=InstantMessageEvent.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"InstantMessageEvent.js","sourceRoot":"","sources":["../../lib/events/InstantMessageEvent.ts"],"names":[],"mappings":";;AAIA;CAQC;AARD,kDAQC"}

View File

@@ -1,6 +1,7 @@
import { UUID } from '../classes/UUID';
import { Vector3 } from '../classes/Vector3';
export declare class LureEvent {
from: UUID;
fromName: string;
lureMessage: string;
regionID: UUID;

View File

@@ -1 +1 @@
{"version":3,"file":"LureEvent.js","sourceRoot":"","sources":["../../lib/events/LureEvent.ts"],"names":[],"mappings":";;AAGA;CASC;AATD,8BASC"}
{"version":3,"file":"LureEvent.js","sourceRoot":"","sources":["../../lib/events/LureEvent.ts"],"names":[],"mappings":";;AAGA;CAUC;AAVD,8BAUC"}

5
dist/index.d.ts vendored
View File

@@ -4,4 +4,7 @@ import { ClientEvents } from './classes/ClientEvents';
import { BVH } from './classes/BVH';
import { AssetType } from './enums/AssetType';
import { HTTPAssets } from './enums/HTTPAssets';
export { Bot, LoginParameters, AssetType, HTTPAssets, ClientEvents, BVH };
import { InstantMessageEventFlags } from './enums/InstantMessageEventFlags';
import { InstantMessageEvent } from './events/InstantMessageEvent';
import { ChatSourceType } from './enums/ChatSourceType';
export { Bot, LoginParameters, AssetType, HTTPAssets, ClientEvents, BVH, InstantMessageEvent, InstantMessageEventFlags, ChatSourceType };

6
dist/index.js vendored
View File

@@ -12,4 +12,10 @@ const AssetType_1 = require("./enums/AssetType");
exports.AssetType = AssetType_1.AssetType;
const HTTPAssets_1 = require("./enums/HTTPAssets");
exports.HTTPAssets = HTTPAssets_1.HTTPAssets;
const InstantMessageEventFlags_1 = require("./enums/InstantMessageEventFlags");
exports.InstantMessageEventFlags = InstantMessageEventFlags_1.InstantMessageEventFlags;
const InstantMessageEvent_1 = require("./events/InstantMessageEvent");
exports.InstantMessageEvent = InstantMessageEvent_1.InstantMessageEvent;
const ChatSourceType_1 = require("./enums/ChatSourceType");
exports.ChatSourceType = ChatSourceType_1.ChatSourceType;
//# sourceMappingURL=index.js.map

2
dist/index.js.map vendored
View File

@@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":";;AAAA,+BAA0B;AAYtB,cAZI,SAAG,CAYJ;AAXP,+DAA0D;AAYtD,0BAZI,iCAAe,CAYJ;AAXnB,yDAAoD;AAchD,uBAdI,2BAAY,CAcJ;AAbhB,uCAAkC;AAc9B,cAdI,SAAG,CAcJ;AATP,iDAA4C;AAMxC,oBANI,qBAAS,CAMJ;AALb,mDAA8C;AAM1C,qBANI,uBAAU,CAMJ"}
{"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":";;AAAA,+BAA0B;AAetB,cAfI,SAAG,CAeJ;AAdP,+DAA0D;AAetD,0BAfI,iCAAe,CAeJ;AAdnB,yDAAoD;AAiBhD,uBAjBI,2BAAY,CAiBJ;AAhBhB,uCAAkC;AAiB9B,cAjBI,SAAG,CAiBJ;AAZP,iDAA4C;AASxC,oBATI,qBAAS,CASJ;AARb,mDAA8C;AAS1C,qBATI,uBAAU,CASJ;AARd,+EAA0E;AAYtE,mCAZI,mDAAwB,CAYJ;AAX5B,sEAAiE;AAU7D,8BAVI,yCAAmB,CAUJ;AATvB,2DAAsD;AAWlD,yBAXI,+BAAc,CAWJ"}

View File

@@ -13,28 +13,62 @@ const bot = new nmv.Bot(loginParameters);
let resp = null;
bot.login().then((response) =>
function connect()
{
bot.clientEvents.onLure.subscribe((lureEvent) =>
bot.login().then((response) =>
{
bot.getRegionMapInfo(lureEvent.gridX, lureEvent.gridY).then((regionInfo) =>
bot.clientEvents.onLure.subscribe((lureEvent) =>
{
console.log('Auto-accepting teleport lure to ' + regionInfo.name + ' (' + regionInfo.avatars.length + ' avatar' + ((regionInfo.avatars.length === 1)?'':'s') + ' present) from ' + lureEvent.fromName + ' with message: ' + lureEvent.lureMessage);
bot.acceptTeleport(lureEvent);
bot.clientCommands.grid.getRegionMapInfo(lureEvent.gridX, lureEvent.gridY).then((regionInfo) =>
{
console.log('Auto-accepting teleport lure to ' + regionInfo.name + ' (' + regionInfo.avatars.length + ' avatar' + ((regionInfo.avatars.length === 1)?'':'s') + ' present) from ' + lureEvent.fromName + ' with message: ' + lureEvent.lureMessage);
//bot.clientCommands.teleport.acceptTeleport(lureEvent);
});
});
bot.clientEvents.onInstantMessage.subscribe((IMEvent) =>
{
if (IMEvent.source === nmv.ChatSourceType.Agent)
{
if (!(IMEvent.flags & nmv.InstantMessageEventFlags.startTyping || IMEvent.flags & nmv.InstantMessageEventFlags.finishTyping))
{
bot.clientCommands.comms.typeInstantMessage(IMEvent.from, 'Thanks for the message! This account is a scripted agent (bot), so cannot reply to your query. Sorry!');
}
}
});
bot.clientEvents.onDisconnected.subscribe((DisconnectEvent) =>
{
console.log("Disconnected from simulator: "+DisconnectEvent.message);
if (!DisconnectEvent.requested)
{
setTimeout(() =>
{
console.log("Reconnecting");
connect();
}, 5000)
}
});
//Establish circuit wit region
resp = response;
return bot.connectToSim();
}).then(() =>
{
// Do some stuff
//bot.clientCommands.comms.typeLocalMessage('Never fear, I am here!', 2000);
//bot.clientCommands.group.sendGroupNotice('503e8ef6-e119-ff5e-2524-24f290dd3867', 'Test', 'testy testy test');
// When it's time to go home, call bot.close();
}).catch((error) =>
{
console.log("Error:");
console.error(error);
setTimeout(() =>
{
connect();
}, 5000)
});
}
//Establish circuit wit region
resp = response;
return bot.connectToSim();
}).then(() =>
{
// Do some stuff
// When it's time to go home, call bot.close();
}).catch((error) =>
{
console.log("Error:");
console.error(error);
});
connect();

View File

@@ -2,7 +2,6 @@ import {LoginHandler} from './LoginHandler';
import {LoginResponse} from './classes/LoginResponse';
import {LoginParameters} from './classes/LoginParameters';
import {Agent} from './classes/Agent';
import {UUID} from './classes/UUID';
import {PacketFlags} from './enums/PacketFlags';
import {UseCircuitCodeMessage} from './classes/messages/UseCircuitCode';
import {CompleteAgentMovementMessage} from './classes/messages/CompleteAgentMovement';
@@ -13,38 +12,29 @@ import {LogoutRequestMessage} from './classes/messages/LogoutRequest';
import {Utils} from './classes/Utils';
import {RegionHandshakeReplyMessage} from './classes/messages/RegionHandshakeReply';
import {RegionProtocolFlags} from './enums/RegionProtocolFlags';
import {AgentThrottleMessage} from './classes/messages/AgentThrottle';
import {AgentDataUpdateRequestMessage} from './classes/messages/AgentDataUpdateRequest';
import {RegionHandleRequestMessage} from './classes/messages/RegionHandleRequest';
import {RegionIDAndHandleReplyMessage} from './classes/messages/RegionIDAndHandleReply';
import * as Long from 'long';
import {MapItemRequestMessage} from './classes/messages/MapItemRequest';
import {GridItemType} from './enums/GridItemType';
import {MapItemReplyMessage} from './classes/messages/MapItemReply';
import {MapBlockRequestMessage} from './classes/messages/MapBlockRequest';
import {MapBlockReplyMessage} from './classes/messages/MapBlockReply';
import {MapInfoReply} from './events/MapInfoReply';
import {TeleportLureRequestMessage} from './classes/messages/TeleportLureRequest';
import {LureEvent} from './events/LureEvent';
import {TeleportFlags} from './enums/TeleportFlags';
import {TeleportProgressMessage} from './classes/messages/TeleportProgress';
import {TeleportStartMessage} from './classes/messages/TeleportStart';
import {SoundTriggerMessage} from './classes/messages/SoundTrigger';
import {AttachedSoundMessage} from './classes/messages/AttachedSound';
import {AvatarAnimationMessage} from './classes/messages/AvatarAnimation';
import {HTTPAssets} from './enums/HTTPAssets';
import * as LLSD from 'llsd';
import {TeleportEvent} from './events/TeleportEvent';
import {ClientEvents} from './classes/ClientEvents';
import {TeleportEventType} from './enums/TeleportEventType';
import {ClientCommands} from './classes/ClientCommands';
import {DisconnectEvent} from './events/DisconnectEvent';
import {KickUserMessage} from './classes/messages/KickUser';
import {StartPingCheckMessage} from './classes/messages/StartPingCheck';
import {CompletePingCheckMessage} from './classes/messages/CompletePingCheck';
import Timer = NodeJS.Timer;
export class Bot
{
private loginParams: LoginParameters;
private currentRegion: Region;
private agent: Agent;
private throttleGenCounter = 0;
private clientEvents: ClientEvents | null = null;
private ping: Timer | null = null;
private pingNumber = 0;
private lastSuccessfulPing = 0;
public clientEvents: ClientEvents | null = null;
public clientCommands: ClientCommands;
constructor(login: LoginParameters)
{
@@ -61,6 +51,7 @@ export class Bot
this.clientEvents = response.clientEvents;
this.currentRegion = response.region;
this.agent = response.agent;
this.clientCommands = new ClientCommands(response.region, response.agent, this);
resolve(response);
}).catch((error: Error) =>
{
@@ -69,6 +60,22 @@ export class Bot
});
}
changeRegion(region: Region)
{
return new Promise((resolve, reject) =>
{
this.currentRegion = region;
this.clientCommands = new ClientCommands(this.currentRegion, this.agent, this);
this.connectToSim().then(() =>
{
resolve();
}).catch((error) =>
{
reject(error);
});
});
}
close()
{
return new Promise((resolve, reject) =>
@@ -92,238 +99,21 @@ export class Bot
this.currentRegion.shutdown();
delete this.currentRegion;
delete this.agent;
resolve();
});
});
}
setBandwidth(total: number)
{
const circuit = this.currentRegion.circuit;
const agentThrottle: AgentThrottleMessage = new AgentThrottleMessage();
agentThrottle.AgentData = {
AgentID: this.agent.agentID,
SessionID: circuit.sessionID,
CircuitCode: 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
};
circuit.sendMessage(agentThrottle, PacketFlags.Reliable);
}
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.clientEvents === null)
delete this.clientCommands;
if (this.ping !== null)
{
reject(new Error('ClientEvents is null'));
return;
clearInterval(this.ping);
this.ping = null;
}
const subscription = this.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.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.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.connectToSim().then(() =>
{
resolve(e);
}).catch((error) =>
{
reject(e);
});
}
});
}
});
}
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) =>
const disconnectEvent = new DisconnectEvent();
disconnectEvent.requested = true;
disconnectEvent.message = 'Logout completed';
if (this.clientEvents)
{
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);
this.clientEvents.onDisconnected.next(disconnectEvent);
}
resolve();
});
});
}
@@ -363,7 +153,10 @@ export class Bot
return circuit.waitForAck(circuit.sendMessage(handshakeReply, PacketFlags.Reliable), 10000)
}).then(() =>
{
this.setBandwidth(1536000);
if (this.clientCommands !== null)
{
this.clientCommands.network.setBandwidth(1536000);
}
const agentRequest = new AgentDataUpdateRequestMessage();
agentRequest.AgentData = {
@@ -374,6 +167,67 @@ export class Bot
this.agent.setInitialAppearance();
this.agent.circuitActive();
this.lastSuccessfulPing = new Date().getTime();
this.ping = setInterval(() =>
{
this.pingNumber++;
if (this.pingNumber > 255)
{
this.pingNumber = 0;
}
const ping = new StartPingCheckMessage();
ping.PingID = {
PingID: this.pingNumber,
OldestUnacked: this.currentRegion.circuit.getOldestUnacked()
};
circuit.sendMessage(ping, PacketFlags.Reliable);
circuit.waitForMessage(Message.CompletePingCheck, 10000, ((pingData: {
pingID: number,
timeSent: number
}, packet: Packet): boolean =>
{
const cpc = packet.message as CompletePingCheckMessage;
if (cpc.PingID.PingID === pingData.pingID)
{
this.lastSuccessfulPing = new Date().getTime();
const pingTime = this.lastSuccessfulPing - pingData.timeSent;
if (this.clientEvents !== null)
{
this.clientEvents.onCircuitLatency.next(pingTime);
}
return true;
}
return false;
}).bind(this, {
pingID: this.pingNumber,
timeSent: new Date().getTime()
}));
if ((new Date().getTime() - this.lastSuccessfulPing) > 60000)
{
// We're dead, jim
this.agent.shutdown();
this.currentRegion.shutdown();
delete this.currentRegion;
delete this.agent;
delete this.clientCommands;
if (this.ping !== null)
{
clearInterval(this.ping);
this.ping = null;
}
const disconnectEvent = new DisconnectEvent();
disconnectEvent.requested = false;
disconnectEvent.message = 'Circuit timeout';
if (this.clientEvents)
{
this.clientEvents.onDisconnected.next(disconnectEvent);
}
}
}, 5000);
circuit.subscribeToMessages(
[
Message.TeleportFailed,
@@ -382,9 +236,7 @@ export class Bot
Message.TeleportStart,
Message.TeleportProgress,
Message.TeleportCancel,
Message.SoundTrigger,
Message.AttachedSound,
Message.AvatarAnimation
Message.KickUser
], (packet: Packet) =>
{
switch (packet.message.id)
@@ -448,24 +300,27 @@ export class Bot
this.clientEvents.onTeleportEvent.next(tpEvent);
break;
}
case Message.SoundTrigger:
case Message.KickUser:
{
const soundTrigger = packet.message as SoundTriggerMessage;
const soundID = soundTrigger.SoundData.SoundID;
// TODO: SoundTrigger clientEvent
break;
}
case Message.AttachedSound:
{
const attachedSound = packet.message as AttachedSoundMessage;
const soundID = attachedSound.DataBlock.SoundID;
// TODO: AttachedSound clientEvent
break;
}
case Message.AvatarAnimation:
{
const avatarAnimation = packet.message as AvatarAnimationMessage;
// TODO: AvatarAnimation clientEvent
const kickUser = packet.message as KickUserMessage;
this.agent.shutdown();
this.currentRegion.shutdown();
delete this.currentRegion;
delete this.agent;
delete this.clientCommands;
if (this.ping !== null)
{
clearInterval(this.ping);
this.ping = null;
}
const disconnectEvent = new DisconnectEvent();
disconnectEvent.requested = false;
disconnectEvent.message = Utils.BufferToStringSimple(kickUser.UserInfo.Reason);
if (this.clientEvents)
{
this.clientEvents.onDisconnected.next(disconnectEvent);
}
break;
}
}
@@ -479,46 +334,4 @@ export class Bot
});
});
}
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);
})
}
});
}
}

View File

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

View File

@@ -1,4 +0,0 @@
export class Assets
{
}

View File

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

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
import * as Long from 'long';
import {HTTPAssets} from "../enums/HTTPAssets";
import {HTTPAssets} from '../enums/HTTPAssets';
export class Utils
{

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

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

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

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

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

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

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

View File

@@ -0,0 +1,6 @@
import {CommandsBase} from './CommandsBase';
export class RegionCommands extends CommandsBase
{
}

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

View File

@@ -0,0 +1,7 @@
export enum InstantMessageEventFlags
{
normal = 0,
busyResponse = 1,
startTyping = 2,
finishTyping = 4
}

View File

@@ -0,0 +1,5 @@
export class DisconnectEvent
{
requested: boolean;
message: string;
}

View File

@@ -0,0 +1,4 @@
export class FriendRequestEvent
{
}

View File

@@ -0,0 +1,4 @@
export class GroupInviteEvent
{
}

View File

@@ -0,0 +1,13 @@
import {ChatSourceType} from '../enums/ChatSourceType';
import {UUID} from '../classes/UUID';
import {InstantMessageEventFlags} from '../enums/InstantMessageEventFlags';
export class InstantMessageEvent
{
source: ChatSourceType;
fromName: string;
from: UUID;
owner: UUID;
message: string;
flags: InstantMessageEventFlags;
}

View File

@@ -3,6 +3,7 @@ import {Vector3} from '../classes/Vector3';
export class LureEvent
{
from: UUID;
fromName: string;
lureMessage: string;
regionID: UUID;

View File

@@ -8,6 +8,9 @@ import {BVH} from './classes/BVH';
import {AssetType} from './enums/AssetType';
import {HTTPAssets} from './enums/HTTPAssets';
import {InstantMessageEventFlags} from './enums/InstantMessageEventFlags';
import {InstantMessageEvent} from './events/InstantMessageEvent';
import {ChatSourceType} from './enums/ChatSourceType';
export {
Bot,
@@ -15,5 +18,8 @@ export {
AssetType,
HTTPAssets,
ClientEvents,
BVH
BVH,
InstantMessageEvent,
InstantMessageEventFlags,
ChatSourceType
};