This article was translated using "DeepL Translator".
This article will teach you to deploy your RPG Maker MV/MZ games using Electron.
This tutorial will use Windows 10 (1909) operating system.
Electron does not currently support Windows Vista and older versions of operating systems.
Update Info
2022/05/03 Update part of the article.
2022/05/01 Fix some contents of package.json.
2022/01/04 Add block the feature of capturing screen.
2021/11/12 Added encrypted content about asar files.
1.First, download Node.js for Windows OS from the following URL and install it on your computer.
https://nodejs.org/en/download/
2.After the installation is complete, type CMD
at the beginning to run the "Command Prompt", and type node -v
and npm -v
respectively to check if the installation is successful.
3.After creating a folder, and add a new file named “package.json” and edit the file to add the following syntax content.
After adding the following syntax, remember to remove // and the comments that follow.
{
"name": "RPG_Game", //The project name used for the output.
//It must be alphanumeric and not contain any half-space.
"version": "1.0.0", //Version number.
//The format must be in the numeric format X.X.X.
"description": "This is the Electron Deployment Test.", //File description.
"main": "index.js",
//[RPG Maker MZ]
"chromium-args": "--force-color-profile=srgb",
//[RPG Maker MV]
"js-flags": "--expose-gc",
"build": {
"appId": "com.rpgmaker.game", //Application ID.
//*You can usually enter com.xxxxx.yyyyy in alphanumeric format.
//xxxxx is the English name of your game title.
//yyyyy is the author's/team's name.
"productName": "Game", //Game Title.
"asar": true, //It is recommended to set this item to true if you need to seal the game content...
"afterPack": "./myAfterPackHook.js", // * If you need to use the "asarmor" encryption suite, please make sure to include this parameter.
"win": {
"icon": "icon/icon.ico", //Game icon, the image format is ico format.
//* Use the png to ico online conversion site and place the ico format image in the icon folder.
"target": {
"target": "dir"
}
}
},
"scripts": {
"start": "electron .",
"pack": "electron-builder --dir",
"dist": "electron-builder"
},
"author": "Mirai", //The author's/team's name.
"copyright": "Copyright © 2021 ${author} All rights reserved.", //Copyright Notice.
"devDependencies": {
"electron": "^11.5.0",
"electron-builder": "^22.5.1",
"asarmor": "^2.0.0" // * If you need to use the "asarmor" encryption suite...
}
}
If you need to use the "asarmor" encryption suite, create a file called "myAfterPackHook.js" and put the following code into this file and save it in this output folder.
const asarmor = require('asarmor');
const { join } = require("path");
exports.default = async ({ appOutDir, packager }) => {
try {
const asarPath = join(packager.getResourcesDir(appOutDir), 'app.asar');
console.log(`applying asarmor patches to ${asarPath}`);
const archive = await asarmor.open(asarPath);
archive.patch(); // apply default patches
await archive.write(asarPath);
} catch (err) {
console.error(err);
}
};
[Demo]
Then use the cd
command on the "Command Prompt" to specify the path to the folder, and enter the npm install
command on the "Command Prompt" to install the required package.
Remember that folder names can only be alphanumeric and do not contain a half-line margin. If you need to use a half-line margin, please replace it with a ( _ ).
4.Open the RPG Maker MV/MZ game project and click "File" → "Deployment…", select "Web Browsers / Android / iOS".
When using RPG Maker MV, select "Web Browsers" and then click "OK" to wait for the deployment to complete.
[RPG Maker MZ]
[RPG Maker MV]
5.Create an "index.js" file ,and enter the following:
const { app, BrowserWindow, ipcMain, shell } = require('electron');
function createWindow() {
const win = new BrowserWindow({
width: 816, //Screen Width
height: 624, //Screen Height
icon: 'icon/icon.png',
useContentSize: true,
autoHideMenuBar: true,
backgroundColor: '#000000',
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
})
const isTest = false; //Whether it is a test mode.
const testString = isTest ? '?test' : '';
app.allowRendererProcessReuse = false;
win.loadURL(`file://${__dirname}/index.html${testString}`);
if (process.platform !== 'darwin') {
win.setMenu(null);
}
require('electron').ipcMain.on('focusMainWindow', function (e) {
win.focus();
});
require('electron').ipcMain.on('openDevTools', function (e) {
win.webContents.openDevTools();
});
require('electron').ipcMain.on('openExternal', function (e, arg) {
shell.openExternal(arg);
});
//* Required with NekoGakuen_BlockedCapture.js plugin.
require('electron').ipcMain.on('setProtection', function (e, arg) {
win.setContentProtection(arg);
});
};
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
app.quit();
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
6.Go to the output folder ,and copy all the files except "package.json" and paste them into the output folder for this of Electron.
[RPG Maker MZ]
[RPG Maker MV]
7.Next, we will divide it into two projects and modify some of the contents in the js folder.
[RPG Maker MZ]
Modify "main.js", "rmmz_core.js" and "rmmz_managers.js" to the following.
isPathRandomized() {
// [Note] We cannot save the game properly when Gatekeeper Path
// Randomization is in effect.
return (
Utils.isNwjs() &&
process.mainModule.filename.startsWith("/private/var")
);
}
Replace..
isPathRandomized() {
// [Note] We cannot save the game properly when Gatekeeper Path
// Randomization is in effect.
if (Utils.isElectronjs()) {
return (__filename.startsWith("/private/var"));
} else {
return (Utils.isNwjs() &&
process.mainModule.filename.startsWith("/private/var"));
}
}
Utils.isNwjs = function() {
return typeof require === "function" && typeof process === "object";
};
Replace..
Utils.isNwjs = function() {
return typeof require === "function" && typeof process === "object";
};
Utils.isElectronjs = function () {
return window && window.process && window.process.versions && window.process.versions['electron'];
};
Utils.isOptionValid = function(name) {
const args = location.search.slice(1);
if (args.split("&").includes(name)) {
return true;
}
if (this.isNwjs() && nw.App.argv.length > 0) {
return nw.App.argv[0].split("&").includes(name);
}
return false;
};
Replace..
Utils.isOptionValid = function (name) {
const args = location.search.slice(1);
if (args.split("&").includes(name)) {
return true;
}
if (this.isElectronjs()) {
if (process.argv.length > 0) {
return process.argv[0].split("&").includes(name);
}
} else {
if (this.isNwjs() && nw.App.argv.length > 0) {
return nw.App.argv[0].split("&").includes(name);
}
}
return false;
};
StorageManager.fileDirectoryPath = function() {
const path = require("path");
const base = path.dirname(process.mainModule.filename);
return path.join(base, "save/");
};
Replace..
StorageManager.fileDirectoryPath = function () {
const path = require("path");
if (Utils.isElectronjs()) {
const base = path.dirname(__filename);
return Utils.isOptionValid('test') ? path.join(base, "save/") : path.join(base, '../../save/');
} else {
const base = path.dirname(process.mainModule.filename);
return path.join(base, "save/");
}
};
SceneManager.reloadGame = function () {
if (Utils.isNwjs()) {
chrome.runtime.reload();
}
};
SceneManager.showDevTools = function () {
if (Utils.isNwjs() && Utils.isOptionValid("test")) {
nw.Window.get().showDevTools();
}
};
Replace..
SceneManager.reloadGame = function () {
if (Utils.isElectronjs()) {
location.reload();
} else {
if (Utils.isNwjs()) {
chrome.runtime.reload();
}
}
};
SceneManager.showDevTools = function () {
if (Utils.isElectronjs()) {
if (Utils.isOptionValid("test")) {
require('electron').ipcRenderer.send('openDevTools');
}
} else {
if (Utils.isNwjs() && Utils.isOptionValid("test")) {
nw.Window.get().showDevTools();
}
}
};
[RPG Maker MV]
Modify “rpg_core.js” and “rpg_managers.js” to the following.
Utils.isNwjs = function() {
return typeof require === 'function' && typeof process === 'object';
};
Replace..
Utils.isNwjs = function() {
return typeof require === 'function' && typeof process === 'object';
};
Utils.isElectronjs = function() {
return window && window.process && window.process.versions && window.process.versions['electron'];
};
Utils.isOptionValid = function (name) {
if (location.search.slice(1).split('&').contains(name)) { return 1; };
if (typeof nw !== "undefined" && nw.App.argv.length > 0 && nw.App.argv[0].split('&').contains(name)) { return 1; };
return 0;
};
Replace..
Utils.isOptionValid = function (name) {
if (location.search.slice(1).split('&').contains(name)) { return 1; };
if (this.isElectronjs()) {
if (this.isNwjs() && process.argv.length > 0 && process.argv[0].split('&').contains(name)) { return 1; };
} else {
if (typeof nw !== "undefined" && nw.App.argv.length > 0 && nw.App.argv[0].split('&').contains(name)) { return 1; };
}
return 0;
};
Input._wrapNwjsAlert = function() {
if (Utils.isNwjs()) {
var _alert = window.alert;
window.alert = function() {
var gui = require('nw.gui');
var win = gui.Window.get();
_alert.apply(this, arguments);
win.focus();
Input.clear();
};
}
};
Replace..
Input._wrapNwjsAlert = function () {
if (Utils.isElectronjs()) {
var _alert = window.alert;
window.alert = function () {
_alert.apply(this, arguments);
require('electron').ipcRenderer.send('focusMainWindow');
Input.clear();
};
} else {
if (Utils.isNwjs()) {
var _alert = window.alert;
window.alert = function () {
var gui = require('nw.gui');
var win = gui.Window.get();
_alert.apply(this, arguments);
win.focus();
Input.clear();
};
}
}
};
StorageManager.localFileDirectoryPath = function() {
var path = require('path');
var base = path.dirname(process.mainModule.filename);
return path.join(base, 'save/');
};
Replace..
StorageManager.localFileDirectoryPath = function () {
var path = require('path');
if (Utils.isElectronjs()) {
var base = path.dirname(__filename);
return Utils.isOptionValid('test') ? path.join(base, 'save/') : path.join(base, '../../save/');
} else {
var base = path.dirname(process.mainModule.filename);
return path.join(base, 'save/');
}
};
SceneManager.initialize = function() {
this.initGraphics();
this.checkFileAccess();
this.initAudio();
this.initInput();
this.initNwjs();
this.checkPluginErrors();
this.setupErrorHandlers();
};
Replace..
SceneManager.initialize = function () {
this.initGraphics();
this.checkFileAccess();
this.initAudio();
this.initInput();
if (!Utils.isElectronjs()) {
this.initNwjs();
}
this.checkPluginErrors();
this.setupErrorHandlers();
};
SceneManager.onKeyDown = function (event) {
if (!event.ctrlKey && !event.altKey) {
switch (event.keyCode) {
case 116: // F5
if (Utils.isNwjs()) {
location.reload();
}
break;
case 119: // F8
if (Utils.isNwjs() && Utils.isOptionValid('test')) {
require('nw.gui').Window.get().showDevTools();
}
break;
}
}
};
Replace..
SceneManager.onKeyDown = function (event) {
if (!event.ctrlKey && !event.altKey) {
switch (event.keyCode) {
case 116: // F5
if (Utils.isElectronjs()) {
location.reload();
} else {
if (Utils.isNwjs()) {
location.reload();
}
}
break;
case 119: // F8
if (Utils.isElectronjs()) {
if (Utils.isOptionValid('test')) {
require('electron').ipcRenderer.send('openDevTools');
}
} else {
if (Utils.isNwjs() && Utils.isOptionValid('test')) {
require('nw.gui').Window.get().showDevTools();
}
}
break;
}
}
};
If the above is very complicated, you can also download quick start template directly from the following GitLab.
https://gitlab.com/mmmm748748/rpg_maker_mv_and_mz_electron/-/tree/en_US/
8.Go back to "Command Prompt" and type npm start
to check if the game can run normally. If the game runs OK, type npm run dist
to run the deployment output.
9.Finally, after the deployment is finished, you can find the contents of the deployment in the "dist/win-unpacked/" folder and run Game.exe.
https://github.com/electron/electron-quick-start
https://qiita.com/RaTTiE/items/63f2e351a93f81bc8039
https://a091234765.pixnet.net/blog/post/402450719-[electron學習筆記]electron安裝檔打包攻略補充_el
https://www.npmjs.com/package/asarmor
Mirai - Patreon:
https://www.patreon.com/MiraiDiary
Mirai - Twitter(X):
https://twitter.com/Mirai_so_Sad
Mirai - itch.io:
https://miraisosad.itch.io
Mirai - Instagram
https://www.instagram.com/miraisosad/
貓咪學園
NekoGakuen
RPG Maker
RPG Maker MV
RPG Maker MZ