Object Wrapper Module

Object Wrapper

Get the module, ID: 5295404854, Source Code

If you don’t know much about wrapping objects, here you go:

Wrapping objects is essentially, in a non-formal definition and in Roblox’s context, adding more features to Roblox instances, like properties, methods and even events.

First of all, you need to create a wrapped version of your instance, using :Wrap(instance), that returns a wrapped instance, which has a type of userdata.

local wrapper = require(game.ServerScriptService.Wrapper)

local wrappedPart = wrapper:Wrap(Instance.new("Part"))
wrappedPart.Name = "hi" --you can still change properties
wrappedPart.Name = workspace --it would get parented to workspace

print(wrappedPart) --Part
print(type(wrappedPart)) --userdata

This module creates custom :Destroy() and :Clone() methods for you, and a custom .Changed event as well, to make them work with the custom properties and features you made, else things would break.

To add a custom property you use :AddProperty(wrappedInstance, propertyName, defaultValue), which creates a new property called propertyName inside of the given wrappedInstance, with a default value of defaultValue.

local wrapper = require(game.ServerScriptService.Wrapper)

local wrappedPart = wrapper:Wrap(Instance.new("Part"))
wrappedPart.Name = "hi" 
wrappedPart.Name = workspace

wrapper:AddProperty(wrappedPart, "MiddleName", "George")
print(wrappedPart.MiddleName) --"Geroge"
wrappedPart.MiddleName = "Mike"
print(wrappedPart.MiddleName) --"Mike"

local clone = wrappedPart:Clone()
wrappedPart.Parent = workspace
print(clone.Name) --"hi"
print(clone.MiddleName) --"Mike"

To add a custom method you use :AddMethod(wrappedInstance, methodName, methodBody), to create a method with the name methodName inside of wrappedInstance, that does what the function methodBody does. Note that, due to how anonymous functions behvave, self inside of methodBody (which would refer to wrappedInstance of course) has to be passed as a first parameter always, and other passed parameters after it.

local wrapper = require(5295404854)

local wrappedPart = wrapper:Wrap(Instance.new("Part"))
wrappedPart.Name = "hi" 
wrappedPart.Name = workspace
wrapper:AddProperty(wrappedPart, "MiddleName", "George")

wrappedPart:AddMethod(wrappedPart, "IsMiddleNameLongerThan", function(self, n)
    return #self.MiddleName > n
end)

print(wrappedPart:IsMiddleNameLongerThan(5)) --true
wrappedPart.MiddleName = "Mike"
print(wrappedPart:IsMiddleNameLongerThan(5)) --false

To add a custom event you use :AddEvent(wrappedInstance, eventName), to create an event inside of wrappedInstance with the name of eventName. This is only responsible for setting up the event, you’re responsible for firing the event (and passing parameters if you want) by doing wrappedInstance[eventName]:Fire(parameters), and making connections to it when needed, just like you would do with normal Roblox events. Let’s say you wanted to make this event, where whenever the MiddleName property changed, it will fire if the new property satisfies wrappedInstance:IsMiddleNameLongerThan(5) == true, basically if the MiddleName is longer than 5 characters. (Note that adding new custom properties will not fire .Changed if a .Changed connection was created before adding the new property, mutating the custom properties will of course). We would need to check inside of the .Changed if the the property was MiddleName, and check if it was longer than 5, and fire the event.

local wrapper = require(game.ServerScriptService.Wrapper)

local wrappedPart = wrapper:Wrap(Instance.new("Part"))
wrappedPart.Name = "hi" 
wrappedPart.Parent = workspace
wrapper:AddProperty(wrappedPart, "MiddleName", nil) --default can be nil


wrapper:AddMethod(wrappedPart, "IsMiddleNameLongerThan", function(self, n)
    return #self.MiddleName > n
end)

wrapper:AddEvent(wrappedPart, "NameSurpassedLength")

wrappedPart.NameSurpassedLength:Connect(function(n) --n is length of the MiddleName that fired the event
	print(n)
end)

wrappedPart.Changed:Connect(function(prop)
    if prop == "MiddleName" then
        if wrappedPart:IsMiddleNameLongerThan(5) then
            wrappedPart.NameSurpassedLength:Fire(#wrappedPart.MiddleName) --this is how to fire event, and pass parameters
        end
    end
end)

wrappedPart.MiddleName = "Geroge" --fires NameSurpassedLength, and prints length
wrappedPart.MiddleName = "Mike" --doesn't

Anywho, that’s it. If you have feedback, or found a problem with the module, I’m happy to hear about it.

Code sample
local wrapper = require(game.ServerScriptService.Wrapper)

local wrappedPart = wrapper:Wrap(Instance.new("Part"))
print(wrappedPart) --Part
print(type(wrappedPart)) --userdata

wrapper:AddProperty(wrappedPart, "MiddleName", "George")
wrappedPart.BrickColor = BrickColor.new("Really red")
wrappedPart.Parent = workspace

wrapper:AddMethod(wrappedPart, "IsMiddleNameLongerThan", function(self, n)
	return #wrappedPart.MiddleName > n
end)

print(wrappedPart:IsMiddleNameLongerThan(5)) --prints true

wrappedPart.MiddleName = "Mike"


local clone = wrappedPart:Clone()
print(clone.MiddleName) --Mike

clone.Changed:Connect(function(prop)
	print(prop, "=", clone[prop])
end)

clone.MiddleName = "starmaq"
clone.Transparency = 0.5
clone.Parent = workspace --fires and prints for all these

local c = wrappedPart.Changed:Connect(function()
	print("hi")
end)

c:Disconnect()

wrappedPart.Name = "hi" --doesn't fire .Changed

(Note that this module has error debugging problems, errors are most of the time weird and unrelated to the actual problem which might making fixing issues slightly harder, might fix at some point)

17 Likes

Hi @starmaq , Thank you for sharing this resource, it is very interesting and useful.

Would you kindly create a link to Source code (preferably Github and/or Pastebin) for people who want to read the source but don’t have any access to a PC or maybe want to contribute to the source

1 Like

Thanks for the suggestion! Will do.