RPC

🌐 Entity-Based RPC (via self.server or self.client)

Every BaseEntity instance gets a self.server property that acts as a proxy to server-side methods.

Example:

self.server:OpenLid()
self.server.plugins.lootable:GiveLoot(playerId)

Internally, metatables route calls based on:

  • The object’s id

  • The method name

  • The class or plugin type

RPC methods must be defined with @rpc(return?) on the server.

🧩 Global RPC (via Server.<method> or Client.<method>)

You can also call non-object-based RPCs from the client using the global Server table. These are typically utility methods not bound to a specific entity.

local data = Server.GetPlayerStats()

They can still be a callback or fire-and-forget style like entity based RPCs


🛡 RPC Internals

When you use @rpc(return?), the system registers:

  • An event handler with the method name under your resource namespace

  • If used inside a class, a entity wide dispatcher that finds the correct entity instance by ID

  • Optional callback registration for returning results

Entity-based RPC Routing Logic

Example using a server rpc called from the client

Server define the rpc:

@model("my_model")
class MyEntity extends BaseEntity {
    @rpc
    DoThing = function()
        print("DoThing")
    end
}

Client calls the RPC from the spawned entity:

@model("my_model")
class MyEntity extends BaseEntity {
    OnSpawn = function()
        self.server:DoThing()
    end
}

That is the same as:

Server["MyEntity.DoThing"](entityId, ...)

And then will be converted to:

TriggerServerEvent("namespace:MyEntity.DoThing", entityId, ...)

Server resolves:

  1. Entity instance via Entities:get(entityId)

  2. Verifies method exists and is exposed

  3. Calls DoThing on that instance

  4. Optionally, returns a value, the client will listen for he return value using callbacks


🔒 RPC Validation

The framework includes automatic safeguards to prevent clients/server from calling methods that:

  • Don’t exist on the class

  • Aren’t registered via @rpc(return?)

  • Target the wrong type of class (e.g. wrong plugin or base class)

This keeps your RPC layer safe and predictable.

Last updated