Remote event weird behavior when passing through hashed table

Try using this function before sending that remote event over:

local func = type --or use typeof
local function typeDump(t, l, checked)
    l = (l and l .. "\t") or ""
    checked = checked or {t}
    for k, v in next, t do
        if type(v) == "table" and not checked[v] then
            checked[v] = true;
            print(l..func(k),k,func(v),v)
            typeDump(v, l, checked)
        else
            print(l..func(k),k,func(v),v)
        end
    end
end

Yes, I have checked the initial keys of the table being passed through. However, if you mean whether or not every table is a key or value then I cannot tell since I haven’t ran a deep check function like you’ve mentioned. Here is the output when I look through the keys before sending: image

EDIT: I did type(i) that is why it’s printing “string”

Also, after trying what I suggested, see if it still errors when not sending that table over if all the data seems accurate in the output.

It’s not about whether the key is numerical or not, it’s about whether or not it goes into the array or dictionary part of the table.

Still seems to error. But if interested, here is the output. image

Nothing seems to be out of place, and the keys seem to be there as anticipated. I can’t understand why it’s erroring though.

perhaps it is this?

I am not sure if it accepts numerical keys that are out of array range.

I don’t quite get what you mean, mind elaborating?

Try sending it after deleting AttackingPlayers or clearing it.

I use the player’s userId to hold track of players currently attacking the boss in the system. I can change it into a string via tostring function if that’ll change anything.

It should fix the issue if it is a string.


Like I mentioned before. Also I accidentally typed numerical, it only accepts string key dictionaries.

One reason, just taking a guess, that this could be erroring is if there is an array that doesn’t start with the index of 1 it will throw the Invalid table key type used error. For example this array would error:

local Table  = {

{[2] = 2, [3]= 4}

}

Numeric keys do not go into the array portion of the table just because they are numbers. Generally, ignoring holes, if your table doesn’t have values at keys from 1 to the maximum number, the higher values will go into the dictionary part. and not the array. Hole behavior is more complicated.

It doesn’t have to start at an index of 1 actually because it will replace those fields with null afaik. It has to be either classified as an array or a string key dictionary, and based on the array size and the space between indices, it chooses which part a numerical index would land in (array or dictionary part).

Yes, I was a bit confused when you said

because I was really sure that wasn’t the case but I trust your judgment, I’ve turned it to a string and the error seems to be gone. However, can you elaborate on what took place here? I was under the impression that it was only the tables passed through directly that were affected by the Roblox checks (first generation tables is what I mean). This is a nested table within the passed in the table which had a numerical index. I’m still a bit confused.

I will leave this thread here. This thread is a good example of how bad Roblox’s design decision was. Lua programmers should mostly not need to know the difference between array and hashtable portions of tables.

Roblox has to serialize all the information it uses to communicate to the server and to the client, it does not just magically send objects and text over. It might be using JSON or some other type of storage format to do so but their serializer / type cannot handle those occasions.

If you mean Sparse Tables that wasn’t really the case with mine as I was sure I was passing in stringed keys. However, I see what you mean now, thanks for elaborating.

So does this mean that any table I send has to be checked for wrongly set up arrays?

EDIT: I meant deep checks for numerical keys that aren’t in ascending order.

They are not really arrays, just dictionaries with numerical keys (because they are not placed into the array part). But yes, you have to make all similar occurrences of huge numbers as keys into strings.

Realistically you need an abstraction layer for sending data through Remotes, period. You don’t want to have to care about this for every table, you’ll also run into this with userdata keys you’ll frequently want.

Serialize the table yourself, I use {Key = ActualKey, Value = ActualValue} recursively and unpack like that, very simple.

local NetworkUtility = {}

local function GetTableSerialization(Source)
    local Serialization = {}

    for Key, Value in pairs(Source) do
        local KeySerialization = nil

        if type(Key) == "table" then
            KeySerialization = GetTableSerialization(Key)
        else
            KeySerialization = Key
        end

        local ValueSerialization = nil
    
        if type(Value) == "table" then
            ValueSerialization = GetTableSerialization(Value)
        else
            ValueSerialization = Value
        end

        local KeyValuePair = {
            Key = KeySerialization,
            Value = ValueSerialization,
        }
        table.insert(Serialization, KeyValuePair)
    end

    return Serialization
end

function NetworkUtility.GetSerialization(...)
    local Serialization = {}
    local Arguments = {
        ...
    }

    for _, Argument in ipairs(Arguments) do
        local ArgumentSerialization = nil

        if type(Argument) == "table" then
            ArgumentSerialization = GetTableSerialization(Argument)
        else
            ArgumentSerialization = Argument
        end

        table.insert(Serialization, ArgumentSerialization)
    end

    return Serialization
end

local function GetTableUnserialization(Source)
    local Unserialization = {}

    for _, KeyValuePair in ipairs(Source) do
        local Key = KeyValuePair.Key
        local KeyUnserialization = nil

        if type(Key) == "table" then
            KeyUnserialization = GetTableUnserialization(Key)
        else
            KeyUnserialization = Key
        end

        local Value = KeyValuePair.Value
        local ValueUnserialization = nil

        if type(Value) == "table" then
            ValueUnserialization = GetTableUnserialization(Value)
        else
            ValueUnserialization = Value
        end

        Unserialization[KeyUnserialization] = ValueUnserialization
    end

    return Unserialization
end

function NetworkUtility.GetUnserialization(Serialization)
    local Unserialization = {}

    for _, Argument in ipairs(Serialization) do
        local ArgumentUnserialization = nil

        if type(Argument) == "table" then
            ArgumentUnserialization = GetTableUnserialization(Argument)
        else
            ArgumentUnserialization = Argument
        end

        table.insert(Unserialization, ArgumentUnserialization)
    end

    return Unserialization
end

return NetworkUtility
1 Like