RPG Maker MZ
Core Improvements v1.2

This plugin might not seem to do much, but it adds some small tweaks to RPG Maker MZ that could improve the experience for both developers and players.

Download (18.91 kB, 27 times downloaded)

Placement

Make sure to place this plugin as high as possible, but possibly below any other core plugins by other creators (unless specified otherwise by the plugin), as this plugin might contain compatibility code for other plugins.

Usage

This plugin features various tweaks:

Data management

The data management tweaks are primarily for stand-alone games, as web storage always goes through the browser storage.

Save location

By default, RPG Maker MZ games store the save file in the application path. This tweak allows you to store it in the data path instead. In NW.js, this path depends on the OS. This also comes with the caveat that you do need to modify the application name in the package.json.

There's an additional option that uses the root folder of the data path, since the data path actually directs to a folder within the main folder, for example, on Windows, this path would be %localappdata%/<app-name>/User Data/Default. This extra option would reduce it to %localappdata%/<app-name>. Do note that the regular data path is safer to use, and you're more certain your OS won't reject it.

Finally, you can save your saves in the home folder. Files will be stored in a subfolder with the application name.

Save folder

The default save folder is 'save', which will automatically be made in the save location folder.

Save file extension

RPG Maker MZ picks the "rmmzsave" extension as the file extension of choice for save games. However, you might want to change this for your game if you so choose.

Configuration settings file name

By default, the configuration file is config.rmmzsave, or, if the save file extension has been edited, that extension will be used. However, with this setting, you can define your own config file name. Make sure you however add the extension manually. Leave empty if you want to use the default.

Script event tweaks

There are two tweaks for the script events. Both tweaks are enabled by default, but can be disabled if needed.

Combine multiple script blocks

This allows you to place multiple script events after each other and make them function as if they're one larger script. If you do need to add a break between two script blocks, make sure to place the following at the end of the script block:

//!EOS

This makes sure the next script block won't be part of the current script.

Note that this option has been made redundant, and is a leftover from the original MV script.

Optimize script execution

By default, JavaScript's eval function is used. Aside from potential security issues, eval is considered to be slow. Further more, each time the script block is being encountered, it has to re-read every line to be evaluated.

What this does is it stores the script in the first command block as a Function object, which is considered a lot faster.

Wait modes

You can create your own wait modes with parameters on top of creating them programmatically. There aren't a lot of instances where you would actually need to do this, as it's primarily for plugin developers, but just in case you do need to create your own wait mode, this gives you the option.

Note that you shouldn't overwrite the existing wait modes or wait modes added by other plugins, unless you know what you're doing. These are:

  • message
  • transfer
  • scroll
  • route
  • animation
  • balloon
  • action
  • gather
  • video
  • image

Note that this feature is only enabled when using Core Essentials v1.6.1 or higher.

Each entry has the following options:

Wait mode The name of the wait mode.
Callback The callback function. This should return true if it's still waiting, and false if it's done.

This plugin overwrites default functionality. Make sure you check whether or not the plugin is compatible with other plugins by checking which functions they overwrite. Below is the list of methods it overwrites:

  • StoreManager.fsMkdir
  • StorageManager.fileDirectoryPath
  • StorageManager.filePath
  • Game_Interpreter.prototype.command355

Download Core Improvements v1.1 (16.85 kB, 47 times downloaded)

Download Core Improvements v1.0 (14.87 kB, 56 times downloaded)

/******************************************************************************
 * CXJ_MZ_CoreImprovements.js                                                 *
 ******************************************************************************
 * By G.A.M. Kertopermono, a.k.a. GaryCXJk                                    *
 ******************************************************************************
 * License: MIT                                                               *
 ******************************************************************************
 * Copyright (c) 2022-2023, G.A.M. Kertopermono                               *
 *                                                                            *
 * 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.                                                  *
 ******************************************************************************/

