From c87d450c463d8beefd8c46b64e40e75541b8805f Mon Sep 17 00:00:00 2001 From: ichijyo-hotaru <90632312+ichijyo-hotaru@users.noreply.github.com> Date: Mon, 20 Sep 2021 20:26:04 +0900 Subject: [PATCH] support dynamic patcher (#224) * support dynamic patcher * fix typo * fix createUI() * delete sample html * merge dynamicHex and dynamicString patch * fix dynamic patch constructor * use strict equality operator --- css/style.css | 12 +++ js/dllpatcher.js | 260 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 272 insertions(+) diff --git a/css/style.css b/css/style.css index 4d7c548..e2bfbf9 100644 --- a/css/style.css +++ b/css/style.css @@ -312,3 +312,15 @@ input[type=radio] { input[type=checkbox]:checked + .patchPreview { display: block; } +input[type=checkbox] ~ ul > li.patch-off { + display: none; +} +input[type=checkbox] ~ ul > li.patch-on { + display: list-item; +} +input[type=checkbox]:checked ~ ul > li.patch-on { + display: none; +} +input[type=checkbox]:checked ~ ul > li.patch-off { + display: list-item; +} \ No newline at end of file diff --git a/js/dllpatcher.js b/js/dllpatcher.js index 725cad7..7f114da 100644 --- a/js/dllpatcher.js +++ b/js/dllpatcher.js @@ -103,6 +103,263 @@ class StandardPatch { } } +class DynamicPatch { + constructor(options) { + this.name = options.name; + this.patches = options.patches; + this.tooltip = options.tooltip; + this.mode = options.mode; + this.target = options.target; + } + + createUI(parent) { + var id = createID(); + var label = this.name; + this.ui = $('
', {'class' : 'patch'}); + this.checkbox = $('')[0]; + this.ui.append(this.checkbox); + this.ui.append(''); + if(this.tooltip) { + this.ui.append('
' + this.tooltip + '
'); + } + parent.append(this.ui); + } + + updateUI(file) { + if (this.mode === 'all') { + this.checkbox.checked = this.checkPatchAll(file, true) === "on"; + } else { + this.checkbox.checked = this.checkPatch(file, true) === "on"; + } + } + + validatePatch(file) { + var status = this.mode === 'all' ? this.checkPatchAll(file) : this.checkPatch(file); + + if(status === "on") { + console.log('"' + this.name + '"', "is enabled!"); + } else if(status === "off") { + console.log('"' + this.name + '"', "is disabled!"); + } else { + return '"' + this.name + '" is neither on nor off! Have you got the right file?'; + } + } + + applyPatch(file) { + this.replaceAll(file, this.checkbox.checked); + } + + replaceAll(file, featureOn) { + for(var i = 0; i < this.patches.length; i++) { + if (Array.isArray(this.patches[i].offset)) { + this.patches[i].offset.forEach((offset) => { + if (this.target === 'string') { + replace(file, offset, + new TextEncoder().encode(featureOn? this.patches[i].on : this.patches[i].off)); + } else { + this.patches[i].on = this.patches[i].on.map((patch, idx) => patch === 'XX' ? file[offset + idx] : patch); + this.patches[i].off = this.patches[i].off.map((patch, idx) => patch === 'XX' ? file[offset + idx] : patch); + replace(file, offset, + featureOn? this.patches[i].on : this.patches[i].off) + } + } + ); + } else { + if (this.target === 'string') { + replace(file, this.patches[i].offset, + new TextEncoder().encode(featureOn? this.patches[i].on : this.patches[i].off)); + } else { + this.patches[i].on = this.patches[i].on.map((patch, idx) => patch === 'XX' ? file[this.patches[i].offset + idx] : patch); + this.patches[i].off = this.patches[i].off.map((patch, idx) => patch === 'XX' ? file[this.patches[i].offset + idx] : patch); + replace(file, this.patches[i].offset, + featureOn? this.patches[i].on : this.patches[i].off); + } + } + } + } + + checkPatch(file, updateUiFlag = false) { + var patchStatus = ""; + if (updateUiFlag) { + var listUi = $('