Sign in to follow this  
micaww

rage-rpc: Universal, asynchronous Remote Procedure Call implementation for RAGE

Recommended Posts

Version 0.2.0 has been released.

This update has a few new convenience features as well as a bug fix.

The bug, found by @Yiin , made CEF fail when retrieving an inbound event with a single quote in it. For example an error message with an apostrophe. This has been solved and the fix is included in the latest release.

As for features, 2 things were added:

1. Send any number of multiplayer objects between server and client. Previously, to access a multiplayer object remotely, you had to send the ID or remote ID of it and then get the entity by that ID on the other side. This is no more! You can now embed any synced multiplayer object right into your arguments, or return them from any of your procedures without extra work. They don't have to be the only argument either. You can put multiplayer objects at any level within your argument object/array. This currently doesn't work for events that communicate with the browser. I may add some kind of way to interface multiplayer objects directly from the browser in the future.

Here are some examples:

/* Allow clients to ask for the server to delete some vehicles */

// Client-side
const veh1 = mp.vehicles.at(0);
const veh2 = mp.players.local.vehicle;
rpc.callServer('deleteVehicles', [veh1, veh2]); 

// Server-side
rpc.register('deleteVehicles', vehicles => {
  vehicles.forEach(veh => veh.destroy());
});
/* Get information on a certain vehicle, including the players currently in it (whether they're currently streamed in or not) */

// Client-side
const veh = mp.vehicles.atRemoteId(6);
rpc.callServer('getVehicleInfo', veh).then(data => {
  // let's print the names of all players in this vehicle
  mp.game.graphics.notify('~g~' + data.occupants.map(ply => ply.name).join(', '));
});

// Server-side
rpc.register('getVehicleInfo', veh => ({
    bodyHealth: veh.bodyHealth,
    plate: veh.numberPlate
    occupants: veh.getOccupants() // an array of Players in the vehicle
}));

2. Add "browser" property to client callback info when a procedure is called from CEF. One thing about native events using mp.trigger is that there is no way to easily tell which browser triggered the event. Now, in client-side register, you can see the browser instance that called the event because it is passed into the caller info. This of course allows you to further manipulate the browser by executing more code, destroying it, etc.

For example, you may want to give browsers the ability to close themselves without creating a separate event for each browser instance:

// Client-side
rpc.register('closeBrowser', (_, { browser }) => {
  // `browser` is the RAGE:MP Browser instance that called this event
  browser.destroy();
});
// Any CEF browser
rpc.callClient('closeBrowser');

Simple as that.

I hope you all find these additions useful!

  • Like 2

Share this post


Link to post
Share on other sites

Beast package. The only thing is I can't use it with es6 import but it's not important. Good job🔥

Share this post


Link to post
Share on other sites

@buxx0 The module is UMD so you can use it with es6 import! I do in my code aswell. Like so:

import * as rpc from 'rage-rpc';

It just doesn't have a default export, so you have to wildcard it.

  • Like 1

Share this post


Link to post
Share on other sites
vor 2 Stunden schrieb OLTEANUadv:

How to install it on clientside?

Rysu9yo.png

 

Hey... you have to integrate the require command correctly in the index.js ... is there an index.js in your folder rage-rpc?

  • Like 1

Share this post


Link to post
Share on other sites
9 hours ago, Shooter said:

 

Hey... you have to integrate the require command correctly in the index.js ... is there an index.js in your folder rage-rpc?

Fixed, thx!

Share this post


Link to post
Share on other sites

Hey

