@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.
- package/README.md +12 -2
- package/dist/client/client-bootstrap.js +11 -14
- package/dist/client/client-core.d.ts +0 -17
- package/dist/client/client-core.js +0 -45
- package/dist/client/controllers/spawner.controller.d.ts +12 -0
- package/dist/client/controllers/spawner.controller.js +51 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.js +1 -0
- package/dist/client/interfaces/appearance.interface.d.ts +19 -0
- package/dist/client/interfaces/appearance.interface.js +2 -0
- package/dist/client/services/appearance.service.d.ts +6 -0
- package/dist/client/services/appearance.service.js +89 -0
- package/dist/client/services/{world/blip.service.d.ts → blip.service.d.ts} +1 -1
- package/dist/client/services/index.d.ts +9 -4
- package/dist/client/services/index.js +9 -8
- package/dist/client/services/{world/marker.service.d.ts → marker.service.d.ts} +1 -1
- package/dist/client/services/{world/ped.service.d.ts → ped.service.d.ts} +1 -1
- package/dist/client/services/spawn.service.d.ts +73 -0
- package/dist/client/services/spawn.service.js +261 -0
- package/dist/client/services/{ui/textui.service.d.ts → textui.service.d.ts} +1 -1
- package/dist/client/services/{world/vehicle.service.d.ts → vehicle.service.d.ts} +1 -1
- package/dist/client/system/processors/export.processor.js +1 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.js +1 -6
- package/dist/server/bootstrap.js +2 -2
- package/dist/server/controllers/command.controller.d.ts +1 -1
- package/dist/server/controllers/command.controller.js +6 -6
- package/dist/server/controllers/session.controller.d.ts +9 -0
- package/dist/server/controllers/session.controller.js +70 -0
- package/dist/server/database/adapters/oxmysql.adapter.js +1 -1
- package/dist/server/decorators/command.d.ts +34 -4
- package/dist/server/decorators/command.js +11 -6
- package/dist/server/decorators/controller.d.ts +22 -0
- package/dist/server/decorators/controller.js +22 -0
- package/dist/server/decorators/export.d.ts +38 -0
- package/dist/server/decorators/export.js +38 -0
- package/dist/server/decorators/guard.d.ts +51 -0
- package/dist/server/decorators/guard.js +43 -0
- package/dist/server/decorators/index.d.ts +4 -4
- package/dist/server/decorators/index.js +7 -4
- package/dist/server/decorators/onFiveMEvent.d.ts +6 -0
- package/dist/server/decorators/{coreEvent.js → onFiveMEvent.js} +8 -3
- package/dist/server/decorators/onFrameworkEvent.d.ts +22 -0
- package/dist/server/decorators/onFrameworkEvent.js +29 -0
- package/dist/server/decorators/onNet.d.ts +58 -0
- package/dist/server/decorators/onNet.js +57 -0
- package/dist/server/decorators/onTick.d.ts +31 -0
- package/dist/server/decorators/onTick.js +31 -0
- package/dist/server/decorators/public.d.ts +19 -8
- package/dist/server/decorators/public.js +19 -8
- package/dist/server/decorators/requiresState.d.ts +18 -17
- package/dist/server/decorators/requiresState.js +18 -17
- package/dist/server/decorators/throttle.d.ts +39 -0
- package/dist/server/decorators/throttle.js +27 -0
- package/dist/server/decorators/utils.d.ts +50 -0
- package/dist/server/decorators/utils.js +50 -0
- package/dist/server/entities/player.js +1 -1
- package/dist/server/error-handler.js +2 -2
- package/dist/server/helpers/resolve-method.d.ts +5 -0
- package/dist/server/helpers/resolve-method.js +18 -0
- package/dist/server/index.js +2 -0
- package/dist/server/loaders/playerSession.loader.js +13 -4
- package/dist/server/services/command.service.d.ts +1 -1
- package/dist/server/services/command.service.js +9 -6
- package/dist/server/system/metadata-server.keys.d.ts +1 -0
- package/dist/server/system/metadata-server.keys.js +1 -0
- package/dist/server/system/processors/command.processor.d.ts +2 -2
- package/dist/server/system/processors/command.processor.js +1 -2
- package/dist/server/system/processors/coreEvent.processor.d.ts +1 -1
- package/dist/server/system/processors/coreEvent.processor.js +6 -3
- package/dist/server/system/processors/export.processor.d.ts +1 -1
- package/dist/server/system/processors/export.processor.js +7 -3
- package/dist/server/system/processors/fivemEvent.processor.d.ts +7 -0
- package/dist/server/system/processors/fivemEvent.processor.js +40 -0
- package/dist/server/system/processors/netEvent.processor.d.ts +1 -1
- package/dist/server/system/processors/netEvent.processor.js +12 -9
- package/dist/server/system/processors.register.js +2 -0
- package/dist/server/system/schema-generator.d.ts +2 -0
- package/dist/server/system/schema-generator.js +34 -0
- package/dist/server/templates/admin/admin.controller-template.d.ts +7 -5
- package/dist/server/templates/auth/auth-provider.contract.d.ts +2 -2
- package/dist/server/types/core-events.d.ts +5 -0
- package/package.json +29 -1
- package/dist/client/loaders/exports.loader.d.ts +0 -1
- package/dist/client/loaders/exports.loader.js +0 -13
- package/dist/client/services/core/index.d.ts +0 -1
- package/dist/client/services/core/index.js +0 -17
- package/dist/client/services/core/spawn.service.d.ts +0 -20
- package/dist/client/services/core/spawn.service.js +0 -143
- package/dist/client/services/streaming/index.d.ts +0 -1
- package/dist/client/services/streaming/index.js +0 -17
- package/dist/client/services/ui/index.d.ts +0 -3
- package/dist/client/services/ui/index.js +0 -19
- package/dist/client/services/world/index.d.ts +0 -4
- package/dist/client/services/world/index.js +0 -20
- package/dist/server/decorators/coreEvent.d.ts +0 -2
- package/dist/server/decorators/netEvent.d.ts +0 -36
- package/dist/server/decorators/netEvent.js +0 -40
- /package/dist/client/services/{world/blip.service.js → blip.service.js} +0 -0
- /package/dist/client/services/{world/marker.service.js → marker.service.js} +0 -0
- /package/dist/client/services/{ui/notification.service.d.ts → notification.service.d.ts} +0 -0
- /package/dist/client/services/{ui/notification.service.js → notification.service.js} +0 -0
- /package/dist/client/services/{world/ped.service.js → ped.service.js} +0 -0
- /package/dist/client/services/{ui/progress.service.d.ts → progress.service.d.ts} +0 -0
- /package/dist/client/services/{ui/progress.service.js → progress.service.js} +0 -0
- /package/dist/client/services/{streaming/streaming.service.d.ts → streaming.service.d.ts} +0 -0
- /package/dist/client/services/{streaming/streaming.service.js → streaming.service.js} +0 -0
- /package/dist/client/services/{ui/textui.service.js → textui.service.js} +0 -0
- /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);
|
|
@@ -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.
|
|
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; } });
|
package/dist/server/bootstrap.js
CHANGED
|
@@ -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(
|
|
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,
|
|
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
|
|
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,
|
|
22
|
+
async onCommandReceived(player, command, args, raw) {
|
|
23
23
|
try {
|
|
24
|
-
logger_1.loggers.command.trace(`Received: /${
|
|
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,
|
|
28
|
+
await this.commandService.execute(player, command, args, raw);
|
|
29
29
|
}
|
|
30
30
|
catch (error) {
|
|
31
|
-
logger_1.loggers.command.error(`Execution failed: /${
|
|
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,
|
|
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 =
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
|
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
|
-
*
|
|
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
|
|
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
|
-
|
|
14
|
-
const
|
|
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;
|