Large scale refactor to add class support!
Instance classes are now strongly typed with real property fields that are derived from the JSON API Dump! This required a lot of reworking across the board: - Classes and Enums are auto-generated in the 'Generated' folder now. This is done using a custom built-in plugin, which can be found in the Plugins folder of this project. - Property objects are now tied to .NET's reflection system. Reading and writing from them will try to redirect into a field of the Instance they are bound to. - Property types that were loosely defined now have proper data types (such as Color3uint8, Content, ProtectedString, SharedString, etc) - Fixed an error with the CFrame directional vectors. - The binary PRNT chunk now writes instances in child->parent order. - Enums are now generated correctly, with up-to-date values. - INST chunks are now referred to as 'Classes' instead of 'Types'. - Unary operator added to Vector2 and Vector3. - CollectionService tags can now be manipulated per-instance using the Instance.Tags member. - The Instance.Archivable property now works correctly. - XML files now save/load metadata correctly. - Cleaned up the property tokens directory. I probably missed a few things, but that's a general overview of everything that changed.
This commit is contained in:
607
Plugins/GenerateApiDump/ApiPlugin.server.lua
Normal file
607
Plugins/GenerateApiDump/ApiPlugin.server.lua
Normal file
@ -0,0 +1,607 @@
|
||||
local HttpService = game:GetService("HttpService")
|
||||
local ServerStorage = game:GetService("ServerStorage")
|
||||
local StarterPlayer = game:GetService("StarterPlayer")
|
||||
local StudioService = game:GetService("StudioService")
|
||||
|
||||
local classes = {}
|
||||
local outStream = ""
|
||||
local stackLevel = 0
|
||||
|
||||
local singletons =
|
||||
{
|
||||
Terrain = workspace:WaitForChild("Terrain");
|
||||
StarterPlayerScripts = StarterPlayer:WaitForChild("StarterPlayerScripts");
|
||||
StarterCharacterScripts = StarterPlayer:WaitForChild("StarterCharacterScripts");
|
||||
}
|
||||
|
||||
local isCoreScript = pcall(function ()
|
||||
local restricted = game:GetService("RobloxPluginGuiService")
|
||||
return tostring(restricted)
|
||||
end)
|
||||
|
||||
local function write(formatString, ...)
|
||||
local tabs = string.rep(' ', stackLevel * 4)
|
||||
local fmt = formatString or ""
|
||||
|
||||
local value = tabs .. fmt:format(...)
|
||||
outStream = outStream .. value
|
||||
end
|
||||
|
||||
local function writeLine(formatString, ...)
|
||||
if not formatString then
|
||||
outStream = outStream .. '\n'
|
||||
return
|
||||
end
|
||||
|
||||
write(formatString .. '\n', ...)
|
||||
end
|
||||
|
||||
local function openStack()
|
||||
writeLine('{')
|
||||
stackLevel = stackLevel + 1
|
||||
end
|
||||
|
||||
local function closeStack()
|
||||
stackLevel = stackLevel - 1
|
||||
writeLine('}')
|
||||
end
|
||||
|
||||
local function clearStream()
|
||||
stackLevel = 0
|
||||
outStream = ""
|
||||
end
|
||||
|
||||
local function exportStream(label)
|
||||
local results = outStream:gsub("\n\n\n", "\n\n")
|
||||
|
||||
if plugin then
|
||||
local export = Instance.new("Script")
|
||||
export.Archivable = false
|
||||
export.Source = results
|
||||
export.Name = label
|
||||
|
||||
plugin:OpenScript(export)
|
||||
end
|
||||
|
||||
if isCoreScript then
|
||||
StudioService:CopyToClipboard(results)
|
||||
elseif not plugin then
|
||||
warn(label)
|
||||
print(results)
|
||||
end
|
||||
end
|
||||
|
||||
local function getTags(object)
|
||||
local tags = {}
|
||||
|
||||
if object.Tags ~= nil then
|
||||
for _,tag in pairs(object.Tags) do
|
||||
tags[tag] = true
|
||||
end
|
||||
end
|
||||
|
||||
if object.Name == "Terrain" then
|
||||
tags.NotCreatable = nil
|
||||
end
|
||||
|
||||
return tags
|
||||
end
|
||||
|
||||
local function upcastInheritance(class, root)
|
||||
local superClass = classes[class.Superclass]
|
||||
|
||||
if not superClass then
|
||||
return
|
||||
end
|
||||
|
||||
if not root then
|
||||
root = class
|
||||
end
|
||||
|
||||
if not superClass.Inherited then
|
||||
superClass.Inherited = root
|
||||
end
|
||||
|
||||
upcastInheritance(superClass, root)
|
||||
end
|
||||
|
||||
local function canCreateClass(class)
|
||||
local tags = getTags(class)
|
||||
local canCreate = true
|
||||
|
||||
if tags.NotCreatable then
|
||||
canCreate = false
|
||||
end
|
||||
|
||||
if tags.Service then
|
||||
canCreate = true
|
||||
end
|
||||
|
||||
if tags.Settings then
|
||||
canCreate = false
|
||||
end
|
||||
|
||||
if singletons[class.Name] then
|
||||
canCreate = true
|
||||
end
|
||||
|
||||
return canCreate
|
||||
end
|
||||
|
||||
local function collectProperties(class)
|
||||
local propMap = {}
|
||||
|
||||
for _,member in ipairs(class.Members) do
|
||||
if member.MemberType == "Property" then
|
||||
local propName = member.Name
|
||||
propMap[propName] = member
|
||||
end
|
||||
end
|
||||
|
||||
return propMap
|
||||
end
|
||||
|
||||
local function createProperty(propName, propType)
|
||||
local category = "DataType";
|
||||
local name = propType
|
||||
|
||||
if propType:find(':') then
|
||||
local data = string.split(propType, ':')
|
||||
category = data[1]
|
||||
name = data[2]
|
||||
end
|
||||
|
||||
return
|
||||
{
|
||||
Name = propName;
|
||||
|
||||
Serialization =
|
||||
{
|
||||
CanSave = true;
|
||||
CanLoad = true;
|
||||
};
|
||||
|
||||
ValueType =
|
||||
{
|
||||
Category = category;
|
||||
Name = name;
|
||||
};
|
||||
|
||||
Security = "None";
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Formatting
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
local formatting = require(script.Parent.Formatting)
|
||||
|
||||
local formatLinks =
|
||||
{
|
||||
["int"] = "Int";
|
||||
["nil"] = "Null";
|
||||
["long"] = "Int";
|
||||
|
||||
["float"] = "Float";
|
||||
["byte[]"] = "Bytes";
|
||||
["double"] = "Double";
|
||||
|
||||
["string"] = "String";
|
||||
["Content"] = "String";
|
||||
["Instance"] = "Null";
|
||||
|
||||
["Color3uint8"] = "Color3";
|
||||
["ProtectedString"] = "String";
|
||||
}
|
||||
|
||||
local function getFormatFunction(valueType)
|
||||
if not formatting[valueType] then
|
||||
valueType = formatLinks[valueType]
|
||||
end
|
||||
|
||||
return formatting[valueType]
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Property Patches
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
local patches = require(script.Parent.PropertyPatches)
|
||||
local patchIndex = {}
|
||||
|
||||
function patchIndex:__index(key)
|
||||
if not rawget(self, key) then
|
||||
rawset(self, key, {})
|
||||
end
|
||||
|
||||
return self[key]
|
||||
end
|
||||
|
||||
local function getPatches(className)
|
||||
local classPatches = patches[className]
|
||||
return setmetatable(classPatches, patchIndex)
|
||||
end
|
||||
|
||||
setmetatable(patches, patchIndex)
|
||||
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- Main
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
local baseUrl = "https://raw.githubusercontent.com/CloneTrooper1019/Roblox-Client-Tracker/roblox/"
|
||||
local toolbar, classButton, enumButton
|
||||
|
||||
if plugin then
|
||||
toolbar = plugin:CreateToolbar("C# API Dump")
|
||||
|
||||
classButton = toolbar:CreateButton(
|
||||
"Dump Classes",
|
||||
"Generates a C# dump of Roblox's Class API.",
|
||||
"rbxasset://textures/Icon_Stream_Off@2x.png"
|
||||
)
|
||||
|
||||
enumButton = toolbar:CreateButton(
|
||||
"Dump Enums",
|
||||
"Generates a C# dump of Roblox's Enum API.",
|
||||
"rbxasset://textures/Icon_Stream_Off@2x.png"
|
||||
)
|
||||
end
|
||||
|
||||
local function getAsync(url)
|
||||
local enabled
|
||||
|
||||
if isCoreScript then
|
||||
enabled = HttpService:GetHttpEnabled()
|
||||
HttpService:SetHttpEnabled(true)
|
||||
end
|
||||
|
||||
local result = HttpService:GetAsync(url)
|
||||
|
||||
if isCoreScript then
|
||||
HttpService:SetHttpEnabled(enabled)
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
local function generateClasses()
|
||||
local version = getAsync(baseUrl .. "version.txt")
|
||||
|
||||
local apiDump = getAsync(baseUrl .. "API-Dump.json")
|
||||
apiDump = HttpService:JSONDecode(apiDump)
|
||||
|
||||
local classNames = {}
|
||||
classes = {}
|
||||
|
||||
for _,class in ipairs(apiDump.Classes) do
|
||||
local className = class.Name
|
||||
local superClass = classes[class.Superclass]
|
||||
|
||||
if singletons[className] then
|
||||
class.Singleton = true
|
||||
class.Object = singletons[className]
|
||||
end
|
||||
|
||||
if superClass and canCreateClass(class) then
|
||||
local classTags = getTags(class)
|
||||
|
||||
if classTags.Service then
|
||||
pcall(function ()
|
||||
if not className:find("Network") then
|
||||
class.Object = game:GetService(className)
|
||||
end
|
||||
end)
|
||||
elseif not classTags.NotCreatable then
|
||||
pcall(function ()
|
||||
class.Object = Instance.new(className)
|
||||
|
||||
if ServerStorage:FindFirstChild("DumpFolder") then
|
||||
class.Object.Name = className
|
||||
class.Object.Parent = ServerStorage.DumpFolder
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
upcastInheritance(class)
|
||||
end
|
||||
|
||||
classes[className] = class
|
||||
table.insert(classNames, className)
|
||||
end
|
||||
|
||||
outStream = ""
|
||||
|
||||
writeLine("// Auto-generated list of creatable Roblox classes.")
|
||||
writeLine("// Updated as of %s", version)
|
||||
writeLine()
|
||||
|
||||
writeLine("using System;")
|
||||
writeLine()
|
||||
|
||||
writeLine("using RobloxFiles.DataTypes;")
|
||||
writeLine("using RobloxFiles.Enums;")
|
||||
writeLine("using RobloxFiles.Utility;")
|
||||
writeLine()
|
||||
|
||||
writeLine("namespace RobloxFiles")
|
||||
openStack()
|
||||
|
||||
for i,className in ipairs(classNames) do
|
||||
local class = classes[className]
|
||||
local classTags = getTags(class)
|
||||
|
||||
local registerClass = canCreateClass(class)
|
||||
|
||||
if class.Inherited then
|
||||
registerClass = true
|
||||
end
|
||||
|
||||
if class.Name == "Instance" or class.Name == "Studio" then
|
||||
registerClass = false
|
||||
end
|
||||
|
||||
local object = class.Object
|
||||
|
||||
if not object then
|
||||
if class.Inherited then
|
||||
object = class.Inherited.Object
|
||||
elseif singletons[className] then
|
||||
object = singletons[className]
|
||||
else
|
||||
registerClass = false
|
||||
end
|
||||
end
|
||||
|
||||
if registerClass then
|
||||
local objectType
|
||||
|
||||
if classTags.NotCreatable and class.Inherited and not class.Singleton then
|
||||
objectType = "abstract class"
|
||||
else
|
||||
objectType = "class"
|
||||
end
|
||||
|
||||
writeLine("public %s %s : %s", objectType, className, class.Superclass)
|
||||
openStack()
|
||||
|
||||
local classPatches = getPatches(className)
|
||||
local redirectProps = classPatches.Redirect
|
||||
|
||||
local propMap = collectProperties(class)
|
||||
local propNames = {}
|
||||
|
||||
for _,propName in pairs(classPatches.Remove) do
|
||||
propMap[propName] = nil
|
||||
end
|
||||
|
||||
for propName in pairs(propMap) do
|
||||
table.insert(propNames, propName)
|
||||
end
|
||||
|
||||
for propName, propType in pairs(classPatches.Add) do
|
||||
if not propMap[propName] then
|
||||
propMap[propName] = createProperty(propName, propType)
|
||||
table.insert(propNames, propName)
|
||||
else
|
||||
propMap[propName].Serialization.CanLoad = true
|
||||
end
|
||||
end
|
||||
|
||||
local firstLine = true
|
||||
table.sort(propNames)
|
||||
|
||||
|
||||
if classTags.Service then
|
||||
writeLine("public %s()", className)
|
||||
openStack()
|
||||
|
||||
writeLine("IsService = true;")
|
||||
closeStack()
|
||||
|
||||
if #propNames > 0 then
|
||||
writeLine()
|
||||
end
|
||||
end
|
||||
|
||||
for i, propName in ipairs(propNames) do
|
||||
local prop = propMap[propName]
|
||||
|
||||
local serial = prop.Serialization
|
||||
local valueType = prop.ValueType.Name
|
||||
|
||||
if serial.CanLoad then
|
||||
local propTags = getTags(prop)
|
||||
|
||||
local redirect = redirectProps[propName]
|
||||
local name = propName
|
||||
local default = ""
|
||||
|
||||
if propName == className then
|
||||
name = name .. '_'
|
||||
end
|
||||
|
||||
if valueType == "int64" then
|
||||
valueType = "long"
|
||||
elseif valueType == "BinaryString" then
|
||||
valueType = "byte[]"
|
||||
end
|
||||
|
||||
local first = name:sub(1, 1)
|
||||
|
||||
if first == first:lower() then
|
||||
local pascal = first:upper() .. name:sub(2)
|
||||
if propMap[pascal] ~= nil and propTags.Deprecated then
|
||||
redirect = pascal
|
||||
end
|
||||
end
|
||||
|
||||
if redirect then
|
||||
local get, set
|
||||
|
||||
if typeof(redirect) == "string" then
|
||||
get = redirect
|
||||
set = redirect .. " = value"
|
||||
else
|
||||
get = redirect.Get
|
||||
set = redirect.Set
|
||||
end
|
||||
|
||||
if not firstLine then
|
||||
writeLine()
|
||||
end
|
||||
|
||||
if propTags.Deprecated then
|
||||
writeLine("[Obsolete]")
|
||||
end
|
||||
|
||||
writeLine("public %s %s", valueType, name)
|
||||
|
||||
openStack()
|
||||
writeLine("get { return %s; }", get)
|
||||
writeLine("set { %s; }", set)
|
||||
closeStack()
|
||||
|
||||
if (i ~= #propNames) then
|
||||
writeLine()
|
||||
end
|
||||
else
|
||||
local value = classPatches.Defaults[propName]
|
||||
local gotValue = (value ~= nil)
|
||||
|
||||
if not gotValue then
|
||||
gotValue, value = pcall(function ()
|
||||
return object[propName]
|
||||
end)
|
||||
end
|
||||
|
||||
local comment = " // Default missing!"
|
||||
local category = prop.ValueType.Category
|
||||
|
||||
if gotValue then
|
||||
local category = prop.ValueType.Category
|
||||
local formatFunc = getFormatFunction(valueType)
|
||||
|
||||
if not formatFunc then
|
||||
local literal = typeof(value)
|
||||
formatFunc = getFormatFunction(literal)
|
||||
end
|
||||
|
||||
if not formatFunc then
|
||||
formatFunc = tostring
|
||||
end
|
||||
|
||||
local result
|
||||
|
||||
if typeof(formatFunc) == "string" then
|
||||
result = formatFunc
|
||||
else
|
||||
result = formatFunc(value)
|
||||
end
|
||||
|
||||
if not serial.CanSave and not propTags.Deprecated then
|
||||
comment = " // [Load-only]"
|
||||
else
|
||||
comment = ""
|
||||
end
|
||||
|
||||
default = " = " .. result
|
||||
end
|
||||
|
||||
if propTags.Deprecated then
|
||||
if not firstLine then
|
||||
writeLine()
|
||||
end
|
||||
|
||||
writeLine("[Obsolete]")
|
||||
end
|
||||
|
||||
if category == "Class" then
|
||||
default = " = null"
|
||||
comment = ""
|
||||
end
|
||||
|
||||
writeLine("public %s %s%s;%s", valueType, name, default, comment)
|
||||
|
||||
if propTags.Deprecated and i ~= #propNames then
|
||||
writeLine()
|
||||
end
|
||||
end
|
||||
|
||||
firstLine = false
|
||||
end
|
||||
end
|
||||
|
||||
closeStack()
|
||||
|
||||
if (i ~= #classNames) then
|
||||
writeLine()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
closeStack()
|
||||
exportStream("Classes")
|
||||
end
|
||||
|
||||
local function generateEnums()
|
||||
local version = getfenv().version():gsub("%. ", ".")
|
||||
clearStream()
|
||||
|
||||
writeLine("// Auto-generated list of Roblox enums.")
|
||||
writeLine("// Updated as of %s", version)
|
||||
writeLine()
|
||||
|
||||
writeLine("namespace RobloxFiles.Enums")
|
||||
openStack()
|
||||
|
||||
local enums = Enum:GetEnums()
|
||||
|
||||
for i, enum in ipairs(enums) do
|
||||
writeLine("public enum %s", tostring(enum))
|
||||
openStack()
|
||||
|
||||
local enumItems = enum:GetEnumItems()
|
||||
local lastValue = -1
|
||||
|
||||
table.sort(enumItems, function (a, b)
|
||||
return a.Value < b.Value
|
||||
end)
|
||||
|
||||
for i, enumItem in ipairs(enumItems) do
|
||||
local text = ""
|
||||
local comma = ','
|
||||
|
||||
local name = enumItem.Name
|
||||
local value = enumItem.Value
|
||||
|
||||
if (value - lastValue) ~= 1 then
|
||||
text = " = " .. value;
|
||||
end
|
||||
|
||||
if i == #enumItems then
|
||||
comma = ""
|
||||
end
|
||||
|
||||
lastValue = value
|
||||
writeLine("%s%s%s", name, text, comma)
|
||||
end
|
||||
|
||||
closeStack()
|
||||
|
||||
if i ~= #enums then
|
||||
writeLine()
|
||||
end
|
||||
end
|
||||
|
||||
closeStack()
|
||||
exportStream("Enums")
|
||||
end
|
||||
|
||||
if plugin then
|
||||
classButton.Click:Connect(generateClasses)
|
||||
enumButton.Click:Connect(generateEnums)
|
||||
else
|
||||
generateClasses()
|
||||
generateEnums()
|
||||
end
|
273
Plugins/GenerateApiDump/Formatting.lua
Normal file
273
Plugins/GenerateApiDump/Formatting.lua
Normal file
@ -0,0 +1,273 @@
|
||||
local Format = {}
|
||||
|
||||
function Format.Null(value)
|
||||
return "null"
|
||||
end
|
||||
|
||||
function Format.Bytes(value)
|
||||
if #value > 0 then
|
||||
local fmt = "Convert.FromBase64String(%q)"
|
||||
return fmt:format(value)
|
||||
else
|
||||
return "new byte[0]"
|
||||
end
|
||||
end
|
||||
|
||||
function Format.String(value)
|
||||
return string.format("%q", value)
|
||||
end
|
||||
|
||||
function Format.Int(value)
|
||||
return string.format("%i", value)
|
||||
end
|
||||
|
||||
function Format.Number(value)
|
||||
local int = math.floor(value)
|
||||
|
||||
if math.abs(value - int) < 0.001 then
|
||||
return Format.Int(int)
|
||||
end
|
||||
|
||||
local result = string.format("%.5f", value)
|
||||
result = result:gsub("%.?0+$", "")
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
function Format.Double(value)
|
||||
local result = Format.Number(value)
|
||||
|
||||
if result == "inf" then
|
||||
return "double.MaxValue"
|
||||
elseif result == "-inf" then
|
||||
return "double.MinValue"
|
||||
else
|
||||
return result
|
||||
end
|
||||
end
|
||||
|
||||
function Format.Float(value)
|
||||
local result = Format.Number(value)
|
||||
|
||||
if result == "inf" then
|
||||
return "float.MaxValue"
|
||||
elseif result == "-inf" then
|
||||
return "float.MinValue"
|
||||
else
|
||||
if result:find("%.") then
|
||||
result = result .. 'f'
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
end
|
||||
|
||||
function Format.Flags(flag, enum)
|
||||
local value = 0
|
||||
|
||||
for _,item in pairs(enum:GetEnumItems()) do
|
||||
if flag[item.Name] then
|
||||
value = value + (2 ^ item.Value)
|
||||
end
|
||||
end
|
||||
|
||||
return value
|
||||
end
|
||||
|
||||
function Format.Axes(axes)
|
||||
return "(Axes)" .. Format.Flags(axes, Enum.Axis)
|
||||
end
|
||||
|
||||
function Format.Faces(faces)
|
||||
return "(Faces)" .. Format.Flags(faces, Enum.NormalId)
|
||||
end
|
||||
|
||||
function Format.EnumItem(item)
|
||||
local enum = tostring(item.EnumType)
|
||||
return enum .. '.' .. item.Name
|
||||
end
|
||||
|
||||
function Format.BrickColor(brickColor)
|
||||
local fmt = "BrickColor.FromNumber(%i)"
|
||||
return fmt:format(brickColor.Number)
|
||||
end
|
||||
|
||||
function Format.Color3(color)
|
||||
if color == Color3.new() then
|
||||
return "new Color3()"
|
||||
end
|
||||
|
||||
local r = Format.Float(color.r)
|
||||
local g = Format.Float(color.g)
|
||||
local b = Format.Float(color.b)
|
||||
|
||||
local fmt = "%s(%s, %s, %s)";
|
||||
local constructor = "new Color3";
|
||||
|
||||
if string.find(r .. g .. b, 'f') then
|
||||
r = Format.Int(color.r * 255)
|
||||
g = Format.Int(color.g * 255)
|
||||
b = Format.Int(color.b * 255)
|
||||
|
||||
constructor = "Color3.FromRGB"
|
||||
end
|
||||
|
||||
return fmt:format(constructor, r, g, b)
|
||||
end
|
||||
|
||||
function Format.UDim(udim)
|
||||
if udim == UDim.new() then
|
||||
return "new UDim()"
|
||||
end
|
||||
|
||||
local scale = Format.Float(udim.Scale)
|
||||
local offset = Format.Int(udim.Offset)
|
||||
|
||||
local fmt = "new UDim(%s, %s)"
|
||||
return fmt:format(scale, offset)
|
||||
end
|
||||
|
||||
function Format.UDim2(udim2)
|
||||
if udim2 == UDim2.new() then
|
||||
return "new UDim2()"
|
||||
end
|
||||
|
||||
local xScale = Format.Float(udim2.X.Scale)
|
||||
local yScale = Format.Float(udim2.Y.Scale)
|
||||
|
||||
local xOffset = Format.Int(udim2.X.Offset)
|
||||
local yOffset = Format.Int(udim2.Y.Offset)
|
||||
|
||||
local fmt = "new UDim2(%s, %s, %s, %s)"
|
||||
return fmt:format(xScale, xOffset, yScale, yOffset)
|
||||
end
|
||||
|
||||
function Format.Vector2(v2)
|
||||
if v2.Magnitude < 0.001 then
|
||||
return "new Vector2()"
|
||||
end
|
||||
|
||||
local x = Format.Float(v2.X)
|
||||
local y = Format.Float(v2.Y)
|
||||
|
||||
local fmt = "new Vector2(%s, %s)"
|
||||
return fmt:format(x, y)
|
||||
end
|
||||
|
||||
function Format.Vector3(v3)
|
||||
if v3.Magnitude < 0.001 then
|
||||
return "new Vector3()"
|
||||
end
|
||||
|
||||
local x = Format.Float(v3.X)
|
||||
local y = Format.Float(v3.Y)
|
||||
local z = Format.Float(v3.Z)
|
||||
|
||||
local fmt = "new Vector3(%s, %s, %s)"
|
||||
return fmt:format(x, y, z)
|
||||
end
|
||||
|
||||
function Format.CFrame(cf)
|
||||
local blankCF = CFrame.new()
|
||||
|
||||
if cf == blankCF then
|
||||
return "new CFrame()"
|
||||
end
|
||||
|
||||
local rot = cf - cf.p
|
||||
|
||||
if rot == blankCF then
|
||||
local fmt = "new CFrame(%s, %s, %s)"
|
||||
|
||||
local x = Format.Float(cf.X)
|
||||
local y = Format.Float(cf.Y)
|
||||
local z = Format.Float(cf.Z)
|
||||
|
||||
return fmt:format(x, y, z)
|
||||
else
|
||||
local comp = { cf:GetComponents() }
|
||||
|
||||
for i = 1,12 do
|
||||
comp[i] = Format.Float(comp[i])
|
||||
end
|
||||
|
||||
local fmt = "new CFrame(%s)"
|
||||
local matrix = table.concat(comp, ", ")
|
||||
|
||||
return fmt:format(matrix)
|
||||
end
|
||||
end
|
||||
|
||||
function Format.NumberRange(nr)
|
||||
local min = nr.Min
|
||||
local max = nr.Max
|
||||
|
||||
local fmt = "new NumberRange(%s)"
|
||||
local value = Format.Float(min)
|
||||
|
||||
if min ~= max then
|
||||
value = value .. ", " .. Format.Float(max)
|
||||
end
|
||||
|
||||
return fmt:format(value)
|
||||
end
|
||||
|
||||
function Format.Ray(ray)
|
||||
if ray == Ray.new() then
|
||||
return "new Ray()"
|
||||
end
|
||||
|
||||
local fmt = "new Ray(%s, %s)"
|
||||
|
||||
local origin = Format.Vector3(ray.Origin)
|
||||
local direction = Format.Vector3(ray.Direction)
|
||||
|
||||
return fmt:format(origin, direction)
|
||||
end
|
||||
|
||||
function Format.Rect(rect)
|
||||
local fmt = "new Rect(%s, %s)"
|
||||
|
||||
local min = Format.Vector2(rect.Min)
|
||||
local max = Format.Vector2(rect.Max)
|
||||
|
||||
return fmt:format(min, max)
|
||||
end
|
||||
|
||||
function Format.ColorSequence(cs)
|
||||
local csKey = cs.Keypoints[1]
|
||||
|
||||
local fmt = "new ColorSequence(%s)"
|
||||
local value = Format.Color3(csKey.Value)
|
||||
|
||||
return fmt:format(value)
|
||||
end
|
||||
|
||||
function Format.NumberSequence(ns)
|
||||
local nsKey = ns.Keypoints[1]
|
||||
|
||||
local fmt = "new NumberSequence(%s)"
|
||||
local value = Format.Float(nsKey.Value)
|
||||
|
||||
return fmt:format(value)
|
||||
end
|
||||
|
||||
function Format.Vector3int16(v3)
|
||||
if v3 == Vector3int16.new() then
|
||||
return "new Vector3int16()"
|
||||
end
|
||||
|
||||
local x = Format.Int(v3.X)
|
||||
local y = Format.Int(v3.Y)
|
||||
local z = Format.Int(v3.Z)
|
||||
|
||||
local fmt = "new Vector3int16(%s, %s, %s)"
|
||||
return fmt:format(x, y, z)
|
||||
end
|
||||
|
||||
function Format.SharedString(str)
|
||||
local fmt = "SharedString.FromBase64(%q)"
|
||||
return fmt:format(str)
|
||||
end
|
||||
|
||||
return Format
|
674
Plugins/GenerateApiDump/PropertyPatches.lua
Normal file
674
Plugins/GenerateApiDump/PropertyPatches.lua
Normal file
@ -0,0 +1,674 @@
|
||||
local function UseColor3(propName)
|
||||
return
|
||||
{
|
||||
Get = "BrickColor.FromColor3(" .. propName .. ')';
|
||||
Set = propName .. " = value.Color";
|
||||
}
|
||||
end
|
||||
|
||||
local GuiTextMixIn =
|
||||
{
|
||||
Redirect =
|
||||
{
|
||||
FontSize =
|
||||
{
|
||||
Get = "FontUtility.GetFontSize(TextSize)";
|
||||
Set = "TextSize = FontUtility.GetFontSize(value)";
|
||||
};
|
||||
|
||||
TextColor = UseColor3("TextColor3");
|
||||
TextWrap = "TextWrapped";
|
||||
};
|
||||
}
|
||||
|
||||
return
|
||||
{
|
||||
Accoutrement =
|
||||
{
|
||||
Remove =
|
||||
{
|
||||
"AttachmentUp";
|
||||
"AttachmentPos";
|
||||
"AttachmentRight";
|
||||
"AttachmentForward";
|
||||
};
|
||||
};
|
||||
|
||||
AnalyticsService =
|
||||
{
|
||||
Defaults = { ApiKey = "" }
|
||||
};
|
||||
|
||||
Attachment =
|
||||
{
|
||||
Remove =
|
||||
{
|
||||
"Axis";
|
||||
"Orientation";
|
||||
"Position";
|
||||
"SecondaryAxis";
|
||||
"WorldAxis";
|
||||
"WorldCFrame";
|
||||
"WorldOrientation";
|
||||
"WorldPosition";
|
||||
"WorldSecondaryAxis";
|
||||
};
|
||||
};
|
||||
|
||||
BasePart =
|
||||
{
|
||||
Add =
|
||||
{
|
||||
Color3uint8 = "Color3uint8";
|
||||
size = "Vector3";
|
||||
};
|
||||
|
||||
Redirect =
|
||||
{
|
||||
Position = "CFrame.Position";
|
||||
BrickColor = UseColor3("Color");
|
||||
Color = "Color3uint8";
|
||||
Size = "size";
|
||||
};
|
||||
|
||||
Defaults =
|
||||
{
|
||||
Color3uint8 = Color3.fromRGB(163, 162, 165);
|
||||
size = Vector3.new(4, 1.2, 2);
|
||||
};
|
||||
|
||||
Remove =
|
||||
{
|
||||
"Orientation";
|
||||
"Rotation";
|
||||
}
|
||||
};
|
||||
|
||||
BinaryStringValue =
|
||||
{
|
||||
Add =
|
||||
{
|
||||
Value = "BinaryString";
|
||||
};
|
||||
|
||||
Defaults =
|
||||
{
|
||||
Value = "";
|
||||
};
|
||||
};
|
||||
|
||||
BodyColors =
|
||||
{
|
||||
Redirect =
|
||||
{
|
||||
HeadColor = UseColor3("HeadColor3");
|
||||
LeftArmColor = UseColor3("LeftArmColor3");
|
||||
RightArmColor = UseColor3("RightArmColor3");
|
||||
LeftLegColor = UseColor3("LeftLegColor3");
|
||||
RightLegColor = UseColor3("RightLegColor3");
|
||||
TorsoColor = UseColor3("TorsoColor3");
|
||||
}
|
||||
};
|
||||
|
||||
BodyAngularVelocity =
|
||||
{
|
||||
Redirect = { angularvelocity = "AngularVelocity" };
|
||||
};
|
||||
|
||||
BodyGyro =
|
||||
{
|
||||
Redirect = { cframe = "CFrame" };
|
||||
};
|
||||
|
||||
Camera =
|
||||
{
|
||||
Redirect = { CoordinateFrame = "CFrame" }
|
||||
};
|
||||
|
||||
DataModelMesh =
|
||||
{
|
||||
Add =
|
||||
{
|
||||
LODX = "Enum:LevelOfDetailSetting";
|
||||
LODY = "Enum:LevelOfDetailSetting";
|
||||
};
|
||||
|
||||
Defaults =
|
||||
{
|
||||
LODX = Enum.LevelOfDetailSetting.High;
|
||||
LODY = Enum.LevelOfDetailSetting.High;
|
||||
};
|
||||
};
|
||||
|
||||
DataStoreService =
|
||||
{
|
||||
Defaults =
|
||||
{
|
||||
AutomaticRetry = true;
|
||||
LegacyNamingScheme = false;
|
||||
}
|
||||
};
|
||||
|
||||
DebuggerWatch =
|
||||
{
|
||||
Defaults = { Expression = "" };
|
||||
};
|
||||
|
||||
DoubleConstrainedValue =
|
||||
{
|
||||
Redirect = { ConstrainedValue = "Value" }
|
||||
};
|
||||
|
||||
Fire =
|
||||
{
|
||||
Add =
|
||||
{
|
||||
heat_xml = "float";
|
||||
size_xml = "float";
|
||||
};
|
||||
|
||||
Defaults =
|
||||
{
|
||||
heat_xml = 9;
|
||||
size_xml = 5;
|
||||
};
|
||||
|
||||
Redirect =
|
||||
{
|
||||
Heat = "heat_xml";
|
||||
Size = "size_xml";
|
||||
};
|
||||
};
|
||||
|
||||
FormFactorPart =
|
||||
{
|
||||
Add =
|
||||
{
|
||||
formFactorRaw = "Enum:FormFactor";
|
||||
};
|
||||
|
||||
Defaults =
|
||||
{
|
||||
formFactorRaw = Enum.FormFactor.Brick;
|
||||
};
|
||||
|
||||
Redirect =
|
||||
{
|
||||
FormFactor = "formFactorRaw";
|
||||
};
|
||||
};
|
||||
|
||||
GuiBase2d =
|
||||
{
|
||||
Redirect = { Localize = "AutoLocalize" }
|
||||
};
|
||||
|
||||
GuiBase3d =
|
||||
{
|
||||
Redirect = { Color = UseColor3("Color3") }
|
||||
};
|
||||
|
||||
GuiObject =
|
||||
{
|
||||
Redirect =
|
||||
{
|
||||
BackgroundColor = UseColor3("BackgroundColor3");
|
||||
BorderColor = UseColor3("BorderColor3");
|
||||
Transparency = "BackgroundTransparency";
|
||||
}
|
||||
};
|
||||
|
||||
HttpService =
|
||||
{
|
||||
Defaults = { HttpEnabled = false }
|
||||
};
|
||||
|
||||
Humanoid =
|
||||
{
|
||||
Add =
|
||||
{
|
||||
Health_XML = "float";
|
||||
InternalHeadScale = "float";
|
||||
InternalBodyScale = "Vector3";
|
||||
};
|
||||
|
||||
Defaults =
|
||||
{
|
||||
Health_XML = 100;
|
||||
InternalHeadScale = 1;
|
||||
InternalBodyScale = Vector3.new(1, 1, 1);
|
||||
};
|
||||
|
||||
Redirect =
|
||||
{
|
||||
Health = "Health_XML";
|
||||
};
|
||||
|
||||
Remove =
|
||||
{
|
||||
"Jump";
|
||||
"Torso";
|
||||
"LeftLeg";
|
||||
"RightLeg";
|
||||
};
|
||||
};
|
||||
|
||||
HumanoidDescription =
|
||||
{
|
||||
Add =
|
||||
{
|
||||
EmotesDataInternal = "string";
|
||||
EquippedEmotesDataInternal = "string";
|
||||
};
|
||||
|
||||
Defaults =
|
||||
{
|
||||
EmotesDataInternal = "";
|
||||
EquippedEmotesDataInternal = "";
|
||||
};
|
||||
};
|
||||
|
||||
InsertService =
|
||||
{
|
||||
Add = { AllowClientInsertModels = "bool" };
|
||||
Defaults = { AllowClientInsertModels = false };
|
||||
};
|
||||
|
||||
IntConstrainedValue =
|
||||
{
|
||||
Redirect = { ConstrainedValue = "Value" }
|
||||
};
|
||||
|
||||
JointInstance =
|
||||
{
|
||||
Add = { IsAutoJoint = "bool" };
|
||||
Defaults = { IsAutoJoint = true };
|
||||
};
|
||||
|
||||
Lighting =
|
||||
{
|
||||
Add =
|
||||
{
|
||||
Technology = "Enum:Technology";
|
||||
};
|
||||
|
||||
Defaults =
|
||||
{
|
||||
LegacyOutlines = false;
|
||||
Technology = Enum.Technology.Compatibility;
|
||||
};
|
||||
|
||||
Redirect =
|
||||
{
|
||||
Outlines = "LegacyOutlines";
|
||||
};
|
||||
|
||||
Remove =
|
||||
{
|
||||
"ClockTime";
|
||||
};
|
||||
};
|
||||
|
||||
LocalizationService =
|
||||
{
|
||||
Remove =
|
||||
{
|
||||
"ForcePlayModeGameLocaleId";
|
||||
"ForcePlayModeRobloxLocaleId";
|
||||
"RobloxForcePlayModeGameLocaleId";
|
||||
"RobloxForcePlayModeRobloxLocaleId";
|
||||
}
|
||||
};
|
||||
|
||||
LocalizationTable =
|
||||
{
|
||||
Add = { Contents = "string" };
|
||||
Defaults = { Contents = "[]" };
|
||||
|
||||
Redirect =
|
||||
{
|
||||
DevelopmentLanguage = "SourceLocaleId";
|
||||
}
|
||||
};
|
||||
|
||||
ManualSurfaceJointInstance =
|
||||
{
|
||||
Add =
|
||||
{
|
||||
Surface0 = "int";
|
||||
Surface1 = "int";
|
||||
};
|
||||
|
||||
Defaults =
|
||||
{
|
||||
Surface0 = -1;
|
||||
Surface1 = -1;
|
||||
}
|
||||
};
|
||||
|
||||
MeshPart =
|
||||
{
|
||||
Redirect = { MeshID = "MeshId" }
|
||||
};
|
||||
|
||||
Model =
|
||||
{
|
||||
Add = { ModelInPrimary = "CFrame" };
|
||||
Defaults = { ModelInPrimary = CFrame.new() };
|
||||
};
|
||||
|
||||
NotificationService =
|
||||
{
|
||||
Remove = {"SelectedTheme"}
|
||||
};
|
||||
|
||||
Part =
|
||||
{
|
||||
Add = { shape = "Enum:PartType" };
|
||||
Redirect = { Shape = "shape" };
|
||||
};
|
||||
|
||||
ParticleEmitter =
|
||||
{
|
||||
Redirect =
|
||||
{
|
||||
VelocitySpread =
|
||||
{
|
||||
Get = "SpreadAngle.X";
|
||||
Set = "SpreadAngle = new Vector2(value, value)";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
PartOperation =
|
||||
{
|
||||
Add =
|
||||
{
|
||||
AssetId = "Content";
|
||||
ChildData = "BinaryString";
|
||||
MeshData = "BinaryString";
|
||||
};
|
||||
|
||||
Defaults =
|
||||
{
|
||||
AssetId = "";
|
||||
ChildData = "";
|
||||
MeshData = "";
|
||||
};
|
||||
};
|
||||
|
||||
PartOperationAsset =
|
||||
{
|
||||
Add =
|
||||
{
|
||||
ChildData = "BinaryString";
|
||||
MeshData = "BinaryString";
|
||||
};
|
||||
|
||||
Defaults =
|
||||
{
|
||||
ChildData = "";
|
||||
MeshData = "";
|
||||
};
|
||||
};
|
||||
|
||||
Players =
|
||||
{
|
||||
Defaults =
|
||||
{
|
||||
MaxPlayersInternal = 16;
|
||||
PreferredPlayersInternal = 0;
|
||||
}
|
||||
};
|
||||
|
||||
RenderingTest =
|
||||
{
|
||||
Remove =
|
||||
{
|
||||
"Position";
|
||||
"Orientation";
|
||||
};
|
||||
};
|
||||
|
||||
ScriptContext =
|
||||
{
|
||||
Remove = { "ScriptsDisabled" }
|
||||
};
|
||||
|
||||
SelectionBox =
|
||||
{
|
||||
Redirect = { SurfaceColor = UseColor3("SurfaceColor3") }
|
||||
};
|
||||
|
||||
SelectionSphere =
|
||||
{
|
||||
Redirect = { SurfaceColor = UseColor3("SurfaceColor3") }
|
||||
};
|
||||
|
||||
ServerScriptService =
|
||||
{
|
||||
Defaults = { LoadStringEnabled = false }
|
||||
};
|
||||
|
||||
Smoke =
|
||||
{
|
||||
Add =
|
||||
{
|
||||
size_xml = "float";
|
||||
opacity_xml = "float";
|
||||
riseVelocity_xml = "float";
|
||||
};
|
||||
|
||||
Defaults =
|
||||
{
|
||||
size_xml = 1;
|
||||
opacity_xml = 0.5;
|
||||
riseVelocity_xml = 1;
|
||||
};
|
||||
|
||||
Redirect =
|
||||
{
|
||||
Size = "size_xml";
|
||||
Opacity = "opacity_xml";
|
||||
RiseVelocity = "riseVelocity_xml";
|
||||
};
|
||||
};
|
||||
|
||||
Sound =
|
||||
{
|
||||
Add =
|
||||
{
|
||||
MaxDistance = "float"; -- ?!
|
||||
|
||||
xmlRead_MaxDistance_3 = "float";
|
||||
xmlRead_MinDistance_3 = "float";
|
||||
};
|
||||
|
||||
Defaults =
|
||||
{
|
||||
xmlRead_MinDistance_3 = 10;
|
||||
xmlRead_MaxDistance_3 = 10000;
|
||||
};
|
||||
|
||||
Redirect =
|
||||
{
|
||||
EmitterSize = "xmlRead_MinDistance_3";
|
||||
MaxDistance = "xmlRead_MaxDistance_3";
|
||||
|
||||
MinDistance = "EmitterSize";
|
||||
Pitch = "PlaybackSpeed";
|
||||
};
|
||||
};
|
||||
|
||||
Sparkles =
|
||||
{
|
||||
Redirect = { Color = "SparkleColor" };
|
||||
};
|
||||
|
||||
StudioData =
|
||||
{
|
||||
Defaults =
|
||||
{
|
||||
SrcPlaceId = 0;
|
||||
SrcUniverseId = 0;
|
||||
};
|
||||
};
|
||||
|
||||
TextBox = GuiTextMixIn;
|
||||
TextLabel = GuiTextMixIn;
|
||||
TextButton = GuiTextMixIn;
|
||||
|
||||
Terrain =
|
||||
{
|
||||
Add =
|
||||
{
|
||||
ClusterGrid = "string";
|
||||
ClusterGridV2 = "string";
|
||||
ClusterGridV3 = "BinaryString";
|
||||
|
||||
SmoothGrid = "BinaryString";
|
||||
PhysicsGrid = "BinaryString";
|
||||
};
|
||||
|
||||
Defaults =
|
||||
{
|
||||
ClusterGrid = "";
|
||||
ClusterGridV2 = "";
|
||||
ClusterGridV3 = "";
|
||||
|
||||
SmoothGrid = "AQU=";
|
||||
PhysicsGrid = "AgMAAAAAAAAAAAAAAAA=";
|
||||
MaterialColors = "AAAAAAAAan8/P39rf2Y/ilY+j35fi21PZmxvZbDqw8faiVpHOi4kHh4lZlw76JxKc3trhHtagcLgc4RKxr21zq2UlJSM";
|
||||
};
|
||||
};
|
||||
|
||||
TerrainRegion =
|
||||
{
|
||||
Add =
|
||||
{
|
||||
ExtentsMax = "Vector3int16";
|
||||
ExtentsMin = "Vector3int16";
|
||||
|
||||
GridV3 = "BinaryString";
|
||||
SmoothGrid = "BinaryString";
|
||||
};
|
||||
|
||||
Defaults =
|
||||
{
|
||||
ExtentsMax = Vector3int16.new();
|
||||
ExtentsMin = Vector3int16.new();
|
||||
|
||||
GridV3 = "";
|
||||
SmoothGrid = "AQU=";
|
||||
};
|
||||
};
|
||||
|
||||
Tool =
|
||||
{
|
||||
Remove =
|
||||
{
|
||||
"GripForward";
|
||||
"GripPos";
|
||||
"GripRight";
|
||||
"GripUp";
|
||||
};
|
||||
};
|
||||
|
||||
TriangleMeshPart =
|
||||
{
|
||||
Add =
|
||||
{
|
||||
InitialSize = "Vector3";
|
||||
LODData = "BinaryString";
|
||||
PhysicsData = "BinaryString";
|
||||
PhysicalConfigData = "SharedString";
|
||||
};
|
||||
|
||||
Defaults =
|
||||
{
|
||||
LODData = "";
|
||||
PhysicsData = "";
|
||||
InitialSize = Vector3.new(1, 1, 1);
|
||||
PhysicalConfigData = "1B2M2Y8AsgTpgAmY7PhCfg==";
|
||||
};
|
||||
};
|
||||
|
||||
TrussPart =
|
||||
{
|
||||
Add = { style = "Enum:Style" };
|
||||
Redirect = { Style = "style" };
|
||||
};
|
||||
|
||||
ViewportFrame =
|
||||
{
|
||||
Add =
|
||||
{
|
||||
CameraCFrame = "CFrame";
|
||||
CameraFieldOfView = "float";
|
||||
};
|
||||
|
||||
Defaults =
|
||||
{
|
||||
CameraCFrame = CFrame.new();
|
||||
CameraFieldOfView = 70;
|
||||
};
|
||||
|
||||
Remove = {"CurrentCamera"};
|
||||
};
|
||||
|
||||
WeldConstraint =
|
||||
{
|
||||
Add =
|
||||
{
|
||||
Part0Internal = "Class:BasePart";
|
||||
Part1Internal = "Class:BasePart";
|
||||
|
||||
CFrame0 = "CFrame";
|
||||
CFrame1 = "CFrame";
|
||||
};
|
||||
|
||||
Defaults =
|
||||
{
|
||||
CFrame0 = CFrame.new();
|
||||
CFrame1 = CFrame.new();
|
||||
|
||||
Part0 = Instance.new("Part");
|
||||
Part1 = Instance.new("Part");
|
||||
};
|
||||
|
||||
Redirect =
|
||||
{
|
||||
Part0 = "Part0Internal";
|
||||
Part1 = "Part1Internal";
|
||||
};
|
||||
};
|
||||
|
||||
Workspace =
|
||||
{
|
||||
Add =
|
||||
{
|
||||
AutoJointsMode = "Enum:AutoJointsMode";
|
||||
CollisionGroups = "string";
|
||||
ExplicitAutoJoints = "bool";
|
||||
|
||||
StreamingMinRadius = "int";
|
||||
StreamingTargetRadius = "int";
|
||||
StreamingPauseMode = "Enum:StreamingPauseMode";
|
||||
|
||||
TerrainWeldsFixed = "bool";
|
||||
};
|
||||
|
||||
Defaults =
|
||||
{
|
||||
AutoJointsMode = Enum.AutoJointsMode.Default;
|
||||
CollisionGroups = "Default^0^1";
|
||||
ExplicitAutoJoints = true;
|
||||
|
||||
StreamingMinRadius = 64;
|
||||
StreamingTargetRadius = 1024;
|
||||
StreamingPauseMode = Enum.StreamingPauseMode.Default;
|
||||
|
||||
TerrainWeldsFixed = true;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user