1
0
Fork 0
mirror of https://github.com/marcrobledo/RomPatcher.js.git synced 2025-06-27 16:25:54 +00:00

Created Embedding Rom Patcher JS (markdown)

Marc Robledo 2024-08-09 19:21:59 +02:00
parent 2326dfe417
commit 5ba1089794

209
Embedding-Rom-Patcher-JS.md Normal file

@ -0,0 +1,209 @@
# Embedding Rom Patcher JS in your site
If you are self-hosting your own translations and/or hack patches, you can embed Rom Patcher JS and provide a nice solution for your users, allowing them to easily apply your patches to their ROMs without requiring them to download a single file, all thanks to the magic of the web!
Take a look at [`index_template.html`](https://github.com/marcrobledo/RomPatcher.js/blob/master/index_template.html) for a template. Basically you need to:
1. [Download the latest version](https://github.com/marcrobledo/RomPatcher.js/releases) and copy the entire `rom-patcher-js/` folder to your site
2. Include **all** file imports from the `<header>` into yours:
```html
<link type="text/css" rel="stylesheet" href="./rom-patcher-js/style.css" media="all" />
<script type="text/javascript" src="./rom-patcher-js/modules/BinFile.js"></script>
...
<script type="text/javascript" src="./rom-patcher-js/RomPatcher.js"></script>
<script type="text/javascript" src="./rom-patcher-js/RomPatcher.webapp.js"></script>
```
3. Copy the needed HTML structure from `index_template.html`:
```html
<div id="rom-patcher-container">
...
</div>
```
4. Build a quick patcher with a simple call to `RomPatcherWeb.initialize`:
```html
<script type="text/javascript">
window.addEventListener('load', function(){
const myPatcherSettings={
language: 'en',
allowDropFiles: false /* if true, it adds drag and drop support,*/
};
RomPatcherWeb.initialize(myPatcherSettings, 'my_patch.ips');
});
</script>
```
&nbsp;
## Providing additional patch information
If you want to improve the user experience, you can provide additional information of your patches.<br/>
Instead of a simple file path, you can build a JSON object like this:
```js
RomPatcherWeb.initialize(myPatcherSettings, {
file: 'my_hack.ips',
name: 'My game improvement (v2.0)', //patch name that will appear in the dropdown button
inputCrc32: 0xdeadbeef, //add checksum validation to patch, will warn user if the ROM is not valid
description: 'This patch translates the game and fixes bugs!', //short description that will appear when user picks this patch
outputName: 'My game (Hack)' //patched ROM name
});
```
It is recommended, though, to store the patch or patches in a single zip file:
```js
RomPatcherWeb.initialize(myPatcherSettings, {
file: 'my_patches.zip', //zip containing patches
patches: [ //information about patches inside the zip
{
file: 'my_hack.ips', //required, must match the patch file name in the zip
name: 'My game improvement hack (v2.0)',
inputCrc32: [0xdeadbeef, 0xd0d0cafe], //an array of valid checksums
description: 'This patch translates the game and fixes bugs! (Recommended)',
outputName: 'My game improvement'
},
{
file: 'my_hack_vanilla.ips',
name: 'My game improvement hack (v2.0, no bugfixes)',
inputCrc32: [0xdeadbeef, 0xd0d0cafe],
description: 'This patch translates the game but keeps the original game\'s bugs untouched for a vanilla experience',
outputName: 'My game improvement'
},
/* ... */
]
});
```
&nbsp;
## Events
If you want to go further, you can run your own code via events:
```js
const myPatcherSettings={
language: 'en',
onloadrom: function (romFile) {
/* this event is triggered when user provides a ROM and before validating it */
/* can be used to: */
/* - modify it before validation (e.g. add/remove/fix header, change endianness...) */
/* - to switch to another patch file in the dropdown selector */
},
onvalidaterom: function (romFile, isRomValid) {
/* this event is triggered after ROM is validated */
/* can be used to show a custom error message if provided ROM is not valid */
},
onpatch: function (romFile) {
/* this event is triggered a ROM is patched */
/* can be used to modify it before the patched ROM file is saved */
}
};
```
In all events, the `romFile` parameter is an instance of [BinFile.js](https://github.com/marcrobledo/RomPatcher.js/blob/master/rom-patcher-js/modules/BinFile.js), which allows easy file data and name manipulation.
&nbsp;
### Example: Fix ROM endianness
N64 ROM files are usually stored in `.z64` (Big Endian) or `.n64` (Little Endian) formats. You can make your patcher compatible with both formats by changing the provided ROM file endianness before patching (and then restoring it after patching).<br/>
```js
const SSB_LITTE_ENDIAN_CRC32 = 0xf0b7c200;
var romIsLittleEndian;
RomPatcher.initialize(
{
onloadrom:function(romFile, patch){
/* if ROM is little endian */
if(romFile.getExtension()==='n64' && romFile.hashMD5()===SSB_LITTE_ENDIAN_CRC32){
/* change endianness to big */
romFile.swapBytes(4);
/* change extension */
romFile.setExtension('z64');
romIsLittleEndian=true;
}else{
romIsLittleEndian=false;
}
},
onpatch:function(patchedRomFile){
/* if ROM was little endian */
if(romIsLittleEndian){
/* revert endianness to little */
romFile.swapBytes(4);
/* revert extension */
romFile.setExtension('n64');
}
}
}, {
file: 'smashremix1.5.2.xdelta',
inputCrc32: 0xeb97929e,
name: 'Smash Remix v1.5.2',
outputName: 'Smash Remix v1.5.2 (Hack)'
}
);
```
&nbsp;
### Example: Choose correct patch automatically
If your zip file contains several patches for different ROMs, you can make Rom Patcher JS so it picks automatically the patch for the provided ROM.
```js
const SML2_CHECKSUM_WORLD = 0xd5ec24e4;
const SML2_CHECKSUM_JAPAN = 0xa715daf5;
const SML2_CHECKSUMS_INVALID = [0xe6f886e5, 0x635a9112, 0xbf733e10, 0x29e0911a];
RomPatcher.initialize(
{
onloadrom: function (romFile) {
const crc32 = romFile.hashCRC32();
/* if ROM region is USA/Europe */
if (crc32 === SML2_CHECKSUM_WORLD)
RomPatcherWeb.pickEmbededFile('SML2DXv181.ips');
/* if ROM region is Japan */
else if (crc32 === SML2_CHECKSUM_JAPAN)
RomPatcherWeb.pickEmbededFile('SML2DXv181_jap.ips');
},
onvalidaterom: function (romFile, isRomValid) {
const crc32 = romFile.hashCRC32();
/* if ROM is a known SML2 revision that is not compatible with the patch*/
if (!isRomValid && SML2_CHECKSUMS_INVALID.indexOf(crc32) !== -1)
RomPatcherWeb.setErrorMessage('Please provide a v1.0 SML2 ROM');
}
}, {
file: 'SML2DXv181.zip',
patches: [
{
file: 'SML2DXv181.ips',
name: 'Super Mario Land 2 DX - 6 Golden Coins (v1.8.1)',
inputCrc32: SML2_CHECKSUM_WORLD,
description: 'SML2 colorization hack (USA/Europe) by toruzz',
outputName: 'Super Mario Land 2 DX - 6 Golden Coins (Hack)',
outputExtension: 'gbc'
},
{
file: 'SML2DXv181_jap.ips',
name: 'Super Mario Land 2 DX - 6-tsu no Kinka (v1.8.1)',
inputCrc32: SML2_CHECKSUM_JAPAN,
description: 'SML2 colorization hack (Japan) by toruzz',
outputName: 'Super Mario Land 2 DX - 6-tsu no Kinka (Hack)',
outputExtension: 'gbc'
}
]
}
);
```
&nbsp;
### Example: Remove header
SNES ROM files are usually stored in `.sfc` (headerless) or `.smc` (headered) formats. You can make your patcher compatible with both formats by detecting if the ROM is headered and remove the header before the ROM is validated.<br/>
```js
RomPatcher.initialize(
{
onloadrom: function (romFile) {
const SMC_HEADER_SIZE=512;
if(romFile.getExtension()==='smc' && ((romFile.fileSize - SMC_HEADER_SIZE) % 0x20000) === 0){
romFile.removeLeadingBytes(SMC_HEADER_SIZE);
romFile.setExtension('sfc');
console.log('removed SMC header');
}
}
}, {
file: 'Tekkaman Blade v1.0.rup',
name: 'English translation by D and Near',
outputName: 'Uchuu no Kishi Tekkaman Blade (English v1.0)',
}
);
```