@open-core/ragemp-adapter 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.
Files changed (84) hide show
  1. package/README.md +51 -0
  2. package/dist/.tsbuildinfo/client.tsbuildinfo +1 -0
  3. package/dist/.tsbuildinfo/root.tsbuildinfo +1 -0
  4. package/dist/.tsbuildinfo/server.tsbuildinfo +1 -0
  5. package/dist/.tsbuildinfo/shared.tsbuildinfo +1 -0
  6. package/dist/client/create-ragemp-client-adapter.d.ts +9 -0
  7. package/dist/client/create-ragemp-client-adapter.js +48 -0
  8. package/dist/client/index.d.ts +9 -0
  9. package/dist/client/index.js +25 -0
  10. package/dist/client/key-maps.d.ts +9 -0
  11. package/dist/client/key-maps.js +128 -0
  12. package/dist/client/native-chat.d.ts +2 -0
  13. package/dist/client/native-chat.js +50 -0
  14. package/dist/client/ragemp-blip-bridge.d.ts +12 -0
  15. package/dist/client/ragemp-blip-bridge.js +139 -0
  16. package/dist/client/ragemp-hasher.d.ts +4 -0
  17. package/dist/client/ragemp-hasher.js +20 -0
  18. package/dist/client/ragemp-local-player-bridge.d.ts +8 -0
  19. package/dist/client/ragemp-local-player-bridge.js +26 -0
  20. package/dist/client/ragemp-log-console.d.ts +11 -0
  21. package/dist/client/ragemp-log-console.js +75 -0
  22. package/dist/client/ragemp-marker-bridge.d.ts +11 -0
  23. package/dist/client/ragemp-marker-bridge.js +57 -0
  24. package/dist/client/ragemp-notification-bridge.d.ts +5 -0
  25. package/dist/client/ragemp-notification-bridge.js +70 -0
  26. package/dist/client/ragemp-platform-bridge.d.ts +141 -0
  27. package/dist/client/ragemp-platform-bridge.js +479 -0
  28. package/dist/client/ragemp-runtime-bridge.d.ts +30 -0
  29. package/dist/client/ragemp-runtime-bridge.js +119 -0
  30. package/dist/client/ragemp-runtime-globals.d.ts +5 -0
  31. package/dist/client/ragemp-runtime-globals.js +57 -0
  32. package/dist/client/ragemp-spawn-bridge.d.ts +15 -0
  33. package/dist/client/ragemp-spawn-bridge.js +107 -0
  34. package/dist/client/ragemp-webview-bridge.d.ts +22 -0
  35. package/dist/client/ragemp-webview-bridge.js +131 -0
  36. package/dist/index.d.ts +4 -0
  37. package/dist/index.js +20 -0
  38. package/dist/server/create-ragemp-server-adapter.d.ts +9 -0
  39. package/dist/server/create-ragemp-server-adapter.js +54 -0
  40. package/dist/server/index.d.ts +11 -0
  41. package/dist/server/index.js +27 -0
  42. package/dist/server/ragemp-capabilities.d.ts +14 -0
  43. package/dist/server/ragemp-capabilities.js +36 -0
  44. package/dist/server/ragemp-engine-events.d.ts +11 -0
  45. package/dist/server/ragemp-engine-events.js +72 -0
  46. package/dist/server/ragemp-entity-server.d.ts +29 -0
  47. package/dist/server/ragemp-entity-server.js +122 -0
  48. package/dist/server/ragemp-exports.d.ts +7 -0
  49. package/dist/server/ragemp-exports.js +36 -0
  50. package/dist/server/ragemp-hasher.d.ts +7 -0
  51. package/dist/server/ragemp-hasher.js +23 -0
  52. package/dist/server/ragemp-npc-lifecycle-server.d.ts +9 -0
  53. package/dist/server/ragemp-npc-lifecycle-server.js +51 -0
  54. package/dist/server/ragemp-ped-server.d.ts +8 -0
  55. package/dist/server/ragemp-ped-server.js +37 -0
  56. package/dist/server/ragemp-player-appearance-lifecycle-server.d.ts +19 -0
  57. package/dist/server/ragemp-player-appearance-lifecycle-server.js +66 -0
  58. package/dist/server/ragemp-player-lifecycle-server.d.ts +7 -0
  59. package/dist/server/ragemp-player-lifecycle-server.js +40 -0
  60. package/dist/server/ragemp-player-server.d.ts +20 -0
  61. package/dist/server/ragemp-player-server.js +89 -0
  62. package/dist/server/ragemp-player-state-sync-server.d.ts +7 -0
  63. package/dist/server/ragemp-player-state-sync-server.js +29 -0
  64. package/dist/server/ragemp-playerinfo.d.ts +6 -0
  65. package/dist/server/ragemp-playerinfo.js +19 -0
  66. package/dist/server/ragemp-resourceinfo.d.ts +5 -0
  67. package/dist/server/ragemp-resourceinfo.js +25 -0
  68. package/dist/server/ragemp-tick.d.ts +7 -0
  69. package/dist/server/ragemp-tick.js +24 -0
  70. package/dist/server/ragemp-vehicle-lifecycle-server.d.ts +10 -0
  71. package/dist/server/ragemp-vehicle-lifecycle-server.js +57 -0
  72. package/dist/server/ragemp-vehicle-server.d.ts +15 -0
  73. package/dist/server/ragemp-vehicle-server.js +59 -0
  74. package/dist/shared/exports-registry.d.ts +29 -0
  75. package/dist/shared/exports-registry.js +87 -0
  76. package/dist/shared/transport/adapter.d.ts +8 -0
  77. package/dist/shared/transport/adapter.js +18 -0
  78. package/dist/shared/transport/helpers.d.ts +24 -0
  79. package/dist/shared/transport/helpers.js +70 -0
  80. package/dist/shared/transport/ragemp.events.d.ts +10 -0
  81. package/dist/shared/transport/ragemp.events.js +45 -0
  82. package/dist/shared/transport/ragemp.rpc.d.ts +27 -0
  83. package/dist/shared/transport/ragemp.rpc.js +181 -0
  84. package/package.json +64 -0
