[Plugin] Easy Enum Attributes

Roblox doesn’t let you add EnumItem attributes manually in the properties window (yet), only by scripting. I fixed that.

Recently I came across this thread, as I came across the lack of an EnumItem attribute type option in the Add Attribute menu. I was able to add an EnumItem attribute via script, and figured I’d share that, as well as my own suggestion of adding a dropdown for EnumItem or something similar. Roblox said it’s difficult to achieve in a user-friendly way with the current amount of enum types exceeding 100, and by a good bit.

I made a reply with a simple function to detect attribute changes and identify Enum’s from string-type attributes. I noted an assumption that it could be used in plugin form. So, that’s what I made.

You can get the plugin here, or click on the title of this thread. This plugin is honestly really simple, and I personally don’t think it’d impact performance–but I haven’t tested it on an experience with a lot of instances. Do let me know if it is negatively impactful to Studio or gameplay and I will fix the issue or remove the plugin until a more suitable method is achieved or is implemented by Roblox themselves.

Use / to retain the string attribute type when setting an enum. i.e /Enum.KeyCode.One
Credit to @Spacerator for this idea!


Showcase — Usage upon install:


To retain string type attributes and store a full enum:


View the new popup widget and select any EnumType with ease:
This list is designed to update automatically using Roblox’s :GetEnums() and :GetEnumItems() methods. For cases in which new Enum types & values are added to or removed from Roblox.

Attributes > Add Attribute > String Type > /Enums (in the value text box)


This is about as far as I can go with this. I’d suggested it to Roblox in my last reply in the linked thread above, that’d be the next best step for this type of thing. My only final want for this is to have the ability to double click the enum that’s replaced the original string and revert back to a string box (unless an EnumItem attribute type is added that functions similarly). However, Roblox staff are the only ones with that kind of power. They would have to implement that into the core structure of Studio. Which, as they stated in the linked thread, is totally doable — it just hasn’t been done yet.


This plugin listens for AttributeChanged, therefore it will not update currently existing Enum.EnumType.Value strings, but will on new changes.

The plugin alone will not detect and make changes in servers, it’s meant for use in Studio. You can have this done in-game using the following in either a server script or LocalScript:

Example (non-plugin) function
function waitForEnum(self)
	local connection
	connection = self.AttributeChanged:Connect(function(attributeName)
		if typeof(self:GetAttribute(attributeName)) == "string" and string.find(string.sub(self:GetAttribute(attributeName),1,6),"Enum.") then -- Make sure attribute type is a string & the inputted text is predicted to be an Enum
			if string.sub(self:GetAttribute(attributeName),1,5) == "/Enum" then connection:Disconnect() self:SetAttribute(attributeName,(string.gsub(self:GetAttribute(attributeName),"/",""))) return waitForEnum(self) end
			local newEnumTable = string.split(self:GetAttribute(attributeName),".") -- eg. "Enum, Keycode, ButtonA"
			if not newEnumTable[2] then return error("Invalid EnumType", 2) end -- No enum type inputted
			if (newEnumTable[2] == "" or newEnumTable[2] == " ") then return end -- Kill function if "Enum." is the only string inputted
			if not Enum[newEnumTable[2]] then return error("Invalid EnumType", 2) end -- Return error if no enum type exists for the given input (roblox will handle the error before reaching mine)
			if not newEnumTable[3] or not Enum[newEnumTable[2]][newEnumTable[3]] then return error("Invalid EnumType value", 2) end -- Return (my) error if an invalid value is inputted for Enum's third position in the above table 
			if Enum[newEnumTable[2]] and Enum[newEnumTable[2]][newEnumTable[3]] then -- Confirm enum exists
				self:SetAttribute(attributeName, Enum[newEnumTable[2]][newEnumTable[3]]) -- Set enum
			end
		end
	end)
end

for i,descendant in pairs(game:GetDescendants()) do waitForEnum(descendant) end
game.DescendantAdded:Connect(waitForEnum) -- Do for all new descendants

Crude method I’d say, but it works :man_shrugging:


You can get the plugin here, or click on the title of this thread.

Do you find this plugin useful?
  • Yes
  • No
  • Somewhat

0 voters

10 Likes

This is awesome.

Suggestion - allow escaping via \, i.e. \Enum.KeyCode.E will just place the string instead of changing the type of the attribute.

1 Like

Love this! I’m currently out getting dinner, but will add it as soon as I can!

Escape characters aren’t possible as invalid enums are automatically detected even if the part of the code doesn’t run; i tried this for myself.

RE: @Spacerator

I was able to do this after some time. Just need to disconnect the RBXScriptConnection and reconnect it after setting the attribute with a replacement string without the escape character (see below). I’ve just updated the plugin to include it.

