Files
fivem/src/server/core/rpc/index.ts

74 lines
2.6 KiB
TypeScript

/**
* 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));
}
});