Null arguments in native events (is this a bug?)

Hey,

While sending a server event with TriggerServerEvent where one of the arguments is nil, I noticed the succeeding were null too.

Here’s a minimal example:

-- server.lua
RegisterServerEvent('testing')
AddEventHandler('testing', function(message, arg, arg2)
    print(message, arg, arg2)
end)
-- client.lua
CreateThread(function()
    -- if I add another 5th argument, arg2 is no longer nil
    TriggerServerEvent('testing', 'mymessage', nil, 'foo')
end)

Output

-- console
[       script:test] mymessage  nil    nil

Is there any reason for this to happen?

Thanks.

@gottfriedleibniz did we mitigate this ever?

Negative.

Also, there was also a person on this forum who said they were going to create a PR for MRV exports>

I just noticed that msgpack is causing this while serializing a list with nil as the latest argument.

--  fivem/data/shared/citizen/scripting/lua/scheduler.lua 
function TriggerServerEvent(eventName, ...)
		local payload = msgpack_pack({...})

Please let me know if you otherwise need help investigating this as I can follow up with a PR.

Tables are packed with the ‘without_hole’ configuration (adopted from MessagePack.lua), meaning arrays with nil values are to be encoded as maps. This generally conflicts with parameter sequences that use table.pack/table.unpack.

I’ve had a fix for this laying around for a while now (see below). However, I was considering moving this implementation directly to the msgpack library (e.g., a special function that overrides the default flags) to avoid the intermediate table creation.

msgpack.setoption('sentinel', false) -- Only allow encoding sentinels (decoding creates nils)

-- Replace nil's in varargs w/ msgpack sentinels
local select = select
local msgpack_null = msgpack.null
local function MsgpackSanitize(...)
    local t = {...}
    for i=1,select("#", ...) do
        if t[i] == nil then
            t[i] = msgpack_null
        end
    end
    return t
end

-- Usage: msgpack.pack(MsgpackSanitize(...))

I was wondering about the same (patching the event or MessagePack)
I was actually going to suggest something similar, but using two tables: the original table, and nulls, instead of a placeholder since I wasn’t sure it could get mixed up with valid occurrences. Something very drafty:

local function test(...)
    local t, n = {...}, select('#', ...)
    local nulls = {}
    for k = 1, n do
        if t[k] == nil then
            table.insert(nulls, k)
        end
    end
    return t, nulls
end

And then eventually restore the original null positioning as enumerated arguments.
Anyway, that sounds good to me! Thanks for the quick reaction.