@amxts/core 0.2.3 → 0.3.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/README.md +5 -5
- package/README.ru.md +5 -5
- package/as/amxts.d.ts +13 -3
- package/as/entities.ts +571 -501
- package/as/events.ts +3323 -557
- package/as/facade.ts +3079 -718
- package/as/fetch.ts +2 -2
- package/as/fs.ts +352 -59
- package/as/hlds.ts +121 -120
- package/as/hooks.ts +10585 -5177
- package/as/lib/check.ts +3 -2
- package/as/natives.ts +856 -1272
- package/as/promise.ts +37 -27
- package/as/vector.ts +94 -14
- package/includes/order.txt +17 -19
- package/node_modules/assemblyscript/std/assembly/index.d.ts +1 -1
- package/package.json +9 -6
- package/runtime/deps/assemblyscript/dist/asc.js +136 -42
- package/runtime/deps/assemblyscript/dist/assemblyscript.js +141 -141
- package/runtime/licenses/README.md +9 -7
- package/runtime/licenses/ReGameDLL-LICENSE +21 -0
- package/runtime/licenses/ReHLDS-LICENSE +21 -0
- package/runtime/licenses/zlib-LICENSE +22 -0
- package/runtime/natives.txt +618 -523
- package/runtime/patches/README.md +87 -1
- package/runtime/patches/assemblyscript-0.28.20-amxts.patch +4838 -416
- package/runtime/patches/wamr-2.4.5-amxts.patch +417 -5
- package/scripts/auto-imports.ts +1 -1
- package/scripts/build-identity.ts +102 -65
- package/scripts/build-wasm.ts +17 -13
- package/scripts/check.ts +4 -1
- package/scripts/client-messages.ts +73 -1
- package/scripts/compile-cache.ts +11 -8
- package/scripts/compile-pool.ts +6 -3
- package/scripts/compile-worker.ts +23 -23
- package/scripts/compile.ts +142 -19
- package/scripts/docs/as/amxts.ts +10 -4
- package/scripts/docs/as/facade.ts +1779 -275
- package/scripts/docs/as/fetch.ts +2 -2
- package/scripts/docs/as/fs.ts +190 -6
- package/scripts/docs/as/vector.ts +81 -0
- package/scripts/docs/entities.ts +12 -0
- package/scripts/docs/events.ts +49 -13
- package/scripts/docs/game.ts +6 -0
- package/scripts/docs/messages.ts +10 -1
- package/scripts/hlds-events.ts +11 -11
- package/scripts/includes.ts +3 -4
- package/scripts/leaf-natives.ts +84 -0
- package/scripts/player-fields.ts +1 -1
- package/scripts/plugin-natives.ts +1 -1
- package/scripts/prebuilt.ts +42 -11
- package/scripts/project.ts +63 -4
- package/scripts/reapi-events.ts +9 -9
- package/scripts/server-env.ts +145 -0
- package/scripts/shared-modules.ts +23 -7
- package/scripts/system.ts +1 -1
- package/scripts/tracked-fs.ts +11 -2
- package/scripts/typed-commands.ts +153 -15
- package/scripts/upgrade-calls.ts +225 -0
- package/scripts/upgrade-names.ts +1 -4
- package/scripts/upgrade.ts +47 -34
- package/src/cli-api.mjs +3 -2
- package/src/system.mjs +21 -11
- package/src/testing/compile.ts +31 -8
- package/src/testing/coroutines.ts +0 -10
- package/src/testing/memory.ts +89 -2
- package/src/testing/natives.ts +67 -30
- package/src/testing/server.ts +1094 -155
- package/src/testing/tables.ts +23 -6
- package/src/typecheck.mjs +110 -0
- package/runtime/licenses/Bun-LICENSE.md +0 -84
package/src/testing/natives.ts
CHANGED
|
@@ -200,7 +200,7 @@ function cvarNumber(value: number): string {
|
|
|
200
200
|
return Number.isInteger(value) ? String(value) : value.toFixed(6);
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
-
function giveWeapon(target: FakePlayer | undefined, name: string): number {
|
|
203
|
+
export function giveWeapon(target: FakePlayer | undefined, name: string): number {
|
|
204
204
|
if (!target) return 0;
|
|
205
205
|
if (name === 'item_kevlar' || name === 'item_assaultsuit') {
|
|
206
206
|
target.armor = 100;
|
|
@@ -214,7 +214,15 @@ function weaponByName(target: FakePlayer | undefined, name: string) {
|
|
|
214
214
|
return target?.items.find(w => w.kind === name);
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
-
|
|
217
|
+
/** A command run as the player's, as the game takes it: a weapon chosen, a side picked in the team menu. */
|
|
218
|
+
export function clientCommand(target: FakePlayer | undefined, line: string): void {
|
|
219
|
+
target?.commands.push(line);
|
|
220
|
+
if (line.startsWith('weapon_')) switchTo(target, line);
|
|
221
|
+
const side = { 'jointeam 1': 'TERRORIST', 'jointeam 2': 'CT', 'jointeam 6': 'SPECTATOR' }[line];
|
|
222
|
+
if (target && side) target.team = side as TeamName;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export function switchTo(target: FakePlayer | undefined, name: string): number {
|
|
218
226
|
const weapon = weaponByName(target, name);
|
|
219
227
|
if (!target || !weapon) return 0;
|
|
220
228
|
target.set('m_pActiveItem', weapon.id);
|
|
@@ -273,17 +281,26 @@ function setHamReturn(call: NativeCall, value: Value): number {
|
|
|
273
281
|
return 1;
|
|
274
282
|
}
|
|
275
283
|
|
|
276
|
-
// The engine's own
|
|
277
|
-
// no name get_user_msgid handed out stands for
|
|
278
|
-
const
|
|
284
|
+
// The engine's own messages, by number: below 64 no user message lives, so
|
|
285
|
+
// no name get_user_msgid handed out stands for them.
|
|
286
|
+
const SVC_NAMES = (
|
|
287
|
+
'BAD NOP DISCONNECT EVENT VERSION SETVIEW SOUND TIME PRINT STUFFTEXT SETANGLE SERVERINFO LIGHTSTYLE UPDATEUSERINFO'
|
|
288
|
+
+ ' DELTADESCRIPTION CLIENTDATA STOPSOUND PINGS PARTICLE DAMAGE SPAWNSTATIC EVENT_RELIABLE SPAWNBASELINE TEMPENTITY'
|
|
289
|
+
+ ' SETPAUSE SIGNONNUM CENTERPRINT KILLEDMONSTER FOUNDSECRET SPAWNSTATICSOUND INTERMISSION FINALE CDTRACK RESTORE'
|
|
290
|
+
+ ' CUTSCENE WEAPONANIM DECALNAME ROOMTYPE ADDANGLE NEWUSERMSG PACKETENTITIES DELTAPACKETENTITIES CHOKE RESOURCELIST'
|
|
291
|
+
+ ' NEWMOVEVARS RESOURCEREQUEST CUSTOMIZATION CROSSHAIRANGLE SOUNDFADE FILETXFERFAILED HLTV DIRECTOR VOICEINIT'
|
|
292
|
+
+ ' VOICEDATA SENDEXTRAINFO TIMESCALE RESOURCELOCATION SENDCVARVALUE SENDCVARVALUE2'
|
|
293
|
+
).split(' ');
|
|
279
294
|
|
|
280
295
|
/**
|
|
281
|
-
* message_begin: a user message by its name, or
|
|
282
|
-
*
|
|
296
|
+
* message_begin: a user message by its name, or the engine's own (a temporary
|
|
297
|
+
* effect, movevars, ...) as `SVC_<name>` - with who it goes to (`dest`,
|
|
298
|
+
* MSG_*) and the point it is seen from.
|
|
283
299
|
*/
|
|
284
300
|
function beginMessage(call: NativeCall, dest: number, type: number, player: number, origin: number[]): number {
|
|
285
|
-
|
|
286
|
-
|
|
301
|
+
const svc = SVC_NAMES[type];
|
|
302
|
+
if (svc) {
|
|
303
|
+
call.server.writing = { name: `SVC_${svc}`, player, args: [], dest, origin };
|
|
287
304
|
return 1;
|
|
288
305
|
}
|
|
289
306
|
const name = [...call.server.messageIds].find(([, id]) => id === type)?.[0];
|
|
@@ -298,7 +315,7 @@ function sendText(call: NativeCall, id: number, variant: 'chat' | 'center' | 'co
|
|
|
298
315
|
const PRINT_VARIANTS = ['', 'notify', 'console', 'chat', 'center'] as const;
|
|
299
316
|
|
|
300
317
|
// Reunion's client_auth_type by its number, as the player's API names each.
|
|
301
|
-
const AUTH_TYPES = ['unknown', 'dproto', 'steam', 'steamEmu', 'revEmu', 'oldRevEmu', 'hltv', 'sc2009', 'avsmp', 'sxei', 'revEmu2013', 'sse3'];
|
|
318
|
+
export const AUTH_TYPES = ['unknown', 'dproto', 'steam', 'steamEmu', 'revEmu', 'oldRevEmu', 'hltv', 'sc2009', 'avsmp', 'sxei', 'revEmu2013', 'sse3'];
|
|
302
319
|
|
|
303
320
|
/** A Pawn string of UTF-8 bytes - a path, a line of a file - as text. */
|
|
304
321
|
function bytesText(call: NativeCall, pointer: number): string {
|
|
@@ -387,6 +404,24 @@ export const NATIVES: Record<string, Native> = {
|
|
|
387
404
|
return 1;
|
|
388
405
|
},
|
|
389
406
|
close_dir: (c, [handle]) => +c.server.handles.delete(handle),
|
|
407
|
+
delete_file: (c, [name]) => +c.server.files.delete(normalizePath(bytesText(c, name))),
|
|
408
|
+
rename_file: (c, [from, to]) => {
|
|
409
|
+
const source = normalizePath(bytesText(c, from));
|
|
410
|
+
const bytes = c.server.files.get(source);
|
|
411
|
+
if (!bytes) return 0;
|
|
412
|
+
c.server.files.delete(source);
|
|
413
|
+
c.server.files.set(normalizePath(bytesText(c, to)), bytes);
|
|
414
|
+
return 1;
|
|
415
|
+
},
|
|
416
|
+
// An empty folder only, as the real one.
|
|
417
|
+
rmdir: (c, [name]) => {
|
|
418
|
+
const folder = normalizePath(bytesText(c, name));
|
|
419
|
+
const inside = [...c.server.files.keys(), ...c.server.folders].some(path => path.startsWith(`${folder}/`));
|
|
420
|
+
return +(!inside && c.server.folders.delete(folder));
|
|
421
|
+
},
|
|
422
|
+
file_size: (c, [name]) => c.server.files.get(normalizePath(bytesText(c, name)))?.length ?? -1,
|
|
423
|
+
// Every file of the fake changed when the server was made.
|
|
424
|
+
GetFileTime: c => Math.floor(c.server.startedAt / 1000),
|
|
390
425
|
// 0 when made; the parent has to be there, as for the real one.
|
|
391
426
|
mkdir: (c, [name]) => {
|
|
392
427
|
const folder = normalizePath(bytesText(c, name));
|
|
@@ -473,6 +508,10 @@ export const NATIVES: Record<string, Native> = {
|
|
|
473
508
|
if (!target) throw new Error(`menu_display: player ${id} is not in game`);
|
|
474
509
|
c.server.displayMenu(target, c.server.menu(menu), page);
|
|
475
510
|
},
|
|
511
|
+
show_menu: (c, [id, keys, text]) => {
|
|
512
|
+
c.server.showMenu(id, keys, c.memory.text(text));
|
|
513
|
+
return 1;
|
|
514
|
+
},
|
|
476
515
|
menu_destroy: (c, [menu]) => {
|
|
477
516
|
c.server.destroyMenu(menu);
|
|
478
517
|
return 1;
|
|
@@ -519,7 +558,7 @@ export const NATIVES: Record<string, Native> = {
|
|
|
519
558
|
},
|
|
520
559
|
|
|
521
560
|
set_hudmessage: (c, [r, g, b, x, y, _effects, _fxtime, hold, _fadein, _fadeout, channel]) => {
|
|
522
|
-
c.server.hud = { color: [r, g, b], x: bitsFloat(x), y: bitsFloat(y), hold: bitsFloat(hold), channel };
|
|
561
|
+
c.server.hud = { color: [r, g, b], x: bitsFloat(x), y: bitsFloat(y), hold: bitsFloat(hold), channel, line: 0, large: false };
|
|
523
562
|
},
|
|
524
563
|
show_hudmessage: (c, [id, format, ...tail]) => sendText(c, id, 'hud', formatPawn(c, c.memory.text(format), tail)),
|
|
525
564
|
|
|
@@ -633,13 +672,7 @@ export const NATIVES: Record<string, Native> = {
|
|
|
633
672
|
rg_switch_weapon: (c, [id, weapon]) => switchTo(player(c, id), entity(c, weapon)?.classname ?? ''),
|
|
634
673
|
user_has_weapon: (c, [id, weapon]) => +!!weaponByName(player(c, id), WEAPON_NAMES[weapon] ?? ''),
|
|
635
674
|
engclient_cmd: (c, [id, command, arg1, arg2]) => {
|
|
636
|
-
|
|
637
|
-
const line = [command, arg1, arg2].map(p => c.memory.text(p)).filter(Boolean).join(' ');
|
|
638
|
-
target?.commands.push(line);
|
|
639
|
-
if (line.startsWith('weapon_')) switchTo(target, line);
|
|
640
|
-
// The team menu's slots, as the game handles `jointeam`.
|
|
641
|
-
const side = { 'jointeam 1': 'TERRORIST', 'jointeam 2': 'CT', 'jointeam 6': 'SPECTATOR' }[line];
|
|
642
|
-
if (target && side) target.team = side as TeamName;
|
|
675
|
+
clientCommand(player(c, id), [command, arg1, arg2].map(p => c.memory.text(p)).filter(Boolean).join(' '));
|
|
643
676
|
},
|
|
644
677
|
rg_reset_maxspeed: () => {},
|
|
645
678
|
|
|
@@ -745,23 +778,23 @@ export const NATIVES: Record<string, Native> = {
|
|
|
745
778
|
|
|
746
779
|
nvault_open: (c, [name]) => {
|
|
747
780
|
const vault = c.memory.text(name);
|
|
748
|
-
c.server.
|
|
781
|
+
c.server.storage(vault);
|
|
749
782
|
c.server.vaultHandles.push(vault);
|
|
750
783
|
return c.server.vaultHandles.length - 1;
|
|
751
784
|
},
|
|
752
785
|
nvault_close: () => {},
|
|
753
786
|
nvault_set: (c, [handle, key, value]) => {
|
|
754
|
-
c.server.
|
|
787
|
+
c.server.storage(c.server.vaultHandles[handle]).set(c.memory.text(key), c.memory.text(value));
|
|
755
788
|
},
|
|
756
789
|
nvault_lookup: (c, [handle, key, value, length, stampAt]) => {
|
|
757
|
-
const found = c.server.
|
|
790
|
+
const found = c.server.storage(c.server.vaultHandles[handle]).get(c.memory.text(key));
|
|
758
791
|
if (found === undefined) return 0;
|
|
759
792
|
c.memory.setText(value, length, found);
|
|
760
793
|
if (stampAt) c.memory.setCell(stampAt, 0);
|
|
761
794
|
return 1;
|
|
762
795
|
},
|
|
763
796
|
nvault_remove: (c, [handle, key]) => {
|
|
764
|
-
c.server.
|
|
797
|
+
c.server.storage(c.server.vaultHandles[handle]).delete(c.memory.text(key));
|
|
765
798
|
},
|
|
766
799
|
|
|
767
800
|
// ------------------------------------------------------------ cvars
|
|
@@ -812,6 +845,12 @@ export const NATIVES: Record<string, Native> = {
|
|
|
812
845
|
// ------------------------------------------------------------ the game (reapi, engine, resemiclip)
|
|
813
846
|
|
|
814
847
|
register_dictionary: (c, [file]) => (c.server.loadDictionary(c.memory.text(file)) ? 1 : 0),
|
|
848
|
+
get_langsnum: c => c.server.dictionary.size,
|
|
849
|
+
get_lang: (c, [id, name]) => {
|
|
850
|
+
const code = [...c.server.dictionary.keys()][id] ?? '';
|
|
851
|
+
[code.charCodeAt(0) || 0, code.charCodeAt(1) || 0, 0].forEach((cell, at) => c.memory.setCell(name + at * 4, cell));
|
|
852
|
+
return 1;
|
|
853
|
+
},
|
|
815
854
|
GetLangTransKey: (c, [key]) => c.server.langKey(c.memory.text(key)),
|
|
816
855
|
LookupLangKey: (c, [out, size, key, id]) => {
|
|
817
856
|
const text = c.server.lookupLang(c.memory.text(key), c.memory.cell(id));
|
|
@@ -1004,7 +1043,7 @@ export const NATIVES: Record<string, Native> = {
|
|
|
1004
1043
|
GetHamReturnString: (c, [out, size]) => c.memory.setText(out, size, String(chain(c).answer)),
|
|
1005
1044
|
GetHamReturnVector: (c, [out]) => c.memory.setVector(out, [0, 0, 0]),
|
|
1006
1045
|
set_dhudmessage: (c, [r, g, b, x, y, _effects, _fxtime, hold]) => {
|
|
1007
|
-
c.server.hud = { color: [r, g, b], x: bitsFloat(x), y: bitsFloat(y), hold: bitsFloat(hold), channel: -1 };
|
|
1046
|
+
c.server.hud = { color: [r, g, b], x: bitsFloat(x), y: bitsFloat(y), hold: bitsFloat(hold), channel: -1, line: 0, large: true };
|
|
1008
1047
|
},
|
|
1009
1048
|
// A server without reapi hears ReGameDLL's events through these (as/hlds.ts).
|
|
1010
1049
|
// register_logevent(function[], argsnum, ...filters): server.gameLog() calls it.
|
|
@@ -1056,13 +1095,7 @@ export const NATIVES: Record<string, Native> = {
|
|
|
1056
1095
|
if (c.server.players.length >= c.server.maxPlayers) return 0;
|
|
1057
1096
|
return c.server.join(text(0), { bot: true, team: 'UNASSIGNED', alive: false }).id;
|
|
1058
1097
|
}
|
|
1059
|
-
if (type === constant('EngFunc_RunPlayerMove'))
|
|
1060
|
-
const bot = player(c, cell(0));
|
|
1061
|
-
const [, yaw] = c.memory.vector(tail[1]);
|
|
1062
|
-
const [forward, msec] = [float(2), cell(7)];
|
|
1063
|
-
call(`RunPlayerMove ${cell(0)} ${vector(1)} ${forward} ${float(3)} ${float(4)} ${cell(5)} ${cell(6)} ${msec}`);
|
|
1064
|
-
if (bot) bot.origin = [bot.origin[0] + Math.cos(yaw * Math.PI / 180) * forward * msec / 1000, bot.origin[1] + Math.sin(yaw * Math.PI / 180) * forward * msec / 1000, bot.origin[2]];
|
|
1065
|
-
}
|
|
1098
|
+
if (type === constant('EngFunc_RunPlayerMove')) c.server.runPlayerMove(cell(0), c.memory.vector(tail[1]), float(2), float(3), float(4), cell(5), cell(6), cell(7));
|
|
1066
1099
|
return 0;
|
|
1067
1100
|
},
|
|
1068
1101
|
dllfunc: (c, [type, ...tail]) => {
|
|
@@ -1111,7 +1144,11 @@ const SAME_AS: Record<string, string> = {
|
|
|
1111
1144
|
write_long: 'write_byte',
|
|
1112
1145
|
// A message sent through the engine, which every plugin's message hooks hear (emessage_end).
|
|
1113
1146
|
emessage_begin: 'message_begin',
|
|
1147
|
+
emessage_begin_f: 'message_begin_f',
|
|
1114
1148
|
ewrite_byte: 'write_byte',
|
|
1149
|
+
ewrite_char: 'write_byte',
|
|
1150
|
+
ewrite_coord_f: 'write_coord_f',
|
|
1151
|
+
ewrite_angle_f: 'write_coord_f',
|
|
1115
1152
|
ewrite_long: 'write_byte',
|
|
1116
1153
|
ewrite_short: 'write_byte',
|
|
1117
1154
|
ewrite_string: 'write_string',
|