diff --git a/js/dllpatcher.js b/js/dllpatcher.js index a99ef0d..8f56525 100644 --- a/js/dllpatcher.js +++ b/js/dllpatcher.js @@ -3,8 +3,148 @@ mods = null; filename = null; errorLog = ""; +// Each unique kind of patch should have createUI, validatePatch, applyPatch, +// updateUI + +StandardPatch = function(options) { + this.name = options.name; + this.shortname = options.shortname; + this.patches = options.patches; +}; + +StandardPatch.prototype.createUI = function(parent) { + var id = this.shortname; + var label = this.name; + parent.append('
'); +}; + +StandardPatch.prototype.updateUI = function(file) { + var id = this.shortname; + var elem = document.getElementById(id); + elem.checked = this.checkPatchBytes(file) == "on"; +}; + +StandardPatch.prototype.validatePatch = function(file) { + var status = this.checkPatchBytes(file); + if(status == "on") { + console.log('"' + this.name + '"', "is enabled!"); + } else if(status == "off") { + console.log('"' + this.name + '"', "is disabled!"); + } else { + success = false; + return '"' + this.name + '" is neither on nor off! Have you got the right dll?'; + } +}; + +StandardPatch.prototype.applyPatch = function(file) { + id = this.shortname; + var enabled = document.getElementById(id).checked; + this.replaceAll(file, enabled); + return enabled ? this.shortname : ""; +}; + +StandardPatch.prototype.replaceAll = function(file, featureOn) { + for(var i = 0; i < this.patches.length; i++) { + replace(file, this.patches[i].offset, + featureOn? this.patches[i].on : this.patches[i].off); + } +} + +StandardPatch.prototype.checkPatchBytes = function(file) { + var patchStatus = ""; + for(var i = 0; i < this.patches.length; i++) { + var patch = this.patches[i]; + if(bytesMatch(file, patch.offset, patch.off)) { + if(patchStatus == "") { + patchStatus = "off"; + } else if(patchStatus != "off"){ + return "on/off mismatch within patch"; + } + } else if(bytesMatch(file, patch.offset, patch.on)) { + if(patchStatus == "") { + patchStatus = "on"; + } else if(patchStatus != "on"){ + return "on/off mismatch within patch"; + } + } else { + return "patch neither on nor off"; + } + } + return patchStatus; +} + +// Each unique kind of patch should have createUI, validatePatch, applyPatch, +// updateUI + +// The DEFAULT state is always the 1st element in the patches array +UnionPatch = function(options) { + this.name = options.name; + this.shortname = options.shortname; + this.offset = options.offset; + this.patches = options.patches; +}; + +UnionPatch.prototype.createUI = function(parent) { + var container = $("
", {"class": "patch-union"}); + container.append('' + this.name + ':'); + for(var i = 0; i < this.patches.length; i++) { + var patch = this.patches[i]; + var id = this.shortname + '-' + patch.shortname; + var label = patch.name; + container.append('
'); + } + parent.append(container); +}; + +UnionPatch.prototype.updateUI = function(file) { + for(var i = 0; i < this.patches.length; i++) { + if(bytesMatch(file, this.offset, this.patches[i].patch)) { + document.getElementById(this.shortname + '-' + this.patches[i].shortname).checked = true; + return; + } + } + // Default fallback + document.getElementById(this.shortname + '-' + this.patches[0].shortname).checked = true; +}; + +UnionPatch.prototype.validatePatch = function(file) { + for(var i = 0; i < this.patches.length; i++) { + if(bytesMatch(file, this.offset, this.patches[i].patch)) { + console.log(this.name, "has", this.patches[i].name, "enabled"); + return; + } + } + return '"' + this.name + '" doesn\'t have a valid patch! Have you got the right dll?'; +}; + +UnionPatch.prototype.applyPatch = function(file) { + var patch = this.getSelected(); + var name = this.shortname + patch.shortname; + replace(file, this.offset, patch.patch); + return patch.shortname == "default" ? "" : name; +}; + +UnionPatch.prototype.getSelected = function() { + for(var i = 0; i < this.patches.length; i++) { + if(document.getElementById(this.shortname + '-' + this.patches[i].shortname).checked) { + return this.patches[i]; + } + } + return null; +} + DllPatcher = function(fname, args) { - mods = args; + mods = []; + for(var i = 0; i < args.length; i++) { + mod = args[i]; + if(mod.type) { + if(mod.type == "union") { + mods.push(new UnionPatch(mod)); + } + } else { // standard patch + mods.push(new StandardPatch(mod)); + } + } filename = fname; loadPatchUI(); }; @@ -33,11 +173,9 @@ saveDll = function() { var fname = filename; for(var i = 0; i < mods.length; i++) { - id = mods[i].shortname; - var enabled = document.getElementById(id).checked; - replaceAll(dllFile, mods[i].patches, enabled); - if(enabled) { - fname += '-' + id; + var enabledStr = mods[i].applyPatch(dllFile); + if(enabledStr) { + fname += '-' + enabledStr; } } fname += '.dll'; @@ -49,67 +187,29 @@ saveDll = function() { loadPatchUI = function() { var patchDiv = $('#patches'); for(var i = 0; i < mods.length; i++) { - var id = mods[i].shortname; - var name = mods[i].name; - patchDiv.append('
'); + mods[i].createUI(patchDiv); } } updatePatchUI = function() { for(var i = 0; i < mods.length; i++) { - var id = mods[i].shortname; - var elem = document.getElementById(id); - elem.checked = checkPatchBytes(mods[i].patches) == "on"; + mods[i].updateUI(dllFile); } } -buildError = function(patchName, message) { - var msg = '"' + patchName + '" ' + message; - console.log(msg); - errorLog += msg + '
'; -} - validatePatches = function() { errorLog = ""; success = true; for(var i = 0; i < mods.length; i++) { - var patch = mods[i]; - var status = checkPatchBytes(patch.patches); - if(status == "on") { - console.log('"' + patch.name + '"', "is enabled!"); - } else if(status == "off") { - console.log('"' + patch.name + '"', "is disabled!"); - } else { + var error = mods[i].validatePatch(dllFile); + if(error) { + errorLog += error + "
"; success = false; - buildError(patch.name, "is neither on nor off! Have you got the right dll?"); } } return success; } -checkPatchBytes = function(patches) { - var patchStatus = ""; - for(var i = 0; i < patches.length; i++) { - patch = patches[i]; - if(bytesMatch(dllFile, patch.offset, patch.off)) { - if(patchStatus == "") { - patchStatus = "off"; - } else if(patchStatus != "off"){ - return "on/off mismatch within patch"; - } - } else if(bytesMatch(dllFile, patch.offset, patch.on)) { - if(patchStatus == "") { - patchStatus = "on"; - } else if(patchStatus != "on"){ - return "on/off mismatch within patch"; - } - } else { - return "patch neither on nor off"; - } - } - return patchStatus; -} - bytesMatch = function(buffer, offset, bytes) { for(var i = 0; i < bytes.length; i++) { if(buffer[offset+i] != bytes[i]) @@ -118,12 +218,6 @@ bytesMatch = function(buffer, offset, bytes) { return true; }; -replaceAll = function(buffer, patches, featureOn) { - for(var i = 0; i < patches.length; i++) { - replace(buffer, patches[i].offset, featureOn? patches[i].on : patches[i].off); - } -} - replace = function(buffer, offset, bytes) { for(var i = 0; i < bytes.length; i++) { buffer[offset+i] = bytes[i]; diff --git a/sdvx3-s2.html b/sdvx3-s2.html index c21610b..9b5cee6 100644 --- a/sdvx3-s2.html +++ b/sdvx3-s2.html @@ -41,26 +41,48 @@ on : [0xB8, 0x01, 0x00, 0x00, 0x00, 0x89, 0x83, 0x78, 0x0A, 0x00, 0x00, 0x90, 0x56, 0x57, 0x90, 0x90]}] }, { - name : "Score as overall percentage (Osu style % display)", - shortname : "percent", - patches : [{offset : 0x1FBD9, - off : [0x8B, 0x85, 0x50, 0x01, 0x00, 0x00, 0x8B, 0x9D, 0x48, 0x01, 0x00, 0x00, 0x8B, 0x8D, 0x54, 0x01, - 0x00, 0x00, 0x8B, 0x95, 0x4C, 0x01, 0x00, 0x00, 0x56, 0x57, 0x3B, 0xC3, 0x75, 0x08, 0x3B, 0xCA, - 0x0F, 0x84, 0x86, 0x00, 0x00, 0x00, 0x8B, 0xF8, 0x81, 0xC7, 0x7C, 0x9F, 0x02, 0x00, 0x8B, 0xF1, - 0x83, 0xD6, 0x00, 0x3B, 0xD6, 0x7C, 0x1C, 0x7F, 0x04, 0x3B, 0xDF, 0x76, 0x16, 0x05, 0x26, 0x43, - 0x00, 0x00, 0x83, 0xD1, 0x00, 0x89, 0x85, 0x50, 0x01, 0x00, 0x00, 0x89, 0x8D, 0x54, 0x01, 0x00, - 0x00, 0xEB, 0x59, 0x8B, 0xF8, 0x81, 0xC7, 0x26, 0x43, 0x00, 0x00, 0x8B, 0xF1, 0x83, 0xD6, 0x00, - 0x3B, 0xD6, 0x7C, 0x1C, 0x7F, 0x04, 0x3B, 0xDF, 0x76, 0x16, 0x05, 0x62, 0x16, 0x00, 0x00, 0x83, - 0xD1, 0x00, 0x89, 0x85, 0x50], - on : [0x56, 0x57, 0x52, 0x51, 0xBE, 0x90, 0x71, 0x7C, 0x18, 0x8B, 0x46, 0x54, 0x99, 0x6A, 0x00, 0x6A, - 0x02, 0x52, 0x50, 0xE8, 0x3F, 0xC4, 0x21, 0x00, 0x8B, 0xC8, 0x8B, 0xFA, 0x8B, 0x46, 0x58, 0x99, - 0x01, 0xC1, 0x11, 0xD7, 0x6A, 0x00, 0x68, 0x80, 0x96, 0x98, 0x00, 0x57, 0x51, 0xE8, 0x25, 0xC4, - 0x21, 0x00, 0x8B, 0xFA, 0x8B, 0xC8, 0x8B, 0x46, 0x54, 0x8B, 0x56, 0x58, 0x01, 0xD0, 0x8B, 0x56, - 0x5C, 0x01, 0xD0, 0x01, 0xC0, 0x99, 0x83, 0xF8, 0x00, 0x0F, 0x85, 0x0F, 0x00, 0x00, 0x00, 0xBF, - 0x00, 0x00, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x0D, 0x00, 0x00, 0x00, 0x52, 0x50, - 0x57, 0x51, 0xE8, 0x90, 0x36, 0x21, 0x00, 0x8B, 0xF8, 0x8B, 0xDA, 0x59, 0x5A, 0x8B, 0x45, 0x08, - 0x8B, 0x40, 0x04, 0xEB, 0x49]}] - }, + type : "union", + name : "Score", + shortname : "score", + offset : 0x1FBD9, + patches : [ + { + name : "Default (NEAR+CRITICAL add to score from 0)", + shortname : "default", + patch : [0x8B, 0x85, 0x50, 0x01, 0x00, 0x00, 0x8B, 0x9D, 0x48, 0x01, 0x00, 0x00, 0x8B, 0x8D, 0x54, 0x01, + 0x00, 0x00, 0x8B, 0x95, 0x4C, 0x01, 0x00, 0x00, 0x56, 0x57, 0x3B, 0xC3, 0x75, 0x08, 0x3B, 0xCA, + 0x0F, 0x84, 0x86, 0x00, 0x00, 0x00, 0x8B, 0xF8, 0x81, 0xC7, 0x7C, 0x9F, 0x02, 0x00, 0x8B, 0xF1, + 0x83, 0xD6, 0x00, 0x3B, 0xD6, 0x7C, 0x1C, 0x7F, 0x04, 0x3B, 0xDF, 0x76, 0x16, 0x05, 0x26, 0x43, + 0x00, 0x00, 0x83, 0xD1, 0x00, 0x89, 0x85, 0x50, 0x01, 0x00, 0x00, 0x89, 0x8D, 0x54, 0x01, 0x00, + 0x00, 0xEB, 0x59, 0x8B, 0xF8, 0x81, 0xC7, 0x26, 0x43, 0x00, 0x00, 0x8B, 0xF1, 0x83, 0xD6, 0x00, + 0x3B, 0xD6, 0x7C, 0x1C, 0x7F, 0x04, 0x3B, 0xDF, 0x76, 0x16, 0x05, 0x62, 0x16, 0x00, 0x00, 0x83, + 0xD1, 0x00, 0x89, 0x85, 0x50], + }, + { + name : "Subtractive (NEAR+ERROR subtract score from 10,000,000)", + shortname : "subtract", + patch : [0x56, 0x57, 0x52, 0x51, 0xBE, 0x90, 0x71, 0x7C, 0x18, 0x8B, 0x46, 0x5C, 0x6A, 0x00, 0x99, 0x6A, + 0x02, 0x52, 0x50, 0xE8, 0x3F, 0xC4, 0x21, 0x00, 0x8B, 0xC8, 0x8B, 0x46, 0x58, 0x8B, 0xFA, 0x99, + 0x6A, 0x00, 0x01, 0xC1, 0x11, 0xD7, 0x68, 0x80, 0x96, 0x98, 0x00, 0x57, 0x51, 0xE8, 0x25, 0xC4, + 0x21, 0x00, 0x8B, 0xFA, 0x8B, 0x56, 0x18, 0x8B, 0xC8, 0x8B, 0x82, 0x80, 0x2C, 0x00, 0x00, 0x01, + 0xC0, 0x99, 0x52, 0x50, 0x57, 0x51, 0xE8, 0xAC, 0x36, 0x21, 0x00, 0xB9, 0x80, 0x96, 0x98, 0x00, + 0xBF, 0x00, 0x00, 0x00, 0x00, 0x29, 0xC1, 0x19, 0xD7, 0x8B, 0xDF, 0x8B, 0xF9, 0x59, 0x5A, 0x8B, + 0x45, 0x08, 0x8B, 0x40, 0x04] + }, + { + name : "Average (Osu style % display)", + shortname : "avg", + patch : [0x56, 0x57, 0x52, 0x51, 0xBE, 0x90, 0x71, 0x7C, 0x18, 0x8B, 0x46, 0x54, 0x99, 0x6A, 0x00, 0x6A, + 0x02, 0x52, 0x50, 0xE8, 0x3F, 0xC4, 0x21, 0x00, 0x8B, 0xC8, 0x8B, 0xFA, 0x8B, 0x46, 0x58, 0x99, + 0x01, 0xC1, 0x11, 0xD7, 0x6A, 0x00, 0x68, 0x80, 0x96, 0x98, 0x00, 0x57, 0x51, 0xE8, 0x25, 0xC4, + 0x21, 0x00, 0x8B, 0xFA, 0x8B, 0xC8, 0x8B, 0x46, 0x54, 0x8B, 0x56, 0x58, 0x01, 0xD0, 0x8B, 0x56, + 0x5C, 0x01, 0xD0, 0x01, 0xC0, 0x99, 0x83, 0xF8, 0x00, 0x0F, 0x85, 0x0F, 0x00, 0x00, 0x00, 0xBF, + 0x00, 0x00, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x0D, 0x00, 0x00, 0x00, 0x52, 0x50, + 0x57, 0x51, 0xE8, 0x90, 0x36, 0x21, 0x00, 0x8B, 0xF8, 0x8B, 0xDA, 0x59, 0x5A, 0x8B, 0x45, 0x08, + 0x8B, 0x40, 0x04, 0xEB, 0x49] + }, + ] + } ]); });