Another Vector4 module, and Vector7?

Hey there, I recently made a Vector4 module because I thought it would be nice to have a version that’s as similar to Vector3 in functionality as possible. :grinning_face_with_smiling_eyes:

So here it is in all it’s glory, Vector4 module with support for all operations Vector3’s have, using meta-methods, all of the functions and constants, etc. There’s also a Vector4int16 version because why not!

Vector4

https://www.roblox.com/library/5906902916/Vector4

Vector4 Main Module Code
local meta = require(script:WaitForChild("Vec4MetaMethods"))

type Vector4 = {
	X : number,
	Y : number,
	Z : number,
	W : number
}

local Vector4 = {}
Vector4.__index = Vector4
Vector4 = meta.copy(Vector4)

function Vector4.new(x : number?, y : number?, z : number?, w : number?): Vector4	
	assert((type(x) == "number") or x == nil, "Vector4's xAxis must be a number")
	assert((type(y) == "number") or y == nil, "Vector4's yAxis must be a number")
	assert((type(z) == "number") or z == nil, "Vector4's zAxis must be a number")
	assert((type(w) == "number") or w == nil, "Vector4's wAxis must be a number")
	
	local newVector = {
		["X"] = x or 0,
		["Y"] = y or 0,
		["Z"] = z or 0,
		["W"] = w or 0
	}
	
	return setmetatable(newVector, Vector4)
end

function Vector4.FromNormalId(normal : EnumItem): Vector4	
	local directions = {
		["Right"] = Vector4.new(1),
		["Left"] = Vector4.new(-1),
		["Top"] = Vector4.new(0, 1),
		["Bottom"] = Vector4.new(0, -1),
		["Back"] = Vector4.new(0, 0, 1),
		["Front"] = Vector4.new(0, 0, -1)
	}
	
	return directions[normal.Name]
end

function Vector4.FromAxis(axis : EnumItem): Vector4	
	local axes = {
		["X"] = Vector4.new(1),
		["Y"] = Vector4.new(0, 1),
		["Z"] = Vector4.new(0, 0, 1)
	}
	
	return axes[axis.Name]
end

function Vector4.FromString(str : string): Vector4	
	local x, y, z, w = string.match(str, "^"..string.rep("([%d%p]+)%s?,%s?", 3).."([%d%p]+)$")
	assert((x and y and z and w), str.." is not compatible with FromString()")

	return Vector4.new(
		tonumber(x),
		tonumber(y),
		tonumber(z),
		tonumber(w)
	)
end

Vector4.zero = Vector4.new()
Vector4.one = Vector4.new(1, 1, 1, 1)

Vector4.xAxis = Vector4.new(1)
Vector4.yAxis = Vector4.new(0, 1)
Vector4.zAxis = Vector4.new(0, 0, 1)
Vector4.wAxis = Vector4.new(0, 0, 0, 1)

Vector4.min = Vector4.new(-math.huge, -math.huge, -math.huge, -math.huge)
Vector4.max = Vector4.new(math.huge, math.huge, math.huge, math.huge)

Vector4.pi = Vector4.new(math.pi, math.pi, math.pi, math.pi)

function Vector4:Magnitude(): number
	return math.sqrt(self.X ^ 2 + self.Y ^ 2 + self.Z ^ 2 + self.W ^ 2)
end

function Vector4:Unit(): Vector4
	local mag = math.sqrt(self.X ^ 2 + self.Y ^ 2 + self.Z ^ 2 + self.W ^ 2)

	return Vector4.new(
		(self.X / mag),
		(self.Y / mag),
		(self.Z / mag),
		(self.W / mag)
	)
end

function Vector4:Cross(other : Vector4): Vector4
	return Vector4.new(
		(self.Y * other.Z) - (self.Z * other.Y),
		(self.Z * other.X) - (self.X * other.Z),
		(self.X * other.Y) - (self.Y * other.X),
		self.W -- Can't cross 4d vectors --
	)
end

function Vector4:Dot(other : Vector4): number
	return (self.X * other.X) + (self.Y * other.Y) + (self.Z * other.Z) + (self.W * other.W)
end

function Vector4:FuzzyEq(other : Vector4, epsilon : number?): boolean
	epsilon = (epsilon or 1e-5)
	
	local function fuzzyEq(a : number, b : number): boolean
		return a == b or math.abs(a - b) <= (math.abs(a) + 1) * epsilon
	end
	
	for _, axis in ipairs({"X", "Y", "Z", "W"}) do
		if not fuzzyEq(self[axis], other[axis]) then
			return false
		end
	end
	
	return true
end

function Vector4:Lerp(goal : Vector4, alpha : number): Vector4
	return (self + (goal - self) * alpha)
end

function Vector4:Max(... : Vector4): Vector4
	local x, y, z, w = {}, {}, {}, {}
	local vectors = {self, ...}
	
	for _, vec in ipairs(vectors) do		
		table.insert(x, vec.X)
		table.insert(y, vec.Y)
		table.insert(z, vec.Z)
		table.insert(w, vec.W)
	end

	return Vector4.new(
		math.max(table.unpack(x)),
		math.max(table.unpack(y)),
		math.max(table.unpack(z)),
		math.max(table.unpack(w))
	)
end

function Vector4:Min(... : Vector4): Vector4
	local x, y, z, w = {}, {}, {}, {}
	local vectors = {self, ...}

	for _, vec in ipairs(vectors) do		
		table.insert(x, vec.X)
		table.insert(y, vec.Y)
		table.insert(z, vec.Z)
		table.insert(w, vec.W)
	end
	
	return Vector4.new(
		math.min(table.unpack(x)),
		math.min(table.unpack(y)),
		math.min(table.unpack(z)),
		math.min(table.unpack(w))
	)
