//============================================================================= // TDDP_PreloadManager.js // Version: 1.1.1 //============================================================================= var Imported = Imported || {}; Imported.TDDP_PreloadManager = "1.1.1"; var TDDP = TDDP || {}; TDDP.PreloadManager = TDDP.PreloadManager || {}; //============================================================================= /*: * @plugindesc 1.1.1 Preload resources on scene/map load as well as game startup for a smoother gameplay experience. id:TDDP_PreloadManager * * @author Tor Damian Design / Galenmereth * * @param Preload On Map Load * @desc If you want to preload all assets found on a map upon loading the map, set this to true. * @default true * * @param Preload System Music * @desc If you want to preload all the Music specified in the Database System tab on startup, set this to true. * @default false * * @param Preload System SFX * @desc If you want to preload all the SFX specified in the Database System tab on startup, set this to true. * @default false * * @param Print Debug to Console * @desc If you want to see debug information in the console (F8) set this to true. * @default false * * @help =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~ * Introduction / Table of contents * =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~ * TDDP PreloadManager lets you preload resources on both startup (before the * game title screen displays) and on map load (in between map transfers) to * ensure resources such as pictures, music and sound effects are preloaded * before called. * * By default MV will stream the resources as they are required. This plugin * serves as an alternative for a smoother gameplay experience at the cost of * more bandwidth. * * This Plugin will load all resources in all event pages on the map, * regardless of if they will be triggered by the player at any time or not. * Since page conditions cannot be predicted as they are dependent on player * interaction, this is a necessity to ensure the right files are ready and * preloaded. * * For updates and easy to use documentation, please go to the plugin's website: * http://mvplugins.tordamian.com/?p=29 * * There you can also download a PDF of the documentation for offline use, and * having the documentation in one cleanly presented place means you can always * be sure it's the most recent available. * * Table of contents * ----------------- * 1. Installation * 2. Advanced Configuration * 3. Terms & Conditions * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * 1. Installation * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Drag and drop plugin .js file into your project's js/plugins folder, then * enable it in the editor interface. * * Make sure this plugin is placed at the top for maximum compatibility. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * 2. Advanced Configuration * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * There is an advanced configuration section if you open the plugin .js file * in a text editor. Look for BOOT PRELOAD CONFIG -- ADVANCED USERS. This lets * you define resources to preload on boot manually. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * 3. Terms & Conditions * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * This plugin is free for both non-commercial and commercial use. * * A big thank you to Degica for making this plugin free for commercial use for * everyone! * * MIT License * * Copyright (c) 2019 Tor Damian Design * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /* * ============================================================================= * BOOT PRELOAD CONFIG -- ADVANCED USERS * ============================================================================= * * Tip: You can omit the filename, it will assume .png since this is what MV * prefers. * * ----------------------------------------------------------------------------- * Image files to load on boot: * ----------------------------------------------------------------------------- * Keys: * animation * battleback1 * battleback2 * character * enemy * face * parallax * picture * svActor * svEnemy * system * tileset * title1 * title2 * * If you have subfolders in any of these folders, just prepend that to the * filename, like this example, where the picture "arrow" is in the "cursors" * subfolder within the system folder: * * system: [ * "balloon", * "cursors/arrow" * ] */ TDDP.bootPreloadImages = { /* Example face: [ "Actor3" ], system: [ "myFile", "subfolder/myOtherFile" ] */ } /* * * ----------------------------------------------------------------------------- * BGM files to load on boot * ----------------------------------------------------------------------------- */ TDDP.bootPreloadBGM = [ // "Town1" ] /* * * ----------------------------------------------------------------------------- * BGS files to load on boot * ----------------------------------------------------------------------------- */ TDDP.bootPreloadBGS = [ // "Quake" ] /* * * ----------------------------------------------------------------------------- * SFX files to load on boot. * ----------------------------------------------------------------------------- */ TDDP.bootPreloadSE = [ // "Open2" ] /* * * ----------------------------------------------------------------------------- * ME files to load on boot. * ----------------------------------------------------------------------------- */ TDDP.bootPreloadME = [ // "Shock1" ] //============================================================================= // END OF BOOT PRELOAD CONFIG //============================================================================= var PreloadManager; (function() { "use strict"; // Skip preloading if event test if (DataManager.isEventTest()) return; //============================================================================= // Setting up parameters //============================================================================= var parameters = $plugins.filter(function(p){return p.description.contains("id:TDDP_PreloadManager")})[0].parameters; var preloadOnMapLoad = Boolean(parameters['Preload On Map Load'] === 'true' || false); var preloadSystemMusic = Boolean(parameters['Preload System Music'] === 'true' || false); var preloadSystemSFX = Boolean(parameters['Preload System SFX'] === 'true' || false); var debug = Boolean(parameters['Print Debug to Console'] === 'true' || false); if(debug) console.log("========= TDDP PreloadManager: Debug mode on =========") PreloadManager = function() { throw new Error('This is a static class'); }; PreloadManager._callOnComplete = false; PreloadManager._filesLoaded = 0; PreloadManager._filesTotal = 0; PreloadManager._ready = false; PreloadManager._preloadedMaps = []; PreloadManager._preloadedAudio = []; PreloadManager._sessionRequestedImages = []; PreloadManager.callOnComplete = function(func) { this._callOnComplete = func; }; PreloadManager.start = function() { this._ready = true; this._sessionRequestedImages = []; this.controlIfReady(true); }; PreloadManager._projectPath = function() { var path = window.location.pathname.replace(/\/[^\/]*$/, "/"); if (path.match(/^\/([A-Z]\:)/)) { path = path.slice(1); } return decodeURIComponent(path); }; PreloadManager.controlAudioFileExistence = function(folder, filename) { this.controlFileExistence("audio/" + folder + "/", filename, [".m4a", ".ogg"]); }; PreloadManager.controlFileExistence = function(folder, filename, extensions) { if (StorageManager.isLocalMode() && Utils.isOptionValid('test')) { var fs = require("fs"); var path = this._projectPath() + folder + filename; for (var i=0, max=extensions.length; i < max; i++) { if (fs.existsSync(path + extensions[i])) return true; } throw new Error("PreloadManager: File " + folder + filename + " could not be found. Does it exist?") } }; PreloadManager.preloadImages = function(type, filename, hue) { if(filename.constructor === Array) { for(var i = 0; i < filename.length; i++) { this.preloadImages(type, filename[i], hue); } } else { if(filename.length > 0) { if (this._isImageRequested(type, filename)) return; var func = "load" + type.charAt(0).toUpperCase() + type.substr(1).toLowerCase(); if(typeof ImageManager[func] === 'undefined') { e = "PreloadManager: " + type + " is not a valid image load key. Check your configuration."; Graphics.printError(e); throw new Error(e); } this._increaseFileNums(); ImageManager[func](filename, hue).addLoadListener(this.onFileLoaded.bind(this, "(" + type + ") " + filename)); this._registerRequestedImage(type, filename); } } }; PreloadManager.preloadBGM = function(audioObject) { this.preloadAudio("bgm", audioObject); }; PreloadManager.preloadBGS = function(audioObject) { this.preloadAudio("bgs", audioObject); }; PreloadManager.preloadSE = function(audioObject) { this.preloadAudio("se", audioObject); } PreloadManager.preloadME = function(audioObject) { this.preloadAudio("me", audioObject); } PreloadManager.preloadAudio = function(type, audioObject) { if (!audioObject) return; if(audioObject.constructor === Array) { for(var i = 0, max = audioObject.length; i < max; i++) { this.preloadAudio(type, audioObject[i]); } } else { if(audioObject.name.length <= 0) return; if(this.isAudioCached(type, audioObject.name)) { if(debug) console.log(type + "/" + audioObject.name + " already preloaded; skipping."); return; } this._increaseFileNums(); this.controlAudioFileExistence(type, audioObject.name); var bufferObject = AudioManager.createBuffer(type, audioObject.name); bufferObject.addLoadListener(this.onAudioFileLoaded.bind(this, type, audioObject.name)); } } PreloadManager.preloadAnimation = function(animationId) { var animation = $dataAnimations[animationId]; this.preloadImages('animation', [animation.animation1Name, animation.animation2Name]); for(var i=0, max=animation.timings.length; i -1) { if(debug) console.log("Map " + mapDebugName + " already preloaded, skipping."); } else { if(debug) console.log("Map " + mapDebugName + " preload starting."); // Map is loaded, preload resources now this.preloadBGM($dataMap.bgm); this.preloadBGS($dataMap.bgs); this.preloadImages('battleback1', $dataMap.battleback1Name); this.preloadImages('battleback2', $dataMap.battleback2Name); this.preloadImages('parallax', $dataMap.parallaxName); // Cycle events and load appropriate resources for(var i = 0, max = $dataMap.events.length; i < max; i++) { var event = $dataMap.events[i]; if(!event) continue; for(var p = 0, pMax = event.pages.length; p < pMax; p++) { var page = event.pages[p]; // Preload character graphic for page this.preloadImages('character', page.image.characterName); for(var l = 0, lMax = page.list.length; l < lMax; l++) { var listEntry = page.list[l]; this.preloadEventListEntry(listEntry); } } }; this._preloadedMaps.push(mapId); } this.start(true); }; PreloadManager.preloadEventListEntry = function(listEntry) { var code = listEntry.code; var parameters = listEntry.parameters; switch(code) { // Show Picture case 231: this.preloadImages('picture', parameters[1]); break; // Play BGM case 241: this.preloadBGM(parameters[0]); break; // Play BGS case 245: this.preloadBGS(parameters[0]); break; // Play ME case 249: this.preloadME(parameters[0]); break; // Play SE case 250: this.preloadSE(parameters[0]); break; // Change Parallax case 284: this.preloadImages('parallax', parameters[0]); break; // Show Text case 101: this.preloadImages('face', parameters[0]); break; // Show Animation case 212: this.preloadAnimation(parameters[1]); break; } }; PreloadManager.onFileLoaded = function(filename) { this._filesLoaded += 1; if(debug) console.log("Loaded file: " + filename + "(" + this._filesLoaded + "/" + this._filesTotal + ")"); this.controlIfReady(); }; PreloadManager.onAudioFileLoaded = function(type, filename) { this._cacheAudio(type, filename); this.onFileLoaded("(" + type + ") " + filename); }; PreloadManager.controlIfReady = function(manual) { if(this.isReady()) { if(debug && !manual) console.log("All files loaded (" + this._filesLoaded + "/" + this._filesTotal + ")"); this._filesTotal = this._filesLoaded = 0; if(this._callOnComplete) { this._callOnComplete.call(); } } } PreloadManager._cacheAudio = function(path, filename) { this._preloadedAudio.push(path + filename); }; PreloadManager._registerRequestedImage = function(type, filename) { this._sessionRequestedImages.push(type + filename); }; PreloadManager._isImageRequested = function(type, filename) { return this._sessionRequestedImages.indexOf(type + filename) > -1; } PreloadManager.isAudioCached = function(path, filename) { return this._preloadedAudio.indexOf(path + filename) > -1; } PreloadManager._increaseFileNums = function() { this._ready = false; this._filesTotal +=1; }; PreloadManager.isReady = function() { if(this._filesLoaded >= this._filesTotal) { if(this._ready || this._filesTotal == 0) { return true; } } return false; }; var _isDatabaseLoaded = function() { DataManager.checkError(); for (var i = 0; i < DataManager._databaseFiles.length; i++) { if (!window[DataManager._databaseFiles[i].name]) { return false; } } return true; } //============================================================================= // Scene_Boot extensions //============================================================================= var Scene_Boot_prototype_create = Scene_Boot.prototype.create; Scene_Boot.prototype.create = function() { Scene_Boot_prototype_create.call(this); this._performPreload(); }; Scene_Boot.prototype._performPreload = function() { if(!_isDatabaseLoaded()) return setTimeout(this._performPreload.bind(this), 5); if(debug) console.log("========= TDDP PreloadManager: Boot Preload ========="); // Preload bootPreloadImages resources if(TDDP.bootPreloadImages) { for(var key in TDDP.bootPreloadImages) { if(TDDP.bootPreloadImages.hasOwnProperty(key)) { PreloadManager.preloadImages(key, TDDP.bootPreloadImages[key]); } } } // Preload bootPreloadBGM resources if(TDDP.bootPreloadBGM && TDDP.bootPreloadBGM.length > 0) { for(var i = 0, max = TDDP.bootPreloadBGM.length; i < max; i++) { PreloadManager.preloadBGM({ name: TDDP.bootPreloadBGM[i], volume: 90, pitch: 100 }); } } // Preload bootPreloadBGS resources if(TDDP.bootPreloadBGS && TDDP.bootPreloadBGS.length > 0) { for(var i = 0, max = TDDP.bootPreloadBGS.length; i < max; i++) { PreloadManager.preloadBGS({ name: TDDP.bootPreloadBGS[i], volume: 90, pitch: 100 }); } } // Preload bootPreloadSE resources if(TDDP.bootPreloadSE && TDDP.bootPreloadSE.length > 0) { for(var i = 0, max = TDDP.bootPreloadSE.length; i < max; i++) { PreloadManager.preloadSE({ name: TDDP.bootPreloadSE[i], volume: 90, pitch: 100 }); } } // Preload bootPreloadME resources if(TDDP.bootPreloadME && TDDP.bootPreloadME.length > 0) { for(var i = 0, max = TDDP.bootPreloadME.length; i < max; i++) { PreloadManager.preloadME({ name: TDDP.bootPreloadME[i], volume: 90, pitch: 100 }); } } // Preload system SFX if set if(preloadSystemSFX) { if(debug) console.log("========= TDDP PreloadManager: Boot Preloading System SFX ========="); for(var i = 0, max = $dataSystem.sounds.length; i < max; i++) { PreloadManager.preloadSE($dataSystem.sounds[i]); } } // Preload system BGM and ME if set if(preloadSystemMusic) { if(debug) console.log("========= TDDP PreloadManager: Boot Preloading System Music ========="); [ $dataSystem.titleBgm, $dataSystem.battleBgm, $dataSystem.boat.bgm, $dataSystem.ship.bgm, $dataSystem.airship.bgm, ].forEach(function(bgm) { PreloadManager.preloadBGM(bgm); }); [ $dataSystem.victoryMe, $dataSystem.defeatMe, $dataSystem.gameoverMe, ].forEach(function(me) { PreloadManager.preloadME(me); }); } PreloadManager.start(); }; //============================================================================= // DataManager extensions //============================================================================= if (preloadOnMapLoad) { var DataManager_loadMapData = DataManager.loadMapData; DataManager.loadMapData = function(mapId) { if(debug) console.log("========= TDDP PreloadManager: Map Preload ========="); this._preloaded = false; DataManager_loadMapData.call(this, mapId); PreloadManager.preloadMapResources(mapId); PreloadManager.callOnComplete(this._onPreloadDone.bind(this)); } DataManager._onPreloadDone = function() { this._preloaded = true; } var DataManager_isMapLoaded = DataManager.isMapLoaded; DataManager.isMapLoaded = function() { return (this.isMapDataLoaded() && this._preloaded); } DataManager.isMapDataLoaded = function() { return DataManager_isMapLoaded.call(this); } } //============================================================================= // Scene_Base extensions //============================================================================= var Scene_Base_prototype_isReady = Scene_Base.prototype.isReady; Scene_Base.prototype.isReady = function() { if(!PreloadManager.isReady()) return false; return Scene_Base_prototype_isReady.call(this); } //============================================================================= // Html5Audio extensions //============================================================================= /** * Sets up the Html5 Audio. * * @static * @method setup * @param {String} url The url of the audio file */ Html5Audio.setup = function (url) { if (!this._initialized) { this.initialize(); } this.clear(); this._load(url); // Changed from this._url = url to call the _load func; this func is never loaded by default }; /** * @static * @method _setupEventHandlers * @private */ Html5Audio._setupEventHandlers = function () { document.addEventListener('touchstart', this._onTouchStart.bind(this)); document.addEventListener('visibilitychange', this._onVisibilityChange.bind(this)); this._audioElement.addEventListener("canplaythrough", this._onLoadedData.bind(this)); // Changed from loaddata to canplaythrough, so it knows streaming is stable enough this._audioElement.addEventListener("error", this._onError.bind(this)); this._audioElement.addEventListener("ended", this._onEnded.bind(this)); }; /** * @static * @method _onLoadedData * @private */ Html5Audio._onLoadedData = function () { this._buffered = true; this._onLoad(); // I removed check for this._unlocked because that shouldn't matter }; })();