@open-core/framework 1.0.5-beta.2 → 1.0.6
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 -8
- package/dist/adapters/contracts/IEngineEvents.d.ts +3 -3
- package/dist/adapters/contracts/IExports.d.ts +2 -2
- package/dist/adapters/contracts/client/IClientLocalPlayerBridge.d.ts +21 -0
- package/dist/adapters/contracts/client/IClientLocalPlayerBridge.js +6 -0
- package/dist/adapters/contracts/client/IClientRuntimeBridge.d.ts +5 -5
- package/dist/adapters/contracts/client/camera/IClientCameraPort.d.ts +107 -0
- package/dist/adapters/contracts/client/camera/IClientCameraPort.js +8 -0
- package/dist/adapters/contracts/client/camera/index.d.ts +1 -0
- package/dist/adapters/contracts/client/camera/index.js +1 -0
- package/dist/adapters/contracts/client/index.d.ts +4 -0
- package/dist/adapters/contracts/client/index.js +4 -0
- package/dist/adapters/contracts/client/ped/IClientPedPort.d.ts +62 -0
- package/dist/adapters/contracts/client/ped/IClientPedPort.js +5 -0
- package/dist/adapters/contracts/client/ped/index.d.ts +1 -0
- package/dist/adapters/contracts/client/ped/index.js +1 -0
- package/dist/adapters/contracts/client/progress/IClientProgressPort.d.ts +53 -0
- package/dist/adapters/contracts/client/progress/IClientProgressPort.js +8 -0
- package/dist/adapters/contracts/client/progress/index.d.ts +1 -0
- package/dist/adapters/contracts/client/progress/index.js +1 -0
- package/dist/adapters/contracts/client/spawn/IClientSpawnBridge.d.ts +5 -6
- package/dist/adapters/contracts/client/spawn/IClientSpawnBridge.js +5 -1
- package/dist/adapters/contracts/client/spawn/IClientSpawnPort.d.ts +19 -0
- package/dist/adapters/contracts/client/spawn/IClientSpawnPort.js +2 -0
- package/dist/adapters/contracts/client/spawn/index.d.ts +2 -0
- package/dist/adapters/contracts/client/spawn/index.js +2 -0
- package/dist/adapters/contracts/client/spawn/types.d.ts +3 -0
- package/dist/adapters/contracts/client/ui/webview/IClientWebViewBridge.d.ts +1 -0
- package/dist/adapters/contracts/client/ui/webview/types.d.ts +2 -0
- package/dist/adapters/contracts/client/vehicle/IClientVehiclePort.d.ts +166 -0
- package/dist/adapters/contracts/client/vehicle/IClientVehiclePort.js +8 -0
- package/dist/adapters/contracts/client/vehicle/index.d.ts +1 -0
- package/dist/adapters/contracts/client/vehicle/index.js +1 -0
- package/dist/adapters/contracts/transport/events.api.d.ts +3 -3
- package/dist/adapters/contracts/transport/index.d.ts +1 -0
- package/dist/adapters/contracts/transport/index.js +1 -0
- package/dist/adapters/contracts/transport/rpc-error.d.ts +17 -0
- package/dist/adapters/contracts/transport/rpc-error.js +28 -0
- package/dist/adapters/contracts/transport/rpc.api.d.ts +3 -3
- package/dist/adapters/node/transport/node.events.d.ts +4 -4
- package/dist/adapters/node/transport/node.rpc.d.ts +3 -3
- package/dist/adapters/node/transport/node.rpc.js +1 -1
- package/dist/contracts.d.ts +1 -0
- package/dist/contracts.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/kernel/logger/client-log-console.js +8 -8
- package/dist/kernel/logger/index.d.ts +1 -1
- package/dist/kernel/logger/index.js +1 -1
- package/dist/kernel/logger/logger.types.d.ts +1 -0
- package/dist/kernel/logger/logger.types.js +35 -0
- package/dist/kernel/logger/transports/buffered.transport.js +4 -4
- package/dist/kernel/logger/transports/console.transport.js +2 -2
- package/dist/kernel/logger/transports/simple-console.transport.js +2 -2
- package/dist/runtime/client/adapter/index.d.ts +5 -0
- package/dist/runtime/client/adapter/index.js +5 -0
- package/dist/runtime/client/adapter/node-camera-port.d.ts +19 -0
- package/dist/runtime/client/adapter/node-camera-port.js +31 -0
- package/dist/runtime/client/adapter/node-client-adapter.js +15 -1
- package/dist/runtime/client/adapter/node-local-player-bridge.d.ts +3 -0
- package/dist/runtime/client/adapter/node-local-player-bridge.js +9 -0
- package/dist/runtime/client/adapter/node-log-console.js +8 -8
- package/dist/runtime/client/adapter/node-ped-port.d.ts +20 -0
- package/dist/runtime/client/adapter/node-ped-port.js +38 -0
- package/dist/runtime/client/adapter/node-progress-port.d.ts +8 -0
- package/dist/runtime/client/adapter/node-progress-port.js +27 -0
- package/dist/runtime/client/adapter/node-runtime-bridge.d.ts +2 -4
- package/dist/runtime/client/adapter/node-spawn-bridge.d.ts +5 -5
- package/dist/runtime/client/adapter/node-spawn-bridge.js +8 -4
- package/dist/runtime/client/adapter/node-vehicle-port.d.ts +31 -0
- package/dist/runtime/client/adapter/node-vehicle-port.js +73 -0
- package/dist/runtime/client/adapter/node-webview-bridge.d.ts +1 -0
- package/dist/runtime/client/adapter/node-webview-bridge.js +2 -0
- package/dist/runtime/client/controllers/appearance.controller.d.ts +3 -3
- package/dist/runtime/client/controllers/appearance.controller.js +11 -10
- package/dist/runtime/client/controllers/spawner.controller.js +4 -3
- package/dist/runtime/client/services/camera.d.ts +4 -26
- package/dist/runtime/client/services/camera.js +21 -27
- package/dist/runtime/client/services/notification.service.d.ts +3 -3
- package/dist/runtime/client/services/notification.service.js +7 -7
- package/dist/runtime/client/services/ped.service.d.ts +6 -21
- package/dist/runtime/client/services/ped.service.js +31 -78
- package/dist/runtime/client/services/progress.service.d.ts +4 -50
- package/dist/runtime/client/services/progress.service.js +11 -143
- package/dist/runtime/client/services/session-bridge.service.js +3 -2
- package/dist/runtime/client/services/spawn.service.d.ts +3 -5
- package/dist/runtime/client/services/spawn.service.js +12 -17
- package/dist/runtime/client/services/vehicle-client.service.d.ts +3 -3
- package/dist/runtime/client/services/vehicle-client.service.js +43 -143
- package/dist/runtime/client/services/vehicle.service.d.ts +4 -41
- package/dist/runtime/client/services/vehicle.service.js +24 -130
- package/dist/runtime/client/webview-bridge.d.ts +3 -0
- package/dist/runtime/client/webview-bridge.js +6 -0
- package/dist/runtime/client/webview.service.d.ts +1 -0
- package/dist/runtime/client/webview.service.js +5 -0
- package/dist/runtime/server/adapter/node-player-appearance-lifecycle-server.js +3 -2
- package/dist/runtime/server/adapter/node-player-lifecycle-server.js +4 -3
- package/dist/runtime/server/adapter/node-vehicle-lifecycle-server.js +2 -1
- package/dist/runtime/server/apis/chat.api.js +6 -5
- package/dist/runtime/server/apis/npcs.api.js +2 -1
- package/dist/runtime/server/apis/parallel-compute.api.js +1 -0
- package/dist/runtime/server/apis/vehicle-modification.api.js +6 -4
- package/dist/runtime/server/apis/vehicles.api.js +7 -4
- package/dist/runtime/server/bootstrap.js +13 -12
- package/dist/runtime/server/controllers/command-export.controller.js +4 -2
- package/dist/runtime/server/controllers/remote-command-execution.controller.js +2 -1
- package/dist/runtime/server/controllers/vehicle.controller.js +6 -5
- package/dist/runtime/server/decorators/command.d.ts +2 -0
- package/dist/runtime/server/decorators/command.js +3 -1
- package/dist/runtime/server/entities/npc.d.ts +1 -1
- package/dist/runtime/server/entities/player.d.ts +1 -1
- package/dist/runtime/server/entities/player.js +10 -3
- package/dist/runtime/server/helpers/command-validation.helper.js +20 -7
- package/dist/runtime/server/helpers/function-helper.d.ts +1 -0
- package/dist/runtime/server/helpers/function-helper.js +15 -8
- package/dist/runtime/server/implementations/local/channel.local.d.ts +1 -1
- package/dist/runtime/server/implementations/local/channel.local.js +3 -2
- package/dist/runtime/server/ports/channel.api-port.d.ts +1 -1
- package/dist/runtime/server/services/parallel/worker-pool.d.ts +1 -1
- package/dist/runtime/server/services/parallel/worker-pool.js +38 -6
- package/dist/runtime/server/services/parallel/worker.js +1 -0
- package/dist/runtime/server/system/processors/onRpc.processor.js +14 -3
- package/dist/runtime/server/system/schema-generator.d.ts +1 -1
- package/dist/runtime/server/system/schema-generator.js +6 -3
- package/dist/runtime/shared/helpers/process-tuple-schema.js +3 -0
- package/dist/runtime/shared/types/system-types.d.ts +55 -0
- package/dist/runtime/shared/types/system-types.js +54 -0
- package/package.json +21 -11
|
@@ -12,6 +12,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
12
12
|
};
|
|
13
13
|
import { inject } from 'tsyringe';
|
|
14
14
|
import { EventsAPI } from '../../../adapters/contracts/transport/events.api';
|
|
15
|
+
import { SYSTEM_EVENTS } from '../../shared/types/system-types';
|
|
15
16
|
import { Controller, OnNet } from '../decorators';
|
|
16
17
|
import { Player } from '../entities/player';
|
|
17
18
|
import { Vehicles } from '../apis/vehicles.api';
|
|
@@ -34,11 +35,11 @@ let VehicleController = class VehicleController {
|
|
|
34
35
|
handleGetData(player, networkId) {
|
|
35
36
|
const vehicle = this.vehicleService.getByNetworkId(networkId);
|
|
36
37
|
if (!vehicle) {
|
|
37
|
-
this.events.emit(
|
|
38
|
+
this.events.emit(SYSTEM_EVENTS.vehicle.dataResult, player.clientID, null);
|
|
38
39
|
return null;
|
|
39
40
|
}
|
|
40
41
|
const data = vehicle.serialize();
|
|
41
|
-
this.events.emit(
|
|
42
|
+
this.events.emit(SYSTEM_EVENTS.vehicle.dataResult, player.clientID, data);
|
|
42
43
|
return data;
|
|
43
44
|
}
|
|
44
45
|
/**
|
|
@@ -47,18 +48,18 @@ let VehicleController = class VehicleController {
|
|
|
47
48
|
handleGetPlayerVehicles(player) {
|
|
48
49
|
const vehicles = this.vehicleService.getPlayerVehicles(player.clientID);
|
|
49
50
|
const serialized = vehicles.map((v) => v.serialize());
|
|
50
|
-
this.events.emit(
|
|
51
|
+
this.events.emit(SYSTEM_EVENTS.vehicle.playerVehiclesResult, player.clientID, serialized);
|
|
51
52
|
return serialized;
|
|
52
53
|
}
|
|
53
54
|
};
|
|
54
55
|
__decorate([
|
|
55
|
-
OnNet(
|
|
56
|
+
OnNet(SYSTEM_EVENTS.vehicle.getData),
|
|
56
57
|
__metadata("design:type", Function),
|
|
57
58
|
__metadata("design:paramtypes", [Player, Number]),
|
|
58
59
|
__metadata("design:returntype", void 0)
|
|
59
60
|
], VehicleController.prototype, "handleGetData", null);
|
|
60
61
|
__decorate([
|
|
61
|
-
OnNet(
|
|
62
|
+
OnNet(SYSTEM_EVENTS.vehicle.getPlayerVehicles),
|
|
62
63
|
__metadata("design:type", Function),
|
|
63
64
|
__metadata("design:paramtypes", [Player]),
|
|
64
65
|
__metadata("design:returntype", void 0)
|
|
@@ -36,6 +36,8 @@ export interface CommandMetadata extends CommandConfig {
|
|
|
36
36
|
security?: SecurityMetadata;
|
|
37
37
|
/** True if the last parameter uses the spread operator (...args) */
|
|
38
38
|
hasSpreadParam?: boolean;
|
|
39
|
+
/** True when a parameter defines a JS default value. */
|
|
40
|
+
defaultParams?: boolean[];
|
|
39
41
|
}
|
|
40
42
|
type ServerCommandHandler = (() => any) | ((player: Player, ...args: any[]) => any);
|
|
41
43
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Player } from '../entities/player';
|
|
2
|
-
import { getParameterNames, getSpreadParameterIndices } from '../helpers/function-helper';
|
|
2
|
+
import { getDefaultParameterIndices, getParameterNames, getSpreadParameterIndices, } from '../helpers/function-helper';
|
|
3
3
|
import { METADATA_KEYS } from '../system/metadata-server.keys';
|
|
4
4
|
// Implementation
|
|
5
5
|
export function Command(configOrName, schema) {
|
|
@@ -20,6 +20,7 @@ export function Command(configOrName, schema) {
|
|
|
20
20
|
throw new Error(`@Command '${config.command}': first parameter must be Player if parameters are present`);
|
|
21
21
|
}
|
|
22
22
|
const paramNames = getParameterNames(descriptor.value);
|
|
23
|
+
const defaultParams = getDefaultParameterIndices(descriptor.value);
|
|
23
24
|
const spreadIndices = getSpreadParameterIndices(descriptor.value);
|
|
24
25
|
const hasSpreadParam = spreadIndices.length > 0 && spreadIndices[spreadIndices.length - 1];
|
|
25
26
|
const metadata = {
|
|
@@ -30,6 +31,7 @@ export function Command(configOrName, schema) {
|
|
|
30
31
|
paramNames,
|
|
31
32
|
expectsPlayer,
|
|
32
33
|
hasSpreadParam,
|
|
34
|
+
defaultParams,
|
|
33
35
|
};
|
|
34
36
|
Reflect.defineMetadata(METADATA_KEYS.COMMAND, metadata, target, propertyKey);
|
|
35
37
|
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { NativeHandle } from 'src/runtime/core/nativehandle';
|
|
2
1
|
import { IEntityServer } from '../../../adapters/contracts/server/IEntityServer';
|
|
3
2
|
import { INpcLifecycleServer } from '../../../adapters/contracts/server/npc-lifecycle/INpcLifecycleServer';
|
|
4
3
|
import { IPedServer } from '../../../adapters/contracts/server/IPedServer';
|
|
@@ -6,6 +5,7 @@ import { Vector3 } from '../../../kernel/utils/vector3';
|
|
|
6
5
|
import { BaseEntity } from '../../core/entity';
|
|
7
6
|
import { Spatial } from '../../core/spatial';
|
|
8
7
|
import { SerializedNpcData } from '../types/npc.types';
|
|
8
|
+
import { NativeHandle } from '../../core';
|
|
9
9
|
export interface NpcAdapters {
|
|
10
10
|
entityServer: IEntityServer;
|
|
11
11
|
pedServer: IPedServer;
|
|
@@ -11,7 +11,7 @@ import { Spatial } from '../../core/spatial';
|
|
|
11
11
|
import { LinkedID } from '../types/linked-id';
|
|
12
12
|
import { PlayerSession } from '../types/player-session.types';
|
|
13
13
|
import { SerializedPlayerData } from '../types/core-exports.types';
|
|
14
|
-
import { NativeHandle } from '
|
|
14
|
+
import { NativeHandle } from '../../core';
|
|
15
15
|
/**
|
|
16
16
|
* Adapter bundle for player operations.
|
|
17
17
|
* Passed to Player instances by PlayerDirectory.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { loggers } from '../../../kernel/logger';
|
|
2
2
|
import { BaseEntity } from '../../core/entity';
|
|
3
|
+
import { SYSTEM_EVENTS } from '../../shared/types/system-types';
|
|
3
4
|
/**
|
|
4
5
|
* Core-level representation of a connected player on the server.
|
|
5
6
|
*
|
|
@@ -30,10 +31,16 @@ export class Player extends BaseEntity {
|
|
|
30
31
|
this._position = adapters.playerInfo.getPlayerPosition(session.clientID);
|
|
31
32
|
}
|
|
32
33
|
getHeading() {
|
|
33
|
-
|
|
34
|
+
const ped = this.adapters.playerServer.getPed(this.clientID.toString());
|
|
35
|
+
if (!ped || ped === 0)
|
|
36
|
+
return 0;
|
|
37
|
+
return this.adapters.entityServer.getHeading(ped);
|
|
34
38
|
}
|
|
35
39
|
setHeading(heading) {
|
|
36
|
-
this.adapters.
|
|
40
|
+
const ped = this.adapters.playerServer.getPed(this.clientID.toString());
|
|
41
|
+
if (!ped || ped === 0)
|
|
42
|
+
return;
|
|
43
|
+
this.adapters.entityServer.setHeading(ped, heading);
|
|
37
44
|
}
|
|
38
45
|
getHandle() {
|
|
39
46
|
return this.clientID;
|
|
@@ -120,7 +127,7 @@ export class Player extends BaseEntity {
|
|
|
120
127
|
* @param type - Message type for styling
|
|
121
128
|
*/
|
|
122
129
|
send(message, type = 'chat') {
|
|
123
|
-
this.emit(
|
|
130
|
+
this.emit(SYSTEM_EVENTS.chat.send, message, type);
|
|
124
131
|
}
|
|
125
132
|
// ─────────────────────────────────────────────────────────────────
|
|
126
133
|
// Spawning / Teleporting
|
|
@@ -4,17 +4,21 @@ import { generateSchemaFromTypes } from '../system/schema-generator';
|
|
|
4
4
|
import { processTupleSchema } from '../../shared/helpers/process-tuple-schema';
|
|
5
5
|
export async function validateAndExecuteCommand(meta, player, args, handler) {
|
|
6
6
|
const paramNames = meta.expectsPlayer ? meta.paramNames.slice(1) : meta.paramNames;
|
|
7
|
+
const defaultParams = meta.expectsPlayer
|
|
8
|
+
? (meta.defaultParams ?? []).slice(1)
|
|
9
|
+
: (meta.defaultParams ?? []);
|
|
7
10
|
let schema = meta.schema;
|
|
8
11
|
if (!meta.expectsPlayer) {
|
|
9
12
|
if (args.length > 0) {
|
|
10
|
-
|
|
11
|
-
|
|
13
|
+
const usage = resolveCommandUsage(meta, paramNames, defaultParams);
|
|
14
|
+
throw new AppError('GAME:BAD_REQUEST', `Incorrect usage, use: ${usage}`, 'client', {
|
|
15
|
+
usage,
|
|
12
16
|
});
|
|
13
17
|
}
|
|
14
18
|
return await handler();
|
|
15
19
|
}
|
|
16
20
|
if (!schema) {
|
|
17
|
-
schema = generateSchemaFromTypes(meta.paramTypes);
|
|
21
|
+
schema = generateSchemaFromTypes(meta.paramTypes, meta.defaultParams);
|
|
18
22
|
if (!schema) {
|
|
19
23
|
if (paramNames.length > 0) {
|
|
20
24
|
throw new AppError('SCHEMA:MISMATCH', `Command '${meta.command}' has parameters ${paramNames.join(', ')} but no schema was provided.`, 'core');
|
|
@@ -39,8 +43,9 @@ export async function validateAndExecuteCommand(meta, player, args, handler) {
|
|
|
39
43
|
inputObj[paramNames[i]] = args[i];
|
|
40
44
|
}
|
|
41
45
|
const validated = await schema.parseAsync(inputObj).catch(() => {
|
|
42
|
-
|
|
43
|
-
|
|
46
|
+
const usage = resolveCommandUsage(meta, paramNames, defaultParams);
|
|
47
|
+
throw new AppError('GAME:BAD_REQUEST', `Incorrect usage, use: ${usage}`, 'client', {
|
|
48
|
+
usage,
|
|
44
49
|
});
|
|
45
50
|
});
|
|
46
51
|
const obj = validated;
|
|
@@ -51,8 +56,9 @@ export async function validateAndExecuteCommand(meta, player, args, handler) {
|
|
|
51
56
|
if (schema instanceof z.ZodTuple) {
|
|
52
57
|
const processedArgs = processTupleSchema(schema, args);
|
|
53
58
|
const validated = await schema.parseAsync(processedArgs).catch(() => {
|
|
54
|
-
|
|
55
|
-
|
|
59
|
+
const usage = resolveCommandUsage(meta, paramNames, defaultParams);
|
|
60
|
+
throw new AppError('GAME:BAD_REQUEST', `Incorrect usage, use: ${usage}`, 'client', {
|
|
61
|
+
usage,
|
|
56
62
|
});
|
|
57
63
|
});
|
|
58
64
|
const finalArgs = validated;
|
|
@@ -71,3 +77,10 @@ export async function validateAndExecuteCommand(meta, player, args, handler) {
|
|
|
71
77
|
// fallback
|
|
72
78
|
return await handler(player);
|
|
73
79
|
}
|
|
80
|
+
function resolveCommandUsage(meta, paramNames, defaultParams) {
|
|
81
|
+
if (meta.usage?.trim()) {
|
|
82
|
+
return meta.usage;
|
|
83
|
+
}
|
|
84
|
+
const renderedParams = paramNames.map((name, index) => defaultParams[index] ? `[${name}]` : `<${name}>`);
|
|
85
|
+
return `/${meta.command}${renderedParams.length > 0 ? ` ${renderedParams.join(' ')}` : ''}`;
|
|
86
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export declare function getParameterNames(func: (...args: any[]) => any): string[];
|
|
2
|
+
export declare function getDefaultParameterIndices(func: (...args: any[]) => any): boolean[];
|
|
2
3
|
/**
|
|
3
4
|
* Detects which parameter indices use the spread operator (...args).
|
|
4
5
|
* Returns an array of booleans where true means the parameter at that index is a spread parameter.
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
export function getParameterNames(func) {
|
|
2
|
-
|
|
3
|
-
.toString()
|
|
4
|
-
.replace(/\/\/.*$/gm, '')
|
|
5
|
-
.replace(/\/\*[\s\S]*?\*\//gm, '');
|
|
6
|
-
const args = stripped
|
|
7
|
-
.slice(stripped.indexOf('(') + 1, stripped.indexOf(')'))
|
|
8
|
-
.split(',')
|
|
2
|
+
return parseParameterTokens(func)
|
|
9
3
|
.map((arg) => arg.replace(/=[\s\S]*/, '').trim())
|
|
10
4
|
.filter(Boolean);
|
|
11
|
-
|
|
5
|
+
}
|
|
6
|
+
export function getDefaultParameterIndices(func) {
|
|
7
|
+
return parseParameterTokens(func).map((arg) => arg.includes('='));
|
|
12
8
|
}
|
|
13
9
|
/**
|
|
14
10
|
* Detects which parameter indices use the spread operator (...args).
|
|
@@ -26,3 +22,14 @@ export function getSpreadParameterIndices(func) {
|
|
|
26
22
|
.filter(Boolean);
|
|
27
23
|
return args.map((arg) => arg.startsWith('...'));
|
|
28
24
|
}
|
|
25
|
+
function parseParameterTokens(func) {
|
|
26
|
+
const stripped = func
|
|
27
|
+
.toString()
|
|
28
|
+
.replace(/\/\/.*$/gm, '')
|
|
29
|
+
.replace(/\/\*[\s\S]*?\*\//gm, '');
|
|
30
|
+
return stripped
|
|
31
|
+
.slice(stripped.indexOf('(') + 1, stripped.indexOf(')'))
|
|
32
|
+
.split(',')
|
|
33
|
+
.map((arg) => arg.trim())
|
|
34
|
+
.filter(Boolean);
|
|
35
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EventsAPI } from '../../../../adapters/contracts/transport/events.api';
|
|
2
|
-
import { RGB } from '
|
|
2
|
+
import { RGB } from '../../../../kernel/utils';
|
|
3
3
|
import { Player } from '../../entities';
|
|
4
4
|
import { Channels } from '../../ports/channel.api-port';
|
|
5
5
|
import { IChannelValidator, ChannelMetadata, ChannelType } from '../../types';
|
|
@@ -12,6 +12,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
12
12
|
};
|
|
13
13
|
import { EventsAPI } from '../../../../adapters/contracts/transport/events.api';
|
|
14
14
|
import { inject, injectable } from 'tsyringe';
|
|
15
|
+
import { SYSTEM_EVENTS } from '../../../shared/types/system-types';
|
|
15
16
|
import { Channels } from '../../ports/channel.api-port';
|
|
16
17
|
import { ChannelType } from '../../types';
|
|
17
18
|
import { Players } from '../../ports/players.api-port';
|
|
@@ -96,7 +97,7 @@ let LocalChannelImplementation = class LocalChannelImplementation extends Channe
|
|
|
96
97
|
if (targetIds.length === 0) {
|
|
97
98
|
return;
|
|
98
99
|
}
|
|
99
|
-
this.events.emit(
|
|
100
|
+
this.events.emit(SYSTEM_EVENTS.chat.addMessage, targetIds, {
|
|
100
101
|
args: [author ?? sender.name, message],
|
|
101
102
|
color: color,
|
|
102
103
|
});
|
|
@@ -111,7 +112,7 @@ let LocalChannelImplementation = class LocalChannelImplementation extends Channe
|
|
|
111
112
|
if (targetIds.length === 0) {
|
|
112
113
|
return;
|
|
113
114
|
}
|
|
114
|
-
this.events.emit(
|
|
115
|
+
this.events.emit(SYSTEM_EVENTS.chat.addMessage, targetIds, {
|
|
115
116
|
args: [author, message],
|
|
116
117
|
color: color,
|
|
117
118
|
});
|
|
@@ -23,7 +23,7 @@ export declare class WorkerPool extends SimpleEventEmitter {
|
|
|
23
23
|
private workerIdCounter;
|
|
24
24
|
private cleanupInterval;
|
|
25
25
|
private isShuttingDown;
|
|
26
|
-
private
|
|
26
|
+
private workerSource;
|
|
27
27
|
constructor(config?: Partial<WorkerPoolConfig>);
|
|
28
28
|
/**
|
|
29
29
|
* Check if using native workers
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
* Tasks are executed in `node:worker_threads` and communicated through
|
|
6
6
|
* structured-cloned messages.
|
|
7
7
|
*/
|
|
8
|
-
import * as path from 'node:path';
|
|
9
8
|
import { Worker } from 'node:worker_threads';
|
|
10
9
|
const DEFAULT_CONFIG = {
|
|
11
10
|
minWorkers: 0,
|
|
@@ -56,9 +55,9 @@ class NativeWorker {
|
|
|
56
55
|
currentTask = null;
|
|
57
56
|
worker;
|
|
58
57
|
pendingResponses = new Map();
|
|
59
|
-
constructor(id,
|
|
58
|
+
constructor(id, workerSource, callbacks) {
|
|
60
59
|
this.id = id;
|
|
61
|
-
this.worker = new Worker(
|
|
60
|
+
this.worker = new Worker(workerSource, { eval: true });
|
|
62
61
|
this.worker.on('message', (response) => {
|
|
63
62
|
const handlers = this.pendingResponses.get(response.id);
|
|
64
63
|
if (handlers) {
|
|
@@ -149,11 +148,44 @@ export class WorkerPool extends SimpleEventEmitter {
|
|
|
149
148
|
workerIdCounter = 0;
|
|
150
149
|
cleanupInterval = null;
|
|
151
150
|
isShuttingDown = false;
|
|
152
|
-
|
|
151
|
+
workerSource;
|
|
153
152
|
constructor(config = {}) {
|
|
154
153
|
super();
|
|
155
154
|
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
156
|
-
this.
|
|
155
|
+
this.workerSource = `
|
|
156
|
+
const { parentPort } = require('worker_threads')
|
|
157
|
+
const { performance } = require('perf_hooks')
|
|
158
|
+
|
|
159
|
+
if (!parentPort) {
|
|
160
|
+
throw new Error('native worker must be executed inside a Worker thread')
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function executeCompute(functionBody, input) {
|
|
164
|
+
const fn = new Function('input', 'return (' + functionBody + ')(input)')
|
|
165
|
+
return fn(input)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
parentPort.on('message', (message) => {
|
|
169
|
+
const startTime = performance.now()
|
|
170
|
+
|
|
171
|
+
try {
|
|
172
|
+
const result = executeCompute(message.functionBody, message.input)
|
|
173
|
+
parentPort.postMessage({
|
|
174
|
+
id: message.id,
|
|
175
|
+
success: true,
|
|
176
|
+
result,
|
|
177
|
+
executionTime: performance.now() - startTime,
|
|
178
|
+
})
|
|
179
|
+
} catch (error) {
|
|
180
|
+
parentPort.postMessage({
|
|
181
|
+
id: message.id,
|
|
182
|
+
success: false,
|
|
183
|
+
error: error instanceof Error ? error.message : String(error),
|
|
184
|
+
executionTime: performance.now() - startTime,
|
|
185
|
+
})
|
|
186
|
+
}
|
|
187
|
+
})
|
|
188
|
+
`;
|
|
157
189
|
// Start cleanup interval
|
|
158
190
|
this.cleanupInterval = setInterval(() => this.cleanupIdleWorkers(), 10000);
|
|
159
191
|
// Spawn minimum workers
|
|
@@ -261,7 +293,7 @@ export class WorkerPool extends SimpleEventEmitter {
|
|
|
261
293
|
spawnWorker() {
|
|
262
294
|
try {
|
|
263
295
|
const id = this.workerIdCounter++;
|
|
264
|
-
const worker = new NativeWorker(id, this.
|
|
296
|
+
const worker = new NativeWorker(id, this.workerSource, {
|
|
265
297
|
onExit: (workerId, code) => {
|
|
266
298
|
const existing = this.workers.get(workerId);
|
|
267
299
|
if (!existing)
|
|
@@ -124,10 +124,21 @@ let OnRpcProcessor = class OnRpcProcessor {
|
|
|
124
124
|
});
|
|
125
125
|
throw error;
|
|
126
126
|
}
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
try {
|
|
128
|
+
if (hasNoDeclaredParams) {
|
|
129
|
+
return await handler();
|
|
130
|
+
}
|
|
131
|
+
return await handler(player, ...validatedArgs);
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
loggers.netEvent.error(`Handler error in RPC`, {
|
|
135
|
+
event: metadata.eventName,
|
|
136
|
+
handler: handlerName,
|
|
137
|
+
playerId: player.clientID,
|
|
138
|
+
accountId: player.accountID,
|
|
139
|
+
}, error);
|
|
140
|
+
throw error;
|
|
129
141
|
}
|
|
130
|
-
return handler(player, ...validatedArgs);
|
|
131
142
|
});
|
|
132
143
|
loggers.netEvent.debug(`Registered RPC: ${metadata.eventName} -> ${handlerName}`);
|
|
133
144
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import z from 'zod';
|
|
2
|
-
export declare function generateSchemaFromTypes(paramTypes: any[]): z.ZodTuple | undefined;
|
|
2
|
+
export declare function generateSchemaFromTypes(paramTypes: any[], defaultParams?: boolean[]): z.ZodTuple | undefined;
|
|
@@ -19,7 +19,10 @@ function typeToZodSchema(type) {
|
|
|
19
19
|
return undefined;
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
-
|
|
22
|
+
function applyOptional(schema, optional) {
|
|
23
|
+
return optional ? schema.optional() : schema;
|
|
24
|
+
}
|
|
25
|
+
export function generateSchemaFromTypes(paramTypes, defaultParams = []) {
|
|
23
26
|
if (!paramTypes || paramTypes.length === 0)
|
|
24
27
|
return z.tuple([]);
|
|
25
28
|
if (paramTypes[0] !== Player) {
|
|
@@ -28,11 +31,11 @@ export function generateSchemaFromTypes(paramTypes) {
|
|
|
28
31
|
if (paramTypes.length === 1)
|
|
29
32
|
return z.tuple([]);
|
|
30
33
|
const argSchemas = [];
|
|
31
|
-
for (const t of paramTypes.slice(1)) {
|
|
34
|
+
for (const [index, t] of paramTypes.slice(1).entries()) {
|
|
32
35
|
const s = typeToZodSchema(t);
|
|
33
36
|
if (!s)
|
|
34
37
|
return undefined;
|
|
35
|
-
argSchemas.push(s);
|
|
38
|
+
argSchemas.push(applyOptional(s, defaultParams[index + 1] ?? false));
|
|
36
39
|
}
|
|
37
40
|
return z.tuple(argSchemas);
|
|
38
41
|
}
|
|
@@ -25,5 +25,8 @@ export function processTupleSchema(schema, args) {
|
|
|
25
25
|
return [...positional, [args[positionalCount]]];
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
+
if (args.length < items.length) {
|
|
29
|
+
return [...args, ...Array.from({ length: items.length - args.length }, () => undefined)];
|
|
30
|
+
}
|
|
28
31
|
return args;
|
|
29
32
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
type ValueOf<T> = T[keyof T];
|
|
2
|
+
declare const SYSTEM_EVENT_NAMESPACE = "opencore";
|
|
3
|
+
export type RemoteCommandExecuteEventName = `${typeof SYSTEM_EVENT_NAMESPACE}:command:execute:${string}`;
|
|
4
|
+
export declare const buildRemoteCommandExecuteEventName: (resourceName: string) => RemoteCommandExecuteEventName;
|
|
5
|
+
export declare const SYSTEM_EVENTS: {
|
|
6
|
+
readonly core: {
|
|
7
|
+
readonly ready: `_systemcore:${string}`;
|
|
8
|
+
readonly requestReady: `_systemcore:${string}`;
|
|
9
|
+
};
|
|
10
|
+
readonly chat: {
|
|
11
|
+
readonly message: `opencore:${string}:${string}`;
|
|
12
|
+
readonly addMessage: `opencore:${string}:${string}`;
|
|
13
|
+
readonly send: `opencore:${string}:${string}`;
|
|
14
|
+
readonly clear: `opencore:${string}:${string}`;
|
|
15
|
+
};
|
|
16
|
+
readonly command: {
|
|
17
|
+
readonly execute: `opencore:${string}:${string}`;
|
|
18
|
+
};
|
|
19
|
+
readonly spawner: {
|
|
20
|
+
readonly spawn: `opencore:${string}:${string}`;
|
|
21
|
+
readonly teleport: `opencore:${string}:${string}`;
|
|
22
|
+
readonly respawn: `opencore:${string}:${string}`;
|
|
23
|
+
};
|
|
24
|
+
readonly appearance: {
|
|
25
|
+
readonly apply: `opencore:${string}:${string}`;
|
|
26
|
+
readonly reset: `opencore:${string}:${string}`;
|
|
27
|
+
};
|
|
28
|
+
readonly vehicle: {
|
|
29
|
+
readonly create: `opencore:${string}:${string}`;
|
|
30
|
+
readonly createResult: `opencore:${string}:${string}`;
|
|
31
|
+
readonly delete: `opencore:${string}:${string}`;
|
|
32
|
+
readonly deleteResult: `opencore:${string}:${string}`;
|
|
33
|
+
readonly repair: `opencore:${string}:${string}`;
|
|
34
|
+
readonly repairResult: `opencore:${string}:${string}`;
|
|
35
|
+
readonly repaired: `opencore:${string}:${string}`;
|
|
36
|
+
readonly setLocked: `opencore:${string}:${string}`;
|
|
37
|
+
readonly getData: `opencore:${string}:${string}`;
|
|
38
|
+
readonly dataResult: `opencore:${string}:${string}`;
|
|
39
|
+
readonly getPlayerVehicles: `opencore:${string}:${string}`;
|
|
40
|
+
readonly playerVehiclesResult: `opencore:${string}:${string}`;
|
|
41
|
+
readonly created: `opencore:${string}:${string}`;
|
|
42
|
+
readonly deleted: `opencore:${string}:${string}`;
|
|
43
|
+
readonly modified: `opencore:${string}:${string}`;
|
|
44
|
+
readonly warpInto: `opencore:${string}:${string}`;
|
|
45
|
+
};
|
|
46
|
+
readonly npc: {
|
|
47
|
+
readonly deleted: `opencore:${string}:${string}`;
|
|
48
|
+
};
|
|
49
|
+
readonly session: {
|
|
50
|
+
readonly playerInit: `opencore:${string}:${string}`;
|
|
51
|
+
readonly teleportTo: `opencore:${string}:${string}`;
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
export type SystemEventName = ValueOf<ValueOf<typeof SYSTEM_EVENTS>>;
|
|
55
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const SYSTEM_EVENT_NAMESPACE = 'opencore';
|
|
2
|
+
const SYSTEM_CORE_EVENT_NAMESPACE = '_systemcore';
|
|
3
|
+
const systemEvent = (scope, action) => `${SYSTEM_EVENT_NAMESPACE}:${scope}:${action}`;
|
|
4
|
+
const systemCoreEvent = (action) => `${SYSTEM_CORE_EVENT_NAMESPACE}:${action}`;
|
|
5
|
+
export const buildRemoteCommandExecuteEventName = (resourceName) => `${SYSTEM_EVENTS.command.execute}:${resourceName}`;
|
|
6
|
+
export const SYSTEM_EVENTS = {
|
|
7
|
+
core: {
|
|
8
|
+
ready: systemCoreEvent('ready'),
|
|
9
|
+
requestReady: systemCoreEvent('request-ready'),
|
|
10
|
+
},
|
|
11
|
+
chat: {
|
|
12
|
+
message: systemEvent('chat', 'message'),
|
|
13
|
+
addMessage: systemEvent('chat', 'addMessage'),
|
|
14
|
+
send: systemEvent('chat', 'send'),
|
|
15
|
+
clear: systemEvent('chat', 'clear'),
|
|
16
|
+
},
|
|
17
|
+
command: {
|
|
18
|
+
execute: systemEvent('command', 'execute'),
|
|
19
|
+
},
|
|
20
|
+
spawner: {
|
|
21
|
+
spawn: systemEvent('spawner', 'spawn'),
|
|
22
|
+
teleport: systemEvent('spawner', 'teleport'),
|
|
23
|
+
respawn: systemEvent('spawner', 'respawn'),
|
|
24
|
+
},
|
|
25
|
+
appearance: {
|
|
26
|
+
apply: systemEvent('appearance', 'apply'),
|
|
27
|
+
reset: systemEvent('appearance', 'reset'),
|
|
28
|
+
},
|
|
29
|
+
vehicle: {
|
|
30
|
+
create: systemEvent('vehicle', 'create'),
|
|
31
|
+
createResult: systemEvent('vehicle', 'createResult'),
|
|
32
|
+
delete: systemEvent('vehicle', 'delete'),
|
|
33
|
+
deleteResult: systemEvent('vehicle', 'deleteResult'),
|
|
34
|
+
repair: systemEvent('vehicle', 'repair'),
|
|
35
|
+
repairResult: systemEvent('vehicle', 'repairResult'),
|
|
36
|
+
repaired: systemEvent('vehicle', 'repaired'),
|
|
37
|
+
setLocked: systemEvent('vehicle', 'setLocked'),
|
|
38
|
+
getData: systemEvent('vehicle', 'getData'),
|
|
39
|
+
dataResult: systemEvent('vehicle', 'dataResult'),
|
|
40
|
+
getPlayerVehicles: systemEvent('vehicle', 'getPlayerVehicles'),
|
|
41
|
+
playerVehiclesResult: systemEvent('vehicle', 'playerVehiclesResult'),
|
|
42
|
+
created: systemEvent('vehicle', 'created'),
|
|
43
|
+
deleted: systemEvent('vehicle', 'deleted'),
|
|
44
|
+
modified: systemEvent('vehicle', 'modified'),
|
|
45
|
+
warpInto: systemEvent('vehicle', 'warpInto'),
|
|
46
|
+
},
|
|
47
|
+
npc: {
|
|
48
|
+
deleted: systemEvent('npc', 'deleted'),
|
|
49
|
+
},
|
|
50
|
+
session: {
|
|
51
|
+
playerInit: systemEvent('player', 'sessionInit'),
|
|
52
|
+
teleportTo: systemEvent('player', 'teleportTo'),
|
|
53
|
+
},
|
|
54
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-core/framework",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "Secure, event-driven TypeScript Framework & Runtime engine for CitizenFX (Cfx).",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -75,12 +75,15 @@
|
|
|
75
75
|
"bench": "npx tsx benchmark/index.ts",
|
|
76
76
|
"bench:core": "npx tsx benchmark/index.ts --core",
|
|
77
77
|
"bench:load": "npx vitest run --project benchmark",
|
|
78
|
-
"bench:all": "npx tsx benchmark/index.ts --all"
|
|
78
|
+
"bench:all": "npx tsx benchmark/index.ts --all",
|
|
79
|
+
"validate": "pnpm check && pnpm typecheck && pnpm test",
|
|
80
|
+
"lint-staged": "lint-staged",
|
|
81
|
+
"prepare": "husky"
|
|
79
82
|
},
|
|
80
83
|
"keywords": [
|
|
81
84
|
"framework",
|
|
82
85
|
"opencore",
|
|
83
|
-
"
|
|
86
|
+
"ragemp",
|
|
84
87
|
"citizenfx",
|
|
85
88
|
"redm",
|
|
86
89
|
"typescript",
|
|
@@ -88,7 +91,7 @@
|
|
|
88
91
|
],
|
|
89
92
|
"author": "OpenCore Team",
|
|
90
93
|
"license": "MPL-2.0",
|
|
91
|
-
"packageManager": "pnpm@10.
|
|
94
|
+
"packageManager": "pnpm@10.33.0",
|
|
92
95
|
"peerDependencies": {
|
|
93
96
|
"reflect-metadata": "^0.2.2",
|
|
94
97
|
"tsyringe": "^4.10.0",
|
|
@@ -98,16 +101,23 @@
|
|
|
98
101
|
"uuid": "^13.0.0"
|
|
99
102
|
},
|
|
100
103
|
"devDependencies": {
|
|
101
|
-
"@biomejs/biome": "^2.
|
|
102
|
-
"@types/node": "^25.0
|
|
103
|
-
"@vitest/coverage-v8": "^4.
|
|
104
|
-
"dependency-cruiser": "^17.3.
|
|
104
|
+
"@biomejs/biome": "^2.4.8",
|
|
105
|
+
"@types/node": "^25.5.0",
|
|
106
|
+
"@vitest/coverage-v8": "^4.1.1",
|
|
107
|
+
"dependency-cruiser": "^17.3.9",
|
|
105
108
|
"eslint-config-prettier": "^10.1.8",
|
|
106
109
|
"eslint-plugin-import": "^2.32.0",
|
|
107
110
|
"graphviz": "^0.0.9",
|
|
108
|
-
"
|
|
111
|
+
"husky": "^9.1.7",
|
|
112
|
+
"lint-staged": "^16.2.6",
|
|
113
|
+
"tinybench": "^6.0.0",
|
|
109
114
|
"tsx": "^4.21.0",
|
|
110
|
-
"typescript": "^
|
|
111
|
-
"vitest": "^4.
|
|
115
|
+
"typescript": "^6.0.2",
|
|
116
|
+
"vitest": "^4.1.1"
|
|
117
|
+
},
|
|
118
|
+
"lint-staged": {
|
|
119
|
+
"*.{js,cjs,mjs,ts,tsx,json,md}": [
|
|
120
|
+
"biome check --write --no-errors-on-unmatched"
|
|
121
|
+
]
|
|
112
122
|
}
|
|
113
123
|
}
|