end

function Vector4:ToString(condense : boolean?): string
	if condense then
		return (self.X .. "," .. self.Y .. "," .. self.Z .. "," .. self.W)
	else
		return tostring(self)
	end
end

function Vector4:GetComponents()
	return self.X, self.Y, self.Z, self.W
end

return Vector4

--[[
Made by M_dgettMann (shadowflame63)

Vector4 has all the functionality Vector3 has. (Excluding deprecated stuff)
There are also a few extras:

> Vector4.min -- All values are -inf
> Vector4.max -- All values are inf
> Vector4.pi -- All values are pi

> Vector4:ToString(condense) -- if condense is true, then returns tostring(Vector4) without the spaces, otherwise identical to tostring(Vector4) 
> Vector4.FromString(str) -- Converts the product from tostring(Vector4) or ToString() back into a Vector4

> Vector4:GetComponents() -- Similar to CFrame:GetComponents(), returns all components of the Vector4

Note: > It's Vector4:Magnitude() and Vector4:Unit(), instead of Vector4.Magnitude and Vector4.Unit
	 > Vector4:Cross() is identical to Vector3:Cross(), so W is ignored
]]
Vector4 MetaMethods Module Code
local metaMethods = {	
	__unm = function(vec4)
		for i, v in pairs(vec4) do
			vec4[i] = -v
		end
		
		return vec4
	end,
	
	__add = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] += v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v + v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v + v1
			end
		end

		return merge
	end,

	__sub = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] -= v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v - v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v - v1
			end
		end

		return merge
	end,

	__mul = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] *= v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v * v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v * v1
			end
		end

		return merge
	end,

	__div = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] /= v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v / v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v / v1
			end
		end

		return merge
	end,

	__mod = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] %= v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v % v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v % v1
			end
		end

		return merge
	end,

	__pow = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] ^= v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v ^ v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v ^ v1
			end
		end

		return merge
	end,
	
	__tostring = function(vec4)
		local tbl = {}
		
		for i, num in pairs(vec4) do
			local str = string.split(tostring(num), ".")
			if str[2] then tbl[i] = #str[2] else tbl[i] = 0 end
		end

		local format = ("%."..tbl.X.."f, %."..tbl.Y.."f, %."..tbl.Z.."f, %."..tbl.W.."f")
		return string.format(format, vec4.X, vec4.Y, vec4.Z, vec4.W)
	end,
	
	__eq = function(vec4, value)
		for i, v in pairs(vec4) do
			if not rawequal(value[i], v) then return false end
		end
		return true
	end,
	
	__lt = function(vec4, value)
		for i, v in pairs(vec4) do
			if value[i] <= v then return false end
		end
		return true
	end,

	__le = function(vec4, value)
		for i, v in pairs(vec4) do
			if value[i] < v then return false end
		end
		return true
	end,
	
	__type = "Vector4"
}

return {
	setup = function(vec4)
		local metaCopy = {}
		for i, v in pairs(metaMethods) do
			metaCopy[i] = v
		end

		return setmetatable(vec4, metaCopy)
	end,
	
	copy = function(vec4)
		if vec4 then
			for i, v in pairs(metaMethods) do
				vec4[i] = v
			end
			return vec4
		else
			return metaMethods
		end
	end,
	
	remove = function(vec4)
		return setmetatable(vec4, nil)
	end
}

)

Vector4int16

https://www.roblox.com/library/5742651074/Vector4int16

Vector4int16 Main Module Code
local meta = require(script:WaitForChild("Vec4int16MetaMethods"))

local function int16(num : number): number
	if num > (2 ^ 15) - 1 then num = (2 ^ 15) - 1 end
	if num < (-2 ^ 15) then num = (-2 ^ 15) end
	return math.round(num)
end

type Vector4int16 = {
	X : number,
	Y : number,
	Z : number,
	W : number
}

local Vector4int16 = {}
Vector4int16.__index = Vector4int16
Vector4int16 = meta.copy(Vector4int16)

function Vector4int16.new(x : number?, y : number?, z : number?, w : number?): Vector4int16
	assert((type(x) == "number") or x == nil, "Vector4int16's xAxis must be a number")
	assert((type(y) == "number") or y == nil, "Vector4int16's yAxis must be a number")
	assert((type(z) == "number") or z == nil, "Vector4int16's zAxis must be a number")
	assert((type(w) == "number") or w == nil, "Vector4int16's wAxis must be a number")
	
	local newVector = {
		["X"] = int16(x or 0),
		["Y"] = int16(y or 0),
		["Z"] = int16(z or 0),
		["W"] = int16(w or 0)
	}
	
	return setmetatable(newVector, Vector4int16)
end

function Vector4int16.FromVector3int16(vec3 : Vector3int16, w : number?): Vector4int16
	return Vector4int16.new(vec3.X, vec3.Y, vec3.Z, w or 0)
end

function Vector4int16.FromString(str : string): Vector4int16
	local x, y, z, w = string.match(str, "^"..string.rep("([%d%p]+)%s?,%s?", 3).."([%d%p]+)$")
	assert((x and y and z and w), str.." is not compatible with FromString()")

	return Vector4int16.new(
		tonumber(x),
		tonumber(y),
		tonumber(z),
		tonumber(w)
	)
