-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13 from flowerLoader/devel
Merge devel for pre-release 3
- Loading branch information
Showing
6 changed files
with
321 additions
and
221 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,99 +1,153 @@ | ||
import { LogSource } from "@flowerloader/api"; | ||
import { FlowerPatch, Patchable, PatchFn } from "@flowerloader/api/FlowerPatch"; | ||
import { WriteLog, WriteDebug } from "./flowerful"; | ||
|
||
const patches: FlowerPatch[] = []; | ||
|
||
//Apply patches | ||
export function ApplyAllPatches() | ||
export class flowerPatcher | ||
{ | ||
for (const patch of patches) | ||
{ | ||
Apply(patch) | ||
} | ||
} | ||
Patches: FlowerPatch[] = []; | ||
MyLogSource: LogSource; | ||
|
||
function FindPatch(obj: Patchable, method: string) | ||
{ | ||
if (!obj[method]) | ||
|
||
//Apply patches | ||
ApplyAllPatches() | ||
{ | ||
console.error(`Method ${method} not found on ${obj}`); | ||
return; | ||
for (const patch of this.Patches) | ||
{ | ||
this.Apply(patch) | ||
} | ||
} | ||
|
||
for (const patch of patches) | ||
FindPatch(obj: Patchable, method: string) | ||
{ | ||
if (patch.obj === obj && patch.methodName === method) | ||
if (!obj[method]) | ||
{ | ||
return patch; | ||
console.error(`Method ${method} not found on ${obj}`); | ||
return; | ||
} | ||
} | ||
|
||
const patch: FlowerPatch = { | ||
obj: obj, | ||
methodName: method, | ||
prefixes: [], | ||
postfixes: [] | ||
} | ||
for (const patch of this.Patches) | ||
{ | ||
if (patch.obj === obj && patch.methodName === method) | ||
{ | ||
return patch; | ||
} | ||
} | ||
|
||
patches.push(patch); | ||
return patch; | ||
} | ||
const patch: FlowerPatch = { | ||
obj: obj, | ||
methodName: method, | ||
prefixes: [], | ||
postfixes: [], | ||
applied: false, | ||
} | ||
|
||
function Apply(patch: FlowerPatch) | ||
{ | ||
/* eslint-disable-next-line @typescript-eslint/ban-types */ | ||
const orig = patch.obj[patch.methodName] as Function; | ||
this.Patches.push(patch); | ||
return patch; | ||
} | ||
|
||
const wrapper: PatchFn = function (...args) | ||
/** | ||
* Binds a patch to an object. All patches are accumulated even after initial binding. | ||
* @param patch | ||
* @returns false if this patch has already been bound | ||
*/ | ||
Apply(patch: FlowerPatch): boolean | ||
{ | ||
WriteDebug(`Running detour for ${patch.methodName}`); | ||
// <-- this = obj | ||
|
||
WriteDebug(`Prefixes ${patch.prefixes.length}`); | ||
//patch.prefixes.forEach(prefix => prefix.call(patch.obj, ...args)); | ||
//Allow ending the detour early | ||
for (const prefix of patch.prefixes) | ||
/** Only apply patches once ever */ | ||
if (patch.applied) | ||
return false; | ||
|
||
/* eslint-disable-next-line @typescript-eslint/ban-types */ | ||
const orig = patch.obj[patch.methodName] as Function; | ||
const Patcher = this; | ||
|
||
const wrapper: PatchFn = function (...args) | ||
{ | ||
if (false === prefix.call(patch.obj, ...args)) | ||
Patcher.MyLogSource.writeDebug(`Running detour for ${patch.methodName}`); | ||
// <-- this = obj | ||
|
||
patch = Patcher.FindPatch(patch.obj, patch.methodName)!; | ||
|
||
Patcher.MyLogSource.writeDebug(`Prefixes ${patch.prefixes.length}`); | ||
//patch.prefixes.forEach(prefix => prefix.call(patch.obj, ...args)); | ||
//Allow ending the detour early | ||
for (const prefix of patch.prefixes) | ||
{ | ||
WriteDebug("Ending detour"); | ||
if (false === prefix.call(patch.obj, ...args)) | ||
{ | ||
Patcher.MyLogSource.writeDebug("Ending detour"); | ||
return; | ||
} | ||
} | ||
|
||
let origRet; | ||
|
||
try | ||
{ | ||
origRet = orig.call(patch.obj, ...args); | ||
} | ||
catch (e) | ||
{ | ||
Patcher.MyLogSource.write(`Error running orig: ${e}`) | ||
return; | ||
} | ||
} | ||
|
||
try | ||
{ | ||
orig.call(patch.obj, ...args); | ||
} | ||
catch (e) | ||
{ | ||
WriteLog("Flower", `Error running orig: ${e}`) | ||
return; | ||
/** | ||
* Todo: allow postfixes to modify the return data here | ||
*/ | ||
|
||
Patcher.MyLogSource.writeDebug(`Postfixes ${patch.postfixes.length}`); | ||
|
||
for (const postfix of patch.postfixes) | ||
{ | ||
try | ||
{ | ||
postfix.call(patch.obj, ...args) | ||
} | ||
catch (e: any) | ||
{ | ||
Patcher.MyLogSource.write(`Failed to run postfix: ${e.message}`); | ||
} | ||
} | ||
|
||
|
||
return origRet; | ||
} | ||
|
||
WriteDebug(`Postfixes ${patch.postfixes.length}`); | ||
patch.postfixes.forEach(postfix => postfix.call(patch.obj, ...args)); | ||
patch.obj[patch.methodName] = wrapper.bind(patch.obj); | ||
return true; | ||
} | ||
|
||
patch.obj[patch.methodName] = wrapper.bind(patch.obj); | ||
} | ||
/** | ||
* Registers a new patch with flower | ||
* @param obj any object that contains a method | ||
* @param methodName the string name of the method to patch | ||
* @param patch a function that runs when the method is called | ||
* @param isPrefix if this should run before the method (afterward otherwise) | ||
* @returns true on success | ||
*/ | ||
RegisterPatch(obj: Patchable, methodName: string, patch: PatchFn, isPrefix: boolean) | ||
{ | ||
|
||
export function RegisterPatch(obj: Patchable, methodName: string, patch: PatchFn, isPrefix: boolean) | ||
{ | ||
this.MyLogSource.writeDebug(`Running RegisterPatch for ${methodName}`); | ||
|
||
WriteDebug(`Running RegisterPatch for ${methodName}`); | ||
const accum = this.FindPatch(obj, methodName); | ||
if (!accum) return false; | ||
|
||
const accum = FindPatch(obj, methodName); | ||
if (!accum) return false; | ||
if (isPrefix) | ||
{ | ||
accum.prefixes.push(patch); | ||
} | ||
else | ||
{ | ||
accum.postfixes.push(patch); | ||
} | ||
|
||
if (isPrefix) | ||
{ | ||
accum.prefixes.push(patch); | ||
this.Apply(accum); | ||
return true; | ||
} | ||
else | ||
|
||
constructor(LogSource: LogSource) | ||
{ | ||
accum.postfixes.push(patch); | ||
this.MyLogSource = LogSource; | ||
} | ||
|
||
return true; | ||
} |
Oops, something went wrong.