@open-core/framework 1.0.1-beta.1 → 1.0.4-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/README.md +12 -2
  2. package/dist/client/client-bootstrap.js +11 -14
  3. package/dist/client/client-core.d.ts +0 -17
  4. package/dist/client/client-core.js +0 -45
  5. package/dist/client/controllers/spawner.controller.d.ts +12 -0
  6. package/dist/client/controllers/spawner.controller.js +51 -0
  7. package/dist/client/index.d.ts +1 -0
  8. package/dist/client/index.js +1 -0
  9. package/dist/client/interfaces/appearance.interface.d.ts +19 -0
  10. package/dist/client/interfaces/appearance.interface.js +2 -0
  11. package/dist/client/services/appearance.service.d.ts +6 -0
  12. package/dist/client/services/appearance.service.js +89 -0
  13. package/dist/client/services/{world/blip.service.d.ts → blip.service.d.ts} +1 -1
  14. package/dist/client/services/index.d.ts +9 -4
  15. package/dist/client/services/index.js +9 -8
  16. package/dist/client/services/{world/marker.service.d.ts → marker.service.d.ts} +1 -1
  17. package/dist/client/services/{world/ped.service.d.ts → ped.service.d.ts} +1 -1
  18. package/dist/client/services/spawn.service.d.ts +73 -0
  19. package/dist/client/services/spawn.service.js +261 -0
  20. package/dist/client/services/{ui/textui.service.d.ts → textui.service.d.ts} +1 -1
  21. package/dist/client/services/{world/vehicle.service.d.ts → vehicle.service.d.ts} +1 -1
  22. package/dist/client/system/processors/export.processor.js +1 -1
  23. package/dist/index.d.ts +0 -2
  24. package/dist/index.js +1 -6
  25. package/dist/server/bootstrap.js +2 -2
  26. package/dist/server/controllers/command.controller.d.ts +1 -1
  27. package/dist/server/controllers/command.controller.js +6 -6
  28. package/dist/server/controllers/session.controller.d.ts +9 -0
  29. package/dist/server/controllers/session.controller.js +70 -0
  30. package/dist/server/database/adapters/oxmysql.adapter.js +1 -1
  31. package/dist/server/decorators/command.d.ts +34 -4
  32. package/dist/server/decorators/command.js +11 -6
  33. package/dist/server/decorators/controller.d.ts +22 -0
  34. package/dist/server/decorators/controller.js +22 -0
  35. package/dist/server/decorators/export.d.ts +38 -0
  36. package/dist/server/decorators/export.js +38 -0
  37. package/dist/server/decorators/guard.d.ts +51 -0
  38. package/dist/server/decorators/guard.js +43 -0
  39. package/dist/server/decorators/index.d.ts +4 -4
  40. package/dist/server/decorators/index.js +7 -4
  41. package/dist/server/decorators/onFiveMEvent.d.ts +6 -0
  42. package/dist/server/decorators/{coreEvent.js → onFiveMEvent.js} +8 -3
  43. package/dist/server/decorators/onFrameworkEvent.d.ts +22 -0
  44. package/dist/server/decorators/onFrameworkEvent.js +29 -0
  45. package/dist/server/decorators/onNet.d.ts +58 -0
  46. package/dist/server/decorators/onNet.js +57 -0
  47. package/dist/server/decorators/onTick.d.ts +31 -0
  48. package/dist/server/decorators/onTick.js +31 -0
  49. package/dist/server/decorators/public.d.ts +19 -8
  50. package/dist/server/decorators/public.js +19 -8
  51. package/dist/server/decorators/requiresState.d.ts +18 -17
  52. package/dist/server/decorators/requiresState.js +18 -17
  53. package/dist/server/decorators/throttle.d.ts +39 -0
  54. package/dist/server/decorators/throttle.js +27 -0
  55. package/dist/server/decorators/utils.d.ts +50 -0
  56. package/dist/server/decorators/utils.js +50 -0
  57. package/dist/server/entities/player.js +1 -1
  58. package/dist/server/error-handler.js +2 -2
  59. package/dist/server/helpers/resolve-method.d.ts +5 -0
  60. package/dist/server/helpers/resolve-method.js +18 -0
  61. package/dist/server/index.js +2 -0
  62. package/dist/server/loaders/playerSession.loader.js +13 -4
  63. package/dist/server/services/command.service.d.ts +1 -1
  64. package/dist/server/services/command.service.js +9 -6
  65. package/dist/server/system/metadata-server.keys.d.ts +1 -0
  66. package/dist/server/system/metadata-server.keys.js +1 -0
  67. package/dist/server/system/processors/command.processor.d.ts +2 -2
  68. package/dist/server/system/processors/command.processor.js +1 -2
  69. package/dist/server/system/processors/coreEvent.processor.d.ts +1 -1
  70. package/dist/server/system/processors/coreEvent.processor.js +6 -3
  71. package/dist/server/system/processors/export.processor.d.ts +1 -1
  72. package/dist/server/system/processors/export.processor.js +7 -3
  73. package/dist/server/system/processors/fivemEvent.processor.d.ts +7 -0
  74. package/dist/server/system/processors/fivemEvent.processor.js +40 -0
  75. package/dist/server/system/processors/netEvent.processor.d.ts +1 -1
  76. package/dist/server/system/processors/netEvent.processor.js +12 -9
  77. package/dist/server/system/processors.register.js +2 -0
  78. package/dist/server/system/schema-generator.d.ts +2 -0
  79. package/dist/server/system/schema-generator.js +34 -0
  80. package/dist/server/templates/admin/admin.controller-template.d.ts +7 -5
  81. package/dist/server/templates/auth/auth-provider.contract.d.ts +2 -2
  82. package/dist/server/types/core-events.d.ts +5 -0
  83. package/package.json +29 -1
  84. package/dist/client/loaders/exports.loader.d.ts +0 -1
  85. package/dist/client/loaders/exports.loader.js +0 -13
  86. package/dist/client/services/core/index.d.ts +0 -1
  87. package/dist/client/services/core/index.js +0 -17
  88. package/dist/client/services/core/spawn.service.d.ts +0 -20
  89. package/dist/client/services/core/spawn.service.js +0 -143
  90. package/dist/client/services/streaming/index.d.ts +0 -1
  91. package/dist/client/services/streaming/index.js +0 -17
  92. package/dist/client/services/ui/index.d.ts +0 -3
  93. package/dist/client/services/ui/index.js +0 -19
  94. package/dist/client/services/world/index.d.ts +0 -4
  95. package/dist/client/services/world/index.js +0 -20
  96. package/dist/server/decorators/coreEvent.d.ts +0 -2
  97. package/dist/server/decorators/netEvent.d.ts +0 -36
  98. package/dist/server/decorators/netEvent.js +0 -40
  99. /package/dist/client/services/{world/blip.service.js → blip.service.js} +0 -0
  100. /package/dist/client/services/{world/marker.service.js → marker.service.js} +0 -0
  101. /package/dist/client/services/{ui/notification.service.d.ts → notification.service.d.ts} +0 -0
  102. /package/dist/client/services/{ui/notification.service.js → notification.service.js} +0 -0
  103. /package/dist/client/services/{world/ped.service.js → ped.service.js} +0 -0
  104. /package/dist/client/services/{ui/progress.service.d.ts → progress.service.d.ts} +0 -0
  105. /package/dist/client/services/{ui/progress.service.js → progress.service.js} +0 -0
  106. /package/dist/client/services/{streaming/streaming.service.d.ts → streaming.service.d.ts} +0 -0
  107. /package/dist/client/services/{streaming/streaming.service.js → streaming.service.js} +0 -0
  108. /package/dist/client/services/{ui/textui.service.js → textui.service.js} +0 -0
  109. /package/dist/client/services/{world/vehicle.service.js → vehicle.service.js} +0 -0