Local/Server Script function
function waitForEnum(self)
	local connection
	connection = self.AttributeChanged:Connect(function(attributeName)
		if typeof(self:GetAttribute(attributeName)) == "string" and (string.sub(self:GetAttribute(attributeName),1,5) == "Enum." or string.sub(self:GetAttribute(attributeName),1,5) == "/Enum") then -- Make sure attribute type is a string & the inputted text is predicted to be an Enum
			if string.sub(self:GetAttribute(attributeName),1,5) == "/Enum" then connection:Disconnect() self:SetAttribute(attributeName,(string.gsub(self:GetAttribute(attributeName),"/",""))) return waitForEnum(self) end
			local newEnumTable = string.split(self:GetAttribute(attributeName),".") -- eg. "Enum, Keycode, ButtonA"
			if not newEnumTable[2] then return error("Invalid EnumType", 2) end -- No enum type inputted
			if (newEnumTable[2] == "" or newEnumTable[2] == " ") then return end -- Kill function if "Enum." is the only string inputted
			if not Enum[newEnumTable[2]] then return error("Invalid EnumType", 2) end -- Return error if no enum type exists for the given input (roblox will handle the error before reaching mine)
			if not newEnumTable[3] or not Enum[newEnumTable[2]][newEnumTable[3]] then return error("Invalid EnumType value", 2) end -- Return (my) error if an invalid value is inputted for Enum's third position in the above table 
			if Enum[newEnumTable[2]] and Enum[newEnumTable[2]][newEnumTable[3]] then -- Confirm enum exists
				self:SetAttribute(attributeName, Enum[newEnumTable[2]][newEnumTable[3]]) -- Set enum
			end
		end
	end)
end

Using the following, we can first create the connection. Then we check the first character, and if it returns with /, disconnect the connection, set the attribute with the string version of the enum inputted, and reconnect the connection by recalling the function.

local connection
connection = self.AttributeChanged:Connect(function(attributeName)
if typeof(self:GetAttribute(attributeName)) == “string” and string.find(self:GetAttribute(attributeName),“Enum.”) then – Make sure attribute type is a string & the inputted text is predicted to be an Enum
if string.sub(self:GetAttribute(attributeName),1,1) == “/” then connection:Disconnect() self:SetAttribute(attributeName,(string.gsub(self:GetAttribute(attributeName),“/”,“”))) return waitForEnum(self) end…

I apologize for reviving this thread. But I wanted to make a slight adjustment to the above snippet of code. Below I’ve changed detecting / to instead detect /Enum for retaining the string attribute type and storing an EnumItem as a string.
This allows for a lot more compatibility with other plugins that may listen for attribute changes and more specifically, string type attributes. This update has been pushed out in the plugin, and is now updated in the documentation here.

local connection
	connection = self.AttributeChanged:Connect(function(attributeName)
		if typeof(self:GetAttribute(attributeName)) == "string" and (string.sub(self:GetAttribute(attributeName),1,5) == "Enum." or string.sub(self:GetAttribute(attributeName),1,5) == "/Enum") then -- Make sure attribute type is a string & the inputted text is predicted to be an Enum
			if string.sub(self:GetAttribute(attributeName),1,5) == "/Enum" then connection:Disconnect() self:SetAttribute(attributeName,(string.gsub(self:GetAttribute(attributeName),"/",""))) return waitForEnum(self) end...

Didn’t think I’d have an update but here we are.

Added a popup widget to select an EnumType from a list of all types (along with their respective value options).

Attributes > Add Attribute > String Type > /Enums (in the value text box)

1 Like

Apologies for the thread revive.

  • Updated popup widget
    • Easier to navigate
    • Uses dropdowns to access an enum item’s list of values
    • Enums & their respective values are in alphabetical order
  • Combined Enum list and Enum values’ lists
  • First selected instance + number of additional selected instances are now listed in the widget’s title
  • Popup widget now force-closes when no instance is selected
    • There was an issue with this in previous versions. Whether it not close at all, opened upon experience launch, etc.
  • Selecting multiple instances now adds the selected EnumItem data to all selected instances
    • This includes commands, /Enum.Type.Value now sets all selected instances’ targeted attribute as the Enum in string format
    • /enums no longer needs to have the ‘e’ in “enums” capitalized. Either will open the popup widget

Let me know of extra commands you’d like to see, improvements you’d like to see, or general feedback on the plugin here. Thanks!


Edit: I’m trying to have minimal reason to toss unneeded updates into this plugin. Personally, I would like to have this plugin work as efficiently as possible with minimal conflict in a developer’s workflow. I would also like to make sure this plugin has little to no conflicts with other plugins. So far, I’ve seen no compatibility issues. However this can change at any point and I’d like to be in a position where this plugin can work with those new changes easily. So all feedback on the current state & future improvements is insanely helpful. Thank you for your time.

1 Like