end

function Vector4int16.UnpackVector(str : string): Vector4int16
	local px = string.sub(str, 1, 2)
	local py = string.sub(str, 3, 4)
	local pz = string.sub(str, 5, 6)
	local pw = string.sub(str, 7, 8)

	return Vector4int16.new(
		string.unpack("i2", px),
		string.unpack("i2", py),
		string.unpack("i2", pz),
		string.unpack("i2", pw)
	)
end

Vector4int16.zero = Vector4int16.new()
Vector4int16.one = Vector4int16.new(1, 1, 1, 1)

Vector4int16.xAxis = Vector4int16.new(1)
Vector4int16.yAxis = Vector4int16.new(0, 1)
Vector4int16.zAxis = Vector4int16.new(0, 0, 1)
Vector4int16.wAxis = Vector4int16.new(0, 0, 0, 1)

Vector4int16.min = Vector4int16.new((-2 ^ 15), (-2 ^ 15), (-2 ^ 15), (-2 ^ 15))
Vector4int16.max = Vector4int16.new((2 ^ 15) - 1, (2 ^ 15) - 1, (2 ^ 15) - 1, (2 ^ 15) - 1)

function Vector4int16:Max(... : Vector4int16): Vector4int16
	local x, y, z, w = {}, {}, {}, {}
	local vectors = {self, ...}

	for _, vec in ipairs(vectors) do		
		table.insert(x, vec.X)
		table.insert(y, vec.Y)
		table.insert(z, vec.Z)
		table.insert(w, vec.W)
	end

	return Vector4int16.new(
		math.max(table.unpack(x)),
		math.max(table.unpack(y)),
		math.max(table.unpack(z)),
		math.max(table.unpack(w))
	)
end

function Vector4int16:Min(... : Vector4int16): Vector4int16
	local x, y, z, w = {}, {}, {}, {}
	local vectors = {self, ...}

	for _, vec in ipairs(vectors) do		
		table.insert(x, vec.X)
		table.insert(y, vec.Y)
		table.insert(z, vec.Z)
		table.insert(w, vec.W)
	end

	return Vector4int16.new(
		math.min(table.unpack(x)),
		math.min(table.unpack(y)),
		math.min(table.unpack(z)),
		math.min(table.unpack(w))
	)
end

function Vector4int16:ToString(condense : boolean?): string
	if condense then
		return (self.X .. "," .. self.Y .. "," .. self.Z .. "," .. self.W)
	else
		return tostring(self)
	end
end

function Vector4int16:PackVector(): string
	local px = string.pack("i2", self.X)
	local py = string.pack("i2", self.Y)
	local pz = string.pack("i2", self.Z)
	local pw = string.pack("i2", self.W)
	
	return (px .. py .. pz .. pw)
end

function Vector4int16:GetComponents()
	return self.X, self.Y, self.Z, self.W
end

return Vector4int16

--[[
Made by M_dgettMann (shadowflame63)

Vector4int16 has all the functionality Vector3int16 has. (Excluding deprecated stuff)
There are also a few extras:

> Vector4int16.min -- All values are -2 ^ 15
> Vector4int16.max -- All values are 2 ^ 15 - 1

> Vector4int16:ToString(condense) -- if condense is true, then returns tostring(Vector4int16) without the spaces, otherwise identical to tostring(Vector4int16) 
> Vector4int16.FromString(str) -- Converts the product from tostring(Vector4int16) or ToString() back into a Vector4int16

> Vector4int16:PackVector() -- Uses string.pack to pack a Vector4int16 into a string with a length of 8 
> Vector4int16.UnpackVector(str) -- Converts the product from PackVector() back into a Vector4int16

> Vector4int16:GetComponents() -- Similar to CFrame:GetComponents(), returns all components of the Vector4int16

What's the purpose of an int16 version? Well it's niche but can be used when tranferring data at lower costs (e.g. RemoteEvents to reduce bandwidth usage)
However, it's mostly a micro-optimisation that many won't use, but I made it because Vector3int16 exists, and string.pack is cool

Note: If you want to convert a Vector4 into a Vector4int16 and visa versa, you'll have to do it the same way as Vector3
]]
Vector4int16 MetaMethods Module Code
local metaMethods = {	
	__unm = function(vec4)
		for i, v in pairs(vec4) do
			vec4[i] = -v
		end
		
		return vec4
	end,
	
	__add = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] += v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v + v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v + v1
			end
		end

		return merge
	end,

	__sub = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] -= v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v - v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v - v1
			end
		end

		return merge
	end,

	__mul = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] *= v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v * v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v * v1
			end
		end

		return merge
	end,

	__div = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] /= v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v / v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v / v1
			end
		end

		return merge
	end,

	__mod = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] %= v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v % v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v % v1
			end
		end

		return merge
	end,

	__pow = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] ^= v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v ^ v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v ^ v1
			end
		end

		return merge
	end,
	
	__tostring = function(vec4)
		local tbl = {}
		
		for i, num in pairs(vec4) do
			local str = string.split(tostring(num), ".")
			if str[2] then tbl[i] = #str[2] else tbl[i] = 0 end
		end

		local format = ("%."..tbl.X.."f, %."..tbl.Y.."f, %."..tbl.Z.."f, %."..tbl.W.."f")
		return string.format(format, vec4.X, vec4.Y, vec4.Z, vec4.W)
	end,
	
	__eq = function(vec4, value)
		for i, v in pairs(vec4) do
			if not rawequal(value[i], v) then return false end
		end
		return true
	end,
	
	__lt = function(vec4, value)
		for i, v in pairs(vec4) do
			if value[i] <= v then return false end
		end
		return true
	end,

	__le = function(vec4, value)
		for i, v in pairs(vec4) do
			if value[i] < v then return false end
		end
		return true
	end,
	
	__type = "Vector4int16"
}