/*:
 * @target MZ
 * @plugindesc Core plugin that adds small improvements.
 * @author G.A.M. Kertopermono
 *
 * @help
 * ============================================================================
 * = About                                                                    =
 * ============================================================================
 *
 * This plugin might not seem to do much, but it adds some small tweaks to RPG
 * Maker MZ that could improve the experience for both developers and players.
 *
 * ============================================================================
 * = Requirements                                                             =
 * ============================================================================
 *
 * This plugin requires the following plugins to work:
 *
 * * CXJ_MZ.CoreEssentials: ^1.0
 *
 * ============================================================================
 * = Placement                                                                =
 * ============================================================================
 *
 * Make sure to place this plugin below the plugins that this plugin requires,
 * but above plugins that rely on this plugin.
 *
 * ============================================================================
 * = Usage                                                                    =
 * ============================================================================
 *
 * This plugin features various tweaks:
 *
 * ---------------
 * Data management
 * ---------------
 *
 * The data management tweaks are primarily for stand-alone games, as web
 * storage always goes through the browser storage.
 *
 * Save location
 * -------------
 *
 * By default, RPG Maker MZ games store the save file in the application
 * path. This tweak allows you to store it in the data path instead. In
 * NW.js, this path depends on the OS. This also comes with the caveat
 * that you do need to modify the application name in the package.json.
 *
 * There's an additional option that uses the root folder of the data
 * path, since the data path actually directs to a folder within the
 * main folder, for example, on Windows, this path would be
 * %localappdata%/<app-name>/User Data/Default. This extra option would
 * reduce it to %localappdata%/<app-name>. Do note that the regular
 * data path is safer to use, and you're more certain your OS won't
 * reject it.
 *
 * Finally, you can save your saves in the home folder. Files will be stored
 * in a subfolder with the application name.
 *
 * Save folder
 * -----------
 *
 * The default save folder is 'save', which will automatically be made in
 * the save location folder.
 *
 * Save file extension
 * -------------------
 *
 * RPG Maker MZ picks the "rmmzsave" extension as the file extension of
 * choice for save games. However, you might want to change this for your
 * game if you so choose.
 *
 * Configuration settings file name
 * --------------------------------
 *
 * By default, the configuration file is config.rmmzsave, or, if the save
 * file extension has been edited, that extension will be used. However,
 * with this setting, you can define your own config file name. Make sure
 * you however add the extension manually. Leave empty if you want to
 * use the default.
 *
 * -------------------
 * Script event tweaks
 * -------------------
 *
 * There are two tweaks for the script events. Both tweaks are enabled by
 * default, but can be disabled if needed.
 *
 * Combine multiple script blocks
 * ------------------------------
 *
 * This allows you to place multiple script events after each other and make
 * them function as if they're one larger script. If you do need to add a
 * break between two script blocks, make sure to place the following at the
 * end of the script block:
 *
 *     //!EOS
 *
 * This makes sure the next script block won't be part of the current script.
 *
 * Note that this option has been made redundant, and is a leftover from the
 * original MV script.
 *
 * Optimize script execution
 * -------------------------
 *
 * By default, JavaScript's eval function is used. Aside from potential
 * security issues, eval is considered to be slow. Further more, each time
 * the script block is being encountered, it has to re-read every line to be
 * evaluated.
 *
 * What this does is it stores the script in the first command block as a
 * Function object, which is considered a lot faster.
 *
 * Wait modes
 * ----------
 *
 * You can create your own wait modes with parameters on top of creating them
 * programmatically. There aren't a lot of instances where you would actually
 * need to do this, as it's primarily for plugin developers, but just in case
 * you do need to create your own wait mode, this gives you the option.
 *
 * Note that you shouldn't overwrite the existing wait modes or wait modes
 * added by other plugins, unless you know what you're doing. These are:
 *
 * * message
 * * transfer
 * * scroll
 * * route
 * * animation
 * * balloon
 * * action
 * * gather
 * * video
 * * image
 *
 * Note that this feature is only enabled when using Core Essentials v1.6.1
 * or higher.
 *
 * Each entry has the following options:
 *
 * Wait mode - The name of the wait mode.
 * Callback  - The callback function. This should return true if it's still
 *             waiting, and false if it's done.
 *
 * ============================================================================
 * = Changelog                                                                =
 * ============================================================================
 *
 * 1.2 (2023-07-12)
 * ------------------
 * 
 * * Fixed: Issue with latest NW.JS version and the data path.
 * * Changed: Improved folder structuring settings.
 * 
 * 1.1 (2022-07-20)
 * ----------------
 *
 * * Added: Wait mode in the plugin parameters.
 * * Changed: Set script combining to false by default.
 *
 * 1.0 (2022-07-15)
 * ----------------
 *
 * * Initial release
 *
 * ============================================================================
 * = Compatibility                                                            =
 * ============================================================================
 *
 * This plugin overwrites default functionality. Make sure you check whether or
 * not the plugin is compatible with other plugins by checking which functions
 * they overwrite. Below is the list of methods it overwrites:
 *
 * * StoreManager.fsMkdir
 * * StorageManager.fileDirectoryPath
 * * StorageManager.filePath
 * * Game_Interpreter.prototype.command355
 *
 * ============================================================================
 * = License                                                                  =
 * ============================================================================
 *
 * Copyright (c) 2022, G.A.M. Kertopermono
 *
 * 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.
 *
 * ============================================================================
 *
 * @param dataManagement
 * @text Data management
 *
 * @param dataManagement.saveLocation
 * @text Save location
 * @desc Where the save data should be saved.
 * @parent dataManagement
 * @type select
 * @default app
 * @option Application path
 * @value app
 * @option Data path
 * @value dataPath
 * @option Data path root
 * @value dataPathRoot
 * @option Home path
 * @value home
 * 
 * @param dataManagement.includeGameId
 * @text Include Game ID
 * @desc Includes the Game ID in the save location.
 * Ignored when application path is used as save location.
 * @parent dataManagement
 * @type boolean
 * @on Include
 * @off Don't include
 * @default false
 * 
 * @param dataManagement.customGameIdentifier
 * @text Custom game identifier
 * @desc This will be used instead of the Game ID.
 * @parent dataManagement
 * @type text
 *
 * @param dataManagement.saveFolder
 * @text Save folder
 * @parent dataManagement
 * @type text
 * @default save
 *
 * @param dataManagement.saveExtension
 * @text Save file extension
 * @parent dataManagement
 * @type text
 * @default rmmzsave
 *
 * @param dataManagement.configFile
 * @text Configuration settings file name
 * @desc The game settings will be stored and read here.
 * Leave empty for default (config.<Save file extension>).
 * @parent dataManagement
 * @type text
 *
 * @param scriptEvent
 * @text Script event tweaks
 *
 * @param scriptEvent.combineMultipleScripts
 * @text Combine multiple script blocks
 * @desc Should the script blocks be interpreted as one block?
 * @parent scriptEvent
 * @type boolean
 * @on Combine
 * @off Don't combine
 * @default false
 *
 * @param scriptEvent.optimizeScriptExecution
 * @text Optimize script execution
 * @desc Should all script blocks be optimized into one function object?
 * @parent scriptEvent
 * @type boolean
 * @on Optimize
 * @off Don't optimize
 * @default true
 *
 * @param waitModes
 * @text Wait modes
 * @desc You can add wait modes through this parameter.
 * @type struct<WaitMode>[]
 */
