@nativewrappers/common 0.0.143 → 0.0.145

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/Command.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  type Restricted = boolean | string | string[];
2
- interface ParameterTypes {
2
+ export interface ParameterTypes {
3
3
  number: number;
4
4
  playerId: number;
5
5
  string: string;
@@ -19,6 +19,40 @@ type MappedParameters<T extends Parameter[]> = {
19
19
  raw: string;
20
20
  };
21
21
  type CommandHandler<T extends Parameter[]> = (args: MappedParameters<T>) => void | Promise<void>;
22
+ type CommandContextObject<T> = {
23
+ source: number;
24
+ raw: string;
25
+ defaultValue?: T;
26
+ };
27
+ type CommandTypeParser<T> = (arg: string, context: CommandContextObject<T>) => T | undefined;
28
+ /**
29
+ * Defines a parser for {@link Command} so that you can dynamically add new parsers,
30
+ * or overwrite existing parsers to your needs.
31
+ *
32
+ *
33
+ * You will need to declare a module to extend the parameter types, like so:
34
+ * declare module "@nativewrappers/{client|common|server}" {
35
+ * interface ParameterTypes {
36
+ * playerId: MyFrameworkPlayer; // your custom player return type here
37
+ * }
38
+ * }
39
+ *
40
+ * @param name - the name of the parser to register
41
+ * @param parser - the parser that will be ran for the specified type, the parser cannot be async, if validation
42
+ * fails you can throw an error, this error will be printed to the console. It should
43
+ * be noted that if there wasn't an argument for an index the parser will never get called.
44
+ * @example
45
+ * ```ts
46
+ * registerParameterType("number", (arg) => {
47
+ * const num = parseInt(arg, 10);
48
+ * if (Number.isNaN(num)) {
49
+ * throw new TypeError(`could not parse argument into a valid number`);
50
+ * }
51
+ * return num;
52
+ * });
53
+ * ```
54
+ */
55
+ export declare function registerParameterType<K extends keyof ParameterTypes>(name: K, parser: CommandTypeParser<ParameterTypes[K]>): void;
22
56
  /**
23
57
  * ```typescript
24
58
  * new Command(["do", "deleteobjects"], async ({source, radius}) => {
package/Command.js CHANGED
@@ -3,7 +3,10 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
3
3
  import { GlobalData } from "./GlobalData";
4
4
  const commands = [];
5
5
  $SERVER: {
6
- on("playerJoining", () => emitNet("chat:addSuggestions", source, commands));
6
+ (() => {
7
+ $CLIENT: if (GlobalData.IS_CLIENT) return;
8
+ on("playerJoining", () => emitNet("chat:addSuggestions", source, commands));
9
+ })();
7
10
  }
8
11
  function registerCommand(name, commandHandler, restricted = true) {
9
12
  if (Array.isArray(name)) {
@@ -30,6 +33,55 @@ function registerCommand(name, commandHandler, restricted = true) {
30
33
  }
31
34
  }
32
35
  __name(registerCommand, "registerCommand");
36
+ const commandTypeParserRegistry = /* @__PURE__ */ new Map();
37
+ function registerParameterType(name, parser) {
38
+ commandTypeParserRegistry.set(name, parser);
39
+ }
40
+ __name(registerParameterType, "registerParameterType");
41
+ registerParameterType("number", (arg) => {
42
+ const num = parseInt(arg, 10);
43
+ if (Number.isNaN(num)) {
44
+ throw new TypeError(`could not parse argument into a valid number`);
45
+ }
46
+ return num;
47
+ });
48
+ registerParameterType("string", (arg) => {
49
+ return arg;
50
+ });
51
+ (() => {
52
+ $CLIENT: if (GlobalData.IS_CLIENT) {
53
+ registerParameterType("playerId", (arg) => {
54
+ const isMe = arg === "me";
55
+ const target = isMe ? GetPlayerServerId(PlayerId()) : parseInt(arg, 10);
56
+ if (Number.isNaN(target)) {
57
+ throw new TypeError(`could not parse argument into a valid playerId`);
58
+ }
59
+ if (isMe) {
60
+ return target;
61
+ }
62
+ if (GetPlayerFromServerId(target) === -1) {
63
+ throw new Error(`player with server id $${target} didn't exist`);
64
+ }
65
+ return target;
66
+ });
67
+ return;
68
+ }
69
+ $SERVER: {
70
+ registerParameterType("playerId", (arg, { source: source2 }) => {
71
+ const target = arg === "me" ? source2 : parseInt(arg, 10);
72
+ if (Number.isNaN(target)) {
73
+ throw new TypeError(`could not parse argument into a valid playerId`);
74
+ }
75
+ if (!DoesPlayerExist(target)) {
76
+ throw new Error(`player at ${source2} didn't exist`);
77
+ }
78
+ return target;
79
+ });
80
+ }
81
+ })();
82
+ registerParameterType("longString", (arg, { raw }) => {
83
+ return raw.substring(raw.indexOf(arg));
84
+ });
33
85
  class Command {
34
86
  /**
35
87
  * Registers a new executable command with optional parameter validation and permission restrictions.
@@ -88,39 +140,31 @@ class Command {
88
140
  raw
89
141
  };
90
142
  if (!this.params) return mapped;
143
+ const defaultContextObject = {
144
+ source: source2,
145
+ raw
146
+ };
91
147
  const result = this.params.every((param, index) => {
92
148
  const arg = args[index];
93
149
  let value = arg;
94
- const hasDefaultValue = param.defaultValue !== void 0;
95
150
  const hasArg = typeof arg === "string";
96
- if (!hasArg && hasDefaultValue) {
151
+ if (!hasArg) {
97
152
  value = param.defaultValue;
98
153
  } else {
99
- switch (param.type) {
100
- case "number":
101
- if (hasDefaultValue && !hasArg) {
102
- value = param.defaultValue;
103
- } else {
104
- value = +arg;
105
- }
106
- break;
107
- case "string":
108
- value = !Number(arg) ? arg : false;
109
- break;
110
- case "playerId":
111
- $SERVER: {
112
- value = arg === "me" ? source2 : +arg;
113
- if (!value || !DoesPlayerExist(value.toString())) value = void 0;
114
- }
115
- $CLIENT: {
116
- value = arg === "me" ? GetPlayerServerId(PlayerId()) : +arg;
117
- if (!value || GetPlayerFromServerId(value) === -1) value = void 0;
118
- }
119
- break;
120
- case "longString":
121
- value = raw.substring(raw.indexOf(arg));
122
- break;
154
+ const parser = commandTypeParserRegistry.get(param.type);
155
+ if (!parser) {
156
+ console.error(
157
+ `${param.type} didn't have a valid parser, did you forget to register it with 'registerParameterType'?`
158
+ );
159
+ return false;
160
+ }
161
+ try {
162
+ value = parser(arg, defaultContextObject);
163
+ } catch (e) {
164
+ globalThis.printError("command parsing", e);
165
+ return false;
123
166
  }
167
+ defaultContextObject.defaultValue = param.defaultValue;
124
168
  }
125
169
  if (value === void 0 && (!param.optional || param.optional && arg)) {
126
170
  return Citizen.trace(
@@ -150,5 +194,6 @@ ${err.message}`);
150
194
  }
151
195
  }
152
196
  export {
153
- Command
197
+ Command,
198
+ registerParameterType
154
199
  };
@@ -1,10 +1,14 @@
1
+ /**
2
+ * The convar type that will be used for the specified decor
3
+ */
1
4
  export declare enum ConVarType {
2
5
  String = 0,
3
6
  Integer = 1,
4
7
  Float = 2,
5
8
  Boolean = 3
6
9
  }
7
- export type DeserializeFn = (data: unknown) => unknown;
10
+ export type DeserializeFn<T extends ConVarType> = (data: InferType<T>) => any;
11
+ type InferType<T extends ConVarType> = T extends ConVarType.String ? string : T extends ConVarType.Integer ? number : T extends ConVarType.Float ? number : T extends ConVarType.Boolean ? boolean : never;
8
12
  /**
9
13
  * Gets the specified `ConVar`s value, this will bind to the parameter of the current class
10
14
  * updating it whenever the ConVar value changes.
@@ -48,4 +52,5 @@ export type DeserializeFn = (data: unknown) => unknown;
48
52
  * }
49
53
  * ```
50
54
  */
51
- export declare function ConVar(name: string, convarType: ConVarType, deserialize?: DeserializeFn): (_initialValue: any, context: ClassFieldDecoratorContext, ..._args: any[]) => void;
55
+ export declare function ConVar<T extends ConVarType>(name: string, convarType: T, deserialize?: DeserializeFn<T>): (_initialValue: any, context: ClassFieldDecoratorContext, ..._args: any[]) => void;
56
+ export {};
package/decors/ConVar.js CHANGED
@@ -21,7 +21,7 @@ const getConvarFunction = /* @__PURE__ */ __name((con_var_type) => {
21
21
  // needed so typescript wont complain about "unreachable code" for the error below
22
22
  default:
23
23
  }
24
- throw new Error("Got invalid ConVarType");
24
+ throw new Error(`Got conVarType: ${con_var_type} but it was not a valid ConVar type, please refer to "ConVarType"`);
25
25
  }, "getConvarFunction");
26
26
  function ConVar(name, convarType, deserialize) {
27
27
  return /* @__PURE__ */ __name(function actualDecorator(_initialValue, context, ..._args) {
@@ -0,0 +1,26 @@
1
+ export type MessageTypeDecoder<T> = {
2
+ decode: (input: Uint8Array) => T;
3
+ name: string;
4
+ };
5
+ export type MessageTypeEncoder<T> = {
6
+ encode: (message: T) => any;
7
+ name: string;
8
+ };
9
+ type ProtoCallback<Message> = (message: Message) => Promise<void>;
10
+ type NetProtoCallback<Message> = (source: number, message: Message) => Promise<void>;
11
+ /**
12
+ * PMA uses ts-proto to define our types, you can see that here: https://github.com/stephenh/ts-proto
13
+ * You will have to modify the generator to add `name` or just use {@param eventName}
14
+ *
15
+ * We use this:
16
+ * content = content.replace(/export const (\w+)[^=]*= \{/g, 'export const $1 = {\n name: "$1" as const,');
17
+ *
18
+ * This makes it very nice to handle events since we only have to give it the Protobuf Object
19
+ *
20
+ */
21
+ export declare function OnProto<T>(messageType: MessageTypeDecoder<T>, eventName?: string): (originalMethod: ProtoCallback<T>, context: ClassMethodDecoratorContext) => void;
22
+ /**
23
+ * This makes it very nice to handle events since we only have to give it the Protobuf Object
24
+ */
25
+ export declare function OnProtoNet<T>(messageType: MessageTypeDecoder<T>, eventName?: string): (originalMethod: NetProtoCallback<T>, context: ClassMethodDecoratorContext) => void;
26
+ export {};
@@ -0,0 +1,50 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ import { Net } from "../net/Net";
4
+ function parseSource(source) {
5
+ const id = source.replace(/^(internal-)?net:/, "");
6
+ return parseInt(id, 10);
7
+ }
8
+ __name(parseSource, "parseSource");
9
+ function OnProto(messageType, eventName) {
10
+ const event = eventName ?? `pb:${messageType.name}`;
11
+ return /* @__PURE__ */ __name(function actualDecorator(originalMethod, context) {
12
+ if (context.private) {
13
+ throw new Error("OnProto does not work on private methods");
14
+ }
15
+ context.addInitializer(function() {
16
+ Net.onRaw(event, async (data) => {
17
+ try {
18
+ const message = messageType.decode(data);
19
+ return await originalMethod.call(this, message);
20
+ } catch (e) {
21
+ globalThis.printError?.("proto event", e);
22
+ }
23
+ });
24
+ });
25
+ }, "actualDecorator");
26
+ }
27
+ __name(OnProto, "OnProto");
28
+ function OnProtoNet(messageType, eventName) {
29
+ const event = eventName ?? `pb:${messageType.name}`;
30
+ return /* @__PURE__ */ __name(function actualDecorator(originalMethod, context) {
31
+ if (context.private) {
32
+ throw new Error("OnProto does not work on private methods");
33
+ }
34
+ context.addInitializer(function() {
35
+ Net.onRawNet(event, async (data, source) => {
36
+ try {
37
+ const message = messageType.decode(data);
38
+ return await originalMethod.call(this, parseSource(source), message);
39
+ } catch (e) {
40
+ globalThis.printError?.("proto event", e);
41
+ }
42
+ });
43
+ });
44
+ }, "actualDecorator");
45
+ }
46
+ __name(OnProtoNet, "OnProtoNet");
47
+ export {
48
+ OnProto,
49
+ OnProtoNet
50
+ };
package/index.d.ts CHANGED
@@ -19,11 +19,13 @@ export * from "./utils/enumValues";
19
19
  export * from "./utils/getStringFromUInt8Array";
20
20
  export * from "./utils/getUInt32FromUint8Array";
21
21
  export * from "./utils/randomInt";
22
+ export * from "./net/Net";
22
23
  export * from "./net/NetworkedMap";
23
24
  export * from "./decors/ConVar";
24
25
  export * from "./decors/Events";
25
26
  export * from "./decors/Exports";
26
27
  export * from "./decors/Permissions";
28
+ export * from "./decors/Proto";
27
29
  export * from "./decors/Resources";
28
30
  export * from "./decors/Ticks";
29
31
  export * from "./collections/CircularBuffer";
package/index.js CHANGED
@@ -19,11 +19,13 @@ export * from "./utils/enumValues";
19
19
  export * from "./utils/getStringFromUInt8Array";
20
20
  export * from "./utils/getUInt32FromUint8Array";
21
21
  export * from "./utils/randomInt";
22
+ export * from "./net/Net";
22
23
  export * from "./net/NetworkedMap";
23
24
  export * from "./decors/ConVar";
24
25
  export * from "./decors/Events";
25
26
  export * from "./decors/Exports";
26
27
  export * from "./decors/Permissions";
28
+ export * from "./decors/Proto";
27
29
  export * from "./decors/Resources";
28
30
  export * from "./decors/Ticks";
29
31
  export * from "./collections/CircularBuffer";
package/net/Net.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ import type { MessageTypeEncoder } from "../decors/Proto";
2
+ type EventCallback = (...args: any[]) => void;
3
+ type RawEventCallback = (data: Uint8Array, source: `internal-net:${number}` | `net:${number}`) => void;
4
+ export declare class Net {
5
+ static emit(eventName: string, ...args: any[]): void;
6
+ static on(eventName: string, cb: EventCallback): void;
7
+ static onNet(eventName: string, cb: EventCallback): void;
8
+ static onRaw(eventName: string, cb: RawEventCallback): void;
9
+ static onRawNet(eventName: string, cb: RawEventCallback): void;
10
+ }
11
+ export declare class NetServer extends Net {
12
+ static emitNet(eventName: string, source: number, ...args: any[]): void;
13
+ static emitProto<T>(source: number, message: MessageTypeEncoder<T>): void;
14
+ static emitRawNet(eventName: string, source: number, data: Uint8Array): void;
15
+ }
16
+ export declare class NetClient extends Net {
17
+ static emitNet(eventName: string, source: number, ...args: any[]): void;
18
+ static emitProto<T>(message: MessageTypeEncoder<T>): void;
19
+ static emitRawNet(eventName: string, data: Uint8Array): void;
20
+ }
21
+ export {};
package/net/Net.js ADDED
@@ -0,0 +1,59 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ class Net {
4
+ static {
5
+ __name(this, "Net");
6
+ }
7
+ static emit(eventName, ...args) {
8
+ emit(eventName, ...args);
9
+ }
10
+ static on(eventName, cb) {
11
+ on(eventName, cb);
12
+ }
13
+ static onNet(eventName, cb) {
14
+ onNet(eventName, cb);
15
+ }
16
+ static onRaw(eventName, cb) {
17
+ RegisterResourceAsEventHandler(eventName);
18
+ addRawEventListener(eventName, cb);
19
+ }
20
+ static onRawNet(eventName, cb) {
21
+ RegisterNetEvent(eventName);
22
+ Net.onRaw(eventName, cb);
23
+ }
24
+ }
25
+ class NetServer extends Net {
26
+ static {
27
+ __name(this, "NetServer");
28
+ }
29
+ static emitNet(eventName, source, ...args) {
30
+ emitNet(eventName, source, ...args);
31
+ }
32
+ static emitProto(source, message) {
33
+ const encoded = message.encode(message);
34
+ NetServer.emitRawNet(message.name, source, encoded);
35
+ }
36
+ static emitRawNet(eventName, source, data) {
37
+ TriggerClientEventInternal(eventName, source, data, data.byteLength);
38
+ }
39
+ }
40
+ class NetClient extends Net {
41
+ static {
42
+ __name(this, "NetClient");
43
+ }
44
+ static emitNet(eventName, source, ...args) {
45
+ emitNet(eventName, source, ...args);
46
+ }
47
+ static emitProto(message) {
48
+ const encoded = message.encode(message);
49
+ NetClient.emitRawNet(message.name, encoded);
50
+ }
51
+ static emitRawNet(eventName, data) {
52
+ TriggerServerEventInternal(eventName, data, data.byteLength);
53
+ }
54
+ }
55
+ export {
56
+ Net,
57
+ NetClient,
58
+ NetServer
59
+ };
@@ -1,10 +1,20 @@
1
+ declare enum MapChangeType {
2
+ SubValueChanged = 0,
3
+ Add = 1,
4
+ Remove = 2,
5
+ Reset = 3,
6
+ Init = 4,
7
+ Resync = 5
8
+ }
9
+ type MapChanges<K, V> = [MapChangeType, K?, V?] | [MapChangeType.SubValueChanged, K, string, any];
1
10
  type ChangeListener<V> = (value: V | undefined) => void;
2
11
  /**
3
12
  * not ready to be used just thoughts right now
4
13
  */
5
14
  export declare class NetworkedMap<K, V> extends Map<K, V> {
6
15
  #private;
7
- constructor(syncName: string, initialValue?: [K, V][]);
16
+ constructor(syncName: string);
17
+ initialize(initialValue: [K, V][]): void;
8
18
  get SyncName(): string;
9
19
  private onPlayerDropped;
10
20
  resync(source: number): void;
@@ -12,7 +22,7 @@ export declare class NetworkedMap<K, V> extends Map<K, V> {
12
22
  removeSubscriber(sub: number): boolean;
13
23
  hasSubscriber(sub: number): boolean;
14
24
  subscriberCount(): number;
15
- private handleSync;
25
+ protected handleSync(data: MapChanges<K, V>[]): void;
16
26
  listenForChange(key: K, fn: ChangeListener<V | undefined>): void;
17
27
  set(key: K, value: V): this;
18
28
  clear(): void;
@@ -1,6 +1,7 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
3
  import { GlobalData } from "../GlobalData";
4
+ import { Net } from "../net/Net";
4
5
  class NetworkedMapEventManager {
5
6
  static {
6
7
  __name(this, "NetworkedMapEventManager");
@@ -17,8 +18,8 @@ class NetworkedMapEventManager {
17
18
  return;
18
19
  }
19
20
  $CLIENT: {
20
- RegisterResourceAsEventHandler(`${GlobalData.CurrentResource}:syncChanges`);
21
- addRawEventListener(`${GlobalData.CurrentResource}:syncChanges`, (msgpack_data) => {
21
+ if (GlobalState.IS_SERVER) return;
22
+ Net.onRaw(`${GlobalData.CurrentResource}:syncChanges`, (msgpack_data) => {
22
23
  const data = msgpack_unpack(msgpack_data);
23
24
  const syncName = data[0];
24
25
  const syncData = data[1];
@@ -46,8 +47,8 @@ class NetworkedMap extends Map {
46
47
  #queuedChanges = [];
47
48
  #changeListeners = /* @__PURE__ */ new Map();
48
49
  #subscribers = /* @__PURE__ */ new Set();
49
- constructor(syncName, initialValue) {
50
- super(initialValue);
50
+ constructor(syncName) {
51
+ super();
51
52
  this.#syncName = syncName;
52
53
  GlobalData.NetworkedTicks.push(this);
53
54
  netManager.addNetworkedMap(this);
@@ -61,6 +62,11 @@ class NetworkedMap extends Map {
61
62
  }
62
63
  }
63
64
  }
65
+ initialize(initialValue) {
66
+ for (const [k, v] of initialValue) {
67
+ this.set(k, v);
68
+ }
69
+ }
64
70
  get SyncName() {
65
71
  return this.#syncName;
66
72
  }
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  ],
9
9
  "license": "MIT",
10
10
  "type": "module",
11
- "version": "0.0.143",
11
+ "version": "0.0.145",
12
12
  "repository": {
13
13
  "type": "git",
14
14
  "url": "https://github.com/nativewrappers/nativewrappers.git"