[Release] Callbacks using exports and with added timeouts!

What exactly is “kimi_callbacks” and what can you do with it?

“kimi_callbacks” is a LUA script for FiveM that allows you to create custom server and client
callbacks in an easy manner. This script does nothing by itself and needs to be used via exports
from other resources.

I decided to create this script as a base for my other scripts and I felt like the others out there
didn’t really exactly suit my needs.

Checkout the AdvancedParking and Advanced Vehicle Interaction Script that both use this feature to get values from the server.

Features

  • Clients can request data from the server.
  • Server can request data from a client.
  • Includes configurable timeouts for requests that take too long.
  • Any amount of values can be returned / send.
  • Uses exports for all functions.
  • Examples explaining all you need to know.
  • Compatible with everything.

Performance

  • This script does not really use any performance, unless a lot of request are running in parallel.
  • Idle: both client and server: 0.00ms
  • 100 parallel server callbacks (for the splitsecond they are active at the same time and chances
    are pretty much 0 to get even 5 at the same time):
    • client side: ~0.30ms
    • server side: ~0.00-0.01ms

Installation

  1. Download the script from Github.
  2. Extract the folder into your resources folder.
  3. Make sure the folder name of the script is kimi_callbacks
  4. Go into your server.cfg and put the line ensure kimi_callbacks as high up as possible.

Where can I get this?

  • Newest version on Github:

Patchnotes

Open me

Update v1.2.0

  • Added asynchronous callbacks.
  • Added additional error checking.
  • Added additional detailed error messages.
  • An error in a callback now immediately throws an error instead of waiting for the timeout.
  • Reformatted everything.
  • Added wiki to Github repo.
  • Added releases.
  • Updated license.

Hotfix v1.1.2

  • Added an additional error check.

Hotfix v1.1.1

  • Fixed error when registering a callback.

Update v1.1

  • Added additional error checks to show user friendly error messages.
  • Exports now defined directly inside the script instead of the fxmanifest file.

Check out my other free scripts as well!

  • CinematicCam - Lets you fly around the world with a lot of different camera functions.
  • DeathCam - Lets you rotate the camera when you are dead.

Also take a look at my store if you want to support my work!

10 Likes

This is super cool. Really good job making this!

2 Likes

nice job :slight_smile:

2 Likes

How can i use this just add in the server is enough or need to export some thing. Give us some examples. @Kiminaze

Just add it like you would any other resource and start it in the server.cfg (though I recommend using “ensure” instead of “start” for this script).

If you want to use it in your resources, there is nothing else you need to do. You don’t need to add anything in your fxmanifest.lua (or __resource.lua) nor do you need to request any data in your script before you can start.

You can just call these functions from your code:

local result = exports["kimi_callbacks"]:Trigger(CALLBACK_NAME)
local result = exports["kimi_callbacks"]:TriggerWithTimeout(CALLBACK_NAME, 500)
exports["kimi_callbacks"]:Register(CALLBACK_NAME, function() end)

These are just arbitrary examples. There are more inside the example folder of the github repository.

1 Like

Needed this thanks

1 Like

There currently seems to be a problem with returning more than one value. Returning one value works fine and is no problem at all. So this bug won’t break any callbacks that only use a single return value. I am still investigating as to why this is happening.
E.g. this will currently not work and only data1 will have its proper value. data2 and data3 will be nil:

local data1, data2, data3 = exports["kimi_callbacks"]:Trigger("doSomething", someOtherData)

Related: Lua exports only allowing a single return value

EDIT: This issue has been fixed by the CFX team. You can now return multiple values without a problem!

1 Like

Can I just start instead of ensure too?

In my server config nothing use ensure so I dont know if it would work for me.

Yea, no problem at all. But running any newer server version should support this :slight_smile:

easy work around.

Server side return should just be made as an array so return {data1 = '‘value’, data2 = ‘value’, data3 = ‘value’} that way you could return more then one value, and get around the issue with it only returning one value easy peasy :smiley:

Yes, you are right, that would work indeed.

But I completely forgot to mention this in this thread:
This issue has been fixed by CFX quite some time ago. It is possible to get more than one return value from exports now :slight_smile:

One thing i have had issues with if i do asyn sql calls ex via oxmysql it tends to return nil insted of the values, even tho the return is located with in the sql call and return should not be called before the data is there might be worth mentioning.

If i do a sync sql call tho there is no problems.

Yes. The thing you are experiencing is completely normal.
A return always returns the current function.

e.g. the return in line 3 is in the scope of the sql callback function thus returning that function and not the callback itself

1   exports["kimi_callbacks"]:Register("sqltest", function(source)
2       MySQL.async.fetchAll("some query", {}, function()
3           return "something"
4       end)
5   end)

Ways around that include the same way you described it (using sync calls) or waiting yourself like this:

exports["kimi_callbacks"]:Register("sqltest", function(source)
    local returnValue = nil
    MySQL.async.fetchAll("some query", {}, function()
        returnValue = "something"
    end)

    while (returnValue == nil) do
        Citizen.Wait(0)
    end

    return returnValue
end)

(this is btw literally what the sync calls do inside mysql-async)

You could also do something like this

exports["kimi_callbacks"]:Register("sqltest", function(source)
    local p = promise.new()
    MySQL.async.fetchAll("some query", {}, function()
        p:resolve("something")
    end)

    return Citizen.Await(p)
end)
1 Like

Oh sheeet, didn’t even know we had those in FiveM hahaha
You always learn something new. Thanks for letting me know :smiley:

1 Like

You’re welcome :smiley:

Ye precise would make more sence to actually just use sync.

Im using OxMySQL moved away from Async the performance vs Ox is way behind.

Yea, that was just an example to show how you could do it :smiley:
Of course this would work with ox as well.

But one thing that people always seem to get “wrong”:
mysql-async does not require a lot of performance. Yes, the queries take at least 50ms, but that is simply a cause of how the script is designed. It waits for the query to finish by using Citizen.Wait, meaning it waits at least one server frame/update (which is 50ms). But it does not require that much performance.

I have written a C# MySQL Connector for FiveM that draws like 1.5ms on server side (simply because it is C#) but most queries take 0-1ms in there.

Hehe im not saying mysql-async is trash in no way, but from a performance view the mysql2 nodejs lib is faster then the mysql “1” lib mysql-async uses.

Read/Wright are actually affected quite abit by the change, i did a small test 60-80% performance gain on the same wright query mysql-async vs OxMySQL so for me the clear choice now is OxMySQL.

Minor update adding user friendly error messages.