@@ -0,0 +1,261 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.SpawnService = void 0;
13
+ const tsyringe_1 = require("tsyringe");
14
+ const shared_1 = require("../../shared");
15
+ const appearance_service_1 = require("./appearance.service");
16
+ const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
17
+ const NETWORK_TIMEOUT_MS = 15000;
18
+ const PED_TIMEOUT_MS = 10000;
19
+ const COLLISION_TIMEOUT_MS = 7000;
20
+ /**
21
+ * Handles all player spawning logic on the client.
22
+ *
23
+ * This service manages the complete lifecycle of a player spawn:
24
+ * - Waiting for the network session
25
+ * - Loading and applying the player model
26
+ * - Ensuring collision and world data is ready
27
+ * - Resurrecting the player cleanly
28
+ * - Applying default ped components for freemode models
29
+ * - Fading the screen in/out during transitions
30
+ *
31
+ * The service is designed to be robust, predictable, and safe for any gamemode.
32
+ */
33
+ let SpawnService = class SpawnService {
34
+ constructor(appearanceService) {
35
+ this.appearanceService = appearanceService;
36
+ this.spawned = false;
37
+ this.spawning = false;
38
+ }
39
+ async init() {
40
+ shared_1.loggers.spawn.debug('SpawnService initialized');
41
+ }
42
+ /**
43
+ * Performs the first spawn of the player.
44
+ *
45
+ * This method handles:
46
+ * - Fade out
47
+ * - Closing loading screens
48
+ * - Setting the player model
49
+ * - Ensuring the ped exists
50
+ * - Ensuring collision is loaded
51
+ * - Resurrecting the player
52
+ * - Preparing the ped for gameplay
53
+ * - Placing the player at the desired position
54
+ * - Fade in
55
+ *
56
+ * It should only be called once when the player joins.
57
+ */
58
+ async spawn(position, model, heading = 0.0, options) {
59
+ if (this.spawning) {
60
+ shared_1.loggers.spawn.warn('Spawn requested while a spawn is already in progress');
61
+ return;
62
+ }
63
+ this.spawning = true;
64
+ try {
65
+ await this.ensureNetworkReady();
66
+ if (!IsScreenFadedOut() && !IsScreenFadingOut()) {
67
+ DoScreenFadeOut(500);
68
+ while (!IsScreenFadedOut()) {
69
+ await delay(0);
70
+ }
71
+ }
72
+ this.closeLoadingScreens();
73
+ await this.setPlayerModel(model);
74
+ const ped = await this.ensurePed();
75
+ await this.applyAppearanceIfNeeded(ped, options === null || options === void 0 ? void 0 : options.appearance);
76
+ await this.ensureCollisionAt(position, ped);
77
+ NetworkResurrectLocalPlayer(position.x, position.y, position.z, heading, 0, false);
78
+ const finalPed = await this.ensurePed();
79
+ await this.setupPedForGameplay(finalPed);
80
+ await this.placePed(finalPed, position, heading);
81
+ this.spawned = true;
82
+ if (!IsScreenFadedIn() && !IsScreenFadingIn()) {
83
+ DoScreenFadeIn(500);
84
+ }
85
+ shared_1.loggers.spawn.info('Player spawned successfully (first spawn)', {
86
+ position: { x: position.x, y: position.y, z: position.z },
87
+ model,
88
+ });
89
+ }
90
+ catch (err) {
91
+ shared_1.loggers.spawn.error('Failed to spawn player', {
92
+ error: err instanceof Error ? err.message : String(err),
93
+ });
94
+ throw err;
95
+ }
96
+ finally {
97
+ this.spawning = false;
98
+ }
99
+ }
100
+ /**
101
+ * Teleports the player instantly to a new position.
102
+ * Does not change the model or resurrect the player.
103
+ * Safe for gameplay use.
104
+ */
105
+ async teleportTo(position, heading) {
106
+ const ped = await this.ensurePed();
107
+ await this.ensureCollisionAt(position, ped);
108
+ FreezeEntityPosition(ped, true);
109
+ SetEntityCoordsNoOffset(ped, position.x, position.y, position.z, false, false, false);
110
+ if (heading !== undefined) {
111
+ SetEntityHeading(ped, heading);
112
+ }
113
+ FreezeEntityPosition(ped, false);
114
+ shared_1.loggers.spawn.debug('Teleported', {
115
+ position: { x: position.x, y: position.y, z: position.z },
116
+ heading,
117
+ });
118
+ }
119
+ /**
120
+ * Respawns the player after death or a gameplay event.
121
+ * Restores health, resurrects the player, loads collision,
122
+ * prepares the ped and teleports them to the desired location.
123
+ */
124
+ async respawn(position, heading = 0.0) {
125
+ const ped = await this.ensurePed();
126
+ await this.ensureCollisionAt(position, ped);
127
+ ClearPedTasksImmediately(ped);
128
+ SetEntityHealth(ped, GetEntityMaxHealth(ped));
129
+ NetworkResurrectLocalPlayer(position.x, position.y, position.z, heading, 0, false);
130
+ const finalPed = await this.ensurePed();
131
+ await this.setupPedForGameplay(finalPed);
132
+ await this.teleportTo(position, heading);
133
+ shared_1.loggers.spawn.info('Player respawned', {
134
+ position: { x: position.x, y: position.y, z: position.z },
135
+ heading,
136
+ });
137
+ }
138
+ /**
139
+ * Returns whether the player has completed their first spawn.
140
+ */
141
+ isSpawned() {
142
+ return this.spawned;
143
+ }
144
+ /**
145
+ * Allows other systems to wait until the player is fully spawned.
146
+ */
147
+ async waitUntilSpawned() {
148
+ while (!this.spawned) {
149
+ await delay(0);
150
+ }
151
+ }
152
+ async ensureNetworkReady() {
153
+ const start = GetGameTimer();
154
+ while (!NetworkIsSessionStarted()) {
155
+ if (GetGameTimer() - start > NETWORK_TIMEOUT_MS) {
156
+ shared_1.loggers.spawn.error('Network session did not start in time');
157
+ throw new Error('NETWORK_TIMEOUT');
158
+ }
159
+ await delay(0);
160
+ }
161
+ }
162
+ closeLoadingScreens() {
163
+ try {
164
+ ShutdownLoadingScreen();
165
+ }
166
+ catch (_a) { }
167
+ try {
168
+ ShutdownLoadingScreenNui();
169
+ }
170
+ catch (_b) { }
171
+ }
172
+ async setPlayerModel(model) {
173
+ const modelHash = GetHashKey(model);
174
+ if (!IsModelInCdimage(modelHash) || !IsModelValid(modelHash)) {
175
+ shared_1.loggers.spawn.error('Invalid model requested', { model });
176
+ throw new Error('MODEL_INVALID');
177
+ }
178
+ RequestModel(modelHash);
179
+ while (!HasModelLoaded(modelHash)) {
180
+ await delay(0);
181
+ }
182
+ SetPlayerModel(PlayerId(), modelHash);
183
+ SetModelAsNoLongerNeeded(modelHash);
184
+ const ped = PlayerPedId();
185
+ if (ped !== 0) {
186
+ SetPedDefaultComponentVariation(ped);
187
+ }
188
+ shared_1.loggers.spawn.debug('Player model set', { model, modelHash });
189
+ }
190
+ async ensurePed() {
191
+ const start = GetGameTimer();
192
+ let ped = PlayerPedId();
193
+ while (ped === 0) {
194
+ if (GetGameTimer() - start > PED_TIMEOUT_MS) {
195
+ shared_1.loggers.spawn.error('PlayerPedId() did not become valid in time');
196
+ throw new Error('PED_TIMEOUT');
197
+ }
198
+ await delay(0);
199
+ ped = PlayerPedId();
200
+ }
201
+ return ped;
202
+ }
203
+ async ensureCollisionAt(position, ped) {
204
+ RequestCollisionAtCoord(position.x, position.y, position.z);
205
+ const start = GetGameTimer();
206
+ while (!HasCollisionLoadedAroundEntity(ped)) {
207
+ if (GetGameTimer() - start > COLLISION_TIMEOUT_MS) {
208
+ shared_1.loggers.spawn.warn('Collision did not fully load around entity in time', {
209
+ x: position.x,
210
+ y: position.y,
211
+ z: position.z,
212
+ });
213
+ break;
214
+ }
215
+ await delay(0);
216
+ }
217
+ }
218
+ async setupPedForGameplay(ped) {
219
+ SetEntityAsMissionEntity(ped, true, true);
220
+ ClearPedTasksImmediately(ped);
221
+ RemoveAllPedWeapons(ped, true);
222
+ ResetEntityAlpha(ped);
223
+ await delay(0);
224
+ SetEntityAlpha(ped, 255, false);
225
+ SetEntityVisible(ped, true, false);
226
+ SetEntityCollision(ped, true, true);
227
+ SetEntityInvincible(ped, false);
228
+ shared_1.loggers.spawn.debug('Ped prepared for gameplay', { ped });
229
+ }
230
+ async placePed(ped, position, heading) {
231
+ FreezeEntityPosition(ped, true);
232
+ SetEntityCoordsNoOffset(ped, position.x, position.y, position.z, false, false, false);
233
+ SetEntityHeading(ped, heading);
234
+ await delay(0);
235
+ FreezeEntityPosition(ped, false);
236
+ }
237
+ async applyAppearanceIfNeeded(ped, appearance) {
238
+ if (!appearance) {
239
+ SetPedDefaultComponentVariation(ped);
240
+ return;
241
+ }
242
+ if (!this.appearanceService.validateAppearance(appearance)) {
243
+ SetPedDefaultComponentVariation(ped);
244
+ return;
245
+ }
246
+ try {
247
+ await this.appearanceService.applyAppearance(ped, appearance);
248
+ }
249
+ catch (error) {
250
+ shared_1.loggers.spawn.error('Failed to apply appearance, using default variation', {
251
+ error: error instanceof Error ? error.message : String(error),
252
+ });
253
+ SetPedDefaultComponentVariation(ped);
254
+ }
255
+ }
256
+ };
257
+ exports.SpawnService = SpawnService;
258
+ exports.SpawnService = SpawnService = __decorate([
259
+ (0, tsyringe_1.injectable)(),
260
+ __metadata("design:paramtypes", [appearance_service_1.AppearanceService])
261
+ ], SpawnService);
@@ -1,4 +1,4 @@
1
- import type { Vector3 } from '../../../utils';
1
+ import type { Vector3 } from '../../utils';
2
2
  export interface TextUIOptions {
3
3
  /** Font (0-8) */
4
4
  font?: number;
@@ -1,4 +1,4 @@
1
- import type { Vector3 } from '../../../utils';
1
+ import type { Vector3 } from '../../utils';
2
2
  export interface VehicleSpawnOptions {
3
3
  /** Model name or hash */
4
4
  model: string;
@@ -18,7 +18,7 @@ let ClientExportProcessor = class ClientExportProcessor {
18
18
  process(target, methodName, metadata) {
19
19
  const handler = target[methodName].bind(target);
20
20
  const handlerName = `${target.constructor.name}.${methodName}`;
21
- exports(metadata.exportName, async (...args) => {
21
+ globalThis.exports(metadata.exportName, async (...args) => {
22
22
  try {
23
23
  return await handler(...args);
24
24
  }
package/dist/index.d.ts CHANGED
@@ -3,5 +3,3 @@ export * as Utils from './utils';
3
3
  export * as Shared from './shared';
4
4
  export * as Server from './server';
5
5
  export * as Client from './client';
6
- export { LoggerService, LogLevel, LogDomain } from './shared/logger';
7
- export type { LogTransport, LogContext, LogEntry, LoggerConfig } from './shared/logger';
package/dist/index.js CHANGED
@@ -33,14 +33,9 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.LogDomain = exports.LogLevel = exports.LoggerService = exports.Client = exports.Server = exports.Shared = exports.Utils = void 0;
36
+ exports.Client = exports.Server = exports.Shared = exports.Utils = void 0;
37
37
  require("reflect-metadata");
38
38
  exports.Utils = __importStar(require("./utils"));
39
39
  exports.Shared = __importStar(require("./shared"));
40
40
  exports.Server = __importStar(require("./server"));
41
41
  exports.Client = __importStar(require("./client"));
42
- // Re-export logger at root level for convenience
43
- var logger_1 = require("./shared/logger");
44
- Object.defineProperty(exports, "LoggerService", { enumerable: true, get: function () { return logger_1.LoggerService; } });
45
- Object.defineProperty(exports, "LogLevel", { enumerable: true, get: function () { return logger_1.LogLevel; } });
46
- Object.defineProperty(exports, "LogDomain", { enumerable: true, get: function () { return logger_1.LogDomain; } });
@@ -7,9 +7,9 @@ const templates_1 = require("./templates");
7
7
  const metadata_scanner_1 = require("../system/metadata.scanner");
8
8
  const processors_register_1 = require("./system/processors.register");
9
9
  const registers_1 = require("./services/registers");
10
- const decorators_1 = require("./decorators");
11
10
  const logger_1 = require("../shared/logger");
12
11
  const auth_provider_contract_1 = require("./templates/auth/auth-provider.contract");
12
+ const controller_1 = require("./decorators/controller");
13
13
  const check = () => {
14
14
  if (!container_1.di.isRegistered(templates_1.PrincipalProviderContract)) {
15
15
  const errorMsg = 'No Principal Provider configured. ' +
@@ -52,6 +52,6 @@ async function initServer() {
52
52
  (0, playerSession_loader_1.playerSessionLoader)();
53
53
  logger_1.loggers.bootstrap.debug('Player session loader active');
54
54
  const scanner = container_1.di.resolve(metadata_scanner_1.MetadataScanner);
55
- scanner.scan(decorators_1.serverControllerRegistry);
55
+ scanner.scan(controller_1.serverControllerRegistry);
56
56
  logger_1.loggers.bootstrap.info('OpenCore Server initialized successfully');
57
57
  }
@@ -3,5 +3,5 @@ import { Player } from '../entities';
3
3
  export declare class CommandNetworkController {
4
4
  private readonly commandService;
5
5
  constructor(commandService: CommandService);
6
- onCommandReceived(player: Player, commandName: string, args: string[], raw: string): Promise<void>;
6
+ onCommandReceived(player: Player, command: string, args: string[], raw: string): Promise<void>;
7
7
  }
@@ -10,7 +10,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.CommandNetworkController = void 0;
13
- const netEvent_1 = require("../decorators/netEvent");
13
+ const onNet_1 = require("../decorators/onNet");
14
14
  const command_service_1 = require("../services/command.service");
15
15
  const entities_1 = require("../entities");
16
16
  const decorators_1 = require("../decorators");
@@ -19,16 +19,16 @@ let CommandNetworkController = class CommandNetworkController {
19
19
  constructor(commandService) {
20
20
  this.commandService = commandService;
21
21
  }
22
- async onCommandReceived(player, commandName, args, raw) {
22
+ async onCommandReceived(player, command, args, raw) {
23
23
  try {
24
- logger_1.loggers.command.trace(`Received: /${commandName}`, {
24
+ logger_1.loggers.command.trace(`Received: /${command}`, {
25
25
  playerId: player.clientID,
26
26
  playerName: player.name,
27
27
  });
28
- await this.commandService.execute(player, commandName, args, raw);
28
+ await this.commandService.execute(player, command, args, raw);
29
29
  }
30
30
  catch (error) {
31
- logger_1.loggers.command.error(`Execution failed: /${commandName}`, {
31
+ logger_1.loggers.command.error(`Execution failed: /${command}`, {
32
32
  playerId: player.clientID,
33
33
  }, error);
34
34
  }
@@ -36,7 +36,7 @@ let CommandNetworkController = class CommandNetworkController {
36
36
  };
37
37
  exports.CommandNetworkController = CommandNetworkController;
38
38
  __decorate([
39
- (0, netEvent_1.OnNet)('core:internal:executeCommand'),
39
+ (0, onNet_1.OnNet)('core:internal:executeCommand'),
40
40
  __metadata("design:type", Function),
41
41
  __metadata("design:paramtypes", [entities_1.Player, String, Array, String]),
42
42
  __metadata("design:returntype", Promise)
@@ -0,0 +1,9 @@
1
+ import { PlayerService } from '../services';
2
+ import { PlayerPersistenceService } from '../services/persistence.service';
3
+ export declare class SessionController {
4
+ private readonly playerManager;
5
+ private readonly persistance;
6
+ constructor(playerManager: PlayerService, persistance: PlayerPersistenceService);
7
+ onPlayerJoining(): Promise<void>;
8
+ onPlayerDropped(): Promise<void>;
9
+ }
@@ -0,0 +1,70 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.SessionController = void 0;
13
+ const shared_1 = require("../../shared");
14
+ const core_event_bus_1 = require("../bus/core-event-bus");
15
+ const decorators_1 = require("../decorators");
16
+ const onFiveMEvent_1 = require("../decorators/onFiveMEvent");
17
+ const services_1 = require("../services");
18
+ const persistence_service_1 = require("../services/persistence.service");
19
+ let SessionController = class SessionController {
20
+ constructor(playerManager, persistance) {
21
+ this.playerManager = playerManager;
22
+ this.persistance = persistance;
23
+ }
24
+ async onPlayerJoining() {
25
+ var _a;
26
+ const clientId = source;
27
+ const license = (_a = GetPlayerIdentifier(clientId.toString(), 0)) !== null && _a !== void 0 ? _a : undefined;
28
+ const player = this.playerManager.bind(clientId, { license });
29
+ shared_1.loggers.session.info(`Player session created`, {
30
+ clientId,
31
+ license: license !== null && license !== void 0 ? license : 'none',
32
+ });
33
+ await this.persistance.handleSessionLoad(player);
34
+ (0, core_event_bus_1.emitCoreEvent)('core:playerSessionCreated', { clientId, license });
35
+ setImmediate(() => {
36
+ const currentPlayer = this.playerManager.getByClient(clientId);
37
+ if (!currentPlayer)
38
+ return;
39
+ (0, core_event_bus_1.emitCoreEvent)('core:playerFullyConnected', { clientId, license });
40
+ });
41
+ }
42
+ async onPlayerDropped() {
43
+ const clientId = Number(source);
44
+ const player = this.playerManager.getByClient(clientId);
45
+ if (player) {
46
+ await this.persistance.handleSessionSave(player);
47
+ }
48
+ this.playerManager.unbindByClient(clientId);
49
+ (0, core_event_bus_1.emitCoreEvent)('core:playerSessionDestroyed', { clientId });
50
+ shared_1.loggers.session.info(`Player session destroyed`, { clientId });
51
+ }
52
+ };
53
+ exports.SessionController = SessionController;
54
+ __decorate([
55
+ (0, onFiveMEvent_1.OnFiveMEvent)('playerJoining'),
56
+ __metadata("design:type", Function),
57
+ __metadata("design:paramtypes", []),
58
+ __metadata("design:returntype", Promise)
59
+ ], SessionController.prototype, "onPlayerJoining", null);
60
+ __decorate([
61
+ (0, onFiveMEvent_1.OnFiveMEvent)('playerDropped'),
62
+ __metadata("design:type", Function),
63
+ __metadata("design:paramtypes", []),
64
+ __metadata("design:returntype", Promise)
65
+ ], SessionController.prototype, "onPlayerDropped", null);
66
+ exports.SessionController = SessionController = __decorate([
67
+ (0, decorators_1.Controller)(),
68
+ __metadata("design:paramtypes", [services_1.PlayerService,
69
+ persistence_service_1.PlayerPersistenceService])
70
+ ], SessionController);
@@ -15,7 +15,7 @@ const database_contract_1 = require("../database.contract");
15
15
  * Get the oxmysql export from FiveM
16
16
  */
17
17
  function getOxMySQL() {
18
- const ox = global.exports['oxmysql'];
18
+ const ox = exports['oxmysql'];
19
19
  if (!ox) {
20
20
  throw new Error('[OpenCore] oxmysql is not available. Make sure oxmysql resource is started before your resource.');
21
21
  }
@@ -1,19 +1,49 @@
1
1
  import type { ClassConstructor } from '../../system/class-constructor';
2
2
  import type z from 'zod';
3
+ import type { Player } from '../entities/player';
3
4
  export interface CommandConfig {
4
- name: string;
5
+ /**
6
+ * The command name (e.g. "revive", "deposit"), used in chat "/revive"
7
+ */
8
+ command: string;
9
+ /**
10
+ * The command description, maybe "/help revive"
11
+ */
5
12
  description?: string;
13
+ /**
14
+ * The command usage, maybe "/revive <player>"
15
+ */
6
16
  usage?: string;
17
+ /**
18
+ * The command schema, used to validate the arguments, validated with zod
19
+ * @example
20
+ * ```ts
21
+ * Server.Command({
22
+ * command: 'revive',
23
+ * schema: z.object({
24
+ * player: z.string(),
25
+ * }),
26
+ * })
27
+ * ```
28
+ */
7
29
  schema?: z.ZodType;
8
30
  }
9
31
  export interface CommandMetadata extends CommandConfig {
10
32
  methodName: string;
11
33
  target: ClassConstructor;
34
+ paramTypes?: any;
12
35
  }
36
+ type ServerCommandHandler = (player: Player, ...args: any[]) => any;
13
37
  /**
14
38
  * Decorator used to mark a controller method as a command.
15
- * The metadata is collected and later bound to FiveM via RegisterCommand().
39
+ * This method will be registered and then executed by the command service.
40
+ * It will depend on the chat you have implemented following the dependency conventions.
16
41
  *
17
- * @param name - The command name (e.g. "revive", "deposit")
42
+ * @param configOrName - The command name (e.g. "revive", "deposit")
43
+ * @validation zod schema
44
+ * @handlerSignature ```ts
45
+ * (player: Server.Player, args: any[]) => any
46
+ * ```
18
47
  */
19
- export declare function Command(configOrName: string | CommandConfig): (target: any, propertyKey: string) => void;
48
+ export declare function Command(configOrName: string | CommandConfig): <T extends ServerCommandHandler>(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<T>) => void;
49
+ export {};
@@ -4,15 +4,20 @@ exports.Command = Command;
4
4
  const metadata_server_keys_1 = require("../system/metadata-server.keys");
5
5
  /**
6
6
  * Decorator used to mark a controller method as a command.
7
- * The metadata is collected and later bound to FiveM via RegisterCommand().
7
+ * This method will be registered and then executed by the command service.
8
+ * It will depend on the chat you have implemented following the dependency conventions.
8
9
  *
9
- * @param name - The command name (e.g. "revive", "deposit")
10
+ * @param configOrName - The command name (e.g. "revive", "deposit")
11
+ * @validation zod schema
12
+ * @handlerSignature ```ts
13
+ * (player: Server.Player, args: any[]) => any
14
+ * ```
10
15
  */
11
16
  function Command(configOrName) {
12
- return (target, propertyKey) => {
13
- // Normalizamos: si pasa solo un string, creamos el objeto config
14
- const config = typeof configOrName === 'string' ? { name: configOrName } : configOrName;
15
- const metadata = Object.assign(Object.assign({}, config), { methodName: propertyKey, target: target.constructor });
17
+ return (target, propertyKey, descriptor) => {
18
+ const config = typeof configOrName === 'string' ? { command: configOrName } : configOrName;
19
+ const paramTypes = Reflect.getMetadata('design:paramtypes', target, propertyKey);
20
+ const metadata = Object.assign(Object.assign({}, config), { methodName: propertyKey, target: target.constructor, paramTypes });
16
21
  Reflect.defineMetadata(metadata_server_keys_1.METADATA_KEYS.COMMAND, metadata, target, propertyKey);
17
22
  };
18
23
  }
@@ -1,3 +1,25 @@
1
1
  import type { ClassConstructor } from '../../system/class-constructor';
2
2
  export declare const serverControllerRegistry: ClassConstructor[];
3
+ /**
4
+ * Class decorator used to mark a class as a Server Controller.
5
+ *
6
+ * This decorator performs the following actions:
7
+ * 1. Marks the class as `@injectable` (via tsyringe) for dependency injection.
8
+ * 2. Defines metadata identifying the class as a 'server' type controller.
9
+ * 3. Automatically adds the class constructor to the `serverControllerRegistry`.
10
+ *
11
+ * @returns The decorator function to apply to the class.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { Controller } from '@core/server/decorators'
16
+ *
17
+ * @Server.Controller()
18
+ * export class PlayerController {
19
+ * constructor(private playerService: PlayerService) {
20
+ * // Dependency injection works automatically here
21
+ * }
22
+ * }
23
+ * ```
24
+ */
3
25
  export declare function Controller(): (target: ClassConstructor) => void;
@@ -5,6 +5,28 @@ exports.Controller = Controller;
5
5
  const tsyringe_1 = require("tsyringe");
6
6
  const metadata_server_keys_1 = require("../system/metadata-server.keys");
7
7
  exports.serverControllerRegistry = [];
8
+ /**
9
+ * Class decorator used to mark a class as a Server Controller.
10
+ *
11
+ * This decorator performs the following actions:
12
+ * 1. Marks the class as `@injectable` (via tsyringe) for dependency injection.
13
+ * 2. Defines metadata identifying the class as a 'server' type controller.
14
+ * 3. Automatically adds the class constructor to the `serverControllerRegistry`.
15
+ *
16
+ * @returns The decorator function to apply to the class.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import { Controller } from '@core/server/decorators'
21
+ *
22
+ * @Server.Controller()
23
+ * export class PlayerController {
24
+ * constructor(private playerService: PlayerService) {
25
+ * // Dependency injection works automatically here
26
+ * }
27
+ * }
28
+ * ```
29
+ */
8
30
  function Controller() {
9
31
  return function (target) {
10
32
  (0, tsyringe_1.injectable)()(target);
@@ -1 +1,39 @@
1
+ /**
2
+ * Export
3
+ * -----------------------------------------
4
+ * Declares a method as an externally accessible export
5
+ * within the FiveM environment.
6
+ *
7
+ * Methods decorated with `@Export()` are automatically
8
+ * registered by the framework and exposed as native
9
+ * FXServer exports, allowing other resources to call them
10
+ * using:
11
+ *
12
+ * exports.resourceName.exportName(...)
13
+ *
14
+ * This decorator is typically used inside controller
15
+ * classes, where the framework’s module loader inspects
16
+ * metadata to register commands, events and exports
17
+ * consistently.
18
+ *
19
+ * @param name Optional name to expose. If omitted,
20
+ * the method name is used.
21
+ *
22
+ * ```ts
23
+ * @Server.Controller()
24
+ * export class AccountController {
25
+ * @Server.Export('getAccountById')
26
+ * getAccount(id: string) {
27
+ * return this.accountService.find(id)
28
+ * }
29
+ * }
30
+ *
31
+ * // From another resource:
32
+ * // const result = exports['core-resource'].getAccountById('1234')
33
+ *```
34
+ * Internally, this decorator stores metadata used by
35
+ * the server bootstrap to automatically register the
36
+ * export through FXServer's `global.exports` API.
37
+ *
38
+ */
1
39
  export declare function Export(name?: string): (target: any, propertyKey: string) => void;