return {
	setup = function(vec4)
		local metaCopy = {}
		for i, v in pairs(metaMethods) do
			metaCopy[i] = v
		end

		return setmetatable(vec4, metaCopy)
	end,
	
	copy = function(vec4)
		if vec4 then
			for i, v in pairs(metaMethods) do
				vec4[i] = v
			end
			return vec4
		else
			return metaMethods
		end
	end,
	
	remove = function(vec4)
		return setmetatable(vec4, nil)
	end
}

However, I found I couldn’t implement Vector4:Cross() because according to this publication (near the end because the rest is gibberish to me) cross products are only possible with 3d and 7d vectors. There are alternatives like triple cross products, etc, but these aren’t the same as Vector3:Cross().

I made these grids in excel to help visualise cross products:

3-axis (x, y, z)

Vector3
Here’s a grid that represents two 3d vectors. The 0’s are the dot product, aka Vector3:Dot(), and the rest is the cross product, aka Vector3:Cross().

4-axis (x, y, z, w)

Vector4
As you can see, this 4d grid is just an extension of the 3d one. But hold on, where did v, u and t come from? That’s where 7d comes in.

7-axis (x, y, z, w, v, u, t)

Vector7
Wow, that’s big. As you can see though, the top left corner is the same as the 3d grid, and there’s no extra axes! You can see the relationship when you compare a row and a column coming off the same 0, they’re all inversed.
Keep in mind though that there are 480 different combinations of this table, this version just matches Vector3.

Well, why does the cross product work with 3d and 7d, but not 4d? This is just a guess, but I’m assuming it’s because there’s no way to order all the axes in a way that fits into the pattern 3d and 7d do. You could use the same technique 2d uses, and fill the extra axes of 7d as 0’s to make a 4d cross product, but this will most likely give an incorrect result because higher dimensions are weird. It may also have something to do with quaternions and octonions.

I’m sure you see where this is going, I made a Vector7 module including :Cross(), and of course Vector7int16 to go along with it:

Vector7

https://www.roblox.com/library/5699748049/Vector7

Vector7 Main Module Code
local meta = require(script:WaitForChild("Vec7MetaMethods"))

type Vector7 = {
	X : number,
	Y : number,
	Z : number,
	W : number,
	V : number,
	U : number,
	T : number
}

local Vector7 = {}
Vector7.__index = Vector7
Vector7 = meta.copy(Vector7)

function Vector7.new(x : number?, y : number?, z : number?, w : number?, v : number?, u : number?, t : number?): Vector7
	assert((type(x) == "number") or x == nil, "Vector7's xAxis must be a number")
	assert((type(y) == "number") or y == nil, "Vector7's yAxis must be a number")
	assert((type(z) == "number") or z == nil, "Vector7's zAxis must be a number")
	assert((type(w) == "number") or w == nil, "Vector7's wAxis must be a number")
	assert((type(v) == "number") or v == nil, "Vector7's vAxis must be a number")
	assert((type(u) == "number") or u == nil, "Vector7's uAxis must be a number")
	assert((type(t) == "number") or t == nil, "Vector7's tAxis must be a number")
	
	local newVector = {
		["X"] = x or 0,
		["Y"] = y or 0,
		["Z"] = z or 0,
		["W"] = w or 0,
		["V"] = v or 0,
		["U"] = u or 0,
		["T"] = t or 0
	}
	
	return setmetatable(newVector, Vector7)
end

function Vector7.FromNormalId(normal : EnumItem): Vector7	
	local directions = {
		["Right"] = Vector7.new(1),
		["Left"] = Vector7.new(-1),
		["Top"] = Vector7.new(0, 1),
		["Bottom"] = Vector7.new(0, -1),
		["Back"] = Vector7.new(0, 0, 1),
		["Front"] = Vector7.new(0, 0, -1)
	}
	
	return directions[normal.Name]
end

function Vector7.FromAxis(axis : EnumItem): Vector7	
	local axes = {
		["X"] = Vector7.new(1),
		["Y"] = Vector7.new(0, 1),
		["Z"] = Vector7.new(0, 0, 1)
	}
	
	return axes[axis.Name]
end

function Vector7.FromString(str : string): Vector7
	local x, y, z, w, v, u, t = string.match(str, "^"..string.rep("([%d%p]+)%s?,%s?", 6).."([%d%p]+)$")
	assert((x and y and z and w and v and u and t), str.." is not compatible with FromString()")

	return Vector7.new(
		tonumber(x),
		tonumber(y),
		tonumber(z),
		tonumber(w),
		tonumber(v),
		tonumber(u),
		tonumber(t)
	)
end

Vector7.zero = Vector7.new()
Vector7.one = Vector7.new(1, 1, 1, 1, 1, 1, 1)

Vector7.xAxis = Vector7.new(1)
Vector7.yAxis = Vector7.new(0, 1)
Vector7.zAxis = Vector7.new(0, 0, 1)
Vector7.wAxis = Vector7.new(0, 0, 0, 1)
Vector7.vAxis = Vector7.new(0, 0, 0, 0, 1)
Vector7.uAxis = Vector7.new(0, 0, 0, 0, 0, 1)
Vector7.tAxis = Vector7.new(0, 0, 0, 0, 0, 0, 1)

