revenge-bundle-next/lib/patcher/README.md
2025-06-09 22:47:21 +07:00

271 lines
6.7 KiB
Markdown

# @revenge-mod/patcher
This is a JavaScript library that allows to monkey patch functions in a way that is easy to use and understand.
It is made by [ryan-0324](https://github.com/ryan-0324) [(source uploaded on Discord)](https://discord.com/channels/1205207689832038522/1284131216156655646/1316076586981789709) and licensed under [CC0](./LICENSE).
This source code is polished and adapted to work with Revenge. We do not claim any rights to this library. You may use it granted you follow the license.
## How does this work?
Think of hooks as separate functions that are called `before`, `after`, or `instead` of the original function.
You can use them to modify the behavior of the original function, or to add new functionality.
### Before hooks
Before hooks allow you to modify the arguments passed to the original function, or to perform some action before the original function is called.
```js
import { before } from '@revenge-mod/patcher'
const obj = {
method: (a) => console.log('Original method called with:', a)
}
before(obj, 'method', ([a]) => {
console.log('Before method called with:', a)
// Modify arguments by returning new array
return [a + 1]
})
obj.method(2)
// CONSOLE OUTPUT:
// Before method called with: 2
// Original method called with: 3
```
### After hooks
After hooks allow you to modify the return value of the original function, or to perform some action after the original function is called.
```js
import { after } from '@revenge-mod/patcher'
const obj = {
method: (a) => a * 2
}
after(obj, 'method', (result) => {
console.log('After method called with result:', result)
// Modify return value
return result + 1
})
console.log(obj.method(2)) // 5
// CONSOLE OUTPUT:
// After method called with result: 4
// 5
```
### Instead hooks
Instead hooks allow you to completely replace the original function with a new one, while still being able to call the original function if needed.
```js
import { instead } from '@revenge-mod/patcher'
const obj = {
method: (a) => {
console.log('Original method called with:', a)
return 'original result'
}
}
instead(obj, 'method', ([a], original) => {
console.log('Instead method called with:', a)
// Call the original function if needed
const originalResult = original('modified')
console.log('Original method was called')
// Return a new value
return 'new value'
})
console.log(obj.method('test')) // 'new value'
// CONSOLE OUTPUT:
// Instead method called with: test
// Original method called with: modified
// Original method was called
// new value
```
### Combining hooks
You can combine multiple hooks on the same function.
```js
import { before, after, instead } from '@revenge-mod/patcher'
const obj = {
method: (a) => a * 2
}
before(obj, 'method', ([a]) => {
console.log('Before method called with:', a)
return [a + 1] // 2 becomes 3
})
instead(obj, 'method', ([a], original) => {
console.log('Instead method called with:', a)
const result = original(a) // Call original with modified arg (3)
console.log('Original method returned:', result)
return result + 1 // 6 becomes 7
})
after(obj, 'method', (result) => {
console.log('After method called with result:', result)
return result + 1 // 7 becomes 8
})
console.log(obj.method(2)) // 8
// CONSOLE OUTPUT:
// Before method called with: 2
// Instead method called with: 3
// Original method returned: 6
// After method called with result: 7
// 8
```
### Stacking hooks
Stacking multiple hooks of same type will execute them in a specific order:
1. **Before hooks** (execute in reverse order - last added runs first)
2. **Instead hooks** (only the last added executes, unless calling original)
3. **After hooks** (execute in order - first added runs first)
Using multiple `before` hooks will execute them in **reverse order** (LIFO - Last In, First Out):
```js
import { before } from '@revenge-mod/patcher'
const obj = {
method: (a) => console.log('Original method called with:', a)
}
before(obj, 'method', ([a]) => {
console.log('First before hook called with:', a)
return [a + 1]
})
before(obj, 'method', ([a]) => {
console.log('Second before hook called with:', a)
return [a + 2]
})
obj.method(2)
// CONSOLE OUTPUT:
// Second before hook called with: 2
// First before hook called with: 4
// Original method called with: 5
```
Multiple `after` hooks execute in **normal order** (FIFO - First In, First Out):
```js
import { after } from '@revenge-mod/patcher'
const obj = {
method: (a) => a * 2
}
after(obj, 'method', (result) => {
console.log('First after hook called with result:', result)
return result + 1
})
after(obj, 'method', (result) => {
console.log('Second after hook called with result:', result)
return result + 2
})
console.log(obj.method(2)) // 7
// CONSOLE OUTPUT:
// First after hook called with result: 4
// Second after hook called with result: 5
// 7
```
Multiple `instead` hooks will only execute the **last one added**. To chain them, you must call the original function:
```js
import { instead } from '@revenge-mod/patcher'
const obj = {
method: (a) => `original-${a}`
}
instead(obj, 'method', ([a], original) => {
console.log('First instead hook called with:', a)
return `first-${original(a)}`
})
instead(obj, 'method', ([a], original) => {
console.log('Second instead hook called with:', a)
// Calling original will execute the previous instead hook
return `second-${original(a)}`
})
console.log(obj.method('test')) // 'second-first-original-test'
// CONSOLE OUTPUT:
// Second instead hook called with: test
// First instead hook called with: test
// second-first-original-test
```
### Removing hooks
Each hook returns an unpatch function that removes the hook:
```js
import { before } from '@revenge-mod/patcher'
const obj = {
method: (a) => console.log('Original method called with:', a)
}
const unpatch = before(obj, 'method', ([a]) => {
console.log('Before method called with:', a)
return [a + 1]
})
obj.method(2)
// CONSOLE OUTPUT:
// Before method called with: 2
// Original method called with: 3
unpatch() // Remove the hook
obj.method(2)
// CONSOLE OUTPUT:
// Original method called with: 2
```
Unpatch functions are safe to call multiple times and won't throw errors.
### Constructor patching
You can also patch constructor functions:
```js
import { before } from '@revenge-mod/patcher'
class MyClass {
constructor(value) {
this.value = value
}
}
const exports = { MyClass }
before(exports, 'MyClass', ([value]) => {
console.log('Constructor called with:', value)
return [`modified-${value}`]
})
const instance = new exports.MyClass('test')
console.log(instance.value) // 'modified-test'
// CONSOLE OUTPUT:
// Constructor called with: test
// modified-test
```