rs3-api-extended 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +87 -2
- package/dist/index.d.ts +4 -0
- package/dist/index.lua +12 -0
- package/dist/plugin.d.ts +28 -0
- package/dist/plugin.lua +92 -0
- package/dist/vars.d.ts +8 -0
- package/dist/vars.lua +1 -0
- package/package.json +43 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mark7625
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,88 @@
|
|
|
1
|
-
#
|
|
1
|
+
# rs3-api-extended
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Custom helpers for RuneScape 3 plugins. Not part of Jagex's API.
|
|
4
|
+
|
|
5
|
+
Everything in this package was written for this project. None of it exists in the game client, and none of it is something you can call from a plain Lua plugin. It compiles to Lua and ships inside your plugin under `lua_modules/rs3-api-extended/`. For the client's own API, which this builds on, see `rs3-api-core`.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { definePlugin, on, vars } from "rs3-api-extended";
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## definePlugin
|
|
12
|
+
|
|
13
|
+
Wires the lifecycle globals the client looks for and runs your modules.
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
definePlugin({
|
|
17
|
+
modules: [login, overlay],
|
|
18
|
+
});
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
A module is any object with optional `init`, `tick`, `draw` and `shutdown` functions, which in practice means a file of exported functions imported with `import * as`. `definePlugin` assigns `PluginLogic` and `PluginShutdown`, adds `PluginDraw` only if something actually draws, and calls each hook through `pcall` so one module throwing does not stop the others. Errors print once per distinct message, prefixed with the plugin's name from `plugin.json`. Pass `name` to override that prefix, or `onError` to handle failures yourself.
|
|
22
|
+
|
|
23
|
+
| Option | Default | What it does |
|
|
24
|
+
| --- | --- | --- |
|
|
25
|
+
| `modules` | `[]` | Objects whose `init`, `tick`, `draw` and `shutdown` get called. |
|
|
26
|
+
| `autoUnsubscribe` | `true` | Detach anything still subscribed through `on` once shutdown has run. |
|
|
27
|
+
| `name` | `Plugin.Name` | Prefix on error messages. |
|
|
28
|
+
| `onError` | prints once per message | Called with each hook failure instead. |
|
|
29
|
+
|
|
30
|
+
## autoUnsubscribe
|
|
31
|
+
|
|
32
|
+
On shutdown, after every module's own `shutdown` has run, any subscription made through `on` and not already detached is detached for you. It is on by default, so a plugin that only ever subscribes in `init` needs no `shutdown` at all:
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { on } from "rs3-api-extended";
|
|
36
|
+
|
|
37
|
+
export function init() {
|
|
38
|
+
on(Event.GameStateChanged, onGameState);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function onGameState(event: GameStateChangedEvent) {
|
|
42
|
+
if (event.newState === GameState.GAME) {
|
|
43
|
+
Chat.AddMessage(ChatType.GENERAL, "This is a test");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
This only covers `on`. A handler attached with `Event.X.Subscribe(handler)` directly is invisible to it, because nothing recorded the pair, so those stay yours to unsubscribe in `shutdown`. Mixing the two is fine: each `on` subscription is forgotten as soon as its unsubscribe runs, so nothing gets detached twice.
|
|
49
|
+
|
|
50
|
+
`unsubscribeAll()` is exported if you want to drop every `on` subscription at some other moment, and `autoUnsubscribe: false` turns the shutdown sweep off entirely.
|
|
51
|
+
|
|
52
|
+
## on
|
|
53
|
+
|
|
54
|
+
Subscribes to an event. The subscription is live as soon as the call returns, and `definePlugin` will clean it up at shutdown, so most of the time you can ignore the return value.
|
|
55
|
+
|
|
56
|
+
What it returns is the matching unsubscribe, for when you want to detach before shutdown:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
let stopListening = () => {};
|
|
60
|
+
|
|
61
|
+
export function init() {
|
|
62
|
+
stopListening = on(Event.SkillTransmit, onSkillTransmit);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function onSkillTransmit(event: SkillTransmitEvent) {
|
|
66
|
+
if (event.newGameplayLevel === 99) {
|
|
67
|
+
stopListening();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Calling it twice is harmless, and so is letting shutdown collect it instead.
|
|
73
|
+
|
|
74
|
+
## vars
|
|
75
|
+
|
|
76
|
+
The client's `var` table, under a name TypeScript allows, since `var` is a reserved word.
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
const lifepoints = vars.VarPlayer.FromID(13379).value;
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Adding a helper
|
|
83
|
+
|
|
84
|
+
Worth adding if more than one plugin would use it. Keep it to functions and tables: no classes, no array helper methods, nothing that drags in TypeScriptToLua's runtime, because release builds reject output that references it. Put the source in `src/`, export it from `index.ts`, and the build type-checks it against the core declarations.
|
|
85
|
+
|
|
86
|
+
## License
|
|
87
|
+
|
|
88
|
+
[MIT](https://github.com/Mark7625/rs3-api-ts/blob/main/LICENSE)
|
package/dist/index.d.ts
ADDED
package/dist/index.lua
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
local ____exports = {}
|
|
2
|
+
do
|
|
3
|
+
local ____plugin = require("plugin")
|
|
4
|
+
____exports.definePlugin = ____plugin.definePlugin
|
|
5
|
+
____exports.on = ____plugin.on
|
|
6
|
+
____exports.unsubscribeAll = ____plugin.unsubscribeAll
|
|
7
|
+
end
|
|
8
|
+
do
|
|
9
|
+
local ____vars = require("vars")
|
|
10
|
+
____exports.vars = ____vars.vars
|
|
11
|
+
end
|
|
12
|
+
return ____exports
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** @noSelfInFile */
|
|
2
|
+
/** @noSelf */
|
|
3
|
+
export interface Module {
|
|
4
|
+
init?(): void;
|
|
5
|
+
tick?(now: number): void;
|
|
6
|
+
draw?(deltaSecs: number): void;
|
|
7
|
+
shutdown?(): void;
|
|
8
|
+
}
|
|
9
|
+
/** @noSelf */
|
|
10
|
+
export interface PluginOptions extends Module {
|
|
11
|
+
name?: string;
|
|
12
|
+
modules?: Module[];
|
|
13
|
+
autoUnsubscribe?: boolean;
|
|
14
|
+
onError?(message: string): void;
|
|
15
|
+
}
|
|
16
|
+
export type Unsubscribe = () => void;
|
|
17
|
+
export type Handler<T> = (event: T) => boolean | void;
|
|
18
|
+
/** @noSelf */
|
|
19
|
+
export interface Subscribable<T> {
|
|
20
|
+
Subscribe(handler: Handler<T>): void;
|
|
21
|
+
Unsubscribe(handler: Handler<T>): void;
|
|
22
|
+
}
|
|
23
|
+
/** @noSelf */
|
|
24
|
+
export declare function on<T>(source: Subscribable<T>, handler: Handler<T>): Unsubscribe;
|
|
25
|
+
/** @noSelf */
|
|
26
|
+
export declare function unsubscribeAll(): void;
|
|
27
|
+
/** @noSelf */
|
|
28
|
+
export declare function definePlugin(options: PluginOptions): void;
|
package/dist/plugin.lua
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
local ____exports = {}
|
|
2
|
+
local tracked = {}
|
|
3
|
+
---
|
|
4
|
+
-- @noSelf
|
|
5
|
+
function ____exports.on(source, handler)
|
|
6
|
+
source.Subscribe(handler)
|
|
7
|
+
local entry = {detach = function()
|
|
8
|
+
pcall(source.Unsubscribe, handler)
|
|
9
|
+
end}
|
|
10
|
+
tracked[#tracked + 1] = entry
|
|
11
|
+
return function()
|
|
12
|
+
local detach = entry.detach
|
|
13
|
+
if detach ~= nil then
|
|
14
|
+
entry.detach = nil
|
|
15
|
+
detach()
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
---
|
|
20
|
+
-- @noSelf
|
|
21
|
+
function ____exports.unsubscribeAll()
|
|
22
|
+
local pending = tracked
|
|
23
|
+
tracked = {}
|
|
24
|
+
for ____, entry in ipairs(pending) do
|
|
25
|
+
local detach = entry.detach
|
|
26
|
+
if detach ~= nil then
|
|
27
|
+
entry.detach = nil
|
|
28
|
+
detach()
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
---
|
|
33
|
+
-- @noSelf
|
|
34
|
+
function ____exports.definePlugin(options)
|
|
35
|
+
local name = options.name or Plugin.Name or "plugin"
|
|
36
|
+
local modules = options.modules or ({})
|
|
37
|
+
local autoUnsubscribe = options.autoUnsubscribe ~= false
|
|
38
|
+
local lastError
|
|
39
|
+
local function report(message)
|
|
40
|
+
if options.onError ~= nil then
|
|
41
|
+
options.onError(message)
|
|
42
|
+
elseif message ~= lastError then
|
|
43
|
+
lastError = message
|
|
44
|
+
print((("[" .. name) .. "] ") .. message)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
local function guard(fn, arg)
|
|
48
|
+
if fn == nil then
|
|
49
|
+
return
|
|
50
|
+
end
|
|
51
|
+
local ok, err = pcall(fn, arg)
|
|
52
|
+
if not ok then
|
|
53
|
+
report(tostring(err))
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
PluginLogic = function(event)
|
|
57
|
+
local now = event.logicTick
|
|
58
|
+
for ____, m in ipairs(modules) do
|
|
59
|
+
guard(m.tick, now)
|
|
60
|
+
end
|
|
61
|
+
guard(options.tick, now)
|
|
62
|
+
end
|
|
63
|
+
local hasDraw = options.draw ~= nil
|
|
64
|
+
for ____, m in ipairs(modules) do
|
|
65
|
+
if m.draw ~= nil then
|
|
66
|
+
hasDraw = true
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
if hasDraw then
|
|
70
|
+
PluginDraw = function(event)
|
|
71
|
+
local delta = event.timeDeltaSecs
|
|
72
|
+
for ____, m in ipairs(modules) do
|
|
73
|
+
guard(m.draw, delta)
|
|
74
|
+
end
|
|
75
|
+
guard(options.draw, delta)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
PluginShutdown = function()
|
|
79
|
+
guard(options.shutdown)
|
|
80
|
+
for ____, m in ipairs(modules) do
|
|
81
|
+
guard(m.shutdown)
|
|
82
|
+
end
|
|
83
|
+
if autoUnsubscribe then
|
|
84
|
+
guard(____exports.unsubscribeAll)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
for ____, m in ipairs(modules) do
|
|
88
|
+
guard(m.init)
|
|
89
|
+
end
|
|
90
|
+
guard(options.init)
|
|
91
|
+
end
|
|
92
|
+
return ____exports
|
package/dist/vars.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** @noSelfInFile */
|
|
2
|
+
/**
|
|
3
|
+
* The game's `var` global (VarPlayer, VarClient, VarClan, ...), re-exported under a
|
|
4
|
+
* name TypeScript allows. `var` is a reserved word, so it cannot be declared directly.
|
|
5
|
+
*
|
|
6
|
+
* const lifepoints = vars.VarPlayer.FromID(13379).value;
|
|
7
|
+
*/
|
|
8
|
+
export const vars: VarApi;
|
package/dist/vars.lua
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
return { vars = var }
|
package/package.json
CHANGED
|
@@ -1,6 +1,45 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rs3-api-extended",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Runtime helpers for RuneScape 3 plugins written in TypeScript: definePlugin, event subscription, and the vars shim. Compiled to readable Lua and bundled into your plugin by rs3-plugin.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Mark7625",
|
|
7
|
+
"homepage": "https://github.com/Mark7625/rs3-api-ts/tree/main/packages/extended#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/Mark7625/rs3-api-ts.git",
|
|
11
|
+
"directory": "packages/extended"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/Mark7625/rs3-api-ts/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"runescape",
|
|
18
|
+
"rs3",
|
|
19
|
+
"plugin",
|
|
20
|
+
"lua",
|
|
21
|
+
"typescript-to-lua"
|
|
22
|
+
],
|
|
23
|
+
"main": "./dist/index",
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"README.md",
|
|
28
|
+
"LICENSE"
|
|
29
|
+
],
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tstl -p tsconfig.json && node scripts/postbuild.js",
|
|
35
|
+
"prepack": "npm run build"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"rs3-api-core": "^0.1.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"rs3-api-core": "^0.1.0",
|
|
42
|
+
"typescript": "6.0.2",
|
|
43
|
+
"typescript-to-lua": "^1.37.1"
|
|
44
|
+
}
|
|
45
|
+
}
|