Initial commit — Southwest Roleplay FiveM
This commit is contained in:
73
src/server/core/rpc/index.ts
Normal file
73
src/server/core/rpc/index.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Server-side RPC — replaces RageMP's mp.events.addProc / mp.events.callRemoteProc.
|
||||
*
|
||||
* Server registers a proc:
|
||||
* rpc.register('getClosestTrunk', async (player, ...args) => { return result; });
|
||||
*
|
||||
* Client calls it via the client RPC module (see src/client/core/rpc/index.ts):
|
||||
* const result = await rpc.call('getClosestTrunk', ...args);
|
||||
*
|
||||
* The wire protocol uses two net events:
|
||||
* _rpc:call player → server { id, name, args }
|
||||
* _rpc:result server → player { id, result, error }
|
||||
*/
|
||||
|
||||
import { playerRegistry } from '../player/player-registry';
|
||||
|
||||
type ProcHandler = (player: import('../player/player-registry').PlayerWrapper, ...args: any[]) => any;
|
||||
|
||||
const handlers = new Map<string, ProcHandler>();
|
||||
|
||||
let clientCallCounter = 0;
|
||||
const clientPending = new Map<string, { resolve: (v: any) => void; reject: (e: any) => void }>();
|
||||
|
||||
RegisterNetEvent('_rpc:clientResult');
|
||||
AddEventHandler('_rpc:clientResult', (callId: string, result: any, error: string | null) => {
|
||||
const cb = clientPending.get(callId);
|
||||
if (!cb) return;
|
||||
clientPending.delete(callId);
|
||||
if (error) cb.reject(new Error(error));
|
||||
else cb.resolve(result);
|
||||
});
|
||||
|
||||
export const rpc = {
|
||||
register(name: string, handler: ProcHandler): void {
|
||||
handlers.set(name, handler);
|
||||
},
|
||||
|
||||
// Server → client proc call (replaces mp.events.callRemoteProc / player.callProc)
|
||||
callClient<T = any>(player: import('../player/player-registry').PlayerWrapper, name: string, ...args: any[]): Promise<T> {
|
||||
const id = `${Date.now()}_${clientCallCounter++}`;
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
clientPending.set(id, { resolve, reject });
|
||||
TriggerClientEvent('_rpc:clientCall', player.id, id, name, args);
|
||||
setTimeout(() => {
|
||||
if (clientPending.has(id)) {
|
||||
clientPending.delete(id);
|
||||
reject(new Error(`Client RPC timeout: ${name}`));
|
||||
}
|
||||
}, 10000);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
RegisterNetEvent('_rpc:call');
|
||||
AddEventHandler('_rpc:call', async (callId: string, name: string, args: any[]) => {
|
||||
const netId = (global as any).source as number;
|
||||
const player = playerRegistry.get(netId);
|
||||
|
||||
if (!player) return;
|
||||
|
||||
const handler = handlers.get(name);
|
||||
if (!handler) {
|
||||
TriggerClientEvent('_rpc:result', netId, callId, null, `No proc registered: ${name}`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await handler(player, ...(args ?? []));
|
||||
TriggerClientEvent('_rpc:result', netId, callId, result, null);
|
||||
} catch (err: any) {
|
||||
TriggerClientEvent('_rpc:result', netId, callId, null, err?.message ?? String(err));
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user