import { Alliance, Archaeology, BlackHoleGenerator, Body, Building, Capitol, Captcha, DistributionCenter, Development, Embassy, Empire, EnergyReserve, Entertainment, EssentiaVein, FoodReserve, GeneticsLab, Inbox, Intelligence, LibraryOfJith, Map, MercenariesGuild, MiningMinistry, MissionCommand, Network19, Observatory, OracleOfAnid, OreStorage, Park, Parliament, PlanetaryCommand, PoliceStation, Security, Shipyard, SpacePort, SpaceStationLab, StationCommand, Stats, SubspaceSupplyDepot, TempleOfTheDrajilites, TheDillonForge, ThemePark, Trade, Transporter, WasteExchanger, WasteRecycling, WaterStorage, } from './endpoints'; import Log from './core/log'; import Config from './core/config'; import Responses from './core/responses'; import Server from './core/server'; import Session from './core/session'; import { rpcLimitHandler } from './core/rpc-limit-handler'; import type { ResponseHandler } from './core/responses'; import type { RpcLimitHandlerOptions } from './core/rpc-limit-handler'; import { LacunaConfig } from './types'; import { version } from '../package.json'; import * as util from './core/util'; // Buildings with methods beyond the shared build/upgrade/downgrade/demolish/ // repair/get_stats_for_level/view set get a dedicated subclass here so // Lacuna#buildingFromUrl returns the right one. Every other building module // is served by the generic Building class. const BUILDING_SUBCLASSES: Record Building> = { archaeology: Archaeology, blackholegenerator: BlackHoleGenerator, capitol: Capitol, distributioncenter: DistributionCenter, development: Development, network19: Network19, oracleofanid: OracleOfAnid, geneticslab: GeneticsLab, waterstorage: WaterStorage, orestorage: OreStorage, foodreserve: FoodReserve, energyreserve: EnergyReserve, entertainment: Entertainment, themepark: ThemePark, wasteexchanger: WasteExchanger, wasterecycling: WasteRecycling, subspacesupplydepot: SubspaceSupplyDepot, thedillonforge: TheDillonForge, templeofthedrajilites: TempleOfTheDrajilites, park: Park, observatory: Observatory, libraryofjith: LibraryOfJith, embassy: Embassy, security: Security, intelligence: Intelligence, mercenariesguild: MercenariesGuild, miningministry: MiningMinistry, parliament: Parliament, trade: Trade, transporter: Transporter, missioncommand: MissionCommand, spacestationlab: SpaceStationLab, policestation: PoliceStation, stationcommand: StationCommand, planetarycommand: PlanetaryCommand, essentiavein: EssentiaVein, shipyard: Shipyard, spaceport: SpacePort, }; class Lacuna { version = version; alliance: Alliance; archaeology: Archaeology; blackHoleGenerator: BlackHoleGenerator; body: Body; capitol: Capitol; captcha: Captcha; config: Config; distributionCenter: DistributionCenter; development: Development; embassy: Embassy; empire: Empire; energyReserve: EnergyReserve; entertainment: Entertainment; essentiaVein: EssentiaVein; foodReserve: FoodReserve; geneticsLab: GeneticsLab; inbox: Inbox; intelligence: Intelligence; libraryOfJith: LibraryOfJith; log: Log; map: Map; mercenariesGuild: MercenariesGuild; miningMinistry: MiningMinistry; missionCommand: MissionCommand; network19: Network19; observatory: Observatory; oracleOfAnid: OracleOfAnid; oreStorage: OreStorage; park: Park; parliament: Parliament; planetaryCommand: PlanetaryCommand; policeStation: PoliceStation; responses: Responses; security: Security; server: Server; session: Session; shipyard: Shipyard; spacePort: SpacePort; spaceStationLab: SpaceStationLab; stationCommand: StationCommand; stats: Stats; subspaceSupplyDepot: SubspaceSupplyDepot; templeOfTheDrajilites: TempleOfTheDrajilites; theDillonForge: TheDillonForge; themePark: ThemePark; trade: Trade; transporter: Transporter; university: Building; wasteExchanger: WasteExchanger; wasteRecycling: WasteRecycling; waterStorage: WaterStorage; constructor(config: LacunaConfig = {}) { this.log = new Log(this); this.config = new Config(this, config); this.responses = new Responses(this); this.server = new Server(this); this.session = new Session(this); // // Endpoints // this.alliance = new Alliance(this, 'alliance'); this.archaeology = new Archaeology(this, 'archaeology'); this.blackHoleGenerator = new BlackHoleGenerator(this, 'blackholegenerator'); this.body = new Body(this, 'body'); this.capitol = new Capitol(this, 'capitol'); this.captcha = new Captcha(this, 'captcha'); this.distributionCenter = new DistributionCenter(this, 'distributioncenter'); this.development = new Development(this, 'development'); this.embassy = new Embassy(this, 'embassy'); this.empire = new Empire(this, 'empire'); this.energyReserve = new EnergyReserve(this, 'energyreserve'); this.entertainment = new Entertainment(this, 'entertainment'); this.essentiaVein = new EssentiaVein(this, 'essentiavein'); this.foodReserve = new FoodReserve(this, 'foodreserve'); this.geneticsLab = new GeneticsLab(this, 'geneticslab'); this.inbox = new Inbox(this, 'inbox'); this.intelligence = new Intelligence(this, 'intelligence'); this.libraryOfJith = new LibraryOfJith(this, 'libraryofjith'); this.map = new Map(this, 'map'); this.mercenariesGuild = new MercenariesGuild(this, 'mercenariesguild'); this.miningMinistry = new MiningMinistry(this, 'miningministry'); this.missionCommand = new MissionCommand(this, 'missioncommand'); this.network19 = new Network19(this, 'network19'); this.observatory = new Observatory(this, 'observatory'); this.oracleOfAnid = new OracleOfAnid(this, 'oracleofanid'); this.oreStorage = new OreStorage(this, 'orestorage'); this.park = new Park(this, 'park'); this.parliament = new Parliament(this, 'parliament'); this.planetaryCommand = new PlanetaryCommand(this, 'planetarycommand'); this.policeStation = new PoliceStation(this, 'policestation'); this.security = new Security(this, 'security'); this.shipyard = new Shipyard(this, 'shipyard'); this.spacePort = new SpacePort(this, 'spaceport'); this.spaceStationLab = new SpaceStationLab(this, 'ssla'); this.stationCommand = new StationCommand(this, 'stationcommand'); this.stats = new Stats(this, 'stats'); this.subspaceSupplyDepot = new SubspaceSupplyDepot(this, 'subspacesupplydepot'); this.templeOfTheDrajilites = new TempleOfTheDrajilites(this, 'templeofthedrajilites'); this.theDillonForge = new TheDillonForge(this, 'thedillonforge'); this.themePark = new ThemePark(this, 'themepark'); this.trade = new Trade(this, 'trade'); this.transporter = new Transporter(this, 'transporter'); this.university = new Building(this, 'university'); this.wasteExchanger = new WasteExchanger(this, 'wasteexchanger'); this.wasteRecycling = new WasteRecycling(this, 'wasterecycling'); this.waterStorage = new WaterStorage(this, 'waterstorage'); } async authenticate(name: string, password: string) { const { result, error } = await this.empire.login({ empire_name: name, password, api_key: this.config.apiKey, }); if (result) { this.session.set(result.session_id); this.log.info(`Logged in as ${name}`); } return { result, error }; } /** * Subscribes to every response this client receives, successful or not. * The handler is given the request that produced it, the resolved * ServerResponse, and a `retry` callback that re-issues the request. * * For a blocking error - an RPC limit ("slow down"), a captcha prompt, or a * rejected session (1006) - the originating call waits for every handler to * finish before returning, and adopts a response a handler returns - so * returning `await event.retry()` makes the caller see the retry's result * instead of the error. * * Returns a function that unsubscribes the handler. */ onResponse(handler: ResponseHandler) { return this.responses.subscribe(handler); } /** * Turns on the built-in handler for the server's RPC limit error, which * logs and retries with a progressive backoff until the call succeeds or * the retry limit is reached. Returns a function that turns it back off. */ enableRpcLimitHandler(options: RpcLimitHandlerOptions = {}) { return this.onResponse(rpcLimitHandler(this, options)); } buildingFromUrl(url: string) { const module = util.removeLeadingSlash(url); const BuildingClass = BUILDING_SUBCLASSES[module] || Building; return new BuildingClass(this, module); } } export default Lacuna;