First of all, congrats on not using loadstring
!
If you’re going to be serializing objects, I’m concerned about the maintainability that comes with storing values as their source-code constructs. I highly recommend you use JSON instead.
For instance, the (verbose) implementation for serializing and deserializing Vector3 values would look like this:
local HttpService = game:GetService("HttpService");
local function vector3ToObject(vector3)
local object = {
X = vector3.X,
Y = vector3.Y,
Z = vector3.Z,
};
return object;
end
local function serializeVector3(vector3)
local object = vector3ToObject(vector3);
local json = HttpService:JSONEncode(object)
return json;
end
local function reviveVector3(object)
local vector3 = Vector3.new(object.X, object.Y, object.Z);
return vector3;
end
local function deserializeVector3(json)
local object = HttpService:JSONDecode(json);
local vector3 = reviveVector3(object);
return vector3;
end
What you’re doing right now is “magic code” and is, for the most part, not a good practice. However, I did de-magicfy your code a little:
local HttpService = game:GetService("HttpService");
local CLASS_NAME_PATTERN = "(%w+).new%((.+)%)";
local ARGUMENT_PATTERN = "%w";
--- Decodes the given value
--- NOTE: This will error if the serialized value is not
--- valid JSON or is a stringified JSON array / table.
--- @param serializedValue string
local function decodePrimitive(serializedValue)
local primitive = HttpService:JSONDecode(serializedValue);
return primitive;
end
--- Decodes the given source
--- @param source string
local function decodeSource(source)
-- This won't error if the source was just a serialized
-- primitive.
local isPrimitive, primitive = pcall(decodePrimitive, source);
if isPrimitive then
return primitive;
end
local className, argumentSource = source:match(CLASS_NAME_PATTERN);
if not className then
local message = ("malformed source %q"):format(source);
error(message, 2);
end
local arguments = {};
for serializedArgument in argumentSource:gmatch(ARGUMENT_PATTERN) do
-- We should only have primitives at this point, so
-- we should NOT suppress errors here.
local value = decodePrimitive(serializedArgument)
table.insert(arguments, value);
end
local class = getfenv(0)[className];
if not class then
local message = ("invalid class name %q"):format(className);
error(message, 2);
end
return class.new(unpack(arguments));
end
And for this, I ran a few quick tests:
local serializedString = '"Hello, world!"';
local serializedBoolean = "true";
local serializedVector3 = "Vector3.new(1, 1, 1)";
print(decodeSource(serializedString));
print(decodeSource(serializedBoolean));
print(decodeSource(serializedVector3));
Hello, world!
true
1, 1, 1
If you have any more questions, feel free to ask!