I have no idea how to phrase the question in the title so I’ll do my best to explain the predicament I’m in here.
So if I’m making a custom object wrapper, like a Color3 wrapper that allows math operations on Color3, is there a way to make it so when you assign a Color3 property to an instance, it doesn’t error?
So for example, let’s say I have this:
local color3 = {}
__add = function(self,otherValue) -- let's say for simplicity we know for sure otherValue is another custom Color3 object, one returned from this module
return color3.new(self.R + otherValue.R, self.G + otherValue.G, self.B + otherValue.B) -- note this returns another custom color3, not a Roblox one
end
function color3.new(r,g,b)
local actualColor3 = Color3.new(r,g,b)
local newColor3 = {}
newColor3.R = actualColor3.R
newColor3.G = actualColor3.G
newColor3.B = actualColor3.B
return setmetatable(newColor3, color3) -- okay, this will return the custom Color3 which supports adding two Color3's
end
Now, if we require the module, it’ll work as normal:
local color3 = require(path.to.module)
local newColor3 = color3.new(1,1,1) -- ok
-- however, if we attempt to assign the Color3 to a part's Color property for example,
part.Color = newColor3 -- this will error because I'm trying to assign a non-native Color3 to an actual Color3 value
So, my question is, is there a way to seamlessly implement this Color3 wrapper that allows the custom Color3 object to be assigned to the property without having to retrieve the actual Roblox Color3 from this new object’s properties?
I had a bunch of problems with this, my solution is using the unary operator.
So I have been working with proxies for around 2 years straight now, and I have come to this issue multiple times, if you set a __unr operator to return the color3 value then you can do something like this:
local color3 = require(path.to.module)
local newColor3 = color3.new(1,1,1) -- ok
-- however, if we attempt to assign the Color3 to a part's Color property for example,
part.Color = -newColor3 -- We use the unary operator, it will return the color3 property, so any time you need the color3 just use the unr
local color3 = {}
__unm = function(self)
return Color3.new(self.R, self.G, self.B)
end
__add = function(self,otherValue) -- let's say for simplicity we know for sure otherValue is another custom Color3 object, one returned from this module
return color3.new(self.R + otherValue.R, self.G + otherValue.G, self.B + otherValue.B) -- note this returns another custom color3, not a Roblox one
end
function color3.new(r,g,b)
local actualColor3 = Color3.new(r,g,b)
local newColor3 = {}
newColor3.R = actualColor3.R
newColor3.G = actualColor3.G
newColor3.B = actualColor3.B
return setmetatable(newColor3, color3) -- okay, this will return the custom Color3 which supports adding two Color3's
end
print(color3.new()) --Returns the table
print(-color3.new()) --Returns the color3
I see, this seems to be the most simple way, and chances are this is probably the best way with least modifications but what if I wanted to support the actual __unm metamethod?
Actually, I just realized doing - on a Color3 would be useless since it would default to Color3.new(0,0,0) which is black, can’t get darker than that, so I wouldn’t really need to implement the actual __unm operator, it is a hacky solution but I suppose it would suffice for now. I’m gonna check and see if any metamethods are called before the error is thrown, to which I’ll post an update but if none are called (and I doubt any are), I’ll mark your post as a solution.
If there’s an actual implementation though, anyone’s free to reply.
You can also use len, you don’t need the length of a vector3:
#color3.new()
And for your question maybe you could use the unr operator for inverting colors, which would be a cool function to have in the vector3. One that you definitely not need is length so you can use that too