Skip to content

Commit

Permalink
Merge pull request #13 from flowerLoader/devel
Browse files Browse the repository at this point in the history
Merge devel for pre-release 3
  • Loading branch information
RobynLlama committed May 21, 2024
2 parents ee9803c + 0bdab37 commit 482ba52
Show file tree
Hide file tree
Showing 6 changed files with 321 additions and 221 deletions.
2 changes: 1 addition & 1 deletion .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
{
"label": "esbuild",
"type": "shell",
"command": "npx esbuild --bundle flowerful.ts --format=esm --outdir=build/ --platform=node",
"command": "npx esbuild --bundle gameSupport/games.coaw.ts --format=esm --outfile=./build/flowerful.js --platform=node",
"windows": {
"command": ""
},
Expand Down
186 changes: 120 additions & 66 deletions flowerful.patches.ts
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;
}
Loading

0 comments on commit 482ba52

Please sign in to comment.