I just discovered rpc and want to use it! It seems really powerful but I am struggling to use it. I made a copy of my server to show my problem. 
I just tried the climbing Client <-> Server example and its not working for me 😥. (https://github.com/micaww/rage-rpc#server-to-client)

Server:(i cuted unrelevant things out. its freeroam with some CEF) -> 

Clientside:

I used:

const rpc = require('rage-rpc');
rpc.register('getIsClimbing', () => mp.players.local.isClimbing());

In "client_packages\freeroam\index.js" and:

const rpc = require('rage-rpc');

rpc.callClient(player, 'getIsClimbing').then(climbing => {
if(climbing){
console.log('The player is climbing!');
}else{
console.log('The player is not climbing!');
}
});

inside "packages\freeroam\events.js"

i created a "rage-rpc" Folder with a index.js of rage-rpc.min.js cause i can't use

 

const rpc = require('rage-rpc');

 

in client_packages for some reason? it gets me this:

9b894af7-17ea-4c60-b440-2fb842eac8f6.jpg

I hope for Help i believe its a stupid thingi am doing wrong 🙄

Hank


 

 

Share this post


Link to post
Share on other sites

Version 0.3.0 has been released!

Sorry everyone for the wait. RPC has been holding up very well and is being used heavily by quite a few people even without updating. Nevertheless, I bring you some more features and bug fixes!

https://github.com/micaww/rage-rpc/releases/tag/v0.3.0

1. Added default export

The default export has been added thanks to @Yiin which makes it easier to import RPC and get going:

// wildcard import using bundler
import * as rpc from 'rage-rpc';

// wildcard import using minified build
import * as rpc from './rage-rpc.min.js';

// default import
import rpc from 'rage-rpc';

// or
import rpc from './rage-rpc.min.js';

 

2. Added event system

There is now an event system that uses the same underlying technology that RPC uses to send messages back and forth between contexts. It can be used as a full-on replacement for the default RAGE:MP events, and it uses nearly the same syntax as the procedure calling functions. The difference between events and procedure calls is:

* An event can have any number of listeners on any context, or none.
* Triggering an event does not return the result of events.

Since it uses the same syntax as the procedure calling API, it's more convenient than using mp.events.add everywhere if you're already using RPC. Also, you can call directly from browser -> server, vice versa, or from browser -> other browsers without intermediate events. Here is a quick run down of the API:

Registering Events

On any context, you can register and unregister any number of event listeners for an event, similar to the mp.events.add and mp.events.remove API:

import rpc from 'rage-rpc';

const handleEvent = (message) => {
  console.log('event handled: '+message);
};

// register the event
rpc.on('coolEvent', handleEvent);

// later on maybe...
// unregister the event handler
rpc.off('coolEvent', handleEvent);

Calling Events

Events can be called from any context and directed towards any context. The API is identical to calling a remote procedure, except that they do not return anything. Events are fire-and-forget, as in they do not return any results or errors:

// serverside
rpc.on('serverEvent', (msg, {player}) => console.log(`message from ${player.name}: ${msg}`));

rpc.triggerClient(mp.players.at(0), 'clientEvent');
rpc.triggerBrowsers(mp.players.at(0), 'browserEvent');

// clientside
rpc.on('clientEvent', () => {
  // set the player to ragdoll
  mp.players.local.setToRagdoll(1000, 10000, 0, false, false, false);
});

rpc.trigger('clientEvent');
rpc.triggerServer('serverEvent', 'hello!!');
rpc.triggerBrowsers('browserEvent', 'aaaahhh');
rpc.triggerBrowser(browser, 'browserEvent', 'yoyoyo');

// browser
rpc.on('browserEvent1', () => {
  if(confirm('Do you want to ragdoll?')){
    rpc.triggerClient('clientEvent'); // ragdoll them!
  }
});
rpc.on('browserEvent2', msg => alert(msg));

rpc.trigger('browserEvent2', 'hello world!');
rpc.triggerServer('serverEvent', 'hey from browser');
rpc.triggerBrowsers('browserEvent1');

Using these events in the place of RPC functions is recommended when you don't need a result back, as it prevents the local context from keeping track of the called procedure and prevents the remote context from returning data back, which makes it outperform typical RPCs that must send information back to the caller.

 

3. Added options to procedure calls

Some options have been added to the procedure calls (not available on events) that give you some more control over the events that you're calling:

* noRet: boolean - Prevent the remote context from sending return data. This saves bandwidth when a response isn't needed. Similar to how events work.
* timeout: number - A timeout, in milliseconds, for the procedure call to run. If the procedure takes longer to return than this time, the promise will reject with "TIMEOUT".

 

4. Added generic types to procedure calls (TypeScript)

Also thanks to @Yiin , if you're using TypeScript, you can now specify the resolution type of the returned Promise using generics:

// some procedure registering
rpc.register('getTheNumber', () => 42);

// calling that procedure
rpc.call<number>('getTheNumber').then(num => {
  // "num" is the number type
});

 

Other Bug Fixes

* Fix sending incorrect entity sometimes from client->server: Sometimes the client would send the wrong MP entity to the server in certain rare situations.

* Fix persisting browserId in CEF: Allows for page reloading without messing up RPC knowing which browser to send events to.

  • Like 3

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.