User:JulienDethurens/Scripts/Heading code
This is code I often put at the top of my code (that's why this page is called "Heading code", btw).
It contains many useful functions, many that I designed for making libraries easier to create.
Variables
The code creates a variable that makes accessing the Terrain object easier, that variable is called "Terrain".
It also creates many variables for some services that I commonly use:
- Players
- StarterPack
- StarterGui
- Lighting
- Debris
- Teams
- BadgeService
- InsertService
local Players = Game:GetService('Players')
local StarterPack = Game:GetService('StarterPack')
local StarterGui = Game:GetService('StarterGui')
local Lighting = Game:GetService('Lighting')
local Debris = Game:GetService('Debris')
local Teams = Game:GetService('Teams')
local BadgeService = Game:GetService('BadgeService')
local InsertService = Game:GetService('InsertService')
local Terrain = Workspace.Terrain
local verify_arg -- Since other functions defined before need to use it, this needs to be defined here.
is_a(value, data_type)
Name | Type | Description |
---|---|---|
value | The value you want to check the type of. | |
data_type | string | The type you want to check for. |
This function returns true if value is of type data_type. Otherwise, it returns false.
It supports the following types:
- all the Lua types (recognized by the Lua type function)
- all the Instance types (recognized by the IsA method
- all the Enum types
- Enum (the enum object itself, accessed through the Enum variable
- Color3
- BrickColor
- Vector2
- Vector3
- CFrame/CoordinateFrame (both names are recognized by the function)
- UDim
- UDim2
- RBXScriptSignal (the real name of events)
- Axes
- Faces
- Ray
Just as a note, you can't use a "fake" value to make it return true with a value that is similar to a real value of the correct data type. If it says that the value is of the correct data type, then the value is of the correct data type.
local function is_a(value, data_type)
-- Supported types: Lua types, Instance types, Enum types, Enum, Color3, BrickColor, Vector2, Vector3, CFrame/CoordinateFrame, UDim, UDim2, RBXScriptSignal, Axes, Faces, Ray
-- Will return false if the type is not supported, even though the value might be of that type.
-- This function can not be fooled by a fake value. If it says the value is a ClickDetector, then it IS a ClickDetector.
-- This function uses a variety of ugly hacks that were found by JulienDethurens.
-- I wish ROBLOX just provided an official way to do this, I wouldn't have to use lots of unrealiable ways to get the info I need... :/
-- Here is a nice collection of bad practices, ugly hacks, and other things you should never use, but that you don't have the choice of using, because of ROBLOX's lack of an official way to distinguish data types:
data_type = verify_arg(data_type, 'string', "data_type")
if type(value) == data_type then return true end -- Lua types
if pcall(function() assert(Game.IsA(value, data_type)) end) then return true end -- Instance types
if pcall(function() assert(Enum[data_type]) end) then -- Enum types
for _, enum in next, Enum[data_type]:GetEnumItems() do
if value == enum then
return true
end
end
elseif pcall(Enum.Material.GetEnumItems, value) then
for _, enum in next, value:GetEnumItems() do
if value == enum then
return true
end
end
end
if data_type == 'Color3' and pcall(function() Instance.new('Color3Value').Value = value end) then return true -- Color3
elseif data_type == 'BrickColor' and pcall(function() Instance.new('BrickColorValue').Value = value end) then return true -- BrickColor
elseif data_type == 'Vector2' and pcall(function() return Vector2.new() + value end) then return true -- Vector2
elseif data_type == 'Vector3' and pcall(function() Instance.new('Vector3Value').Value = value end) then return true -- Vector3
elseif (data_type == 'CFrame' or data_type == 'CoordinateFrame') and pcall(function() Instance.new('CFrameValue').Value = value end) then return true -- CFrame
elseif data_type == 'UDim' and pcall(function() return UDim.new() + value end) then return true -- UDim
elseif data_type == 'UDim2' and pcall(function() Instance.new('Frame').Position = value end) then return true -- UDim2
elseif data_type == 'Ray' and pcall(function() Ray.new(Vector3.new(), Vector3.new()).Distance(value, Vector3.new()) end) then return true -- Ray
elseif data_type == 'Axes' and pcall(function() Instance.new('ArcHandles').Axes = value end) then return true -- Axes
elseif data_type == 'Faces' and pcall(function() Instance.new('Handles').Faces = value end) then return true -- Faces
elseif data_type == 'Enum' and pcall(Enum.Material.GetEnumItems, value) then return true -- Enum
elseif data_type == 'RBXScriptSignal' then
local _, connection = pcall(function() return Game.AllowedGearTypeChanged.connect(value) end)
if _ and connection then
connection:disconnect()
return true
end
end
return false
end
cpp_is_a(value, data_type)
Name | Type | Description |
---|---|---|
value | The value you want to check the type of. | |
data_type | string | The type you want to check if the value is of. |
This function is like the is_a function, but is used with the C++ types used by ROBLOX methods and properties. It should be used to know if a certain value would be accepted by a method or a property.
It supports the following types:
- int
- double
- bool
- string
- float
local function cpp_is_a(value, data_type)
-- Same as is_a, but for methods and properties. Only supports basic types.
-- Supports: int, double, bool, string, float
-- Note: this function should be used to know if it is safe to send an argument to a method or a property, as it will also return true for values that will be automatically coerced by ROBLOX.
data_type = verify_arg(data_type, 'string', "data_type")
if data_type == 'int' then
if pcall(function() Instance.new('IntValue').Value = value end) then
return true
end
elseif data_type == 'double' then
if pcall(function() Instance.new('NumberValue').Value = value end) then
return true
end
elseif data_type == 'bool' then
if pcall(function() Instance.new('BoolValue').Value = value end) then
return true
end
elseif data_type == 'string' then
if pcall(function() Instance.new('StringValue').Value = value end) then
return true
end
elseif data_type == 'float' then
if pcall(function() Instance.new('ClickDetector').MaxActivationDistance = value end) then
return true
end
end
return false
end
get_type(value)
Name | Type | Description |
---|---|---|
value | The value you want to get the type of. |
This function returns the most specific type it can get for a certain value. It supports all the types supported by the is_a function.
local function get_type(value)
-- Returns the most specific type it can return. Supports the same types as the is_a function, except the enum types.
if is_a(value, 'Instance') then return value.ClassName
elseif is_a(value, 'Enum') then return 'Enum'
elseif is_a(value, 'Color3') then return 'Color3'
elseif is_a(value, 'BrickColor') then return 'BrickColor'
elseif is_a(value, 'Vector2') then return 'Vector2'
elseif is_a(value, 'Vector3') then return 'Vector3'
elseif is_a(value, 'CFrame') then return 'CFrame'
elseif is_a(value, 'UDim') then return 'UDim'
elseif is_a(value, 'UDim2') then return 'UDim2'
elseif is_a(value, 'Ray') then return 'Ray'
elseif is_a(value, 'Axes') then return 'Axes'
elseif is_a(value, 'Faces') then return 'Faces'
elseif is_a(value, 'RBXScriptSignal') then return 'RBXScriptSignal'
else return type(value)
end
end
verify_arg(value, data_type, arg_name, optional)
Name | Type | Description |
---|---|---|
value | The value you want the verify the type of. | |
data_type | string | The data type the value should be of. |
arg_name | string | The name of the argument. |
optional | boolean | Whether the argument can be nil or not. |
This function will check if value is of type data_type. If not, it will print an error message relating to the type.
Use it in functions that receive arguments to check if arguments are of the correct type. Using this function can make debugging a lot easier (trust me, that's from experience).
function verify_arg(value, data_type, arg_name, optional)
-- Makes the function that called the calling function error, with an error message relating to a wrong type. Supports all the types supported by the is_a and the cpp_is_a functions.
-- Also supports coercion for the number and string types.
-- Returns the value, as it might be automatically converted if a coercion has been done.
if type(data_type) ~= 'string' then error("bad 'data_type' argument (string expected, got " .. get_type(data_type) .. ")", 2) end
if type(arg_name) ~= 'string' then error("bad 'arg_name' argument (string expected, got " .. get_type(arg_name) .. ")") end
if optional and value == nil then
return value
elseif type(value) == data_type then
return value
elseif is_a(value, data_type) or cpp_is_a(value, data_type) then
return value
elseif data_type == 'number' and tonumber(value) then
return tonumber(value)
elseif data_type == 'string' and type(value) == 'number' then
return tostring(value)
else
error("bad '" .. arg_name .. "'" .. (optional and " optional" or "") .. " argument (" .. data_type .. " expected, got " .. get_type(value) .. ")", 3)
end
end
modify(instance, t)
Name | Type | Description |
---|---|---|
instance | Instance | The instance you want to edit. |
t | table | The changes you want to make to instance. |
This function allows you to edit the properties and the hierarchy of a certain object. Because I am too lazy to explain exactly how it works, and because you already have the code anyways, I will only give you an example:
local part = modify(Instance.new('Part'), {
Name = "Wall";
Position = Vector3.new(10, 50, 10);
with (Instance.new('Fire'), {
Heat = 10;
Size = 50;
});
})
That code creates a part, sets its name to "Wall", sets its position to a certain Vector3, creates a Fire object in it, sets some of the properties of that Fire object, and stores the part in the part variable.
local function modify(instance, t)
instance = verify_arg(instance, 'Instance', "instance")
t = verify_arg(t, 'table', "t")
for key, value in next, t do
if type(key) == 'number' then
value.Parent = instance
else
instance[key] = value
end
end
return instance
end
call_on_descendants(instance, func)
Name | Type | Description |
---|---|---|
instance | Instance | The object you want to call a function on all the descendants of. |
func | function | The function you want to call on all the descendants of the object. |
This function calls func on all the descendants of instance, including instance itself.
local function call_on_descendants(instance, func)
-- Calls 'func' on 'instance' and all its descendants, with the instance or descendant as argument.
instance = verify_arg(instance, 'Instance', "instance")
func = verify_arg(func, 'function', "func")
func(instance)
for _, child in next, instance:GetChildren() do
call_on_descendants(child, func)
end
end
get_nearest_ancestor(instance, class_name)
Name | Type | Description |
---|---|---|
instance | Instance | The object of which you want to find an ancestor. |
class_name | string | The class name of the ancestor you want to find. |
This function returns the nearest ancestor of instance of type class_name in ascending order.
local function get_nearest_ancestor(instance, class_name)
-- Returns the nearest ancestor of a certain instance which is of a certain type.
instance = verify_arg(instance, 'Instance', "instance")
class_name = verify_arg(class_name, 'string', "class_name")
local ancestor = instance
repeat
ancestor = ancestor.Parent
if ancestor == nil then
return nil
end
until ancestor:IsA(class_name)
return ancestor
end
get_character(descendant)
Name | Type | Description |
---|---|---|
descendant | Instance | The descendant of the character you want to get. |
This function returns the character a descendant is a part of.
local function get_character(descendant)
-- Returns a character from one of its descendants.
descendant = verify_arg(descendant, 'Instance', "descendant")
local character = descendant
repeat
if character.Parent then
character = character.Parent
else
return nil
end
until Players:GetPlayerFromCharacter(character)
return character
end
show_message(text, lifetime)
Name | Type | Description |
---|---|---|
text | string | The text you want to show in the message. |
lifetime | number | The time, in seconds, during which the message must be displayed. |
This function shows a message and removes it after a certain time.
local function show_message(text, lifetime)
-- Shows a message for a certain time, which is set to be 3 seconds by default.
text = verify_arg(text, 'string', "text")
lifetime = verify_arg(lifetime, 'number', "lifetime")
local message = Instance.new('Message')
message.Text = text
Debris:AddItem(message, lifetime or 3)
end
show_hint(text, lifetime)
Name | Type | Description |
---|---|---|
text | string | The text you want to show in the hint. |
lifetime | number | The time, in seconds, during which the hint must be displayed. |
This function shows a hint and removes it after a certain time.
local function show_hint(text, lifetime)
-- Shows a hint for a certain time, which is set to be 3 seconds by default.
text = verify_arg(text, 'string', "text")
lifetime = verify_arg(lifetime, 'number', "lifetime")
local hint = Instance.new('Hint')
hint.Text = text
Debris:AddItem(hint, lifetime or 3)
end
Entire code
Here is the whole code:
local Players = Game:GetService('Players')
local StarterPack = Game:GetService('StarterPack')
local StarterGui = Game:GetService('StarterGui')
local Lighting = Game:GetService('Lighting')
local Debris = Game:GetService('Debris')
local Teams = Game:GetService('Teams')
local BadgeService = Game:GetService('BadgeService')
local InsertService = Game:GetService('InsertService')
local Terrain = Workspace.Terrain
local verify_arg -- Since other functions defined before need to use it, this needs to be defined here.
local function is_a(value, data_type)
-- Supported types: Lua types, Instance types, Enum types, Enum, Color3, BrickColor, Vector2, Vector3, CFrame/CoordinateFrame, UDim, UDim2, RBXScriptSignal, Axes, Faces, Ray
-- Will return false if the type is not supported, even though the value might be of that type.
-- This function can not be fooled by a fake value. If it says the value is a ClickDetector, then it IS a ClickDetector.
-- This function uses a variety of ugly hacks that were found by JulienDethurens.
-- I wish ROBLOX just provided an official way to do this, I wouldn't have to use lots of unrealiable ways to get the info I need... :/
-- Here is a nice collection of bad practices, ugly hacks, and other things you should never use, but that you don't have the choice of using, because of ROBLOX's lack of an official way to distinguish data types:
data_type = verify_arg(data_type, 'string', "data_type")
if type(value) == data_type then return true end -- Lua types
if pcall(function() assert(Game.IsA(value, data_type)) end) then return true end -- Instance types
if pcall(function() assert(Enum[data_type]) end) then -- Enum types
for _, enum in next, Enum[data_type]:GetEnumItems() do
if value == enum then
return true
end
end
elseif pcall(Enum.Material.GetEnumItems, value) then
for _, enum in next, value:GetEnumItems() do
if value == enum then
return true
end
end
end
if data_type == 'Color3' and pcall(function() Instance.new('Color3Value').Value = value end) then return true -- Color3
elseif data_type == 'BrickColor' and pcall(function() Instance.new('BrickColorValue').Value = value end) then return true -- BrickColor
elseif data_type == 'Vector2' and pcall(function() return Vector2.new() + value end) then return true -- Vector2
elseif data_type == 'Vector3' and pcall(function() Instance.new('Vector3Value').Value = value end) then return true -- Vector3
elseif (data_type == 'CFrame' or data_type == 'CoordinateFrame') and pcall(function() Instance.new('CFrameValue').Value = value end) then return true -- CFrame
elseif data_type == 'UDim' and pcall(function() return UDim.new() + value end) then return true -- UDim
elseif data_type == 'UDim2' and pcall(function() Instance.new('Frame').Position = value end) then return true -- UDim2
elseif data_type == 'Ray' and pcall(function() Ray.new(Vector3.new(), Vector3.new()).Distance(value, Vector3.new()) end) then return true -- Ray
elseif data_type == 'Axes' and pcall(function() Instance.new('ArcHandles').Axes = value end) then return true -- Axes
elseif data_type == 'Faces' and pcall(function() Instance.new('Handles').Faces = value end) then return true -- Faces
elseif data_type == 'Enum' and pcall(Enum.Material.GetEnumItems, value) then return true -- Enum
elseif data_type == 'RBXScriptSignal' then
local _, connection = pcall(function() return Game.AllowedGearTypeChanged.connect(value) end)
if _ and connection then
connection:disconnect()
return true
end
end
return false
end
local function cpp_is_a(value, data_type)
-- Same as is_a, but for methods and properties. Only supports basic types.
-- Supports: int, double, bool, string, float
-- Note: this function should be used to know if it is safe to send an argument to a method or a property, as it will also return true for values that will be automatically coerced by ROBLOX.
data_type = verify_arg(data_type, 'string', "data_type")
if data_type == 'int' then
if pcall(function() Instance.new('IntValue').Value = value end) then
return true
end
elseif data_type == 'double' then
if pcall(function() Instance.new('NumberValue').Value = value end) then
return true
end
elseif data_type == 'bool' then
if pcall(function() Instance.new('BoolValue').Value = value end) then
return true
end
elseif data_type == 'string' then
if pcall(function() Instance.new('StringValue').Value = value end) then
return true
end
elseif data_type == 'float' then
if pcall(function() Instance.new('ClickDetector').MaxActivationDistance = value end) then
return true
end
end
return false
end
local function get_type(value)
-- Returns the most specific type it can return. Supports the same types as the is_a function, except the enum types.
if is_a(value, 'Instance') then return value.ClassName
elseif is_a(value, 'Enum') then return 'Enum'
elseif is_a(value, 'Color3') then return 'Color3'
elseif is_a(value, 'BrickColor') then return 'BrickColor'
elseif is_a(value, 'Vector2') then return 'Vector2'
elseif is_a(value, 'Vector3') then return 'Vector3'
elseif is_a(value, 'CFrame') then return 'CFrame'
elseif is_a(value, 'UDim') then return 'UDim'
elseif is_a(value, 'UDim2') then return 'UDim2'
elseif is_a(value, 'Ray') then return 'Ray'
elseif is_a(value, 'Axes') then return 'Axes'
elseif is_a(value, 'Faces') then return 'Faces'
elseif is_a(value, 'RBXScriptSignal') then return 'RBXScriptSignal'
else return type(value)
end
end
function verify_arg(value, data_type, arg_name, optional)
-- Makes the function that called the calling function error, with an error message relating to a wrong type. Supports all the types supported by the is_a and the cpp_is_a functions.
-- Also supports coercion for the number and string types.
-- Returns the value, as it might be automatically converted if a coercion has been done.
if type(data_type) ~= 'string' then error("bad 'data_type' argument (string expected, got " .. get_type(data_type) .. ")", 2) end
if type(arg_name) ~= 'string' then error("bad 'arg_name' argument (string expected, got " .. get_type(arg_name) .. ")") end
if optional and value == nil then
return value
elseif type(value) == data_type then
return value
elseif is_a(value, data_type) or cpp_is_a(value, data_type) then
return value
elseif data_type == 'number' and tonumber(value) then
return tonumber(value)
elseif data_type == 'string' and type(value) == 'number' then
return tostring(value)
else
error("bad '" .. arg_name .. "'" .. (optional and " optional" or "") .. " argument (" .. data_type .. " expected, got " .. get_type(value) .. ")", 3)
end
end
local function modify(instance, t)
instance = verify_arg(instance, 'Instance', "instance")
t = verify_arg(t, 'table', "t")
for key, value in next, t do
if type(key) == 'number' then
value.Parent = instance
else
instance[key] = value
end
end
return instance
end
local function call_on_descendants(instance, func)
-- Calls 'func' on 'instance' and all its descendants, with the instance or descendant as argument.
instance = verify_arg(instance, 'Instance', "instance")
func = verify_arg(func, 'function', "func")
func(instance)
for _, child in next, instance:GetChildren() do
call_on_descendants(child, func)
end
end
local function get_nearest_ancestor(instance, class_name)
-- Returns the nearest ancestor of a certain instance which is of a certain type.
instance = verify_arg(instance, 'Instance', "instance")
class_name = verify_arg(class_name, 'string', "class_name")
local ancestor = instance
repeat
ancestor = ancestor.Parent
if ancestor == nil then
return nil
end
until ancestor:IsA(class_name)
return ancestor
end
local function get_character(descendant)
-- Returns a character from one of its descendants.
descendant = verify_arg(descendant, 'Instance', "descendant")
local character = descendant
repeat
if character.Parent then
character = character.Parent
else
return nil
end
until Players:GetPlayerFromCharacter(character)
return character
end
local function show_message(text, lifetime)
-- Shows a message for a certain time, which is set to be 3 seconds by default.
text = verify_arg(text, 'string', "text")
lifetime = verify_arg(lifetime, 'number', "lifetime")
local message = Instance.new('Message')
message.Text = text
Debris:AddItem(message, lifetime or 3)
end
local function show_hint(text, lifetime)
-- Shows a hint for a certain time, which is set to be 3 seconds by default.
text = verify_arg(text, 'string', "text")
lifetime = verify_arg(lifetime, 'number', "lifetime")
local hint = Instance.new('Hint')
hint.Text = text
Debris:AddItem(hint, lifetime or 3)
end