Files
node-metaverse/lib/classes/commands/FriendCommands.ts
Casper Warden 41f79d969e Bit of tidyup
2021-09-22 15:34:53 +01:00

322 lines
14 KiB
TypeScript

import { CommandsBase } from './CommandsBase';
import { Region } from '../Region';
import { Agent } from '../Agent';
import { Bot } from '../../Bot';
import { Subscription } from 'rxjs';
import { Message } from '../../enums/Message';
import { Packet } from '../Packet';
import { OnlineNotificationMessage } from '../messages/OnlineNotification';
import { OfflineNotificationMessage } from '../messages/OfflineNotification';
import { TerminateFriendshipMessage } from '../messages/TerminateFriendship';
import { AcceptFriendshipMessage } from '../messages/AcceptFriendship';
import { ImprovedInstantMessageMessage } from '../messages/ImprovedInstantMessage';
import { InstantMessageDialog } from '../../enums/InstantMessageDialog';
import { Utils } from '../Utils';
import { DeclineFriendshipMessage } from '../messages/DeclineFriendship';
import { ChangeUserRightsMessage } from '../messages/ChangeUserRights';
import { FindAgentMessage } from '../messages/FindAgent';
import { IPAddress } from '../IPAddress';
import { FilterResponse } from '../../enums/FilterResponse';
import { GrantUserRightsMessage } from '../messages/GrantUserRights';
import { Friend } from '../public/Friend';
import { RightsFlags } from '../../enums/RightsFlags';
import { FriendOnlineEvent } from '../../events/FriendOnlineEvent';
import { FriendRemovedEvent } from '../../events/FriendRemovedEvent';
import { FriendRightsEvent } from '../../events/FriendRightsEvent';
import { UUID } from '../UUID';
import { PacketFlags } from '../../enums/PacketFlags';
import { MapLocation } from '../public/interfaces/MapLocation';
import { FriendRequestEvent } from '../../events/FriendRequestEvent';
import { FolderType } from '../../enums/FolderType';
import { Vector3 } from '../Vector3';
export class FriendCommands extends CommandsBase
{
friendMessages: Subscription;
friendsList: {
[key: string]: Friend
} = {};
constructor(region: Region, agent: Agent, bot: Bot)
{
super(region, agent, bot);
// FriendResponse is handled by Comms because it's part of the InstantMessageImproved module.
// We don't handle it here because it's always accompanied by an OnlineNotificationMessage.
this.friendMessages = this.circuit.subscribeToMessages([
Message.OnlineNotification,
Message.OfflineNotification,
Message.TerminateFriendship,
Message.ChangeUserRights
], async (packet: Packet) =>
{
switch (packet.message.id)
{
case Message.OnlineNotification:
{
const msg = packet.message as OnlineNotificationMessage;
for (const agentEntry of msg.AgentBlock)
{
const uuidStr = agentEntry.AgentID.toString();
if (this.friendsList[uuidStr] === undefined)
{
this.friendsList[uuidStr] = await this.bot.clientCommands.grid.avatarKey2Name(agentEntry.AgentID) as Friend;
this.friendsList[uuidStr].online = false;
this.friendsList[uuidStr].myRights = RightsFlags.None;
this.friendsList[uuidStr].theirRights = RightsFlags.None;
}
if (this.friendsList[uuidStr].online !== true)
{
this.friendsList[uuidStr].online = true;
const friendOnlineEvent = new FriendOnlineEvent();
friendOnlineEvent.friend = this.friendsList[uuidStr];
friendOnlineEvent.online = true;
this.bot.clientEvents.onFriendOnline.next(friendOnlineEvent);
}
}
break;
}
case Message.OfflineNotification:
{
const msg = packet.message as OfflineNotificationMessage;
for (const agentEntry of msg.AgentBlock)
{
const uuidStr = agentEntry.AgentID.toString();
if (this.friendsList[uuidStr] === undefined)
{
this.friendsList[uuidStr] = await this.bot.clientCommands.grid.avatarKey2Name(agentEntry.AgentID) as Friend;
this.friendsList[uuidStr].online = false;
this.friendsList[uuidStr].myRights = RightsFlags.None;
this.friendsList[uuidStr].theirRights = RightsFlags.None;
}
if (this.friendsList[uuidStr].online !== false)
{
this.friendsList[uuidStr].online = false;
const friendOnlineEvent = new FriendOnlineEvent();
friendOnlineEvent.friend = this.friendsList[uuidStr];
friendOnlineEvent.online = false;
this.bot.clientEvents.onFriendOnline.next(friendOnlineEvent);
}
}
break;
}
case Message.TerminateFriendship:
{
const msg = packet.message as TerminateFriendshipMessage;
const friendID = msg.ExBlock.OtherID;
const uuidStr = friendID.toString();
if (this.friendsList[uuidStr] !== undefined)
{
const event = new FriendRemovedEvent();
event.friend = this.friendsList[uuidStr];
this.bot.clientEvents.onFriendRemoved.next(event);
delete this.friendsList[uuidStr];
}
break;
}
case Message.ChangeUserRights:
{
const msg = packet.message as ChangeUserRightsMessage;
for (const rightsEntry of msg.Rights)
{
let uuidStr = '';
if (rightsEntry.AgentRelated.equals(this.agent.agentID))
{
// My rights
uuidStr = msg.AgentData.AgentID.toString();
if (this.friendsList[uuidStr] === undefined)
{
this.friendsList[uuidStr] = await this.bot.clientCommands.grid.avatarKey2Name(rightsEntry.AgentRelated) as Friend;
this.friendsList[uuidStr].online = false;
this.friendsList[uuidStr].myRights = RightsFlags.None;
this.friendsList[uuidStr].theirRights = RightsFlags.None;
}
this.friendsList[uuidStr].myRights = rightsEntry.RelatedRights;
}
else
{
uuidStr = rightsEntry.AgentRelated.toString();
if (this.friendsList[uuidStr] === undefined)
{
this.friendsList[uuidStr] = await this.bot.clientCommands.grid.avatarKey2Name(rightsEntry.AgentRelated) as Friend;
this.friendsList[uuidStr].online = false;
this.friendsList[uuidStr].myRights = RightsFlags.None;
this.friendsList[uuidStr].theirRights = RightsFlags.None;
}
this.friendsList[uuidStr].theirRights = rightsEntry.RelatedRights;
}
const friendRightsEvent = new FriendRightsEvent();
friendRightsEvent.friend = this.friendsList[uuidStr];
friendRightsEvent.theirRights = this.friendsList[uuidStr].theirRights;
friendRightsEvent.myRights = this.friendsList[uuidStr].myRights;
this.bot.clientEvents.onFriendRights.next(friendRightsEvent);
}
break;
}
}
});
}
async grantFriendRights(friend: Friend | UUID | string, rights: RightsFlags)
{
let friendKey = UUID.zero();
if (friend instanceof UUID)
{
friendKey = friend;
}
else if (friend instanceof Friend)
{
friendKey = friend.getKey();
}
else if (typeof friend === 'string')
{
friendKey = new UUID(friend);
}
else
{
throw new Error('"Friend" parameter must be Friend, UUID or string');
}
const request: GrantUserRightsMessage = new GrantUserRightsMessage();
request.AgentData = {
AgentID: this.agent.agentID,
SessionID: this.circuit.sessionID
};
request.Rights = [
{
'AgentRelated': friendKey,
'RelatedRights': rights
}
];
const sequenceNo = this.circuit.sendMessage(request, PacketFlags.Reliable);
return await this.circuit.waitForAck(sequenceNo, 10000);
}
async getFriendMapLocation(friend: Friend | UUID | string): Promise<MapLocation>
{
let friendKey = UUID.zero();
if (friend instanceof UUID)
{
friendKey = friend;
}
else if (friend instanceof Friend)
{
friendKey = friend.getKey();
}
else if (typeof friend === 'string')
{
friendKey = new UUID(friend);
}
else
{
throw new Error('"Friend" parameter must be Friend, UUID or string');
}
const request: FindAgentMessage = new FindAgentMessage();
request.AgentBlock = {
'Hunter': this.agent.agentID,
'Prey': friendKey,
'SpaceIP': IPAddress.zero()
};
request.LocationBlock = [
{
GlobalX: 0.0,
GlobalY: 0.0
}
];
this.circuit.sendMessage(request, PacketFlags.Reliable);
const response: FindAgentMessage = await this.circuit.waitForMessage<FindAgentMessage>(Message.FindAgent, 10000, (filterMsg: FindAgentMessage) =>
{
if (filterMsg.AgentBlock.Hunter.equals(this.agent.agentID) && filterMsg.AgentBlock.Prey.equals(friendKey))
{
return FilterResponse.Finish;
}
return FilterResponse.NoMatch;
});
const globalPos = Utils.RegionCoordinatesToHandle(response.LocationBlock[0].GlobalX, response.LocationBlock[0].GlobalY);
const mapInfo = await this.bot.clientCommands.grid.getRegionMapInfo(globalPos.regionX, globalPos.regionY);
return {
'regionName': mapInfo.block.name,
'mapImage': mapInfo.block.mapImage,
'regionHandle': globalPos.regionHandle,
'regionX': globalPos.regionX,
'regionY': globalPos.regionY,
'localX': Math.floor(globalPos.localX),
'localY': Math.floor(globalPos.localY),
'avatars': mapInfo.avatars
};
}
async acceptFriendRequest(event: FriendRequestEvent): Promise<void>
{
const accept: AcceptFriendshipMessage = new AcceptFriendshipMessage();
accept.AgentData = {
AgentID: this.agent.agentID,
SessionID: this.circuit.sessionID
};
accept.TransactionBlock = {
TransactionID: event.requestID
};
accept.FolderData = [];
accept.FolderData.push(
{
'FolderID': this.agent.inventory.findFolderForType(FolderType.CallingCard)
}
);
const sequenceNo = this.circuit.sendMessage(accept, PacketFlags.Reliable);
return await this.circuit.waitForAck(sequenceNo, 10000);
}
async rejectFriendRequest(event: FriendRequestEvent): Promise<void>
{
const reject: DeclineFriendshipMessage = new DeclineFriendshipMessage();
reject.AgentData = {
AgentID: this.agent.agentID,
SessionID: this.circuit.sessionID
};
reject.TransactionBlock = {
TransactionID: event.requestID
};
const sequenceNo = this.circuit.sendMessage(reject, PacketFlags.Reliable);
return await this.circuit.waitForAck(sequenceNo, 10000);
}
async sendFriendRequest(to: UUID | string, message: string): Promise<void>
{
if (typeof to === 'string')
{
to = new UUID(to);
}
const requestID = UUID.random();
const agentName = this.agent.firstName + ' ' + this.agent.lastName;
const im: ImprovedInstantMessageMessage = new ImprovedInstantMessageMessage();
im.AgentData = {
AgentID: this.agent.agentID,
SessionID: this.circuit.sessionID
};
im.MessageBlock = {
FromGroup: false,
ToAgentID: to,
ParentEstateID: 0,
RegionID: UUID.zero(),
Position: Vector3.getZero(),
Offline: 0,
Dialog: InstantMessageDialog.FriendshipOffered,
ID: requestID,
Timestamp: Math.floor(new Date().getTime() / 1000),
FromAgentName: Utils.StringToBuffer(agentName),
Message: Utils.StringToBuffer(message),
BinaryBucket: Utils.StringToBuffer('')
};
im.EstateBlock = {
EstateID: 0
};
const sequenceNo = this.circuit.sendMessage(im, PacketFlags.Reliable);
return await this.circuit.waitForAck(sequenceNo, 10000);
}
shutdown()
{
this.friendMessages.unsubscribe();
}
}