UNPKG

@geheimgang188/fmod-service-api

Version:
276 lines 23.6 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.FmodPlayer = void 0; const fmod_types_1 = require("./fmod-types"); const tiny_typed_emitter_1 = require("tiny-typed-emitter"); class FmodPlayer extends tiny_typed_emitter_1.TypedEmitter { constructor(api, bankDir, logger) { super(); this._initCalled = false; this._firstConnection = true; this._loadedBanksByName = new Map(); this._localisedBanks = new Set(); this._languages = new Set(); this._eventsByName = new Map(); this._globalParamsByName = new Map(); this._api = api; this._logger = logger; this._banks = new fmod_types_1.FmodBank(bankDir); } /** * Returns the current language, if localisation is enabled, and undefined otherwise. */ get currentLanguage() { return this._currentLanguage; } /** * Returns all events that have been registered for this player. */ get allEvents() { return Array.from(this._eventsByName.values()); } /** * Returns all global parameters that have been registered for this player. */ get allGlobalParameters() { return Array.from(this._globalParamsByName.values()); } /** * Initialise the player by connecting it to the FMOD service * using the provided API. */ init() { var _a, _b; if (this._initCalled) throw new Error('init() already called'); this._initCalled = true; (_a = this._logger) === null || _a === void 0 ? void 0 : _a.info('Initialising FMOD Player'); for (const event of this._eventsByName.values()) { event.init(this._api, this); } for (const param of this._globalParamsByName.values()) { param.init('global', this._api); } (_b = this._logger) === null || _b === void 0 ? void 0 : _b.info('Connecting to FMOD and loading banks'); this._api.connect(); this._api.once('connect', () => this.initBanks().catch(err => { var _a, _b; return (_a = this._logger) === null || _a === void 0 ? void 0 : _a.error(`Error initialising banks: ${(_b = err === null || err === void 0 ? void 0 : err.message) !== null && _b !== void 0 ? _b : err}`); })); this._api.on('reconnect', () => this.handleReconnect().catch(err => { var _a, _b; return (_a = this._logger) === null || _a === void 0 ? void 0 : _a.error(`Error trying to reconnect: ${(_b = err === null || err === void 0 ? void 0 : err.message) !== null && _b !== void 0 ? _b : err}`); })); this._api.on('disconnect', () => this.handleDisconnect()); } /** * Close the API connection. */ close() { this._api.disconnect(); } ensureBankLoaded(bankName) { return __awaiter(this, void 0, void 0, function* () { var _a, _b; if (this._loadedBanksByName.has(bankName)) { return; } let bankToLoad = bankName; const isLocalised = this.isLocalisedBank(bankName); if (isLocalised) { if (this._currentLanguage === undefined) { throw new Error(`Language not initialised!`); } bankToLoad = this._banks.localisedBankName(bankName, this._currentLanguage); } (_a = this._logger) === null || _a === void 0 ? void 0 : _a.info(`Bank ${bankName} not loaded, loading ${isLocalised ? 'localised ' : ''}bank ${bankToLoad} now`); try { yield this._api.loadBank(this._banks.bankPath(bankToLoad)); } catch (err) { if ((err === null || err === void 0 ? void 0 : err.message.indexOf('FMOD Exception 70')) >= 0) { // No issue, bank is loaded already, nothing more to do. (_b = this._logger) === null || _b === void 0 ? void 0 : _b.debug(`Bank ${bankName} is already loaded.`); } else { throw err; } } this._loadedBanksByName.set(bankName, { bankName, isLocalised, loadedLanguage: this._currentLanguage }); }); } ensureBankUnloaded(bankName, force) { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c, _d; if (!this._loadedBanksByName.has(bankName) && !force) { return; } const isLocalisedBank = this.isLocalisedBank(bankName); if (isLocalisedBank) { const bankInfo = this._loadedBanksByName.get(bankName); // If we know what language is loaded, unload it. // If not, any could be loaded, so unload all. if ((bankInfo === null || bankInfo === void 0 ? void 0 : bankInfo.loadedLanguage) !== undefined) { (_a = this._logger) === null || _a === void 0 ? void 0 : _a.debug(`Unloading localised bank ${bankName} in language ${bankInfo.loadedLanguage}`); yield this._api.unloadBank(this._banks.localisedBankPath(bankName, bankInfo.loadedLanguage)); } else { (_b = this._logger) === null || _b === void 0 ? void 0 : _b.debug(`Unloading all localised banks for ${bankName} because currently loaded language is unknown`); for (const lang of this._languages) { (_c = this._logger) === null || _c === void 0 ? void 0 : _c.debug(`Unloading localised bank ${bankName} in language ${lang}`); yield this._api.unloadBank(this._banks.localisedBankPath(bankName, lang)); } } } else { (_d = this._logger) === null || _d === void 0 ? void 0 : _d.debug(`Unloading non-localised bank ${bankName}`); yield this._api.unloadBank(this._banks.bankPath(bankName)); } this._loadedBanksByName.delete(bankName); }); } /** * * @param bankNames Banks which are localised. If e.g. Voice is localised, the player will load * Voice_en, Voice_de etc. according to the languages that have been configured. * @param languages Languages supported by the localised banks. This is the Locale Code in FMOD, * not the full name of the language. * @param initialLanguage Default language to use when none has been configured. */ configureLocalisation(bankNames, languages, initialLanguage) { if (this._initCalled) throw new Error('Localisation must be configured before initialisation.'); if (initialLanguage === undefined) throw new Error('Initial language must be provided.'); if (languages.indexOf(initialLanguage) < 0) throw new Error('Initial language must be a valid language.'); bankNames.forEach((bankName) => this._localisedBanks.add(bankName)); languages.forEach(language => this._languages.add(language)); this._defaultLanguage = initialLanguage; } /** * Set a new language. The language must have been configured in the localisation setup. * * Loading a new language causes localised banks to be unloaded in the previous language * and reloaded in the new language. */ setLanguage(language) { return __awaiter(this, void 0, void 0, function* () { var _a, _b; if (!this._languages.has(language)) throw new Error(`Invalid language ${language}, not configured.`); this._currentLanguage = language; for (const [bankName, bankInfo] of this._loadedBanksByName.entries()) { if (bankInfo.isLocalised) { if (bankInfo.loadedLanguage !== language) { (_a = this._logger) === null || _a === void 0 ? void 0 : _a.debug(`Unloading bank ${bankName} because its language is ${(_b = bankInfo.loadedLanguage) !== null && _b !== void 0 ? _b : 'unknown'}`); yield this.ensureBankUnloaded(bankName, true); yield this.ensureBankLoaded(bankName); } } } }); } resetAllParameters() { return __awaiter(this, void 0, void 0, function* () { for (const event of this._eventsByName.values()) { for (const param of event.params) { yield param.setDefaultValue(); } } for (const param of this.allGlobalParameters) { yield param.setDefaultValue(); } }); } /** * Stops **all** running events, including snapshots. */ stopAllEvents() { return this._api.stopStartedEvents(); } /** * Retrieves an event by its name (event path). */ getEvent(eventName) { const event = this._eventsByName.get(eventName); if (event === undefined) { throw new Error(`Event ${eventName} is not registered.`); } return event; } /** * Retrieves a global parameter by name (parameter path). */ getGlobalParameter(paramName) { const param = this._globalParamsByName.get(paramName); if (param === undefined) { throw new Error(`Parameter ${paramName} is not registered as global parameter.`); } return param; } /** * Registers an event so it can later on be retrieved with the `getEvent()` function. */ registerEvent(event) { if (this._eventsByName.has(event.eventName)) throw new Error(`Event ${event.eventName} is already registered.`); this._eventsByName.set(event.eventName, event); } /** * Registers a global parameter so it can later on be retrieved with the `getGlobalParameter()` function. */ registerGlobalParam(param) { if (this._globalParamsByName.has(param.name)) throw new Error(`Global parameter ${param.name} is already registered.`); this._globalParamsByName.set(param.name, param); } initBanks() { return __awaiter(this, void 0, void 0, function* () { this._loadedBanksByName.clear(); const loadedBanks = yield this._api.listLoadedBankPaths(); for (const bankName of loadedBanks) { // If a bank is localised, we don't know which one is currently loaded // as they all have the same path. this._loadedBanksByName.set(bankName, { bankName, isLocalised: this.isLocalisedBank(bankName), loadedLanguage: undefined, }); } // Master banks always have to be loaded. yield this.ensureBankLoaded('Master'); yield this.ensureBankLoaded('Master.strings'); if (this._defaultLanguage !== undefined) { yield this.setLanguage(this._defaultLanguage); } if (this._firstConnection) { this._firstConnection = false; setImmediate(() => this.emit('init')); } else { setImmediate(() => this.emit('reconnect')); } }); } handleReconnect() { return __awaiter(this, void 0, void 0, function* () { var _a; (_a = this._logger) === null || _a === void 0 ? void 0 : _a.warn(`Reconnected. Resetting loaded banks and initialising banks again.`); this._currentLanguage = undefined; yield this.initBanks(); }); } handleDisconnect() { var _a; (_a = this._logger) === null || _a === void 0 ? void 0 : _a.warn('FMOD API disconnected.'); } isLocalisedBank(bankName) { return this._localisedBanks.has(bankName); } } exports.FmodPlayer = FmodPlayer; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm1vZC1wbGF5ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBpLWdlbmVyYXRvci9mbW9kLXBsYXllci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7QUFBQSw2Q0FBdUQ7QUFDdkQsMkRBQWtEO0FBbUJsRCxNQUFzQixVQUE2RCxTQUFRLGlDQUE4QjtJQXdCckgsWUFBdUIsR0FBYSxFQUFFLE9BQWUsRUFBRSxNQUFnQjtRQUNuRSxLQUFLLEVBQUUsQ0FBQztRQWRKLGdCQUFXLEdBQUcsS0FBSyxDQUFDO1FBQ3BCLHFCQUFnQixHQUFHLElBQUksQ0FBQztRQUtmLHVCQUFrQixHQUFnQyxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBRTVELG9CQUFlLEdBQWdCLElBQUksR0FBRyxFQUFFLENBQUM7UUFDekMsZUFBVSxHQUFnQixJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQ3BDLGtCQUFhLEdBQTJCLElBQUksR0FBRyxFQUFFLENBQUM7UUFDbEQsd0JBQW1CLEdBQStCLElBQUksR0FBRyxFQUFFLENBQUM7UUFJekUsSUFBSSxDQUFDLElBQUksR0FBRyxHQUFHLENBQUM7UUFDaEIsSUFBSSxDQUFDLE9BQU8sR0FBRyxNQUFNLENBQUM7UUFDdEIsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLHFCQUFRLENBQUUsT0FBTyxDQUFFLENBQUM7SUFDMUMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsSUFBSSxlQUFlO1FBQ2YsT0FBTyxJQUFJLENBQUMsZ0JBQWdCLENBQUM7SUFDakMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsSUFBSSxTQUFTO1FBQ1QsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFFLElBQUksQ0FBQyxhQUFhLENBQUMsTUFBTSxFQUFFLENBQUUsQ0FBQztJQUNyRCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxJQUFJLG1CQUFtQjtRQUNuQixPQUFPLEtBQUssQ0FBQyxJQUFJLENBQUUsSUFBSSxDQUFDLG1CQUFtQixDQUFD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