Vector7.min = Vector7.new(-math.huge, -math.huge, -math.huge, -math.huge, -math.huge, -math.huge, -math.huge)
Vector7.max = Vector7.new(math.huge, math.huge, math.huge, math.huge, math.huge, math.huge, math.huge)

Vector7.pi = Vector7.new(math.pi, math.pi, math.pi, math.pi, math.pi, math.pi, math.pi)

function Vector7:Magnitude(): number
	return math.sqrt(self.X ^ 2 + self.Y ^ 2 + self.Z ^ 2 + self.W ^ 2 + self.V ^ 2 + self.U ^ 2 + self.T ^ 2)
end

function Vector7:Unit(): Vector7
	local mag = math.sqrt(self.X ^ 2 + self.Y ^ 2 + self.Z ^ 2 + self.W ^ 2 + self.V ^ 2 + self.U ^ 2 + self.T ^ 2)
	
	return Vector7.new(
		(self.X / mag),
		(self.Y / mag),
		(self.Z / mag),
		(self.W / mag),
		(self.V / mag),
		(self.U / mag),
		(self.T / mag)
	)
end

function Vector7:Cross(other : Vector7): Vector7
	return Vector7.new(
		((self.Y * other.Z) - (self.Z * other.Y)) + ((self.W * other.V) - (self.V * other.W)) + ((self.T * other.U) - (self.U * other.T)),
		((self.Z * other.X) - (self.X * other.Z)) + ((self.T * other.U) - (self.U * other.T)) + ((self.V * other.W) - (self.W * other.V)),
		((self.X * other.Y) - (self.Y * other.X)) + ((self.U * other.T) - (self.T * other.U)) + ((self.W * other.V) - (self.V * other.W)),
		((self.U * other.V) - (self.V * other.U)) + ((self.X * other.T) - (self.T * other.X)) + ((self.Z * other.Y) - (self.Y * other.Z)),
		((self.T * other.W) - (self.W * other.T)) + ((self.X * other.U) - (self.U * other.X)) + ((self.Y * other.Z) - (self.Z * other.Y)),
		((self.W * other.T) - (self.T * other.W)) + ((self.Y * other.V) - (self.V * other.Y)) + ((self.X * other.Z) - (self.Z * other.X)),
		((self.V * other.U) - (self.U * other.V)) + ((self.Z * other.W) - (self.W * other.Z)) + ((self.X * other.Y) - (self.Y * other.X))
	)
	-- There's 480 total combinations for the cross product of 7d, this one matches the cross product of Vector3
	-- ((self.Z * other.X) - (self.X * other.Z)) in the yAxis is flipped due to Roblox using the right-hand rule
end

function Vector7:Dot(other : Vector7): number
	return (self.X * other.X) + (self.Y * other.Y) + (self.Z * other.Z) + (self.W * other.W) + (self.V * other.V) + (self.U * other.U) + (self.T * other.T)
end

function Vector7:FuzzyEq(other : Vector7, epsilon : number?): boolean
	epsilon = (epsilon or 1e-5)
	
	local function fuzzyEq(a : number, b : number): boolean
		return a == b or math.abs(a - b) <= (math.abs(a) + 1) * epsilon
	end
	
	for _, axis in ipairs({"X", "Y", "Z", "W", "V", "U", "T"}) do
		if not fuzzyEq(self[axis], other[axis]) then
			return false
		end
	end
	
	return true
end

function Vector7:Lerp(goal : Vector7, alpha : number): Vector7
	return (self + (goal - self) * alpha)
end

function Vector7:Max(... : Vector7): Vector7
	local x, y, z, w, v, u, t = {}, {}, {}, {}, {}, {}, {}
	local vectors = {self, ...}

	for _, vec in ipairs(vectors) do
		table.insert(x, vec.X)
		table.insert(y, vec.Y)
		table.insert(z, vec.Z)
		table.insert(w, vec.W)
		table.insert(v, vec.V)
		table.insert(u, vec.U)
		table.insert(t, vec.T)
	end

	return Vector7.new(
		math.max(table.unpack(x)),
		math.max(table.unpack(y)),
		math.max(table.unpack(z)),
		math.max(table.unpack(w)),
		math.max(table.unpack(v)),
		math.max(table.unpack(u)),
		math.max(table.unpack(t))
	)
end

function Vector7:Min(... : Vector7): Vector7
	local x, y, z, w, v, u, t = {}, {}, {}, {}, {}, {}, {}
	local vectors = {self, ...}

	for _, vec in ipairs(vectors) do
		table.insert(x, vec.X)
		table.insert(y, vec.Y)
		table.insert(z, vec.Z)
		table.insert(w, vec.W)
		table.insert(v, vec.V)
		table.insert(u, vec.U)
		table.insert(t, vec.T)
	end

	return Vector7.new(
		math.min(table.unpack(x)),
		math.min(table.unpack(y)),
		math.min(table.unpack(z)),
		math.min(table.unpack(w)),
		math.min(table.unpack(v)),
		math.min(table.unpack(u)),
		math.min(table.unpack(t))
	)
end

function Vector7:ToString(condense : boolean?): string
	if condense then
		return (self.X .. "," .. self.Y .. "," .. self.Z .. "," .. self.W .. "," .. self.V .. "," .. self.U .. "," .. self.T)
	else
		return tostring(self)
	end
end

function Vector7:GetComponents()
	return self.X, self.Y, self.Z, self.W, self.V, self.U, self.T