@@ -0,0 +1,7 @@
1
+ import { ITick } from '@open-core/framework/contracts/server';
2
+ /**
3
+ * Rage Multiplayer implementation of ITick using native setTick
4
+ */
5
+ export declare class RageMPTick implements ITick {
6
+ setTick(handler: () => void | Promise<void>): void;
7
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.RageMPTick = void 0;
10
+ const tsyringe_1 = require("tsyringe");
11
+ /**
12
+ * Rage Multiplayer implementation of ITick using native setTick
13
+ */
14
+ let RageMPTick = class RageMPTick {
15
+ setTick(handler) {
16
+ setInterval(() => {
17
+ void handler();
18
+ }, 0);
19
+ }
20
+ };
21
+ exports.RageMPTick = RageMPTick;
22
+ exports.RageMPTick = RageMPTick = __decorate([
23
+ (0, tsyringe_1.injectable)()
24
+ ], RageMPTick);
@@ -0,0 +1,10 @@
1
+ import { IVehicleServer } from '@open-core/framework/contracts/server';
2
+ import { IVehicleLifecycleServer } from '@open-core/framework/contracts/server';
3
+ import type { CreateVehicleServerRequest, CreateVehicleServerResult, WarpPlayerIntoVehicleRequest } from '@open-core/framework/contracts/server';
4
+ export declare class RageMPVehicleLifecycleServer extends IVehicleLifecycleServer {
5
+ private readonly vehicleServer;
6
+ private toRageMPSeatIndex;
7
+ constructor(vehicleServer: IVehicleServer);
8
+ create(request: CreateVehicleServerRequest): CreateVehicleServerResult;
9
+ warpPlayerIntoVehicle(request: WarpPlayerIntoVehicleRequest): Promise<void>;
10
+ }
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.RageMPVehicleLifecycleServer = void 0;
16
+ const tsyringe_1 = require("tsyringe");
17
+ const server_1 = require("@open-core/framework/contracts/server");
18
+ const server_2 = require("@open-core/framework/contracts/server");
19
+ let RageMPVehicleLifecycleServer = class RageMPVehicleLifecycleServer extends server_2.IVehicleLifecycleServer {
20
+ toRageMPSeatIndex(seatIndex) {
21
+ return seatIndex < 0 ? 0 : seatIndex + 1;
22
+ }
23
+ constructor(vehicleServer) {
24
+ super();
25
+ this.vehicleServer = vehicleServer;
26
+ }
27
+ create(request) {
28
+ const handle = this.vehicleServer.createServerSetter(request.modelHash, 'automobile', request.position.x, request.position.y, request.position.z, request.heading);
29
+ if (!Number.isFinite(handle) || handle < 0) {
30
+ throw new Error('Failed to create vehicle entity');
31
+ }
32
+ return {
33
+ handle,
34
+ networkId: this.vehicleServer.getNetworkIdFromEntity(handle),
35
+ };
36
+ }
37
+ async warpPlayerIntoVehicle(request) {
38
+ const player = mp.players.at(Number(request.playerSrc));
39
+ const vehicle = mp.vehicles.at(request.networkId);
40
+ const seatIndex = this.toRageMPSeatIndex(request.seatIndex);
41
+ await new Promise((resolve) => setTimeout(resolve, 200));
42
+ try {
43
+ player.putIntoVehicle(vehicle, seatIndex);
44
+ }
45
+ catch {
46
+ const offset = new mp.Vector3(vehicle.position.x + 1.5, vehicle.position.y, vehicle.position.z);
47
+ player.position = offset;
48
+ player.heading = vehicle.heading;
49
+ }
50
+ }
51
+ };
52
+ exports.RageMPVehicleLifecycleServer = RageMPVehicleLifecycleServer;
53
+ exports.RageMPVehicleLifecycleServer = RageMPVehicleLifecycleServer = __decorate([
54
+ (0, tsyringe_1.injectable)(),
55
+ __param(0, (0, tsyringe_1.inject)(server_1.IVehicleServer)),
56
+ __metadata("design:paramtypes", [server_1.IVehicleServer])
57
+ ], RageMPVehicleLifecycleServer);
@@ -0,0 +1,15 @@
1
+ import { IVehicleServer } from '@open-core/framework/contracts/server';
2
+ /**
3
+ * Rage Multiplayer implementation of server-side vehicle operations.
4
+ */
5
+ export declare class RageMPVehicleServer extends IVehicleServer {
6
+ createServerSetter(modelHash: number, _vehicleType: string, x: number, y: number, z: number, heading: number): number;
7
+ getColours(handle: number): [number, number];
8
+ setColours(handle: number, primary: number, secondary: number): void;
9
+ getNumberPlateText(handle: number): string;
10
+ setNumberPlateText(handle: number, text: string): void;
11
+ setDoorsLocked(handle: number, state: number): void;
12
+ getNetworkIdFromEntity(handle: number): number;
13
+ getEntityFromNetworkId(networkId: number): number;
14
+ networkIdExists(networkId: number): boolean;
15
+ }
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.RageMPVehicleServer = void 0;
10
+ const tsyringe_1 = require("tsyringe");
11
+ const server_1 = require("@open-core/framework/contracts/server");
12
+ /**
13
+ * Rage Multiplayer implementation of server-side vehicle operations.
14
+ */
15
+ let RageMPVehicleServer = class RageMPVehicleServer extends server_1.IVehicleServer {
16
+ createServerSetter(modelHash, _vehicleType, x, y, z, heading) {
17
+ const vehicle = mp.vehicles.new(modelHash, new mp.Vector3(x, y, z), {
18
+ heading,
19
+ });
20
+ return vehicle.id;
21
+ }
22
+ getColours(handle) {
23
+ const vehicle = mp.vehicles.at(handle);
24
+ return [vehicle.getColor(0), vehicle.getColor(1)];
25
+ }
26
+ setColours(handle, primary, secondary) {
27
+ mp.vehicles.at(handle).setColor(primary, secondary);
28
+ }
29
+ getNumberPlateText(handle) {
30
+ return mp.vehicles.at(handle).numberPlate;
31
+ }
32
+ setNumberPlateText(handle, text) {
33
+ mp.vehicles.at(handle).numberPlate = text;
34
+ }
35
+ setDoorsLocked(handle, state) {
36
+ mp.vehicles.at(handle).locked = state >= 2;
37
+ }
38
+ getNetworkIdFromEntity(handle) {
39
+ // This implementation attempts to mimic FiveM behavior in RageMP,
40
+ // but it's not guaranteed to be fully implemented.
41
+ if (!mp.vehicles.exists(handle))
42
+ return 0;
43
+ return mp.vehicles.at(handle).id;
44
+ }
45
+ getEntityFromNetworkId(networkId) {
46
+ // This implementation attempts to mimic FiveM behavior in RageMP,
47
+ // but it's not guaranteed to be fully implemented.
48
+ if (!mp.vehicles.exists(networkId))
49
+ return 0;
50
+ return mp.vehicles.at(networkId).id;
51
+ }
52
+ networkIdExists(networkId) {
53
+ return mp.vehicles.exists(networkId);
54
+ }
55
+ };
56
+ exports.RageMPVehicleServer = RageMPVehicleServer;
57
+ exports.RageMPVehicleServer = RageMPVehicleServer = __decorate([
58
+ (0, tsyringe_1.injectable)()
59
+ ], RageMPVehicleServer);
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Replicates FiveM's `exports` system for RageMP.
3
+ * Registry layout: Map<resource, Map<exportName, handler>>
4
+ */
5
+ type ExportArgs = readonly unknown[];
6
+ type ExportHandler = (...args: ExportArgs) => unknown;
7
+ type NamespaceProxy = Record<string, ExportHandler>;
8
+ export type ExportsProxy = {
9
+ readonly [resource: string]: NamespaceProxy;
10
+ };
11
+ export declare class ExportsRegistry {
12
+ private readonly registry;
13
+ private readonly namespaceProxyCache;
14
+ register(resource: string, name: string, handler: ExportHandler): void;
15
+ call(resource: string, name: string, ...args: ExportArgs): unknown;
16
+ private createNamespaceProxy;
17
+ private getOrCreateNamespaceProxy;
18
+ /**
19
+ * Returns the namespace proxy for a resource if it has registered exports.
20
+ * Matches FiveM behavior where unknown resources return undefined.
21
+ */
22
+ resourceProxy<T>(resource: string): T | undefined;
23
+ createProxy(): ExportsProxy;
24
+ list(resource: string): string[];
25
+ }
26
+ export declare const exportsRegistry: ExportsRegistry;
27
+ export declare function registerExport(resource: string, name: string, handler: ExportHandler): void;
28
+ export declare function callExport(resource: string, name: string, ...args: ExportArgs): unknown;
29
+ export {};
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ /**
3
+ * Replicates FiveM's `exports` system for RageMP.
4
+ * Registry layout: Map<resource, Map<exportName, handler>>
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.exportsRegistry = exports.ExportsRegistry = void 0;
8
+ exports.registerExport = registerExport;
9
+ exports.callExport = callExport;
10
+ class ExportsRegistry {
11
+ constructor() {
12
+ this.registry = new Map();
13
+ this.namespaceProxyCache = new Map();
14
+ }
15
+ register(resource, name, handler) {
16
+ let namespace = this.registry.get(resource);
17
+ if (!namespace) {
18
+ namespace = new Map();
19
+ this.registry.set(resource, namespace);
20
+ }
21
+ if (namespace.has(name)) {
22
+ throw new Error(`[exports] Export "${name}" already registered in "${resource}".`);
23
+ }
24
+ namespace.set(name, handler);
25
+ }
26
+ call(resource, name, ...args) {
27
+ const handler = this.registry.get(resource)?.get(name);
28
+ if (!handler) {
29
+ const resourceExists = this.registry.has(resource);
30
+ if (!resourceExists) {
31
+ throw new Error(`[exports] Resource "${resource}" has no registered exports.`);
32
+ }
33
+ throw new Error(`[exports] Export "${name}" not found in resource "${resource}".`);
34
+ }
35
+ return handler(...args);
36
+ }
37
+ createNamespaceProxy(resource) {
38
+ return new Proxy({}, {
39
+ get: (_, name) => (...args) => this.call(resource, name, ...args),
40
+ });
41
+ }
42
+ getOrCreateNamespaceProxy(resource) {
43
+ let namespaceProxy = this.namespaceProxyCache.get(resource);
44
+ if (!namespaceProxy) {
45
+ namespaceProxy = this.createNamespaceProxy(resource);
46
+ this.namespaceProxyCache.set(resource, namespaceProxy);
47
+ }
48
+ return namespaceProxy;
49
+ }
50
+ /**
51
+ * Returns the namespace proxy for a resource if it has registered exports.
52
+ * Matches FiveM behavior where unknown resources return undefined.
53
+ */
54
+ resourceProxy(resource) {
55
+ if (!this.registry.has(resource))
56
+ return undefined;
57
+ return this.getOrCreateNamespaceProxy(resource);
58
+ }
59
+ createProxy() {
60
+ return new Proxy({}, {
61
+ get: (_, resource) => this.getOrCreateNamespaceProxy(resource),
62
+ });
63
+ }
64
+ list(resource) {
65
+ return [...(this.registry.get(resource)?.keys() ?? [])];
66
+ }
67
+ }
68
+ exports.ExportsRegistry = ExportsRegistry;
69
+ /**
70
+ * RageMP loads each resource as an independent bundle in the same Node.js process.
71
+ * Storing the registry instance on `global` ensures it is shared across all bundles.
72
+ */
73
+ const REGISTRY_GLOBAL_KEY = '__OPENCORE_EXPORTS_REGISTRY__';
74
+ function resolveSharedRegistry() {
75
+ const globalContext = global;
76
+ if (!globalContext[REGISTRY_GLOBAL_KEY]) {
77
+ globalContext[REGISTRY_GLOBAL_KEY] = new ExportsRegistry();
78
+ }
79
+ return globalContext[REGISTRY_GLOBAL_KEY];
80
+ }
81
+ exports.exportsRegistry = resolveSharedRegistry();
82
+ function registerExport(resource, name, handler) {
83
+ exports.exportsRegistry.register(resource, name, handler);
84
+ }
85
+ function callExport(resource, name, ...args) {
86
+ return exports.exportsRegistry.call(resource, name, ...args);
87
+ }
@@ -0,0 +1,8 @@
1
+ import { MessagingTransport, type RuntimeContext } from '@open-core/framework/contracts';
2
+ import { RageMPEvents } from './ragemp.events';
3
+ import { RageMPRpc } from './ragemp.rpc';
4
+ export declare class RageMPMessagingTransport extends MessagingTransport {
5
+ readonly context: RuntimeContext;
6
+ readonly events: RageMPEvents;
7
+ readonly rpc: RageMPRpc<RuntimeContext>;
8
+ }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RageMPMessagingTransport = void 0;
4
+ const contracts_1 = require("@open-core/framework/contracts");
5
+ const ragemp_events_1 = require("./ragemp.events");
6
+ const ragemp_rpc_1 = require("./ragemp.rpc");
7
+ function getRuntimeContext() {
8
+ return 'local' in mp.players ? 'client' : 'server';
9
+ }
10
+ class RageMPMessagingTransport extends contracts_1.MessagingTransport {
11
+ constructor() {
12
+ super(...arguments);
13
+ this.context = getRuntimeContext();
14
+ this.events = new ragemp_events_1.RageMPEvents(this.context);
15
+ this.rpc = new ragemp_rpc_1.RageMPRpc(this.context);
16
+ }
17
+ }
18
+ exports.RageMPMessagingTransport = RageMPMessagingTransport;
@@ -0,0 +1,24 @@
1
+ import type { RuntimeContext } from '@open-core/framework/contracts';
2
+ /**
3
+ * Normalizes RageMP's different server/client event subscription signatures
4
+ * into a single uniform interface.
5
+ *
6
+ * Analogous to FiveM's `onNet`:
7
+ * - Server: RageMP prepends the PlayerMp as the first native argument.
8
+ * We expose it as-is so callers can read player.id before any await.
9
+ * - Client: no source argument; we pass undefined to keep the signature uniform.
10
+ */
11
+ export declare function onNet(context: RuntimeContext, event: string, handler: (source: PlayerMp | undefined, ...args: any[]) => void): void;
12
+ /**
13
+ * Normalizes RageMP's server/client event emission into a single interface.
14
+ *
15
+ * Analogous to FiveM's `TriggerClientEvent` / `TriggerServerEvent`:
16
+ * - Server, target=-1 → mp.players.call (broadcast to all connected players)
17
+ * - Server, target=id → single player, skipped silently if disconnected
18
+ * - Server, target=id[] → per-player send, each skipped if disconnected
19
+ * - Client → mp.events.callRemote to server (target is ignored)
20
+ *
21
+ * NOTE: Only player targets are supported — vehicles/peds are not valid
22
+ * network targets, matching FiveM's TriggerClientEvent semantics.
23
+ */
24
+ export declare function emitNet(context: RuntimeContext, event: string, target: number | number[] | -1, ...payload: any[]): void;
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.onNet = onNet;
4
+ exports.emitNet = emitNet;
5
+ /**
6
+ * Resolves a player by numeric ID, returning undefined when the player no
7
+ * longer exists (disconnected, invalid handle, etc.).
8
+ *
9
+ * NOTE: This helper only covers players — vehicles and peds are not
10
+ * addressable network targets in either FiveM or RageMP's emitNet.
11
+ */
12
+ function resolvePlayer(id) {
13
+ const player = mp.players.at(id);
14
+ if (player && mp.players.exists(player))
15
+ return player;
16
+ return undefined;
17
+ }
18
+ /**
19
+ * Normalizes RageMP's different server/client event subscription signatures
20
+ * into a single uniform interface.
21
+ *
22
+ * Analogous to FiveM's `onNet`:
23
+ * - Server: RageMP prepends the PlayerMp as the first native argument.
24
+ * We expose it as-is so callers can read player.id before any await.
25
+ * - Client: no source argument; we pass undefined to keep the signature uniform.
26
+ */
27
+ function onNet(context, event, handler) {
28
+ if (context === 'server') {
29
+ mp.events.add(event, (player, ...args) => {
30
+ // Validate the player is still connected before forwarding.
31
+ // A 'playerQuit' event fires with the player still technically present;
32
+ // all other events should be safe to guard this way.
33
+ if (!mp.players.exists(player.id))
34
+ return;
35
+ handler(player, ...args);
36
+ });
37
+ }
38
+ else {
39
+ mp.events.add(event, (...args) => handler(undefined, ...args));
40
+ }
41
+ }
42
+ /**
43
+ * Normalizes RageMP's server/client event emission into a single interface.
44
+ *
45
+ * Analogous to FiveM's `TriggerClientEvent` / `TriggerServerEvent`:
46
+ * - Server, target=-1 → mp.players.call (broadcast to all connected players)
47
+ * - Server, target=id → single player, skipped silently if disconnected
48
+ * - Server, target=id[] → per-player send, each skipped if disconnected
49
+ * - Client → mp.events.callRemote to server (target is ignored)
50
+ *
51
+ * NOTE: Only player targets are supported — vehicles/peds are not valid
52
+ * network targets, matching FiveM's TriggerClientEvent semantics.
53
+ */
54
+ function emitNet(context, event, target, ...payload) {
55
+ if (context !== 'server') {
56
+ mp.events.callRemote(event, ...payload);
57
+ return;
58
+ }
59
+ if (target === -1) {
60
+ mp.players.call(event, payload);
61
+ return;
62
+ }
63
+ if (Array.isArray(target)) {
64
+ for (const id of target) {
65
+ resolvePlayer(id)?.call(event, payload);
66
+ }
67
+ return;
68
+ }
69
+ resolvePlayer(target)?.call(event, payload);
70
+ }
@@ -0,0 +1,10 @@
1
+ import { EventsAPI, type RuntimeContext } from '@open-core/framework/contracts';
2
+ export declare class RageMPEvents extends EventsAPI<RuntimeContext> {
3
+ private readonly context;
4
+ constructor(context: RuntimeContext);
5
+ on(event: string, handler: (source: {
6
+ clientId: number | undefined;
7
+ raw: PlayerMp | undefined;
8
+ }, ...args: any[]) => void): void;
9
+ emit(event: string, ...args: any[]): void;
10
+ }
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RageMPEvents = void 0;
4
+ const contracts_1 = require("@open-core/framework/contracts");
5
+ const helpers_1 = require("./helpers");
6
+ function isPlayerTarget(value) {
7
+ return (typeof value === 'object' &&
8
+ value !== null &&
9
+ 'clientID' in value &&
10
+ typeof value.clientID === 'number');
11
+ }
12
+ class RageMPEvents extends contracts_1.EventsAPI {
13
+ constructor(context) {
14
+ super();
15
+ this.context = context;
16
+ }
17
+ on(event, handler) {
18
+ (0, helpers_1.onNet)(this.context, event, (source, ...args) => {
19
+ handler({ clientId: source?.id, raw: source }, ...args);
20
+ });
21
+ }
22
+ emit(event, ...args) {
23
+ // Client-side: always send to server; target is not used.
24
+ if (this.context !== 'server') {
25
+ (0, helpers_1.emitNet)(this.context, event, -1, ...args);
26
+ return;
27
+ }
28
+ // Server-side: first arg is the target descriptor.
29
+ const [target, ...payload] = args;
30
+ if (target === 'all') {
31
+ (0, helpers_1.emitNet)(this.context, event, -1, ...payload);
32
+ return;
33
+ }
34
+ if (Array.isArray(target)) {
35
+ (0, helpers_1.emitNet)(this.context, event, target, ...payload);
36
+ return;
37
+ }
38
+ if (isPlayerTarget(target)) {
39
+ (0, helpers_1.emitNet)(this.context, event, target.clientID, ...payload);
40
+ return;
41
+ }
42
+ (0, helpers_1.emitNet)(this.context, event, target, ...payload);
43
+ }
44
+ }
45
+ exports.RageMPEvents = RageMPEvents;
@@ -0,0 +1,27 @@
1
+ import { RpcAPI, type RuntimeContext } from '@open-core/framework/contracts';
2
+ export declare class RageMPRpc<C extends RuntimeContext = RuntimeContext> extends RpcAPI<C> {
3
+ private readonly context;
4
+ private readonly pending;
5
+ private requestSeq;
6
+ private readonly handlers;
7
+ private readonly channel;
8
+ private readonly requestEvent;
9
+ private readonly responseEvent;
10
+ private readonly defaultTimeoutMs;
11
+ constructor(context: C);
12
+ on<TArgs extends any[], TResult>(name: string, handler: (ctx: {
13
+ requestId: string;
14
+ clientId?: number;
15
+ raw?: unknown;
16
+ }, ...args: TArgs) => TResult | Promise<TResult>): void;
17
+ call<TResult = unknown>(name: string, ...args: any[]): Promise<TResult>;
18
+ notify(name: string, ...args: any[]): Promise<void>;
19
+ private normalizeInvocation;
20
+ private isValidTarget;
21
+ private sendAndWait;
22
+ private createRequestId;
23
+ private resolveServerTarget;
24
+ private handleRequestMessage;
25
+ private handleResponseMessage;
26
+ private emitResponse;
27
+ }