@amxts/resemiclip 0.1.0 → 0.1.1
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/README.md +2 -2
- package/README.ru.md +2 -2
- package/package.json +2 -2
- package/prebuilt/linux/resemiclip.aot +0 -0
- package/prebuilt/manifest.json +17 -9
- package/prebuilt/windows/resemiclip.aot +0 -0
- package/src/index.ts +21 -9
package/README.md
CHANGED
|
@@ -50,14 +50,14 @@ Teammates walk through each other:
|
|
|
50
50
|
semiclip.rule = (player, target) => player.team == target.team;
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
Setting the rule is all it takes: the module works every pair out, and works a player's pairs out again when he spawns, dies, changes sides, comes or leaves. Setting `rule` takes the rules over from ReSemiclip's config; `semiclip.rule = null` gives them back, and so
|
|
53
|
+
Setting the rule is all it takes: the module works every pair out, and works a player's pairs out again when he spawns, dies, changes sides, comes or leaves. Setting `rule` takes the rules over from ReSemiclip's config; `semiclip.rule = null` gives them back, and so do the plugins' reload, a map change and the plugin that set the rule stopping - unloaded or reloaded - until a rule is set again.
|
|
54
54
|
|
|
55
55
|
### A rule that changes in play
|
|
56
56
|
|
|
57
57
|
`spawnProtected` below is the plugin's own [field on `Player`](https://amxts.github.io/docs/game/players#shared-player-fields), declared with `declare module`: it starts `false`, every plugin on the server reads and writes it, and it is cleared when the player leaves. A player who has just spawned walks through everyone alive for 3 seconds, and teammates walk through each other:
|
|
58
58
|
|
|
59
59
|
```ts
|
|
60
|
-
declare module "
|
|
60
|
+
declare module "@amxts/core" {
|
|
61
61
|
interface Player {
|
|
62
62
|
spawnProtected: boolean;
|
|
63
63
|
}
|
package/README.ru.md
CHANGED
|
@@ -50,14 +50,14 @@ export default defineConfig({
|
|
|
50
50
|
semiclip.rule = (player, target) => player.team == target.team;
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
Больше ничего не нужно: модуль рассчитывает каждую пару и заново рассчитывает пары игрока, когда тот появляется, умирает, меняет команду, входит или уходит. Присваивание `rule` забирает правила у конфига ReSemiclip; `semiclip.rule = null` возвращает их, и так же — перезагрузка
|
|
53
|
+
Больше ничего не нужно: модуль рассчитывает каждую пару и заново рассчитывает пары игрока, когда тот появляется, умирает, меняет команду, входит или уходит. Присваивание `rule` забирает правила у конфига ReSemiclip; `semiclip.rule = null` возвращает их, и так же — перезагрузка плагинов, смена карты и остановка плагина, который задал правило (его выгрузили или перезагрузили), пока правило не задано снова.
|
|
54
54
|
|
|
55
55
|
### Правило, которое меняется в игре
|
|
56
56
|
|
|
57
57
|
`spawnProtected` ниже — собственное [поле плагина в `Player`](https://amxts.github.io/ru/docs/game/players#общие-поля-игрока), объявленное через `declare module`: сначала оно `false`, его читают и пишут все плагины сервера, а когда игрок уходит, оно сбрасывается. Только что появившийся игрок 3 секунды проходит сквозь всех живых, а союзники — сквозь друг друга:
|
|
58
58
|
|
|
59
59
|
```ts
|
|
60
|
-
declare module "
|
|
60
|
+
declare module "@amxts/core" {
|
|
61
61
|
interface Player {
|
|
62
62
|
spawnProtected: boolean;
|
|
63
63
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amxts/resemiclip",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.1",
|
|
5
5
|
"description": "Who walks through whom, for amxts plugins: the ReSemiclip module's rules as players, not bit masks.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "kukson777",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"lint:fix": "oxfmt && oxlint --fix --silent || oxlint --fix --silent || oxlint --fix"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"@amxts/core": "^0.
|
|
43
|
+
"@amxts/core": "^0.2.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@e18e/eslint-plugin": "^0.8.1",
|
|
Binary file
|
package/prebuilt/manifest.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": 1,
|
|
3
3
|
"module": "@amxts/resemiclip",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.1",
|
|
5
5
|
"from": {
|
|
6
6
|
"@amxts/core": {
|
|
7
|
-
"version": "0.
|
|
8
|
-
"hash": "
|
|
7
|
+
"version": "0.2.0",
|
|
8
|
+
"hash": "86146344f98b3f7285b3307a254d359d7080ae7c"
|
|
9
9
|
},
|
|
10
10
|
"@amxts/resemiclip": {
|
|
11
|
-
"version": "0.1.
|
|
12
|
-
"hash": "
|
|
11
|
+
"version": "0.1.1",
|
|
12
|
+
"hash": "a1d17a605015e6566c550aff3796ab8fef8c0fd1"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"options": {
|
|
@@ -22,8 +22,11 @@
|
|
|
22
22
|
"entities.ts",
|
|
23
23
|
"events.ts",
|
|
24
24
|
"facade.ts",
|
|
25
|
+
"fetch.ts",
|
|
25
26
|
"flags.ts",
|
|
27
|
+
"hlds.ts",
|
|
26
28
|
"hooks.ts",
|
|
29
|
+
"kit.ts",
|
|
27
30
|
"modules/resemiclip.ts",
|
|
28
31
|
"natives.ts",
|
|
29
32
|
"promise.ts",
|
|
@@ -39,13 +42,18 @@
|
|
|
39
42
|
"systems": {
|
|
40
43
|
"windows": {
|
|
41
44
|
"file": "prebuilt/windows/resemiclip.aot",
|
|
42
|
-
"size":
|
|
43
|
-
"sha256": "
|
|
45
|
+
"size": 757502,
|
|
46
|
+
"sha256": "68baa44290f910b7c8106482d74d315364bda163a25072156b8975de437a5d55"
|
|
44
47
|
},
|
|
45
48
|
"linux": {
|
|
46
49
|
"file": "prebuilt/linux/resemiclip.aot",
|
|
47
|
-
"size":
|
|
48
|
-
"sha256": "
|
|
50
|
+
"size": 768642,
|
|
51
|
+
"sha256": "7267b8eae9880c2bf0bf02af8d06903706bb24fd9b54bb796bf132557cba2525"
|
|
49
52
|
}
|
|
53
|
+
},
|
|
54
|
+
"surface": {
|
|
55
|
+
"proxy": "// GENERATED by scripts/shared-modules.ts: ~/modules/resemiclip in a plugin that does not own it.\n// Each function runs in resemiclip.aot, the one instance on the server.\nimport { Reader as __Reader, Writer as __Writer, beginCallback as __beginCallback, callBack as __callBack, receiveFunction as __receiveFunction, remoteTarget as __remoteTarget, sendFunction as __sendFunction, Service as __Service } from \"~/remote\";\nimport { Player as __Player } from \"~/facade\";\nimport { Player } from \"~/facade\";\n\nexport type SemiclipRule = (player: Player, target: Player) => boolean;\n\n/** Semiclip in resemiclip's plugin: each field is read and written there, each method runs there. */\nexport class Semiclip {\n\tconstructor(public __handle: i32) {}\n\n\tget rule(): ((a0: __Player, a1: __Player) => bool) | null {\n\t\tconst w = __service.begin(0);\n\t\tw.i32(this.__handle);\n\t\treturn __r0(__service.call(w));\n\t}\n\tset rule(value: ((a0: __Player, a1: __Player) => bool) | null) {\n\t\tconst w = __service.begin(1);\n\t\tw.i32(this.__handle);\n\t\t__w0(w, value);\n\t\t__service.call(w);\n\t}\n\n\tupdate(player?: Player): void {\n\t\tconst __w = __service.begin(2);\n\t\t__w.i32(this.__handle);\n\t\t__w2(__w, player);\n\t\tconst __r = __service.call(__w);\n\t}\n\n\tpassesThrough(player: Player): Array<__Player> {\n\t\tconst __w = __service.begin(3);\n\t\t__w.i32(this.__handle);\n\t\t__w3(__w, player);\n\t\tconst __r = __service.call(__w);\n\t\treturn __r4(__r);\n\t}\n}\n\nexport const semiclip = new Semiclip(1);\n\nconst __service = new __Service(\"resemiclip\", -273317570);\n\nfunction __w1(w: __Writer, v: (a0: __Player, a1: __Player) => bool): void { w.i32(__sendFunction(changetype<usize>(v), 0, __invoke)); }\n\nfunction __r1(r: __Reader): (a0: __Player, a1: __Player) => bool { return changetype<(a0: __Player, a1: __Player) => bool>(__receiveFunction(r, changetype<usize>(__stub0))); }\n\nfunction __w0(w: __Writer, v: ((a0: __Player, a1: __Player) => bool) | null): void {\n\tif (v == null) {\n\t\tw.bool(false);\n\t\treturn;\n\t}\n\tw.bool(true);\n\t__w1(w, v!);\n}\n\nfunction __r0(r: __Reader): ((a0: __Player, a1: __Player) => bool) | null {\n\tif (!r.bool()) return null;\n\treturn __r1(r);\n}\n\nfunction __w3(w: __Writer, v: __Player): void { w.i32(<i32>v.id); }\n\nfunction __r3(r: __Reader): __Player { return new __Player(r.i32()); }\n\nfunction __w2(w: __Writer, v: __Player | null): void {\n\tif (v == null) {\n\t\tw.bool(false);\n\t\treturn;\n\t}\n\tw.bool(true);\n\t__w3(w, v!);\n}\n\nfunction __r2(r: __Reader): __Player | null {\n\tif (!r.bool()) return null;\n\treturn __r3(r);\n}\n\nfunction __w4(w: __Writer, v: Array<__Player>): void {\n\tw.i32(v.length);\n\tfor (let i: i32 = 0; i < v.length; i++) __w3(w, v[i]);\n}\n\nfunction __r4(r: __Reader): Array<__Player> {\n\tconst count = r.i32();\n\tconst list = new Array<__Player>();\n\tfor (let i: i32 = 0; i < count; i++) list.push(__r3(r));\n\treturn list;\n}\n\nfunction __w5(w: __Writer, v: bool): void { w.bool(v); }\n\nfunction __r5(r: __Reader): bool { return r.bool(); }\n\nfunction __stub0(a0: __Player, a1: __Player): bool {\n\tconst target = __remoteTarget();\n\tconst w = __beginCallback(target);\n\t__w3(w, a0);\n\t__w3(w, a1);\n\tconst r = __callBack(target, w);\n\treturn __r5(r);\n}\n\nfunction __invoke(fn: usize, sig: i32, r: __Reader, w: __Writer): void {\n\tswitch (sig) {\n\t\tcase 0: {\n\t\t\tconst a0 = __r3(r);\n\t\t\tconst a1 = __r3(r);\n\t\t\tconst f = changetype<(a0: __Player, a1: __Player) => bool>(fn);\n\t\t\tconst result = f(a0, a1);\n\t\t\t__w5(w, result);\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n\n",
|
|
56
|
+
"serve": "// GENERATED by scripts/shared-modules.ts: ~/modules/resemiclip, run by this plugin for every other.\nimport { Reader as __Reader, Writer as __Writer, beginCallback as __beginCallback, callBack as __callBack, receiveFunction as __receiveFunction, remoteTarget as __remoteTarget, sendFunction as __sendFunction, Handles as __Handles, serve as __serve } from \"~/remote\";\nimport * as __m from \"~/modules/resemiclip\";\nimport { Player as __Player } from \"~/facade\";\nimport { Semiclip as __M_Semiclip } from \"~/modules/resemiclip\";\n\nconst __handles = new __Handles();\n// The exported objects are handles 1, 2, ... - the numbers the proxies have.\n__handles.id(changetype<usize>(__m.semiclip));\n\nfunction __dispatch(op: i32, r: __Reader, w: __Writer): void {\n\tswitch (op) {\n\t\tcase 0: {\n\t\t\tconst o = __r0(r);\n\t\t\t__w1(w, o.rule);\n\t\t\tbreak;\n\t\t}\n\t\tcase 1: {\n\t\t\tconst o = __r0(r);\n\t\t\to.rule = __r1(r);\n\t\t\tbreak;\n\t\t}\n\t\tcase 2: {\n\t\t\tconst o = __r0(r);\n\t\t\tconst a0 = __r3(r);\n\t\t\to.update(a0);\n\t\t\tbreak;\n\t\t}\n\t\tcase 3: {\n\t\t\tconst o = __r0(r);\n\t\t\tconst a0 = __r4(r);\n\t\t\tconst result = o.passesThrough(a0);\n\t\t\t__w5(w, result);\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nfunction __stub0(a0: __Player, a1: __Player): bool {\n\tconst target = __remoteTarget();\n\tconst w = __beginCallback(target);\n\t__w4(w, a0);\n\t__w4(w, a1);\n\tconst r = __callBack(target, w);\n\treturn __r6(r);\n}\n\nfunction __invoke(fn: usize, sig: i32, r: __Reader, w: __Writer): void {\n\tswitch (sig) {\n\t\tcase 0: {\n\t\t\tconst a0 = __r4(r);\n\t\t\tconst a1 = __r4(r);\n\t\t\tconst f = changetype<(a0: __Player, a1: __Player) => bool>(fn);\n\t\t\tconst result = f(a0, a1);\n\t\t\t__w6(w, result);\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nfunction __w0(w: __Writer, v: __M_Semiclip): void { w.i32(__handles.id(changetype<usize>(v))); }\n\nfunction __r0(r: __Reader): __M_Semiclip { return changetype<__M_Semiclip>(__handles.at(r.i32())); }\n\nfunction __w2(w: __Writer, v: (a0: __Player, a1: __Player) => bool): void { w.i32(__sendFunction(changetype<usize>(v), 0, __invoke)); }\n\nfunction __r2(r: __Reader): (a0: __Player, a1: __Player) => bool { return changetype<(a0: __Player, a1: __Player) => bool>(__receiveFunction(r, changetype<usize>(__stub0))); }\n\nfunction __w1(w: __Writer, v: ((a0: __Player, a1: __Player) => bool) | null): void {\n\tif (v == null) {\n\t\tw.bool(false);\n\t\treturn;\n\t}\n\tw.bool(true);\n\t__w2(w, v!);\n}\n\nfunction __r1(r: __Reader): ((a0: __Player, a1: __Player) => bool) | null {\n\tif (!r.bool()) return null;\n\treturn __r2(r);\n}\n\nfunction __w4(w: __Writer, v: __Player): void { w.i32(<i32>v.id); }\n\nfunction __r4(r: __Reader): __Player { return new __Player(r.i32()); }\n\nfunction __w3(w: __Writer, v: __Player | null): void {\n\tif (v == null) {\n\t\tw.bool(false);\n\t\treturn;\n\t}\n\tw.bool(true);\n\t__w4(w, v!);\n}\n\nfunction __r3(r: __Reader): __Player | null {\n\tif (!r.bool()) return null;\n\treturn __r4(r);\n}\n\nfunction __w5(w: __Writer, v: Array<__Player>): void {\n\tw.i32(v.length);\n\tfor (let i: i32 = 0; i < v.length; i++) __w4(w, v[i]);\n}\n\nfunction __r5(r: __Reader): Array<__Player> {\n\tconst count = r.i32();\n\tconst list = new Array<__Player>();\n\tfor (let i: i32 = 0; i < count; i++) list.push(__r4(r));\n\treturn list;\n}\n\nfunction __w6(w: __Writer, v: bool): void { w.bool(v); }\n\nfunction __r6(r: __Reader): bool { return r.bool(); }\n\n__serve(\"resemiclip\", -273317570, __dispatch);\n",
|
|
57
|
+
"callbacks": true
|
|
50
58
|
}
|
|
51
59
|
}
|
|
Binary file
|
package/src/index.ts
CHANGED
|
@@ -5,20 +5,22 @@
|
|
|
5
5
|
* rule reads may have changed. How to use it: README.md.
|
|
6
6
|
*/
|
|
7
7
|
import { ClientPutinserverEvent, Player, TeamInfoMessage, game, server } from "@amxts/core";
|
|
8
|
-
import { LibType_Library } from "
|
|
9
|
-
import {
|
|
8
|
+
import { LibType_Library } from "@amxts/core/constants";
|
|
9
|
+
import { callingPlugin, onPluginStop } from "@amxts/core/kit";
|
|
10
|
+
import { LibraryExists, resemiclip_get_user_mask, resemiclip_set_user_mask, resemiclip_take_control } from "@amxts/core/natives";
|
|
10
11
|
|
|
11
12
|
export default defineModule({
|
|
12
13
|
meta: { name: "resemiclip" },
|
|
13
14
|
imports: [{ from: "@amxts/resemiclip", name: "semiclip" }],
|
|
14
15
|
setup() {
|
|
15
16
|
server.addEventListener("init", start);
|
|
16
|
-
server.addEventListener("
|
|
17
|
+
server.addEventListener("putInServer", joined);
|
|
17
18
|
server.addEventListener("disconnected", event => left(event.player));
|
|
18
|
-
server.
|
|
19
|
-
server.addEventListener("
|
|
19
|
+
server.addMessageListener("team", teamChanged);
|
|
20
|
+
server.addEventListener("playerChange", event => changed(event.player));
|
|
20
21
|
game.addEventListener("spawn", event => changed(event.player), true);
|
|
21
22
|
game.addEventListener("killed", event => changed(event.player), true);
|
|
23
|
+
onPluginStop(stopped);
|
|
22
24
|
},
|
|
23
25
|
});
|
|
24
26
|
|
|
@@ -29,6 +31,8 @@ export default defineModule({
|
|
|
29
31
|
export type SemiclipRule = (player: Player, target: Player) => boolean;
|
|
30
32
|
|
|
31
33
|
let current: SemiclipRule | null = null;
|
|
34
|
+
/** The plugin that set the rule, as `callingPlugin()` numbers it. */
|
|
35
|
+
let currentFrom = 0;
|
|
32
36
|
|
|
33
37
|
/** The server is up. A rule set while the plugins are still loading waits for it. */
|
|
34
38
|
let started = false;
|
|
@@ -73,6 +77,7 @@ export class Semiclip {
|
|
|
73
77
|
set rule(rule: SemiclipRule | null) {
|
|
74
78
|
if (rule != null && current != null && rule != current) console.warn("[ReSemiclip] a rule was set over another one: the last one set is used");
|
|
75
79
|
current = rule;
|
|
80
|
+
currentFrom = callingPlugin();
|
|
76
81
|
if (started) apply();
|
|
77
82
|
}
|
|
78
83
|
|
|
@@ -95,13 +100,20 @@ export class Semiclip {
|
|
|
95
100
|
*/
|
|
96
101
|
passesThrough(player: Player) {
|
|
97
102
|
const mask = loaded() ? resemiclip_get_user_mask(player.id) : 0;
|
|
98
|
-
return
|
|
103
|
+
return server.players.filter(other => other.id != player.id && (mask & bitOf(other)) != 0);
|
|
99
104
|
}
|
|
100
105
|
}
|
|
101
106
|
|
|
102
107
|
/** Who walks through whom: the rule, the pairs worked out again, and what ReSemiclip has. */
|
|
103
108
|
export const semiclip = new Semiclip();
|
|
104
109
|
|
|
110
|
+
/** The plugin that set the rule stopped: its rule goes, and ReSemiclip has the rules back until a rule is set again. */
|
|
111
|
+
function stopped(plugin: number) {
|
|
112
|
+
if (current == null || currentFrom != plugin) return;
|
|
113
|
+
current = null;
|
|
114
|
+
if (started) apply();
|
|
115
|
+
}
|
|
116
|
+
|
|
105
117
|
function start() {
|
|
106
118
|
started = true;
|
|
107
119
|
apply();
|
|
@@ -142,18 +154,18 @@ function changed(player: Player) {
|
|
|
142
154
|
function left(player: Player) {
|
|
143
155
|
masks.delete(player.id);
|
|
144
156
|
if (activeRule() == null) return;
|
|
145
|
-
for (const other of
|
|
157
|
+
for (const other of server.players) {
|
|
146
158
|
if (other.id != player.id) tell(other, withBit(maskOf(other), player, false));
|
|
147
159
|
}
|
|
148
160
|
}
|
|
149
161
|
|
|
150
162
|
function updateAll(rule: SemiclipRule) {
|
|
151
|
-
const players =
|
|
163
|
+
const players = server.players;
|
|
152
164
|
for (const player of players) tell(player, maskFor(players.filter(other => other.id != player.id && rule(player, other))));
|
|
153
165
|
}
|
|
154
166
|
|
|
155
167
|
function updatePlayer(player: Player, rule: SemiclipRule) {
|
|
156
|
-
const others =
|
|
168
|
+
const others = server.players.filter(other => other.id != player.id);
|
|
157
169
|
tell(player, maskFor(others.filter(other => rule(player, other))));
|
|
158
170
|
for (const other of others) tell(other, withBit(maskOf(other), player, rule(other, player)));
|
|
159
171
|
}
|