Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

[Entity Component System] How to get an EntityID from an Instance?

I'm developing an Entity Component System and I need a method for finding EntityIDs from Roblox Instances.

I have already considered a couple solutions:

1) A function which searches every "Instances" component in a table of components for a matching entity, then returns the entityID associated with that component.


local Instances = {

	42 = [Button = workspace.Part]

}

local function FindEntityFromInstance(obj)

for entityID, component in pairs(Instances) do

	local component = Instances(index)
	for key, value in pairs(component) do
		if value == obj then return entityID end
	end	

end

print(FindEntityFromInstance(workspace.Part))	--42

2) A table of Instance-EntityID pairs which is updated whenever an instance is added or removed from a component. I can index this table with a given instances to find it's associated entity.


local InstanceEntityIndex = {workspace.Part = 42}

function FindEntiyFromInstance(obj)
	return InstanceEntityIndex[obj]
end

print(FindEntityFromInstance(workspace.Part)) --42

3) Every instance can be wrapped in a table with an EntityID property. These tables can be indexed similar to the second method, but will simplify how Instances fit into my framework and will allow for instances to be shared by entities or have custom tags which aren't replicated.


local WrapperIndex = {}

local function WrapInstance(obj)

	local wrapper = {}
	
	local wrapperMeta = {
		__index = obj,
		__newIndex = function(tab, property, value)
			
			if obj[property] then
				obj[property] = value
			else
				tab[property] = value		
			end
	
		end
	}
	
	setmetatable(wrapper, wrapperMeta)
	WrapperIndex[obj] = wrapper

	return wrapper

end

local function GetInstanceWrapper(obj)
	return WrapperIndex[obj]
end

local wrapper = WrapInstance(workspace.Part)
wrapper.entityID = 42

print(GetInstanceWrapper(workspace.Part).entityID)	--42

4) Every instance can have a StringValue or IntValue named EntityID with the EntityID as their value.

5) Something to do with Collection Service

Some Issues:

  • I probably won't be able to use StringValues, IntValues or Collection Service because of replication issues. The client and server will keep track of their own unique entities and components.

  • There will be several entities with instance components in the game and this is a frequent problem, so looping over them all to compare is expensive.

  • I'm building a survival game, so the more memory I can conserve the better.

  • An Instance can be used by multiple components in an entity

I'll probably be using the second method because I don't have to loop over several components to make instance comparisons and it takes comparatively less memory than the other methods.

If anyone has any different suggestions or input on which method I described is best suited to my situation, please let me know.

2 comments

1

Every instances have three methods that called :SetAttribute(), GetAttribute() and GetAttributes(). May be you can use it to set/get EntityID, but there aren't much docs about the methods so I may wrong about it.

0

I thought they haven't implemented custom attributes yet but looking into it you can enable them. There's also surprisingly little documentation on them on the dev site. Anwyways that would probably suffer the same replication issues as Collection Service or string/int values

1 answer

✓ Accepted answer

So you have an instance and you want to know all the entities that refer to that instance, given that any entity may have 1+ components that refer to the instance?

You very likely need solution #2, except it'll map an instance to a list of entities that it's referenced by (or perhaps a list of entity-component pairs, if required). You can't beat looking up a value in a table (or even doing it twice) - even searching through small lists is more expensive.

Your metatable solution won't work; you'd have to wrap if obj[property] then in a pcall because Roblox will error the moment you even try to read from a property that doesn't exist.

StringValues, IntValues, and CollectionService all work and replicate perfectly fine, unless you want them to not replicated to certain clients. If you don't mind all components replicating to all clients, you can even use CollectionService as a functional ECS, as it keeps track of which instances have which tags. You would probably have to encode all component data as Instances (ex StringValue etc) that are children of the target Instance.

I wouldn't recommend trying to use CollectionService for just part of your ECS, and definitely not for an ID system (you could probably do it, but solution #2 is better).

Minor point: your examples have syntax errors regarding table initialization; you need [], like this:

local Instances = {
	[42] = {Button = workspace.Part}
}

That applies to every value, including string literals (with the shortcut syntax being the exception, ex {Key = 5} is fine - it's the same as {["Key"] = 5})

A mild warning against metatables (specifically __newindex, though what you propose is essentially harmless aside from the bug): beware that overriding __newindex with complex code can obfuscate what's going on. You want to avoid the extreme case where you're looking at a line like a.b = c and you're not sure whether this is going to call a bunch of functions or whether it's a simple table assignment, so you have to spend time looking up what a is and deciphering whether b is already defined on or not (since that impacts whether __newindex is called).

1 comment

0

Thanks for the input! I wrote the code inside of scripting helpers so there was bound to be some errors. I'll go with some mutation of the second solution, maybe a table where the instance GUID is the key and the value is a table of component's the instance is used by along with the corresponding entity ID.

This discussion is preserved as it was. New answers, comments, and votes are closed.