end

return Vector7

--[[
Made by M_dgettMann (shadowflame63)

Vector7 has all the functionality Vector3 has. (Excluding deprecated stuff)
There's also a few extras:

> Vector7.min -- All values are -inf
> Vector7.max -- All values are inf
> Vector7.pi -- All values are pi

> Vector7:ToString(condense) -- if condense is true, then returns tostring(Vector7) without the spaces, otherwise identical to tostring(Vector7) 
> Vector7.FromString(str) -- Converts the product from tostring(Vector7) or ToString() back into a Vector7

> Vector7:GetComponents() -- Similar to CFrame:GetComponents(), returns all components of the Vector7

Credit for 7d cross products: https://en.wikipedia.org/wiki/Seven-dimensional_cross_product#Multiplication_table
Note: It's Vector7:Magnitude() and Vector7:Unit(), instead of Vector7.Magnitude and Vector7.Unit
]]
Vector7 MetaMethods Module Code
local metaMethods = {	
	__unm = function(vec7)
		for i, v in pairs(vec7) do
			vec7[i] = -v
		end
		
		return vec7
	end,
	
	__add = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] += v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v + v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v + v1
			end
		end

		return merge
	end,

	__sub = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] -= v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v - v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v - v1
			end
		end

		return merge
	end,

	__mul = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] *= v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v * v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v * v1
			end
		end

		return merge
	end,

	__div = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] /= v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v / v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v / v1
			end
		end

		return merge
	end,

	__mod = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] %= v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v % v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v % v1
			end
		end

		return merge
	end,

	__pow = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] ^= v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v ^ v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v ^ v1
			end
		end

		return merge
	end,
	
	__tostring = function(vec7)
		local tbl = {}
		
		for i, num in pairs(vec7) do
			local str = string.split(tostring(num), ".")
			if str[2] then tbl[i] = #str[2] else tbl[i] = 0 end
		end

		local format = ("%."..tbl.X.."f, %."..tbl.Y.."f, %."..tbl.Z.."f, %."..tbl.W.."f, %."..tbl.V.."f, %."..tbl.U.."f, %."..tbl.T.."f")
		return string.format(format, vec7.X, vec7.Y, vec7.Z, vec7.W, vec7.V, vec7.U, vec7.T)
	end,
	
	__eq = function(vec7, value)
		for i, v in pairs(vec7) do
			if not rawequal(value[i], v) then return false end
		end
		return true
	end,
	
	__lt = function(vec7, value)
		for i, v in pairs(vec7) do
			if value[i] <= v then return false end
		end
		return true
	end,

	__le = function(vec7, value)
		for i, v in pairs(vec7) do
			if value[i] < v then return false end
		end
		return true
	end,
	
	__type = "Vector7"
}

return {
	setup = function(vec7)
		local metaCopy = {}
		for i, v in pairs(metaMethods) do
			metaCopy[i] = v
		end

		return setmetatable(vec7, metaCopy)
	end,
	
	copy = function(vec7)
		if vec7 then
			for i, v in pairs(metaMethods) do
				vec7[i] = v
			end
			return vec7
		else
			return metaMethods
		end
	end,
	
	remove = function(vec7)
		return setmetatable(vec7, nil)
	end
}

)

Vector7int16

https://www.roblox.com/library/5431302799/Vector7int16

Vector7int16 Main Module Code
local meta = require(script:WaitForChild("Vec7int16MetaMethods"))

local function int16(num : number): number
	if num > (2 ^ 15) - 1 then num = (2 ^ 15) - 1 end
	if num < (-2 ^ 15) then num = (-2 ^ 15) end
	return math.round(num)
end

type Vector7int16 = {
	X : number,
	Y : number,
	Z : number,
	W : number,
	V : number,
	U : number,
	T : number
}

local Vector7int16 = {}
Vector7int16.__index = Vector7int16
Vector7int16 = meta.copy(Vector7int16)

function Vector7int16.new(x : number?, y : number?, z : number?, w : number?, v : number?, u : number?, t : number?): Vector7int16
	assert((type(x) == "number") or x == nil, "Vector7int16's xAxis must be a number")
	assert((type(y) == "number") or y == nil, "Vector7int16's yAxis must be a number")
	assert((type(z) == "number") or z == nil, "Vector7int16's zAxis must be a number")
	assert((type(w) == "number") or w == nil, "Vector7int16's wAxis must be a number")
	assert((type(v) == "number") or v == nil, "Vector7int16's vAxis must be a number")
	assert((type(u) == "number") or u == nil, "Vector7int16's uAxis must be a number")
	assert((type(t) == "number") or t == nil, "Vector7int16's tAxis must be a number")

	local newVector = {
		["X"] = int16(x or 0),
		["Y"] = int16(y or 0),
		["Z"] = int16(z or 0),
		["W"] = int16(w or 0),
		["V"] = int16(v or 0),
		["U"] = int16(u or 0),
		["T"] = int16(t or 0)
	}

	return setmetatable(newVector, Vector7int16)
end

function Vector7int16.FromString(str : string): Vector7int16	
	local x, y, z, w, v, u, t = string.match(str, "^"..string.rep("([%d%p]+)%s?,%s?", 6).."([%d%p]+)$")
	assert((x and y and z and w and v and u and t), str.." is not compatible with FromString()")

	return Vector7int16.new(
		tonumber(x),
		tonumber(y),
		tonumber(z),
		tonumber(w),
		tonumber(v),
		tonumber(u),
		tonumber(t)
	)
