"Message buffer too small for table" and recursive tables

I have a bunch of sprites that form ad hoc groups during gameplay, and I need each sprite to have a reference to the group. I implemented the group as a table in the level, but when I went to send this table to the sprites, I get the “Message buffer too small for table” error.

I should think a recursive table is too big, if it’s trying to send the whole table!

I suppose it could just be that it’s trying to send everything up to the recursive points, but regardless, I would much prefer if I could send the table by reference, instead of trying to send the whole thing. Is there a way I could send just a reference to the group instead of the entire group? This group is going to be changing during play, and I only want to update the group once, not the group copy in every sprite.

Well, I suppose I might be able to rethink some of the structure of what needs to know what if I can’t; but this does raise another concern as well: objects in tables are references, right? When I have an object linking to a sprite that also has the group object in a table, which in turn holds a table of sprite objects, which have the group object… We are only talking about one group object and one sprite object here, right? I read somewhere that lua variables are always references, but this table size issue (being more than a single reference to 1 variable) has me a bit concerned.

So I guess that’s two questions: passing a reference to the table, and making sure I’m not making a giant (non)recursive blob even without worrying about messaging.

Yes Lua tables are passed by reference. But when you post a message the table data get serialised into a binary format and at that point each reference to the table will be serialised and take up precious bytes in the message buffer.

It is often the case that the developer uses a shared Lua module to store game state in.
Perhaps this would help in your situation too.

Yes, like Mathias wrote, store the state in a Lua module, keyed by some kind of group id, and only send the group id in the messages.

Here’s an example with a “grouper” module that tracks groups and objects belonging to groups.

-- grouper.lua
local M = {}

local groups = {}

local count = 0

-- create a group
-- @return id of the created group
function M.create()
	local group_id = hash("group"..count)
	local group = {
		id = group_id,
		objects = {},
	}
	groups[group_id] = group
	return group_id
end

-- add an object to a group
function M.add(group_id, object)
	local group = groups[group_id]
	assert(group)
	group.objects[#group.objects + 1] = object
end

function M.remove(group_id, object)
	local group = groups[group_id]
	assert(group)
	local objects = group.objects
	for i=1,#objects do
		if objects[i] == object then
			table.remove(objects, i)
			return true
		end
	end
	return false
end

function M.get(group_id)
	local group = groups[group_id]
	assert(group)
	return group.objects
end

return M

Here’s an example of how it can be used:

-- foo.script

local grouper = require("grouper")

local function leave_group(self)
	if self.group_id then
		grouper.remove(self.group_id, go.get_id())
	end
end

local function join_group(self, group_id)
	self.group_id = message.group_id
	grouper.add(message.group_id, go.get_id())
end

function init(self)
	-- create a group and add this game object to the group
	self.group_id = grouper.create()
	grouper.add(go.get_id())

	-- some kind of movement direction
	self.direction = vmath.vector3()

	-- raycast 100 pixels in front of the object
	-- if we hit something we bring it to our group
	local raycast_groups = { hash("objects") }
	timer.delay(0.5, true, function()
		local from = go.get_position()
		local to = from + self.direction * 100
		local hits = physics.raycast(from, to, raycast_groups)
		if hits then
			for i=1,#hits do
				-- send a message to the object we hit that it should join our group
				msg.post(hits[i].id, "join_group", { group_id = self.group_id })
			end
		end
	end)
end

function final(self)
	-- remove the object from the group it belongs to
	leave_group(self)
end

function update(self, dt)
	-- apply some kind of steering behaviour and movement logic
end

function on_message(self, message_id, message, sender)
	if message_id == hash("join_group") then
		leave_group(self)
		join_group(self, message.group_id)
	end
end
2 Likes