User:JulienDethurens/Scripts/Heading code: Difference between revisions
>JulienDethurens No edit summary |
>JulienDethurens |
||
Line 143: | Line 143: | ||
This function will check if <var>value</var> is of type <var>data_type</var>. If not, it will print an error message: | This function will check if <var>value</var> is of type <var>data_type</var>. If not, it will print an error message: | ||
bad argument #arg_num to func_name (data_type expected, got [the type of the argument, found with the get_type function). | bad argument #arg_num to func_name (data_type expected, got [the type of the argument, found with the get_type function]). | ||
Use it in functions that receive arguments to check if arguments are of the correct type. Using this function can make debugging <strong>a lot</strong> easier (trust me, that's from experience). | Use it in functions that receive arguments to check if arguments are of the correct type. Using this function can make debugging <strong>a lot</strong> easier (trust me, that's from experience). |
Revision as of 03:36, 9 April 2012
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
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: Lua types, Instance types, Enum types, Enum, Color3, BrickColor, Vector2, Vector3, CFrame/CoordinateFrame, UDim, UDim2, RBXScriptSignal, 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:
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
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_num, func_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_num | number | The № of the arg. Used in the error message. |
func_name | string | The name of the function. Used in the error message. |
optional | boolean | Whether the argument is optional or not. If true, the value nil will also be accepted. |
This function will check if value is of type data_type. If not, it will print an error message:
bad argument #arg_num to func_name (data_type expected, got [the type of the argument, found with the get_type function]).
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).
local function verify_arg(value, data_type, arg_num, func_name, optional)
-- Makes the function that called the calling function error, with an error message relating to a wrong type. Supports the same types as the is_a function.
-- 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 argument #2 to 'verify_arg' (string expected, got " .. type(data_type) .. ")", 2) end
if tonumber(arg_num) then
arg_num = tonumber(arg_num)
else
error("bad argument #3 to 'verify_arg' (number expected, got " .. type(arg_num) .. ")")
end
if type(func_name) ~= 'string' then error("bad argument #4 to 'verify_arg' (string expected, got " .. type(func_name) .. ")") end
if optional and value == nil then
return value
elseif 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 argument #" .. arg_num .. " to " .. func_name .. " (" .. 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)
verify_arg(instance, 'Instance', 1, "modify")
verify_arg(t, 'table', 2, "modify")
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(object, func)
Name | Type | Description |
---|---|---|
object | 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 object, including object itself.
local function call_on_descendants(object, func)
-- Calls 'func' on 'object' and all its descendants, with the object or descendant as argument.
verify_arg(object, 'Instance', 1, "func")
verify_arg(func, 'function', 2, "func")
func(object)
for _, child in next, object:GetChildren() do
call_on_descendants(child, func)
end
end
get_nearest_ancestor(object, class_name)
Name | Type | Description |
---|---|---|
object | 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 object of type class_name in ascending order.
local function get_nearest_ancestor(object, class_name)
-- Returns the nearest ancestor of a certain object which is of a certain type.
local ancestor = object
repeat
ancestor = ancestor.Parent
if ancestor == nil then
return nil
end
until ancestor:IsA(class_name)
return ancestor
end
The Code
This is the entirety of the 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 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:
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 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
local function verify_arg(value, data_type, arg_num, func_name, optional)
-- Makes the function that called the calling function error, with an error message relating to a wrong type. Supports the same types as the is_a function.
-- 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 argument #2 to 'verify_arg' (string expected, got " .. type(data_type) .. ")", 2) end
if tonumber(arg_num) then
arg_num = tonumber(arg_num)
else
error("bad argument #3 to 'verify_arg' (number expected, got " .. type(arg_num) .. ")")
end
if type(func_name) ~= 'string' then error("bad argument #4 to 'verify_arg' (string expected, got " .. type(func_name) .. ")") end
if optional and value == nil then
return value
elseif 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 argument #" .. arg_num .. " to " .. func_name .. " (" .. data_type .. " expected, got " .. get_type(value) .. ")", 3)
end
end
local function modify(instance, t)
verify_arg(instance, 'Instance', 1, "modify")
verify_arg(t, 'table', 2, "modify")
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(object, func)
-- Calls 'func' on 'object' and all its descendants, with the object or descendant as argument.
verify_arg(object, 'Instance', 1, "func")
verify_arg(func, 'function', 2, "func")
func(object)
for _, child in next, object:GetChildren() do
call_on_descendants(child, func)
end
end
local function get_nearest_ancestor(object, class_name)
-- Returns the nearest ancestor of a certain object which is of a certain type.
local ancestor = object
repeat
ancestor = ancestor.Parent
if ancestor == nil then
return nil
end
until ancestor:IsA(class_name)
return ancestor
end