end

function Vector7int16.UnpackVector(str: string): Vector7int16
	local px = string.sub(str, 1, 2)
	local py = string.sub(str, 3, 4)
	local pz = string.sub(str, 5, 6)
	local pw = string.sub(str, 7, 8)
	local pv = string.sub(str, 9, 10)
	local pu = string.sub(str, 11, 12)
	local pt = string.sub(str, 13, 14)

	return Vector7int16.new(
		string.unpack("i2", px),
		string.unpack("i2", py),
		string.unpack("i2", pz),
		string.unpack("i2", pw),
		string.unpack("i2", pv),
		string.unpack("i2", pu),
		string.unpack("i2", pt)
	)
end

Vector7int16.zero = Vector7int16.new()
Vector7int16.one = Vector7int16.new(1, 1, 1, 1, 1, 1, 1)

Vector7int16.xAxis = Vector7int16.new(1)
Vector7int16.yAxis = Vector7int16.new(0, 1)
Vector7int16.zAxis = Vector7int16.new(0, 0, 1)
Vector7int16.wAxis = Vector7int16.new(0, 0, 0, 1)
Vector7int16.vAxis = Vector7int16.new(0, 0, 0, 0, 1)
Vector7int16.uAxis = Vector7int16.new(0, 0, 0, 0, 0, 1)
Vector7int16.tAxis = Vector7int16.new(0, 0, 0, 0, 0, 0, 1)

Vector7int16.min = Vector7int16.new((-2 ^ 15), (-2 ^ 15), (-2 ^ 15), (-2 ^ 15), (-2 ^ 15), (-2 ^ 15), (-2 ^ 15))
Vector7int16.max = Vector7int16.new((2 ^ 15) - 1, (2 ^ 15) - 1, (2 ^ 15) - 1, (2 ^ 15) - 1, (2 ^ 15) - 1, (2 ^ 15) - 1, (2 ^ 15) - 1)

function Vector7int16:Max(... : Vector7int16): Vector7int16
	local x, y, z, w, v, u, t = {}, {}, {}, {}, {}, {}, {}
	local vectors = {self, ...}

	for _, vec in ipairs(vectors) do
		table.insert(x, vec.X)
		table.insert(y, vec.Y)
		table.insert(z, vec.Z)
		table.insert(w, vec.W)
		table.insert(v, vec.V)
		table.insert(u, vec.U)
		table.insert(t, vec.T)
	end

	return Vector7int16.new(
		math.max(table.unpack(x)),
		math.max(table.unpack(y)),
		math.max(table.unpack(z)),
		math.max(table.unpack(w)),
		math.max(table.unpack(v)),
		math.max(table.unpack(u)),
		math.max(table.unpack(t))
	)
end

function Vector7int16:Min(... : Vector7int16): Vector7int16
	local x, y, z, w, v, u, t = {}, {}, {}, {}, {}, {}, {}
	local vectors = {self, ...}

	for _, vec in ipairs(vectors) do
		table.insert(x, vec.X)
		table.insert(y, vec.Y)
		table.insert(z, vec.Z)
		table.insert(w, vec.W)
		table.insert(v, vec.V)
		table.insert(u, vec.U)
		table.insert(t, vec.T)
	end

	return Vector7int16.new(
		math.min(table.unpack(x)),
		math.min(table.unpack(y)),
		math.min(table.unpack(z)),
		math.min(table.unpack(w)),
		math.min(table.unpack(v)),
		math.min(table.unpack(u)),
		math.min(table.unpack(t))
	)
end

function Vector7int16:ToString(condense : boolean?): string
	if condense then
		return (self.X .. "," .. self.Y .. "," .. self.Z .. "," .. self.W .. "," .. self.V .. "," .. self.U .. "," .. self.T)
	else
		return tostring(self)
	end
end

function Vector7int16:PackVector(): string
	local px = string.pack("i2", self.X)
	local py = string.pack("i2", self.Y)
	local pz = string.pack("i2", self.Z)
	local pw = string.pack("i2", self.W)
	local pv = string.pack("i2", self.V)
	local pu = string.pack("i2", self.U)
	local pt = string.pack("i2", self.T)
	
	return (px .. py .. pz .. pw .. pv .. pu .. pt)
end

function Vector7int16:GetComponents()
	return self.X, self.Y, self.Z, self.W, self.V, self.U, self.T
end

return Vector7int16

