import { CommandsBase } from './CommandsBase'; import { Region } from '../Region'; import { TeleportEventType } from '../../enums/TeleportEventType'; import { TeleportLureRequestMessage } from '../messages/TeleportLureRequest'; import { Vector3 } from '../Vector3'; import { TeleportLocationRequestMessage } from '../messages/TeleportLocationRequest'; import * as Long from 'long'; import { Agent } from '../Agent'; import { Subscription } from 'rxjs'; import { TeleportEvent } from '../../events/TeleportEvent'; import { LureEvent } from '../../events/LureEvent'; import { TeleportFlags } from '../../enums/TeleportFlags'; import { PacketFlags } from '../../enums/PacketFlags'; import { RegionInfoReplyEvent } from '../../events/RegionInfoReplyEvent'; import { Bot } from '../../Bot'; import { Utils } from '../Utils'; export class TeleportCommands extends CommandsBase { private expectingTeleport = false; private teleportSubscription: Subscription; constructor(region: Region, agent: Agent, bot: Bot) { super(region, agent, bot); this.teleportSubscription = this.bot.clientEvents.onTeleportEvent.subscribe((e: TeleportEvent) => { if (e.eventType === TeleportEventType.TeleportCompleted) { if (!this.expectingTeleport) { if (e.simIP === 'local') { // Local TP - no need for any other shindiggery return; } const newRegion: Region = new Region(this.agent, this.bot.clientEvents, this.currentRegion.options); newRegion.circuit.circuitCode = this.currentRegion.circuit.circuitCode; newRegion.circuit.secureSessionID = this.currentRegion.circuit.secureSessionID; newRegion.circuit.sessionID = this.currentRegion.circuit.sessionID; newRegion.circuit.udpBlacklist = this.currentRegion.circuit.udpBlacklist; newRegion.circuit.ipAddress = e.simIP; newRegion.circuit.port = e.simPort; newRegion.activateCaps(e.seedCapability); this.bot.changeRegion(newRegion, false).then(() => { // Change region successful }).catch((error) => { console.log('Failed to change region'); console.error(error); }); } } }); } shutdown(): void { this.teleportSubscription.unsubscribe(); } private awaitTeleportEvent(requested: boolean): Promise { return new Promise((resolve, reject) => { if (this.currentRegion.caps.eventQueueClient) { if (this.bot.clientEvents === null) { reject(new Error('ClientEvents is null')); return; } this.expectingTeleport = true; const subscription = this.bot.clientEvents.onTeleportEvent.subscribe((e: TeleportEvent) => { if (e.eventType === TeleportEventType.TeleportFailed || e.eventType === TeleportEventType.TeleportCompleted) { setTimeout(() => { this.expectingTeleport = false; }); 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 const region: Region = new Region(this.agent, this.bot.clientEvents, this.currentRegion.options); 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; region.activateCaps(e.seedCapability); this.bot.changeRegion(region, requested).then(() => { resolve(e); }).catch((error) => { reject(error); }); } }); } else { reject(new Error('EventQueue not ready')); } }); } acceptTeleport(lure: LureEvent): Promise { return new Promise((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); this.awaitTeleportEvent(true).then((event: TeleportEvent) => { resolve(event); }).catch((err) => { reject(err); }); }); } teleportToRegionCoordinates(x: number, y: number, position: Vector3, lookAt: Vector3): Promise { const globalPos = Utils.RegionCoordinatesToHandle(x, y); return this.teleportToHandle(globalPos.regionHandle, position, lookAt); } teleportToHandle(handle: Long, position: Vector3, lookAt: Vector3): Promise { return new Promise((resolve, reject) => { const rtm = new TeleportLocationRequestMessage(); rtm.AgentData = { AgentID: this.agent.agentID, SessionID: this.circuit.sessionID }; rtm.Info = { LookAt: lookAt, Position: position, RegionHandle: handle }; this.circuit.sendMessage(rtm, PacketFlags.Reliable); this.awaitTeleportEvent(true).then((event: TeleportEvent) => { resolve(event); }).catch((err) => { reject(err); }); }); } teleportTo(regionName: string, position: Vector3, lookAt: Vector3): Promise { return new Promise((resolve, reject) => { this.bot.clientCommands.grid.getRegionByName(regionName).then((region: RegionInfoReplyEvent) => { this.teleportToHandle(region.handle, position, lookAt).then((event: TeleportEvent) => { resolve(event); }).catch((err) => { reject(err); }) }).catch((err) => { reject(err); }); }); } }