Skip to content

Instantly share code, notes, and snippets.

@MrAsynchronous
Created May 17, 2023 22:06
Show Gist options
  • Save MrAsynchronous/4801f8c14c57a510fee791a3e8b2c66c to your computer and use it in GitHub Desktop.
Save MrAsynchronous/4801f8c14c57a510fee791a3e8b2c66c to your computer and use it in GitHub Desktop.
local EnumsInternal = {}
local makeEnum
-- Luau can only type enumSpec adaptively if we describe it as an adaptive table first and then reassign it using its adaptive table type.
local enumSpec = {}
enumSpec = setmetatable({}, {
__newindex = function(self, name, spec)
makeEnum(name, spec)
end
}) :: typeof(enumSpec)
local Enums = setmetatable({}, {
__newindex = function()
error('Enums may not be added at runtime.')
end,
__tostring = function()
return '[ Enum Provider ]'
end,
__index = function(self, key)
if key == 'All' then
return {unpack(EnumsInternal)}
elseif EnumsInternal[key] then
return EnumsInternal[key]
else
error(`"{key}" is not a valid enum.`)
end
end,
__iter = function(self)
return next, EnumsInternal
end
}) :: typeof(enumSpec)
export type CustomEnumItem<IndexMap> = {
Name: string,
Value: number,
Enum: CustomEnum<IndexMap>
}
export type CustomEnum<IndexMap> = {
GetEnumItems: (CustomEnum<IndexMap>)->{CustomEnumItem<IndexMap>},
EnumName: string
} & IndexMap
local enum_meta = {
__index = function(self, key)
if key == "GetEnumItems" then
return function(self): {CustomEnumItem<any>}
return table.clone(self._itemsArray)
end
elseif key == "EnumName" then
return self._name
elseif self._itemsMap[key] then
return self._itemsMap[key]
else
error(`{key} is not a valid property, function, or EnumItem`)
end
end,
__newindex = function()
error("Can't set properties of CustomEnum")
end,
__metatable = "Enum metatable not available",
__tostring = function(self)
return `[Custom Enum "{self._name}"]`
end,
__iter = function(self)
return next, self._itemsArray
end
}
local enumItem_meta = {
__metatable = "EnumItem metatable not available",
__tostring = function(self)
return `[Custom Enum Item {self._enum._name}.{self._key} [{self._value}]]`
end,
__index = function(self, key)
if key == "Name" then
return self._key
elseif key == "Value" then
return self._value
elseif key == "Enum" then
return self._enum
else
error(`{key} is not a valid member of CustomEnumItem`)
end
end,
__newindex = function(self, key, value)
error("Can't set properties of CustomEnumItem")
end
}
function makeEnum<T>(enumName: string, spec: T): T
for key, value in spec do
assert(typeof(key) == "string", "Enum keys must be strings")
assert(typeof(value) == "number", "Enum values must be numbers")
assert(value % 1 == 0 and value > 0, "Enum values must be integers greater than 0")
for otherKey, otherValue in spec do
assert(key == otherKey or value ~= otherValue, `Enum values must be unique. {otherKey} and {key} both share {value}`)
end
end
local itemsArray = {}
local itemsMap = {}
local enum = setmetatable({
_itemsArray = itemsArray,
_itemsMap = itemsMap,
_name = enumName,
}, enum_meta)
for key, value in spec do
local item = setmetatable({
_value = value,
_key = key,
_enum = enum
}, enumItem_meta)
table.insert(itemsArray, item)
itemsMap[key] = item
itemsMap[value] = item
end
EnumsInternal[enumName] = enum
return enum :: typeof(spec)
end
enumSpec.WorldEditorAction = {
Cut = 1,
Copy = 2,
Paste = 3,
Delete = 4,
Edit = 5
}
export type WorldEditorAction = CustomEnumItem<typeof(enumSpec.WorldEditorAction)>
enumSpec.WorldContextMenuType = {
World = 1,
Stamp = 2,
Circuit = 3
}
export type WorldContextMenuType = CustomEnumItem<typeof(enumSpec.WorldContextMenuType)>
enumSpec.WorldEditorTool = {
Selector = 1,
Dragger = 2,
Rotator = 3
}
export type WorldEditorTool = CustomEnumItem<typeof(enumSpec.WorldEditorTool)>
enumSpec.InventoryCategory = {
Stamps = 1,
Souvenirs = 2,
Worlds = 3,
Stickers = 4,
}
export type InventoryCategory = CustomEnumItem<typeof(enumSpec.InventoryCategory)>
enumSpec.ToolboxStampSort = {
Relevance = 1,
Likes = 2,
Favorites = 3
}
export type ToolboxStampSort = CustomEnumItem<typeof(enumSpec.ToolboxStampSort)>
enumSpec.ToolboxCategory = {
Inventory = 1,
Library = 2
}
export type ToolboxCategory = CustomEnumItem<typeof(enumSpec.ToolboxCategory)>
enumSpec.GuiTheme = {
Light = 1,
Dark = 2
}
export type GuiTheme = CustomEnumItem<typeof(enumSpec.GuiTheme)>
enumSpec.StampSort = {
New = 1,
Player = 2,
}
enumSpec.WorldSort = {
New = 1,
Player = 2
}
export type WorldSort = CustomEnumItem<typeof(enumSpec.WorldSort)>
enumSpec.WorldMutation = {
PlaceStamp = 1,
MoveStamp = 2,
DeleteStamp = 3,
}
export type WorldMutation = CustomEnumItem<typeof(enumSpec.WorldMutation)>
enumSpec.StampDialogAction = {
New = 1,
LoadInventory = 2,
LoadMarketplace = 3,
LoadMagica = 4,
}
export type StampDialogAction = CustomEnumItem<typeof(enumSpec.StampDialogAction)>
enumSpec.WorldEntryAction = {
NewSort = 1,
PlayerSort = 2,
CreateWorld = 3,
}
export type WorldEntryAction = CustomEnumItem<typeof(enumSpec.WorldEntryAction)>
enumSpec.ServerRunContext = {
Hub = 1,
WorldPlay = 2,
WorldEdit = 3,
All = 4
}
export type ServerRunContext = CustomEnumItem<typeof(enumSpec.ServerRunContext)>
enumSpec.ButtonType = {
Text = 1,
Image = 2,
Viewport = 3
}
export type ButtonType = CustomEnumItem<typeof(enumSpec.ButtonType)>
enumSpec.InterfaceContext = {
None = 1,
Standalone = 2,
VoxelEditor = 3
}
export type InterfaceContext = CustomEnumItem<typeof(enumSpec.InterfaceContext)>
enumSpec.VoxelEditorTool = {
None = 1,
Select = 2,
Add = 3,
Subtract = 4,
MagicWand = 5,
Eyedropper = 6,
Style = 7,
Extrude = 8,
Move = 9,
Rotate = 10,
}
export type VoxelEditorTool = CustomEnumItem<typeof(enumSpec.VoxelEditorTool)>
enumSpec.TerrainEditorTool = {
None = 1,
Select = 2,
Add = 3,
Subtract = 4,
Paint = 5,
Smooth = 6,
Transform = 7,
}
export type TerrainEditorTool = CustomEnumItem<typeof(enumSpec.TerrainEditorTool)>
enumSpec.TerrainEditorTargetingMode = {
LockToPlane = 1,
Free = 2,
}
export type TerrainEditorTargetingMode = CustomEnumItem<typeof(enumSpec.TerrainEditorTargetingMode)>
enumSpec.TerrainEditorShapeMode = {
Box = 1,
Sphere = 2,
Wedge = 3,
}
export type TerrainEditorMode = CustomEnumItem<typeof(enumSpec.TerrainEditorShapeMode)>
enumSpec.TerrainEditorAction = {
Style = 1,
Load = 2,
Exit = 3
}
export type TerrainEditorAction = CustomEnumItem<typeof(enumSpec.TerrainEditorAction)>
enumSpec.VoxelEditorAction = {
Style = 1,
Load = 2,
Discard = 3,
Save = 4,
SaveAs = 5,
Delete = 6
}
export type VoxelEditorAction = CustomEnumItem<typeof(enumSpec.VoxelEditorAction)>
enumSpec.VoxelEditorTargetingMode = {
None = 1,
Cell = 2,
Face = 3,
}
export type VoxelEditorTargetingMode = CustomEnumItem<typeof(enumSpec.VoxelEditorTargetingMode)>
enumSpec.DamageType = {
Bludgeoning = 1,
Slashing = 2,
Piercing = 3,
Water = 4,
Fire = 5,
Earth = 6,
Wind = 7,
Lightning = 8,
Force = 9,
Sonic = 10,
Light = 11,
Shadow = 12,
Acid = 13,
Poison = 14,
Ice = 15,
Radioactive = 16,
Spirit = 17
}
export type DamageType = CustomEnumItem<typeof(enumSpec.DamageType)>
enumSpec.VoxelUnionChannel = {
Plastic = 1,
Translucent = 2,
TranslucentNeon = 3,
Neon = 4,
Metal = 5,
Slate = 6
}
export type VoxelUnionChannel = CustomEnumItem<typeof(enumSpec.VoxelUnionChannel)>
enumSpec.VoxelId = {
-- Blue
Aqua = 1,
BrightBlue = 2,
BrightBluishGreen = 3,
EarthBlue = 4,
LightRoyalBlue = 5,
MediumAzur = 6,
MediumBlue = 7,
SandBlue = 8,
-- Green
BrightGreen = 9,
BrightYellowishGreen = 10,
DarkGreen = 11,
EarthGreen = 12,
OliveGreen = 13,
SandGreen = 14,
SpringYellowishGreen = 15,
-- Yellow
BrickYellow = 16,
BrightYellow = 17,
CoolYellow = 18,
Gold = 19,
-- Orange
BrightOrange = 20,
DarkBrown = 21,
DarkOrange = 22,
FlameYellowOrange = 23,
LightNougat = 24,
MediumNougat = 25,
Nougat = 26,
SandBrown = 27,
-- Red
BrightRed = 28,
DarkRed = 29,
FlourescentReddishOrange = 30,
ReddishBrown = 31,
VibrantCoral = 32,
-- Purple
BrightPurple = 33,
BrightReddishViolet = 34,
BrightViolet = 35,
Lavender = 36,
LightPurple = 37,
MediumLavendar = 38,
MediumLilac = 39,
-- Black
Black = 40,
DarkStoneGrey = 41,
MediumStoneGrey = 42,
TitaniumMetallic = 43,
White = 44,
-- Glass
Glass = 45,
-- Bludgeoning, Slashing, Piercing
DarkMetal = 46,
LightMetal = 47,
MediumMetal = 48,
-- Water
Foam = 49,
Ocean = 50,
-- Fire
Cinder = 51,
Ember = 52,
Flame = 53,
-- Earth
Dirt = 54,
Stone = 55,
-- Wind
Breeze = 56,
Gust = 57,
Gale = 58,
-- Lightning
Tesla = 59,
Volta = 60,
Ampere = 61,
Watt = 62,
-- Force
Nova = 63,
Impulse = 64,
-- Sonic
Subsonic = 65,
Supersonic = 66,
-- Light
Starlight = 67,
Divinity = 68,
-- Shadow
Penumbra = 69,
Darkness = 70,
-- Acid
StrongAcid = 71,
WeakAcid = 72,
-- Poison
Malaise = 73,
Plague = 74,
-- Ice
Frost = 75,
Ice = 76,
-- Radioactive
Wasteland = 77,
Uranium = 78,
-- Spirit
Haunt = 79,
Scream = 80
}
export type VoxelId = CustomEnumItem<typeof(enumSpec.VoxelId)>
return Enums
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment