Here Full tutorial about Metatables
In each table you can create a special table for the player and this is better for controlling the players better (e.g I have a specific player that I must store in Metatable and Checking for his Health)
--This is the main module table. It will hold both the constructor (.new) and any methods (like DoSomethingPlease).
local Module = {}
function Module.new(player: Player)
--setmetatable(..., Module) sets the metatable of self to Module, allowing method lookups like self:DoSomethingPlease() to work.
local self = setmetatable({
player = player,
Character = player.Character or player.CharacterAdded:Wait()
}, Module)
print(self) --> shows the object and its contents
--Because Lua will look for missing keys (like methods) in the metatable (which is Module), this is how self gains access to DoSomethingPlease
--prints the function reference
print(self:DoSomethingPlease) --> 100 Health
return self
end
function Module.DoSomethingPlease(self): number
--It returns the current health of the player humanoid
return self.Character.Humanoid.Health
end
return Module
__index
index__
The indexing access operation table[key] This event happens when table is not a table or when key is not present in table. The metavalue is looked up in the metatable of table. The
metavalue for this event can be either a function, a table or any value with an __index
metavalue
--count will be used to track how many "checks" (missing key accesses) are made
local oldtable = {count = 0}
local table = setmetatable(oldtable, {
__index = function(self, _k)
--The __index function is triggered whenever you try to access a key that doesn’t exist in the table
self.count = self.count + 1
return self.count
end,
})
--These keys (Hi, Testing, 155) do not exist in the table
print(t.Hi) -- 1
print(t.Testing) -- 2
print(t[155]) -- 3
Some example here about index
local tab1 = {foo = 'bar'}
local tab2 = setmetatable({}, {__index = tab1})
print(tab2.foo) --> 'bar'
__newindex
__NewIndex
is my favorite and I prefer to use it most of the time because it checks if there is anything new or not and if there is something new it will send it to the function
but I heard about it as a hacker loophole I don’t know 
local Table = setmetatable({}, {
--Instead of actually storing the key-value pair in the table
__newindex = function(self, _k, v)
print(_k) --> Hi or YSH or Hello
--rawset bypasses the __newindex call and stores the key-value pair directly in the table
rawset(self, _k, v)
end,
})
Table.Hi = 1
Table.Hello = 2
Table.YSH = 3
print(Table.Hi) --> 1
Calculation operators
local A = {1}
local B = {1}
--both A and B are simple tables holding one numeric value
local vectorMt = {
--defines what happens when two tables using this metatable are added together +
__add = function(a, b)
--the addition (+) operation. If any operand for an addition is not a number, Lua will try to call a metamethod
print("Add")
return {a[1] + b[1]} --> 1 + 1
end,
__sub = function(a, b)
--the subtraction (-) operation. Behavior similar to the addition operation
print("Sub")
return {a[1] - b[1]} --> 1 - 1
end,
__mul = function(a, b)
--the multiplication (*) operation. Behavior similar to the addition operation
print("Mul")
return {a[1] * b[1]} --> 1 * 1
end,
__div = function(a, b)
--the division (/) operation. Behavior similar to the addition operation
print("Div")
return {a[1] / b[1]} --> 1 / 1
end,
__mod = function(a, b)
--the modulo (%) operation. Behavior similar to the addition operation
print("Mod")
return {a[1] % b[1]} --> 1 % 1
end,
__pow = function(a, b)
--the exponentiation (^) operation. Behavior similar to the addition operation
print("Pow")
return {a[1] ^ b[1]} --> 1 ^ 1
end,
__idiv = function(a, b)
--the floor division (//) operation. Behavior similar to the addition operation
print("idiv")
return {a[1] // b[1]} --> 1 // 1
end,
}
setmetatable(A, vectorMt)
setmetatable(B, vectorMt)
print((A + B)[1]) --> 2
print((A - B)[1]) --> 0
print((A * B)[1]) --> 1
print((A / B)[1]) --> 1
print((A % B)[1]) --> 0
print((A ^ B)[1]) --> 1
print((A // B)[1]) --> 1
Bitwise operators (others not important)
-
__bor(a, b)
: the bitwise OR (|) operation. Behavior similar to the bitwise AND operation.
-
__bxor(a, b)
: the bitwise exclusive OR (binary ~) operation. Behavior similar to the bitwise AND operation.
-
__bnot(a)
: the bitwise NOT (unary ~) operation. Behavior similar to the bitwise AND operation.
-
__shl(a, b)
: the bitwise left shift (<<) operation. Behavior similar to the bitwise AND operation.
-
__shr(a)
: the bitwise right shift (>>) operation. Behavior similar to the bitwise AND operation.
pairs, ipairs
Same as __pairs()
, except for the __ipairs()
function
local t = setmetatable({}, {
__pairs = function(tbl)
local function iter(array, index)
index = index + 1
local value = nil
if index <= #array then
value = 1
end
if nil ~= value then return index, value end
end
return iter, tbl, 0
end
})
--This stores a key-value pair in the table If you used the default pairs() this would show up in the loop
t.HelloWorld = 1
for i, v in pairs(t) do
--i = HelloWorld
--v = 1
print(i, v)
end
__eq
Lua only calls __eq
if both tables being compared share the same __eq
function (or at least the same metatable) 
local A = {1}
local B = {1}
local vectorMt = {
--the equal (==) operation. Behavior similar to the addition operation
--except that Lua will try a metamethod only when the values being compared are either both tables or both full userdata and they are not primitively equal
--The result of the call is always converted to a boolean
__eq = function(a, b)
print("Eq")
return {a[1] == b[1]}
end,
}
setmetatable(A, vectorMt)
setmetatable(B, vectorMt)
print((A == B)) --> True
__It
local A = {1}
local B = {1}
local vectorMt = {
--he less than (<) operation. Behavior similar to the addition operation
--except that Lua will try a metamethod only when the values being compared are neither both numbers nor both strings
--Moreover, the result of the call is always converted to a boolean
__lt = function(a, b)
print("It")
return {a[1] < b[1]} -- It doesn't matter if it's (<) or (>)
end,
}
setmetatable(A, vectorMt)
setmetatable(B, vectorMt)
print((A > B)) --> True
__le
By default Lua doesn’t know how to compare tables like table1 <= table2
, so it throws an error unless you define a metatable with __le

local A = {1}
local B = {1}
local vectorMt = {
__le = function(a, b)
print("le")
return {a[1] <= b[1]} -- It doesn't matter if it's (<=) or (>=)
end,
}
setmetatable(A, vectorMt)
setmetatable(B, vectorMt)
print((A >= B)) --> True
for more information here!
I talked about the important things, you can search for more. This is what I could help with.
https://www.lua.org/manual/5.4/manual.html#2.4