--[[
Made by M_dgettMann (shadowflame63)

Vector7int16 has all the functionality Vector3int16 has. (Excluding deprecated stuff)
There are also a few extras:

> Vector7int16.min -- All values are -2 ^ 15
> Vector7int16.max -- All values are 2 ^ 15 - 1

> Vector7int16:ToString(condense) -- if condense is true, then returns tostring(Vector7int16) without the spaces, otherwise identical to tostring(Vector7int16) 
> Vector7int16.FromString(str) -- Converts the product from tostring(Vector7int16) or ToString() back into a Vector7int16

> Vector7int16:PackVector() -- Uses string.pack to pack a Vector7int16 into a string with a length of 14 
> Vector7int16.UnpackVector(str) -- Converts the product from PackVector() back into a Vector7int16

> Vector7int16:GetComponents() -- Similar to CFrame:GetComponents(), returns all components of the Vector7int16

What's the purpose of an int16 version? Well it's niche but can be used when tranferring data at lower costs (e.g. RemoteEvents to reduce bandwidth usage)
However, it's mostly a micro-optimisation that many won't use, but I made it because Vector3int16 exists, and string.pack is cool

Note: If you want to convert a Vector7 into a Vector7int16 and visa versa, you'll have to do it the same way as Vector3
]]
Vector7int16 MetaMethods Module Code
local metaMethods = {	
	__unm = function(vec7)
		for i, v in pairs(vec7) do
			vec7[i] = -v
		end
		
		return vec7
	end,
	
	__add = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] += v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v + v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v + v1
			end
		end

		return merge
	end,

	__sub = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] -= v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v - v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v - v1
			end
		end

		return merge
	end,

	__mul = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] *= v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v * v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v * v1
			end
		end

		return merge
	end,

	__div = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] /= v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v / v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v / v1
			end
		end

		return merge
	end,

	__mod = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] %= v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v % v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v % v1
			end
		end

		return merge
	end,

	__pow = function(v1, v2)
		local merge = {}

		local m1 = getmetatable(v1)
		local m2 = getmetatable(v2)

		if m1 and m2 then
			assert(m1.__type == m1.__type, "Vectors must be the same type")
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v
			end

			for i, v in pairs(v2) do
				if merge[i] then
					merge[i] ^= v
				else
					merge[i] = v
				end
			end

		elseif m1 and (type(v2) == "number") then
			setmetatable(merge, m1)

			for i, v in pairs(v1) do
				merge[i] = v ^ v2
			end

		elseif m2 and (type(v1) == "number") then
			setmetatable(merge, m2)

			for i, v in pairs(v2) do
				merge[i] = v ^ v1
			end
		end

		return merge
	end,
	
	__tostring = function(vec7)
		local tbl = {}
		
		for i, num in pairs(vec7) do
			local str = string.split(tostring(num), ".")
			if str[2] then tbl[i] = #str[2] else tbl[i] = 0 end
		end

		local format = ("%."..tbl.X.."f, %."..tbl.Y.."f, %."..tbl.Z.."f, %."..tbl.W.."f, %."..tbl.V.."f, %."..tbl.U.."f, %."..tbl.T.."f")
		return string.format(format, vec7.X, vec7.Y, vec7.Z, vec7.W, vec7.V, vec7.U, vec7.T)
	end,
	
	__eq = function(vec7, value)
		for i, v in pairs(vec7) do
			if not rawequal(value[i], v) then return false end
		end
		return true
	end,
	
	__lt = function(vec7, value)
		for i, v in pairs(vec7) do
			if value[i] <= v then return false end
		end
		return true
	end,

	__le = function(vec7, value)
		for i, v in pairs(vec7) do
			if value[i] < v then return false end
		end
		return true
	end,
	
	__type = "Vector7int16"
}

return {
	setup = function(vec7)
		local metaCopy = {}
		for i, v in pairs(metaMethods) do
			metaCopy[i] = v
		end

		return setmetatable(vec7, metaCopy)
	end,
	
	copy = function(vec7)
		if vec7 then
			for i, v in pairs(metaMethods) do
				vec7[i] = v
			end
			return vec7
		else
			return metaMethods
		end
	end,
	
	remove = function(vec7)
		return setmetatable(vec7, nil)
	end
}

Why did I decide to make such a creation? Well, the fact that cross products only work in 3d and 7d intrigued me so I did some research and wrote it up.

If you can find a use case for such a niche thing, then I applaud you. :clap: Thanks for checking out this weird and long post, and I hope you like what I’ve made, even if it’s a bit wild. :sweat_smile:

14 Likes

This is extremely insane! How long did this took?

2 Likes

I made this over the weekend, took a while to understand the table for all the axes but got it in the end.

1 Like

Nice but I don’t see the use of it, 3 numbers are enough

4 Likes

Well there isn’t really a use for Vector7, it was just made for fun. But Vector4 does have a use as it actually makes quaternions which aid with rotation.

3 Likes

Why not put vector4 in community resources? Its pretty cool.

2 Likes

Because there’s already a few out there (I think), so it would be repetitive.

1 Like

No, there’s only scripting questions about it, but no resource

Proof? Search this
“Vector4 #resources:community-resources

2 Likes

Huh, thought there were some. Guess I could move this topic to community resources. Edit: This topic has now been moved to community resources, thanks for the suggestion. :grinning_face_with_smiling_eyes:

1 Like

This can be very useful. It can store position, rotation, and even transparency in the same Vector7!

2 Likes

Remember, a vector stores numerical data that represents size or position. Rotation and transparency would work, but not position.

2 Likes

Yeah, I was thinking Vector7.new(positionx,positiony,positionz,rotationx,rotationy,rotationz,transparency) then I could use a script to decode it

3 Likes

That would work as data storage but those position values could be used for size or position of a part. That’s why using values other than for dimensional purposes doesn’t really make sense. Vectors are basically the equivalent of a space in the dimension of the vector.

2 Likes

You could, and it’s in fact the only reasonable use for anything above Vector4, but there are better alternatives, like just using a table.

2 Likes

Vectors represent position / direction, not sure what transparency has to do with it? :neutral_face:

1 Like

yeah he seems like a beginner. I, for example, have a Vector255 module where I store the player data in binary. /s

2 Likes

.

I have been scripting since around 2019

I was giving an example of storing multiple numerical values in the vector

1 Like

Transparency is a int. In the roblox database.

Coding challenge: VectorN (a vector object that has N axes). Not sure what you could use it for tho…

that would be a dynamic array:

local DynamicArray = {4.24, 22, 96, 123.76, 43, 7.5}