2020-01-06 12:10:40 +00:00
|
|
|
import { UUID } from './UUID';
|
|
|
|
|
import { Agent } from './Agent';
|
|
|
|
|
import { Region } from './Region';
|
|
|
|
|
import { Vector3 } from './Vector3';
|
|
|
|
|
import * as Long from 'long';
|
2025-01-17 23:37:54 +00:00
|
|
|
import type { ClientEvents } from './ClientEvents';
|
2020-01-06 12:10:40 +00:00
|
|
|
import { InventoryFolder } from './InventoryFolder';
|
2025-01-17 23:37:54 +00:00
|
|
|
import type { BotOptionFlags} from '..';
|
|
|
|
|
import { LoginFlags } from '..';
|
2020-11-23 10:32:32 +00:00
|
|
|
import { InventoryLibrary } from '../enums/InventoryLibrary';
|
2017-11-24 01:00:56 +00:00
|
|
|
|
|
|
|
|
export class LoginResponse
|
|
|
|
|
{
|
2025-01-17 23:37:54 +00:00
|
|
|
public loginFlags: LoginFlags;
|
|
|
|
|
public loginMessage: string;
|
|
|
|
|
public agent: Agent;
|
|
|
|
|
public region: Region;
|
|
|
|
|
public events: {
|
2017-11-24 01:00:56 +00:00
|
|
|
categories: {
|
|
|
|
|
categoryID: number,
|
|
|
|
|
categoryName: string
|
|
|
|
|
}[]
|
|
|
|
|
} = {
|
|
|
|
|
categories: []
|
|
|
|
|
};
|
2025-01-17 23:37:54 +00:00
|
|
|
public classifieds: {
|
2017-11-24 01:00:56 +00:00
|
|
|
categories: {
|
|
|
|
|
categoryID: number,
|
|
|
|
|
categoryName: string
|
|
|
|
|
}[]
|
|
|
|
|
|
|
|
|
|
} = {
|
|
|
|
|
categories: []
|
|
|
|
|
};
|
2025-01-17 23:37:54 +00:00
|
|
|
public searchToken: string;
|
|
|
|
|
public mfaHash?: string;
|
|
|
|
|
public clientEvents: ClientEvents;
|
2017-11-24 01:00:56 +00:00
|
|
|
|
2025-01-17 23:37:54 +00:00
|
|
|
public constructor(json: any, clientEvents: ClientEvents, options: BotOptionFlags)
|
2017-11-24 01:00:56 +00:00
|
|
|
{
|
2017-12-14 02:06:28 +00:00
|
|
|
this.clientEvents = clientEvents;
|
2017-11-30 04:11:59 +00:00
|
|
|
this.agent = new Agent(this.clientEvents);
|
2017-12-14 02:06:28 +00:00
|
|
|
this.region = new Region(this.agent, this.clientEvents, options);
|
2025-01-17 23:37:54 +00:00
|
|
|
if (json.agent_id)
|
2017-12-20 02:00:12 +00:00
|
|
|
{
|
2025-01-17 23:37:54 +00:00
|
|
|
this.agent.agentID = new UUID(json.agent_id);
|
2017-12-20 02:00:12 +00:00
|
|
|
}
|
|
|
|
|
|
2020-11-19 16:27:29 +00:00
|
|
|
for (const key of Object.keys(json))
|
2017-11-24 01:00:56 +00:00
|
|
|
{
|
|
|
|
|
const val: any = json[key];
|
|
|
|
|
switch (key)
|
|
|
|
|
{
|
|
|
|
|
case 'inventory-skeleton':
|
2020-11-19 16:27:29 +00:00
|
|
|
for (const item of val)
|
2017-11-24 01:00:56 +00:00
|
|
|
{
|
2020-11-23 10:32:32 +00:00
|
|
|
const folder = new InventoryFolder(InventoryLibrary.Main, this.agent.inventory.main, this.agent);
|
2025-01-17 23:37:54 +00:00
|
|
|
folder.typeDefault = parseInt(item.type_default, 10);
|
|
|
|
|
folder.version = parseInt(item.version, 10);
|
|
|
|
|
folder.name = String(item.name);
|
|
|
|
|
folder.folderID = new UUID(item.folder_id);
|
|
|
|
|
folder.parentID = new UUID(item.parent_id);
|
|
|
|
|
this.agent.inventory.main.skeleton.set(folder.folderID.toString(), folder);
|
2020-11-19 16:27:29 +00:00
|
|
|
}
|
2017-11-24 01:00:56 +00:00
|
|
|
break;
|
|
|
|
|
case 'inventory-skel-lib':
|
2020-11-19 16:27:29 +00:00
|
|
|
for (const item of val)
|
2017-11-24 01:00:56 +00:00
|
|
|
{
|
2020-11-23 10:32:32 +00:00
|
|
|
const folder = new InventoryFolder(InventoryLibrary.Library, this.agent.inventory.library, this.agent);
|
2025-01-17 23:37:54 +00:00
|
|
|
folder.typeDefault = parseInt(item.type_default, 10);
|
|
|
|
|
folder.version = parseInt(item.version, 10);
|
|
|
|
|
folder.name = String(item.name);
|
|
|
|
|
folder.folderID = new UUID(item.folder_id);
|
|
|
|
|
folder.parentID = new UUID(item.parent_id);
|
|
|
|
|
this.agent.inventory.library.skeleton.set(folder.folderID.toString(), folder);
|
2020-11-19 16:27:29 +00:00
|
|
|
}
|
2017-11-24 01:00:56 +00:00
|
|
|
break;
|
|
|
|
|
case 'inventory-root':
|
2017-12-19 23:43:00 +00:00
|
|
|
{
|
2025-01-17 23:37:54 +00:00
|
|
|
this.agent.inventory.main.root = new UUID(val[0].folder_id);
|
2020-11-23 10:32:32 +00:00
|
|
|
const folder = new InventoryFolder(InventoryLibrary.Main, this.agent.inventory.main, this.agent);
|
2017-12-19 23:43:00 +00:00
|
|
|
folder.typeDefault = 0;
|
|
|
|
|
folder.version = 0;
|
|
|
|
|
folder.name = 'root';
|
2025-01-17 23:37:54 +00:00
|
|
|
folder.folderID = new UUID(val[0].folder_id);
|
2017-12-19 23:43:00 +00:00
|
|
|
folder.parentID = UUID.zero();
|
2025-01-17 23:37:54 +00:00
|
|
|
this.agent.inventory.main.skeleton.set(folder.folderID.toString(), folder);
|
2017-11-24 01:00:56 +00:00
|
|
|
break;
|
2017-12-19 23:43:00 +00:00
|
|
|
}
|
2017-11-24 01:00:56 +00:00
|
|
|
case 'inventory-lib-owner':
|
2025-01-17 23:37:54 +00:00
|
|
|
this.agent.inventory.library.owner = new UUID(val[0].agent_id);
|
2017-11-24 01:00:56 +00:00
|
|
|
break;
|
|
|
|
|
case 'inventory-lib-root':
|
2017-12-19 23:43:00 +00:00
|
|
|
{
|
2025-01-17 23:37:54 +00:00
|
|
|
this.agent.inventory.library.root = new UUID(val[0].folder_id);
|
2020-11-23 10:32:32 +00:00
|
|
|
const folder = new InventoryFolder(InventoryLibrary.Library, this.agent.inventory.library, this.agent);
|
2017-12-19 23:43:00 +00:00
|
|
|
folder.typeDefault = 0;
|
|
|
|
|
folder.version = 0;
|
|
|
|
|
folder.name = 'root';
|
2025-01-17 23:37:54 +00:00
|
|
|
folder.folderID = new UUID(val[0].folder_id);
|
2017-12-19 23:43:00 +00:00
|
|
|
folder.parentID = UUID.zero();
|
2025-01-17 23:37:54 +00:00
|
|
|
this.agent.inventory.library.skeleton.set(folder.folderID.toString(), folder);
|
2017-11-24 01:00:56 +00:00
|
|
|
break;
|
2017-12-19 23:43:00 +00:00
|
|
|
}
|
2017-11-24 01:00:56 +00:00
|
|
|
case 'agent_access_max':
|
|
|
|
|
this.agent.accessMax = String(val);
|
|
|
|
|
break;
|
|
|
|
|
case 'event_notifications':
|
|
|
|
|
// dunno what this does just yet
|
|
|
|
|
break;
|
|
|
|
|
case 'secure_session_id':
|
|
|
|
|
this.region.circuit.secureSessionID = new UUID(val);
|
|
|
|
|
break;
|
|
|
|
|
case 'openid_token':
|
|
|
|
|
this.agent.openID.token = String(val);
|
|
|
|
|
break;
|
|
|
|
|
case 'region_x':
|
|
|
|
|
this.region.xCoordinate = parseInt(val, 10);
|
|
|
|
|
break;
|
|
|
|
|
case 'ao_transition':
|
|
|
|
|
this.agent.AOTransition = (val !== 0);
|
|
|
|
|
break;
|
|
|
|
|
case 'global-textures':
|
2020-11-19 16:27:29 +00:00
|
|
|
for (const obj of val)
|
2017-11-24 01:00:56 +00:00
|
|
|
{
|
2025-01-17 23:37:54 +00:00
|
|
|
if (obj.cloud_texture_id)
|
2017-11-24 01:00:56 +00:00
|
|
|
{
|
2025-01-17 23:37:54 +00:00
|
|
|
this.region.textures.cloudTextureID = obj.cloud_texture_id;
|
2017-11-24 01:00:56 +00:00
|
|
|
}
|
2025-01-17 23:37:54 +00:00
|
|
|
if (obj.sun_texture_id)
|
2017-11-24 01:00:56 +00:00
|
|
|
{
|
2025-01-17 23:37:54 +00:00
|
|
|
this.region.textures.sunTextureID = obj.sun_texture_id;
|
2017-11-24 01:00:56 +00:00
|
|
|
}
|
2025-01-17 23:37:54 +00:00
|
|
|
if (obj.moon_texture_id)
|
2017-11-24 01:00:56 +00:00
|
|
|
{
|
2025-01-17 23:37:54 +00:00
|
|
|
this.region.textures.moonTextureID = obj.moon_texture_id;
|
2017-11-24 01:00:56 +00:00
|
|
|
}
|
2020-11-19 16:27:29 +00:00
|
|
|
}
|
2017-11-24 01:00:56 +00:00
|
|
|
break;
|
2022-05-06 12:20:50 +01:00
|
|
|
case 'mfa_hash':
|
|
|
|
|
this.mfaHash = String(val);
|
|
|
|
|
break;
|
2017-11-24 01:00:56 +00:00
|
|
|
case 'search_token':
|
|
|
|
|
this.searchToken = String(val);
|
|
|
|
|
break;
|
|
|
|
|
case 'login-flags':
|
2025-01-17 23:37:54 +00:00
|
|
|
{
|
2023-11-09 18:06:49 +00:00
|
|
|
let flags: LoginFlags = 0 as LoginFlags;
|
2020-11-19 16:27:29 +00:00
|
|
|
for (const obj of val)
|
2017-11-24 01:00:56 +00:00
|
|
|
{
|
2025-01-17 23:37:54 +00:00
|
|
|
if (obj.ever_logged_in === 'Y')
|
2017-11-24 01:00:56 +00:00
|
|
|
{
|
|
|
|
|
flags = flags | LoginFlags.everLoggedIn;
|
|
|
|
|
}
|
2025-01-17 23:37:54 +00:00
|
|
|
if (obj.daylight_savings === 'Y')
|
2017-11-24 01:00:56 +00:00
|
|
|
{
|
|
|
|
|
flags = flags | LoginFlags.daylightSavings;
|
|
|
|
|
}
|
2025-01-17 23:37:54 +00:00
|
|
|
if (obj.stipend_since_login === 'Y')
|
2017-11-24 01:00:56 +00:00
|
|
|
{
|
|
|
|
|
flags = flags | LoginFlags.stipendSinceLogin;
|
|
|
|
|
}
|
2025-01-17 23:37:54 +00:00
|
|
|
if (obj.gendered === 'Y')
|
2017-11-24 01:00:56 +00:00
|
|
|
{
|
|
|
|
|
flags = flags | LoginFlags.gendered;
|
|
|
|
|
}
|
2020-11-19 16:27:29 +00:00
|
|
|
}
|
2017-11-24 01:00:56 +00:00
|
|
|
this.loginFlags = flags;
|
|
|
|
|
break;
|
2025-01-17 23:37:54 +00:00
|
|
|
}
|
2017-11-24 01:00:56 +00:00
|
|
|
case 'buddy-list':
|
2025-01-17 23:37:54 +00:00
|
|
|
{
|
2020-11-19 16:27:29 +00:00
|
|
|
for (const obj of val)
|
2017-11-24 01:00:56 +00:00
|
|
|
{
|
|
|
|
|
this.agent.buddyList.push({
|
2025-01-17 23:37:54 +00:00
|
|
|
buddyRightsGiven: obj.buddy_rights_given !== 0,
|
|
|
|
|
buddyID: new UUID(obj.buddy_id),
|
|
|
|
|
buddyRightsHas: obj.buddy_rights_has !== 0,
|
2017-11-24 01:00:56 +00:00
|
|
|
});
|
2020-11-19 16:27:29 +00:00
|
|
|
}
|
2017-11-24 01:00:56 +00:00
|
|
|
break;
|
2025-01-17 23:37:54 +00:00
|
|
|
}
|
2017-11-24 01:00:56 +00:00
|
|
|
case 'sim_port':
|
2017-11-26 01:14:02 +00:00
|
|
|
this.region.circuit.port = parseInt(val, 10);
|
2017-11-24 01:00:56 +00:00
|
|
|
break;
|
|
|
|
|
case 'sim_ip':
|
2017-11-26 01:14:02 +00:00
|
|
|
this.region.circuit.ipAddress = String(val);
|
2017-11-24 01:00:56 +00:00
|
|
|
break;
|
|
|
|
|
case 'agent_appearance_service':
|
2025-01-17 23:37:54 +00:00
|
|
|
{
|
2017-11-24 01:00:56 +00:00
|
|
|
this.agent.agentAppearanceService = val;
|
|
|
|
|
break;
|
2025-01-17 23:37:54 +00:00
|
|
|
}
|
2017-11-24 01:00:56 +00:00
|
|
|
case 'ui-config':
|
2020-11-19 16:27:29 +00:00
|
|
|
for (const item of val)
|
2017-11-24 01:00:56 +00:00
|
|
|
{
|
2025-01-17 23:37:54 +00:00
|
|
|
if (item.allow_first_life === 'Y')
|
2017-11-24 01:00:56 +00:00
|
|
|
{
|
|
|
|
|
this.agent.uiFlags.allowFirstLife = true;
|
|
|
|
|
}
|
2020-11-19 16:27:29 +00:00
|
|
|
}
|
2017-11-24 01:00:56 +00:00
|
|
|
break;
|
|
|
|
|
case 'look_at':
|
2020-01-07 21:01:20 +00:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
this.agent.cameraLookAt = LoginResponse.parseVector3(val);
|
|
|
|
|
}
|
2025-01-17 23:37:54 +00:00
|
|
|
catch (_error: unknown)
|
2020-01-07 21:01:20 +00:00
|
|
|
{
|
|
|
|
|
console.error('Invalid look_at from LoginResponse');
|
|
|
|
|
}
|
2017-11-24 01:00:56 +00:00
|
|
|
break;
|
|
|
|
|
case 'openid_url':
|
|
|
|
|
this.agent.openID.url = String(val);
|
|
|
|
|
break;
|
|
|
|
|
case 'max-agent-groups':
|
|
|
|
|
this.agent.maxGroups = parseInt(val, 10);
|
|
|
|
|
break;
|
|
|
|
|
case 'session_id':
|
|
|
|
|
this.region.circuit.sessionID = new UUID(val);
|
|
|
|
|
break;
|
|
|
|
|
case 'agent_flags':
|
|
|
|
|
this.agent.agentFlags = parseInt(val, 10);
|
|
|
|
|
break;
|
|
|
|
|
case 'event_categories':
|
2020-11-19 16:27:29 +00:00
|
|
|
for (const item of val)
|
2017-11-24 01:00:56 +00:00
|
|
|
{
|
|
|
|
|
this.events.categories.push({
|
2025-01-17 23:37:54 +00:00
|
|
|
'categoryID': parseInt(item.category_id, 10),
|
|
|
|
|
'categoryName': String(item.category_name)
|
2017-11-24 01:00:56 +00:00
|
|
|
});
|
2020-11-19 16:27:29 +00:00
|
|
|
}
|
2017-11-24 01:00:56 +00:00
|
|
|
break;
|
|
|
|
|
case 'start_location':
|
|
|
|
|
this.agent.startLocation = String(val);
|
|
|
|
|
break;
|
|
|
|
|
case 'agent_region_access':
|
|
|
|
|
this.agent.regionAccess = String(val);
|
|
|
|
|
break;
|
|
|
|
|
case 'last_name':
|
|
|
|
|
this.agent.lastName = String(val);
|
|
|
|
|
break;
|
|
|
|
|
case 'cof_version':
|
|
|
|
|
this.agent.cofVersion = parseInt(val, 10);
|
|
|
|
|
break;
|
|
|
|
|
case 'home':
|
|
|
|
|
this.agent.home = LoginResponse.parseHome(val);
|
|
|
|
|
break;
|
|
|
|
|
case 'classified_categories':
|
2020-11-19 16:27:29 +00:00
|
|
|
for (const item of val)
|
2017-11-24 01:00:56 +00:00
|
|
|
{
|
|
|
|
|
this.classifieds.categories.push({
|
2025-01-17 23:37:54 +00:00
|
|
|
'categoryID': parseInt(item.category_id, 10),
|
|
|
|
|
'categoryName': String(item.category_name)
|
2017-11-24 01:00:56 +00:00
|
|
|
});
|
2020-11-19 16:27:29 +00:00
|
|
|
}
|
2017-11-24 01:00:56 +00:00
|
|
|
break;
|
|
|
|
|
case 'snapshot_config_url':
|
|
|
|
|
this.agent.snapshotConfigURL = String(val);
|
|
|
|
|
break;
|
|
|
|
|
case 'region_y':
|
|
|
|
|
this.region.yCoordinate = parseInt(val, 10);
|
|
|
|
|
break;
|
|
|
|
|
case 'agent_access':
|
|
|
|
|
this.agent.agentAccess = String(val);
|
|
|
|
|
break;
|
|
|
|
|
case 'circuit_code':
|
|
|
|
|
this.region.circuit.circuitCode = parseInt(val, 10);
|
|
|
|
|
break;
|
|
|
|
|
case 'message':
|
|
|
|
|
this.loginMessage = String(val);
|
|
|
|
|
break;
|
|
|
|
|
case 'gestures':
|
2020-11-19 16:27:29 +00:00
|
|
|
for (const item of val)
|
2017-11-24 01:00:56 +00:00
|
|
|
{
|
|
|
|
|
this.agent.gestures.push({
|
2025-01-17 23:37:54 +00:00
|
|
|
'assetID': new UUID(item.asset_id),
|
|
|
|
|
'itemID': new UUID(item.item_id)
|
2017-11-24 01:00:56 +00:00
|
|
|
});
|
2020-11-19 16:27:29 +00:00
|
|
|
}
|
2017-11-24 01:00:56 +00:00
|
|
|
break;
|
|
|
|
|
case 'udp_blacklist':
|
2025-01-17 23:37:54 +00:00
|
|
|
{
|
2017-11-24 01:00:56 +00:00
|
|
|
const list = String(val).split(',');
|
|
|
|
|
this.region.circuit.udpBlacklist = list;
|
|
|
|
|
break;
|
2025-01-17 23:37:54 +00:00
|
|
|
}
|
2017-11-24 01:00:56 +00:00
|
|
|
case 'seconds_since_epoch':
|
|
|
|
|
this.region.circuit.timestamp = parseInt(val, 10);
|
|
|
|
|
break;
|
|
|
|
|
case 'seed_capability':
|
2017-11-30 04:11:59 +00:00
|
|
|
this.region.activateCaps(String(val));
|
2017-11-24 01:00:56 +00:00
|
|
|
break;
|
|
|
|
|
case 'first_name':
|
|
|
|
|
this.agent.firstName = String(val).replace(/"/g, '');
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-11-19 16:27:29 +00:00
|
|
|
}
|
2017-11-30 04:11:59 +00:00
|
|
|
this.agent.setCurrentRegion(this.region);
|
2017-11-24 01:00:56 +00:00
|
|
|
}
|
2025-01-17 23:37:54 +00:00
|
|
|
|
|
|
|
|
private static toRegionHandle(x_global: number, y_global: number): Long
|
|
|
|
|
{
|
|
|
|
|
let x_origin: number = x_global;
|
|
|
|
|
x_origin -= x_origin % 256;
|
|
|
|
|
let y_origin: number = y_global;
|
|
|
|
|
y_origin -= y_origin % 256;
|
|
|
|
|
return new Long(x_origin, y_origin, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static parseVector3(str: string): Vector3
|
|
|
|
|
{
|
|
|
|
|
const num = str.replace(/[[\]r\s]/g, '').split(',');
|
|
|
|
|
const x = parseFloat(num[0]);
|
|
|
|
|
const y = parseFloat(num[1]);
|
|
|
|
|
const z = parseFloat(num[2]);
|
|
|
|
|
if (isNaN(x) || isNaN(y) || isNaN(z))
|
|
|
|
|
{
|
|
|
|
|
throw new Error('Invalid Vector');
|
|
|
|
|
}
|
|
|
|
|
return new Vector3([x, y, z]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static parseHome(home: string | { region_handle: string, look_at: string, position: string }): {
|
|
|
|
|
'regionHandle'?: Long,
|
|
|
|
|
'position'?: Vector3,
|
|
|
|
|
'lookAt'?: Vector3
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
const result: {
|
|
|
|
|
'regionHandle'?: Long,
|
|
|
|
|
'position'?: Vector3,
|
|
|
|
|
'lookAt'?: Vector3
|
|
|
|
|
} = {};
|
|
|
|
|
|
|
|
|
|
let parseStart: { region_handle: string, look_at: string, position: string } | null = null;
|
|
|
|
|
if (typeof home === 'string')
|
|
|
|
|
{
|
|
|
|
|
const json = home.replace(/[[\]']/g, '"');
|
|
|
|
|
parseStart = JSON.parse(json);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
parseStart = home;
|
|
|
|
|
}
|
|
|
|
|
const parsed = parseStart as { region_handle: string, look_at: string, position: string };
|
|
|
|
|
if (parsed.region_handle)
|
|
|
|
|
{
|
|
|
|
|
const coords = parsed.region_handle.replace(/r/g, '').split(', ');
|
|
|
|
|
result.regionHandle = LoginResponse.toRegionHandle(parseInt(coords[0], 10), parseInt(coords[1], 10));
|
|
|
|
|
}
|
|
|
|
|
if (parsed.position)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
result.position = this.parseVector3('[' + parsed.position + ']');
|
|
|
|
|
}
|
|
|
|
|
catch (_error: unknown)
|
|
|
|
|
{
|
|
|
|
|
result.position = new Vector3([128.0, 128.0, 0.0]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (parsed.look_at)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
result.lookAt = this.parseVector3('[' + parsed.look_at + ']');
|
|
|
|
|
}
|
|
|
|
|
catch (_error: unknown)
|
|
|
|
|
{
|
|
|
|
|
result.lookAt = new Vector3([128.0, 128.0, 0.0]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2017-11-24 01:00:56 +00:00
|
|
|
}
|