/*~struct~WaitMode:
 * @param waitMode
 * @text Wait mode
 * @type text
 *
 * @param callback
 * @text Callback
 * @type multiline_string
 */

(() => {
  window.CXJ_MZ = window.CXJ_MZ || {};
  const {
    CXJ_MZ
  } = window;
  CXJ_MZ.CoreImprovements = CXJ_MZ.CoreImprovements || {};
  CXJ_MZ.CoreImprovements.version = '1.2';

  if (!CXJ_MZ.CoreEssentials) {
    throw new Error('CoreEssentials has not been initialized. Make sure you load CoreEssentials before this plugin.');
  }

  const hasVersion = {
    CoreEssentials: {
      '1.6.1': CXJ_MZ.CoreEssentials.isVersion('CXJ_MZ.CoreEssentials', '1.6.1'),
    },
  };

  const {
    CoreEssentials,
  } = CXJ_MZ;

  /* ------------------------------------------------------------------------
   * - Default parameters                                                   -
   * ------------------------------------------------------------------------
   */

  const parameters = CoreEssentials.getParameters('CXJ_MZ_CoreImprovements', {
    'dataManagement.saveLocation': 'app',
    'dataManagement.includeGameId': false,
    'dataManagement.customGameIdentifier': '',
    'dataManagement.saveFolder': 'save',
    'dataManagement.saveExtension': 'rmmzsave',
    'dataManagement.configFile': '',
    'scriptEvent.combineMultipleScripts': true,
    'scriptEvent.optimizeScriptExecution': true,
    waitModes: [],
  }, {
    'dataManagement.saveLocation': 'text',
    'dataManagement.includeGameId': 'boolean',
    'dataManagement.customGameIdentifier': 'text',
    'dataManagement.saveFolder': 'text',
    'dataManagement.saveExtension': 'text',
    'dataManagement.configFile': 'text',
    'scriptEvent.combineMultipleScripts': 'boolean',
    'scriptEvent.optimizeScriptExecution': 'boolean',
    waitModes: ['array', 'object', {
      waitMode: 'text',
      callback: 'function',
    }],
  });

  // All parameter wait modes get stored.
  if (hasVersion.CoreEssentials['1.6.1'] && parameters['waitModes'] && parameters['waitModes'].length) {
    parameters['waitModes'].forEach((data) => {
      const {
        waitMode,
        callback,
      } = data;

      CoreEssentials.addWaitMode(waitMode, callback);
    });
  }

  /* --------------------------------------------------------------------------
   * - Private functions                                                      -
   * -                                                                        -
   * - These are helper functions that aren't meant to be used outside the    -
   * - plugin.                                                                -
   * --------------------------------------------------------------------------
   */
  const getDataPath = (onRoot = false, includeGameId = false) => {
    const path = require('path');
    const appName = nw.App.manifest.name;
    const gameId = `${parameters['dataManagement.includeGameId'] || $dataSystem.advanced.gameId}`;
    let dataPath = nw.App.dataPath ?? nw.App.basePath;
    if (onRoot) {
      base = base.slice(0, base.indexOf(appName) + appName.length);
    }
    if (appName === 'rmmz-game' || includeGameId) {
      dataPath = path.join(dataPath, gameId);
    }
    return dataPath;
  }

  (() => {

    /* --------------------------------------------------------------------
     * - StoreManager.fsMkdir (Override)                                  -
     * --------------------------------------------------------------------
     */

    CoreEssentials.setNoConflict('StoreManager.fsMkdir');
    StorageManager.fsMkdir = function(path) {
      const fs = require('fs');
      if (!fs.existsSync(path)) {
        // Ensures that folders are created recursively.
        fs.mkdirSync(path, {
          recursive: true,
        });
      }
    };

    /* --------------------------------------------------------------------
     * - StorageManager.fileDirectoryPath (Override)                      -
     * --------------------------------------------------------------------
     */

    CoreEssentials.setNoConflict('StorageManager.fileDirectoryPath');
    StorageManager.fileDirectoryPath = function() {
      const path = require('path');
      const os = require('os');
      let base = '';
      const saveLocation = parameters['dataManagement.saveLocation'];
      const includeGameId = parameters['dataManagement.includeGameId'];
      // We'll need to make sure there's a trailing slash in the path name.
      const saveFolder = parameters['dataManagement.saveFolder'].replace(/[\\\/]*$/, '/');
      const appName = nw.App.manifest.name;
      const gameId = `${parameters['dataManagement.includeGameId'] || $dataSystem.advanced.gameId}`;
      switch (saveLocation) {
        case 'dataPath':
          base = getDataPath(false, includeGameId);
          break;
        case 'dataPathRoot':
          base = getDataPath(true, includeGameId);
          break;
        case 'home':
          base = path.join(os.homedir(), appName);
          if (includeGameId) {
            base = path.join(base, gameId);
          }
        case 'app':
        default:
          base = global.__dirname;
          break;
      }
      return path.join(base, saveFolder);
    };

    /* --------------------------------------------------------------------
     * - StorageManager.filePath (Override)                               -
     * --------------------------------------------------------------------
     */

    CoreEssentials.setNoConflict('StorageManager.filePath');
    StorageManager.filePath = function(saveName) {
      const dir = this.fileDirectoryPath();
      const ext = parameters['dataManagement.saveExtension'].replace(/^\.*/, '.');
      const saveFile = parameters[`dataManagement.${saveName}File`] || `${saveName}${ext}`;
      return `${dir}${saveFile}`;
    };

    /* --------------------------------------------------------------------
     * - Game_Interpreter.prototype.command355 (Override)                 -
     * --------------------------------------------------------------------
     */

    /**
     * @method command355
     * @private
     */
    CoreEssentials.setNoConflict('Game_Interpreter.prototype.command355');
    Game_Interpreter.prototype.command355 = function() {
      const current = this.currentCommand();
      const optimize = parameters['scriptEvent.optimizeScriptExecution'];
      const combine = parameters['scriptEvent.combineMultipleScripts'];
      let script = `${current.parameters[0]}\n`;
      let count = 0;
      while (this.nextEventCode() === 655 || (
        combine &&
        this.nextEventCode() === 355 &&
        this.currentCommand().parameters[0].trim() !== '//!EOS'
      )) {
        this._index++;
        count++;
        script = `${script}${this.currentCommand().parameters[0]}\n`;
      }
      if (optimize) {
        if (current._reloader) {
          this._index+= current._reloader.count;
        } else {
          current._reloader = {
            count,
            func: new Function(script),
          };
        }
        current._reloader.func.call(this);
      } else {
        eval(script);
      }
    }
  })();
})();
                                

Creator: GaryCXJk

Release date: 2022-07-20

Last updated: 2023-07-12

Downloads: 0

License: The MIT License

Requirements: