Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge devel for pre-release 3 #13

Merged
merged 25 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
259723c
fixes orig's return value not being stored or returned. Prep work fo…
May 17, 2024
ae0440b
postfix safety with try/catch
May 17, 2024
334f882
adds a timeout to wait for tGameMain to exist
May 17, 2024
b312c6a
change timeout to 100 for safety on slower machines
May 18, 2024
634f491
using the next branch of @flowerloader/api
May 18, 2024
a2721bd
implement late binding patches
May 18, 2024
989cf95
make readme prettier
May 19, 2024
7d782a6
Revert "make readme prettier"
AlbinoGeek May 19, 2024
a6d1c24
fixes orig's return value not being stored or returned. Prep work fo…
May 17, 2024
e2bc63f
postfix safety with try/catch
May 17, 2024
a59b4f7
adds a timeout to wait for tGameMain to exist
May 17, 2024
92b83fd
change timeout to 100 for safety on slower machines
May 18, 2024
5e06299
using the next branch of @flowerloader/api
May 18, 2024
336c0d4
implement late binding patches
May 18, 2024
ed16983
Revert "make readme prettier"
AlbinoGeek May 19, 2024
4c683e3
Merge branch 'devel' of https://github.com/flowerLoader/core into devel
May 19, 2024
c23785f
Revert "Revert "make readme prettier""
May 19, 2024
dbd03a8
complete rewrite to support game-agnostic core
May 20, 2024
1c51d59
flower.core object complete(?)
May 20, 2024
8328a77
convert flowerful.patches to object
May 20, 2024
0fe4313
optimize flower.core constructor
May 20, 2024
a82ed73
update for new objects
May 20, 2024
b04f988
update task to output filename
May 20, 2024
bec530f
corrected quotes to backticks
May 20, 2024
0bdab37
update packages for prerelease 3
May 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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