roblonium-web/Game/FinobeTools/PBSTools/ConfigTool.rbxm

1384 lines
45 KiB
Plaintext

<roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.roblox.com/roblox.xsd" version="4">
<External>null</External>
<External>nil</External>
<Item class="Tool" referent="RBX0">
<Properties>
<bool name="CanBeDropped">true</bool>
<bool name="Enabled">true</bool>
<CoordinateFrame name="Grip">
<X>0</X>
<Y>0</Y>
<Z>-0.699999988</Z>
<R00>-0</R00>
<R01>0</R01>
<R02>1</R02>
<R10>1</R10>
<R11>-0</R11>
<R12>0</R12>
<R20>0</R20>
<R21>1</R21>
<R22>0</R22>
</CoordinateFrame>
<string name="Name">ConfigTool</string>
<Content name="TextureId"><url>http://www.roblox.com/asset/?id=59102714</url></Content>
<string name="ToolTip">Configure Parts</string>
</Properties>
<Item class="Part" referent="RBX1">
<Properties>
<bool name="Anchored">false</bool>
<float name="BackParamA">-0.5</float>
<float name="BackParamB">0.5</float>
<token name="BackSurface">0</token>
<token name="BackSurfaceInput">0</token>
<float name="BottomParamA">-0.5</float>
<float name="BottomParamB">0.5</float>
<token name="BottomSurface">0</token>
<token name="BottomSurfaceInput">0</token>
<int name="BrickColor">199</int>
<CoordinateFrame name="CFrame">
<X>-35</X>
<Y>1.60000002</Y>
<Z>3.5</Z>
<R00>0</R00>
<R01>0</R01>
<R02>-1</R02>
<R10>0</R10>
<R11>1</R11>
<R12>0</R12>
<R20>1</R20>
<R21>0</R21>
<R22>0</R22>
</CoordinateFrame>
<bool name="CanCollide">true</bool>
<float name="Elasticity">0.5</float>
<float name="Friction">0.300000012</float>
<float name="FrontParamA">-0.5</float>
<float name="FrontParamB">0.5</float>
<token name="FrontSurface">0</token>
<token name="FrontSurfaceInput">0</token>
<float name="LeftParamA">-0.5</float>
<float name="LeftParamB">0.5</float>
<token name="LeftSurface">0</token>
<token name="LeftSurfaceInput">0</token>
<bool name="Locked">true</bool>
<token name="Material">256</token>
<string name="Name">Handle</string>
<float name="Reflectance">0</float>
<float name="RightParamA">-0.5</float>
<float name="RightParamB">0.5</float>
<token name="RightSurface">0</token>
<token name="RightSurfaceInput">0</token>
<Vector3 name="RotVelocity">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Vector3>
<float name="TopParamA">-0.5</float>
<float name="TopParamB">0.5</float>
<token name="TopSurface">0</token>
<token name="TopSurfaceInput">0</token>
<float name="Transparency">0</float>
<Vector3 name="Velocity">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Vector3>
<token name="formFactorRaw">2</token>
<token name="shape">1</token>
<Vector3 name="size">
<X>1</X>
<Y>0.800000012</Y>
<Z>2</Z>
</Vector3>
</Properties>
<Item class="SpecialMesh" referent="RBX2">
<Properties>
<token name="LODX">2</token>
<token name="LODY">2</token>
<Content name="MeshId"><url>http://www.roblox.com/asset/?id=16884681</url></Content>
<token name="MeshType">5</token>
<string name="Name">Mesh</string>
<Vector3 name="Offset">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Vector3>
<Vector3 name="Scale">
<X>0.600000024</X>
<Y>0.600000024</Y>
<Z>0.600000024</Z>
</Vector3>
<Content name="TextureId"><url>http://www.roblox.com/asset/?id=16884673</url></Content>
<Vector3 name="VertexColor">
<X>1</X>
<Y>1</Y>
<Z>1</Z>
</Vector3>
</Properties>
</Item>
</Item>
<Item class="LocalScript" referent="RBX3">
<Properties>
<bool name="Disabled">false</bool>
<Content name="LinkedSource"><null></null></Content>
<string name="Name">ConfigurationLocal</string>
<ProtectedString name="Source">-- general functions
function waitForProperty(instance, name)
&#9;while not instance[name] do
&#9;&#9;instance.Changed:wait()
&#9;end
end
function waitForChild(instance, name)
&#9;while not instance:FindFirstChild(name) do
&#9;&#9;instance.ChildAdded:wait()
&#9;end
end
local RbxGui
if LoadLibrary then
&#9;RbxGui = LoadLibrary(&quot;RbxGui&quot;)
else
&#9;return
end
local isRestricted = (game.PlaceId == 41324860 or game.PlaceId == 129686177)
local Tool = script.Parent
enabled = true
game:GetService(&quot;ContentProvider&quot;):Preload(&quot;http://www.roblox.com/asset/?id=59785529&quot;)
game:GetService(&quot;ContentProvider&quot;):Preload(&quot;http://www.roblox.com/asset/?id=61423967&quot;)
game:GetService(&quot;ContentProvider&quot;):Preload(&quot;http://www.roblox.com/asset/?id=61427382&quot;)
local configIconImage = &quot;http://www.roblox.com/asset/?id=59785529&quot;
local configIconOverImage = &quot;http://www.roblox.com/asset/?id=61423967&quot;
local configIconHoverImage = &quot;http://www.roblox.com/asset/?id=61427382&quot;
local highlightedImage = nil
waitForChild(Tool, &quot;PlayerOwner&quot;)
local playerOwner = Tool.PlayerOwner
local STATIC_BASE_PLATE = nil
local ServiceConnections
local guiMain
local screen
local selectionGui
local player
local playerArea
local canTween = true
local gridRecalc
local lastPart
local lastConfig = nil
local lastVehicleSeat = nil
local origValueMap = {}
local valueConnections = {}
local objectValueSelect = {}
local adornmentTable = {}
local colorPaletteSelectMode = false
local needsIconReset = false
local textSize = 5
--Constants
local width = UDim.new(3, 0)
local height = 20
local transparency = 0.5
local buttonColor = BrickColor.new(&quot;Mid gray&quot;)
local frameColor = BrickColor.new(&quot;Pastel yellow&quot;)
local function isInModel(part)
&#9;if part == game.Workspace then
&#9;&#9;return false, nil
&#9;elseif part:IsA(&quot;Model&quot;) then
&#9;&#9;return true, part
&#9;else
&#9;&#9;return isInModel(part.Parent)
&#9;end
end
function constrained(valueObject)
&#9;return (valueObject:IsA(&quot;IntConstrainedValue&quot;) or valueObject:IsA(&quot;DoubleConstrainedValue&quot;))
end
function sharedProcess(name, parentFrame)
&#9;local subFrame = Instance.new(&quot;Frame&quot;)
&#9;subFrame.Name = name
&#9;subFrame.Size = UDim2.new(1.0, 0, 0, height)
&#9;subFrame.BackgroundTransparency = 1.0
&#9;subFrame.BorderSizePixel = 0
&#9;
&#9;local label = Instance.new(&quot;TextLabel&quot;)
&#9;label.Font = Enum.Font.ArialBold
&#9;label.Position = UDim2.new(0.0, 0, 0.0, 0)
&#9;label.Size = UDim2.new(0.5, 0, 1.0, 0)
&#9;label.FontSize = textSize
&#9;label.TextColor = BrickColor.White()
&#9;label.Text = name
&#9;label.Parent = subFrame
&#9;label.BackgroundTransparency = 1.0
&#9;label.BorderSizePixel = 0
&#9;return subFrame
end
function createTextBox(size, text)
&#9;local textBox = Instance.new(&quot;TextBox&quot;)
&#9;textBox.Position = UDim2.new(0.5, 1, 0.0, 1)
&#9;textBox.Size = size
&#9;textBox.BackgroundTransparency = 1
&#9;textBox.FontSize = textSize - 3
&#9;textBox.TextColor3 = Color3.new(1,1,1)
&#9;textBox.Text = text&#9;
&#9;textBox.ZIndex = 2
&#9;local textBoxBacking = Instance.new(&quot;TextButton&quot;)
&#9;textBoxBacking.Text = &quot;&quot;
&#9;textBoxBacking.Style = Enum.ButtonStyle.RobloxButtonDefault
&#9;textBoxBacking.Size = UDim2.new(1,0,1,0)
&#9;textBoxBacking.Parent = textBox
&#9;return textBox
end
function setCheckBoxValue(checkBox, value)
&#9;if value then
&#9;&#9;checkBox.Text = &quot;X&quot;
&#9;else
&#9;&#9;checkBox.Text = &quot;&quot;
&#9;end
end
function createCheckBox(value)
&#9;local checkBox = Instance.new(&quot;TextButton&quot;)
&#9;checkBox.Position = UDim2.new(0.75, -(height-4)/2, 0.0, 2)
&#9;checkBox.Size = UDim2.new(0.0, height-4, 0.0, height-4)
&#9;checkBox.Style = Enum.ButtonStyle.RobloxButtonDefault
&#9;checkBox.TextColor3 = Color3.new(1,1,1)
&#9;checkBox.FontSize = textSize
&#9;setCheckBoxValue(checkBox, value)
&#9;return checkBox
end
function processBoolValue(value, guiFrame)
&#9;local subFrame = sharedProcess(value.Name, guiFrame)
&#9;local checkBox = createCheckBox(value.Value)
&#9;
&#9;--Tie the two values together... we&apos;ll need to break these connections later
&#9;checkBox.MouseButton1Down:connect(function() value.Value = not(value.Value) end)
&#9;valueConnections[#valueConnections+1] = value.Changed:connect(function(newValue) setCheckBoxValue(checkBox, newValue) end)&#9;
&#9;checkBox.Parent = subFrame
&#9;return subFrame
end
function processConstrainedNumberValue(value, guiFrame)
&#9;local subFrame = sharedProcess(value.Name, guiFrame)
&#9;local textBox = createTextBox(UDim2.new(0.5,-2, 1.0, -2), value.ConstrainedValue, function(textBox) value.ConstrainedValue = textBox.Text end)
&#9;textBox.Name = value.Name
&#9;--Tie the two values together... we&apos;ll need to break these connections later
&#9;textBox.Changed:connect(function(prop)
&#9;&#9;if prop == &quot;Text&quot; then
&#9;&#9;&#9;local prevValue = value.ConstrainedValue
&#9;&#9;&#9;if textBox.Text ~= &quot;&quot; then
&#9;&#9;&#9;&#9;pcall(function() value.ConstrainedValue = textBox.Text end)
&#9;&#9;&#9;end
&#9;&#9;&#9;textBox.Text = value.ConstrainedValue
&#9;&#9;end
&#9;end)
&#9;valueConnections[#valueConnections+1] = value.Changed:connect(function(newValue) textBox.Text = newValue end)
&#9;
&#9;textBox.Parent = subFrame
&#9;return subFrame;
end
function processIntValue(value, guiFrame)
&#9;local subFrame = sharedProcess(value.Name, guiFrame)
&#9;local textBox = createTextBox(UDim2.new(0.5,-2, 1.0, -2), value.Value, function(textBox) value.Value = textBox.Text end)
&#9;textBox.Name = value.Name
&#9;--Tie the two values together... we&apos;ll need to break these connections later
&#9;textBox.Changed:connect(function(prop)
&#9;&#9;if prop == &quot;Text&quot; then
&#9;&#9;&#9;local prevValue = value.Value
&#9;&#9;&#9;if textBox.Text ~= &quot;&quot; then
&#9;&#9;&#9;&#9;pcall(function() value.Value = textBox.Text end)
&#9;&#9;&#9;end
&#9;&#9;&#9;textBox.Text = value.Value
&#9;&#9;end
&#9;end)
&#9;valueConnections[#valueConnections+1] = value.Changed:connect(function(newValue) textBox.Text = newValue end)
&#9;
&#9;textBox.Parent = subFrame
&#9;return subFrame;
end
function processPropertyValue(object, name, field, guiFrame)
&#9;origValueMap[name] = object[field]
&#9;local subFrame = sharedProcess(name, guiFrame)
&#9;local textBox = createTextBox(UDim2.new(0.5,-2, 1.0, -2), object[field], function(textBox) object[field] = textBox.Text end)
&#9;textBox.Name = name
&#9;--Tie the two values together... we&apos;ll need to break these connections later
&#9;textBox.Changed:connect(function(prop)
&#9;&#9;if prop == &quot;Text&quot; then
&#9;&#9;&#9;if textBox.Text ~= &quot;&quot; then
&#9;&#9;&#9;&#9;local success = pcall(function() object[field] = textBox.Text end)
&#9;&#9;&#9;end
&#9;&#9;&#9;textBox.Text = object[field]
&#9;&#9;end
&#9;end)
&#9;valueConnections[#valueConnections+1] = object.Changed:connect(function(property) if property == field then textBox.Text = object[field] end end)
&#9;
&#9;textBox.Parent = subFrame
&#9;return subFrame
end
function processEnumValue(value, guiFrame)
&#9;local subFrame = sharedProcess(value.Name, guiFrame)
&#9;local valueChildren = value:GetChildren()
&#9;local enumNames = {}
&#9;for i = 1, #valueChildren do
&#9;&#9;if valueChildren[i]:IsA(&quot;BoolValue&quot;) and valueChildren[i].Value == true then
&#9;&#9;&#9;table.insert(enumNames,valueChildren[i].Name)
&#9;&#9;end
&#9;end
&#9;local valueToChange = value
&#9;local enumSelect = function(item)
&#9;&#9;valueToChange.Value = tostring(item)
&#9;end
&#9;local dropDownEnumMenu, updateEnumSelection = RbxGui.CreateDropDownMenu(enumNames, enumSelect)
&#9;dropDownEnumMenu.Position = UDim2.new(0.5,0,0,0)
&#9;dropDownEnumMenu.Size = UDim2.new(0.5,0,0,20)
&#9;dropDownEnumMenu.Parent = subFrame
&#9;for i = 1, #valueChildren do
&#9;&#9;if value.Value == valueChildren[i].Name then
&#9;&#9;&#9;dropDownEnumMenu.DropDownMenuButton.Text = valueChildren[i].Name
&#9;&#9;&#9;break
&#9;&#9;end
&#9;end
&#9;return subFrame
end
function processNumberValue(value, guiFrame)
&#9;return processIntValue(value, guiFrame)
end
function processStringValue(value, guiFrame)
&#9;return processIntValue(value, guiFrame)
end
function inBaseplate(instance)
&#9;if instance == STATIC_BASE_PLATE then return true end
&#9;local instanceCopy = instance
&#9;while instanceCopy and (instanceCopy.Parent ~= nil or instanceCopy.Parent ~= game.Workspace) do
&#9;&#9;if instanceCopy.Parent == STATIC_BASE_PLATE then
&#9;&#9;&#9;return true
&#9;&#9;end
&#9;&#9;instanceCopy = instanceCopy.Parent
&#9;end
&#9;return false
end
function onMouseLeave(hoverSelection, selectedButtonTable, oldButton)
&#9;if oldButton[0] then
&#9;&#9;local notSelected = true;
&#9;&#9;local selectionText = &quot;&quot;;
&#9;&#9;for key, value in pairs(selectedButtonTable) do
&#9;&#9;&#9;if oldButton[0] == value then
&#9;&#9;&#9;&#9;notSelected = false
&#9;&#9;&#9;else
&#9;&#9;&#9;&#9;selectionText = value.BackgroundColor.Name;
&#9;&#9;&#9;end
&#9;&#9;end
&#9;&#9;if notSelected then
&#9;&#9;&#9;hoverSelection.Text = selectionText;
&#9;&#9;&#9;oldButton[0].Parent.BackgroundColor = BrickColor.Black();
&#9;&#9;end
&#9;end
&#9;oldButton[0] = nil
end
function onMouseEnter(hoverSelection, guiButton, selectedButtonTable, oldButton)
&#9;onMouseLeave(hoverSelection, selectedButtonTable, oldButton)
&#9;hoverSelection.Text = guiButton.BackgroundColor.Name
&#9;if guiButton ~= selectedButton then
&#9;&#9;guiButton.Parent.BackgroundColor = BrickColor.White();
&#9;&#9;oldButton[0] = guiButton
&#9;end
end
function changeColorSelection(colorHolder, paletteFrame, guiButton, selectedButtonTable)
&#9;if selectedButtonTable[colorHolder] ~= nil then
&#9;&#9;selectedButtonTable[colorHolder].Parent.BackgroundColor = BrickColor.Black();
&#9;end
&#9;guiButton.Parent.BackgroundColor = BrickColor.Yellow();
&#9;colorHolder.BackgroundColor = guiButton.BackgroundColor
&#9;selectedButtonTable[colorHolder] = guiButton
end
function onMouseUp(colorHolder, paletteFrame, guiButton, selectedButtonTable)
&#9;changeColorSelection(colorHolder, paletteFrame, guiButton, selectedButtonTable)
&#9;onMouseLeavePalette(paletteFrame)
end
function onShowColorDialog(paletteFrame)
&#9;paletteFrame.Visible = not(paletteFrame.Visible)
&#9;colorPaletteSelectMode = true
end
function onMouseEnterPalette(mouse)
&#9;colorPaletteSelectMode = true
end
function onMouseLeavePalette(paletteFrame)
&#9;colorPaletteSelectMode = false
&#9;paletteFrame.Visible = false
end
function processBrickColorValue(value, guiFrame)
&#9;local subFrame = sharedProcess(value.Name, guiFrame)
&#9;local sideBar = Instance.new(&quot;Frame&quot;)
&#9;sideBar.Position = UDim2.new(0.5, 0, 0.0, 0)
&#9;sideBar.Size = UDim2.new(0.5, 0, 1.0, 0)
&#9;sideBar.BackgroundTransparency = 1.0
&#9;sideBar.Parent = subFrame
&#9;sideBar.BorderSizePixel = 0
&#9;local primaryColor = Instance.new(&quot;TextButton&quot;)
&#9;primaryColor.Position = UDim2.new(0.0, 1, 0.0, 1)
&#9;primaryColor.Size = UDim2.new(0.0, height-2, 0, height-2)
&#9;primaryColor.Text = &quot;&quot;&#9;
&#9;primaryColor.FontSize = textSize
&#9;primaryColor.BackgroundColor = value.Value
&#9;primaryColor.BorderColor = BrickColor.Black()
&#9;primaryColor.Parent = sideBar
&#9;local hoverSelection = Instance.new(&quot;TextLabel&quot;)
&#9;hoverSelection.Position = UDim2.new(0.0, height+2, 0.0, 0)
&#9;hoverSelection.Size = UDim2.new(1.0, -height - 4, 1.0, 0)
&#9;hoverSelection.Text = &quot;&quot;
&#9;hoverSelection.Font = Enum.Font.ArialBold
&#9;hoverSelection.FontSize = textSize
&#9;hoverSelection.BackgroundTransparency = 1.0
&#9;hoverSelection.BorderSizePixel = 0
&#9;hoverSelection.TextColor = BrickColor.White()
&#9;hoverSelection.Text = primaryColor.BackgroundColor.Name;
&#9;hoverSelection.Parent = sideBar
&#9;local paletteFrame = Instance.new(&quot;Frame&quot;)
&#9;paletteFrame.Position = UDim2.new(primaryColor.Position.X.Scale, primaryColor.Position.X.Offset + height, primaryColor.Position.Y.Scale, primaryColor.Position.Y.Offset - height*7)
&#9;paletteFrame.Size = UDim2.new(0, height*8, 0, height*8)
&#9;paletteFrame.BackgroundColor = BrickColor.White()
&#9;paletteFrame.BorderColor = BrickColor.White()
&#9;paletteFrame.Visible = false;
&#9;paletteFrame.Parent = sideBar
&#9;paletteFrame.ZIndex = 2
&#9;paletteFrame.MouseEnter:connect(function() onMouseEnterPalette(mouse) end)
&#9;paletteFrame.MouseLeave:connect(function() onMouseLeavePalette(paletteFrame, mouse) end)
&#9;primaryColor.MouseButton1Down:connect(function() onShowColorDialog(paletteFrame) end)
&#9;local selectedButtonTable = {}
&#9;local colorButtonTable = {}
&#9;local oldButton = {}
&#9;for xOffset = 0, 7 do
&#9;&#9;for yOffset = 0,7 do
&#9;&#9;&#9;local guiFrame = Instance.new(&quot;Frame&quot;)
&#9;&#9;&#9;guiFrame.Position = UDim2.new(1.0/8 * xOffset, 0, 1.0/8*yOffset, 0)
&#9;&#9;&#9;guiFrame.Size = UDim2.new(1.0/8, 0, 1.0/8, 0)
&#9;&#9;&#9;guiFrame.BackgroundColor = BrickColor.White();
&#9;&#9;&#9;guiFrame.BorderSizePixel = 0
&#9;&#9;&#9;guiFrame.Parent = paletteFrame;
&#9;&#9;&#9;guiFrame.ZIndex = 2
&#9;&#9;
&#9;&#9;&#9;local guiButton = Instance.new(&quot;TextButton&quot;)
&#9;&#9;&#9;guiButton.FontSize = textSize
&#9;&#9;&#9;guiButton.Position = UDim2.new(0.0, 1, 0.0, 1)
&#9;&#9;&#9;guiButton.Size = UDim2.new(1.0, -2, 1.0, -2)
&#9;&#9;&#9;guiButton.Text = &quot;&quot;
&#9;&#9;&#9;guiButton.BorderSizePixel = 0
&#9;&#9;&#9;guiButton.AutoButtonColor = false
&#9;&#9;&#9;local color = BrickColor.palette(xOffset + yOffset*8)
&#9;&#9;&#9;colorButtonTable[color.Number] = guiButton
&#9;&#9;&#9;guiButton.BackgroundColor = color
&#9;&#9;&#9;guiButton.MouseEnter:connect(function() onMouseEnter(hoverSelection, guiButton, selectedButtonTable, oldButton) end)
&#9;&#9;&#9;guiButton.MouseButton1Up:connect(function() onMouseUp(primaryColor, paletteFrame, guiButton, selectedButtonTable, oldButton) end)
&#9;&#9;&#9;guiButton.MouseButton1Up:connect(function() value.Value = guiButton.BackgroundColor end)
&#9;&#9;&#9;guiButton.Parent = guiFrame
&#9;&#9;&#9;guiButton.ZIndex = 2
&#9;&#9;&#9;if guiButton.BackgroundColor == primaryColor.BackgroundColor then
&#9;&#9;&#9;&#9;guiFrame.BackgroundColor = BrickColor.White()
&#9;&#9;&#9;&#9;selectedButtonTable[primaryColor] = guiButton
&#9;&#9;&#9;end
&#9;&#9;end
&#9;end
&#9;valueConnections[#valueConnections+1] = value.Changed:connect(function(newValue) changeColorSelection(primaryColor, paletteFrame, colorButtonTable[newValue.Number], selectedButtonTable) end)&#9;
&#9;return subFrame
end
function onObjectValueMouseClick(guiFrame, value, objectButton)
&#9;objectValueSelect[&quot;Value&quot;] = value
&#9;objectValueSelect[&quot;Frame&quot;] = guiFrame
&#9;objectValueSelect[&quot;Enabled&quot;] = true
&#9;onObjectValueMouseLeave(value, objectButton)
end
function onObjectValueMouseEnter(value, objectButton)
&#9;objectValueSelect[&quot;HoverValue&quot;] = value
&#9;if value.Value then
&#9;&#9;objectButton.BackgroundColor = BrickColor.Blue()
&#9;else
&#9;&#9;objectButton.BackgroundColor = BrickColor.White()
&#9;end
end
&#9;
function onObjectValueMouseLeave(value, objectButton)
&#9;if objectValueSelect[&quot;HoverValue&quot;] == value then
&#9;&#9;objectValueSelect[&quot;HoverValue&quot;] = nil
&#9;end
&#9;objectButton.BackgroundColor = buttonColor
end
function onObjectValueCancel()
&#9;if objectValueSelect[&quot;Enabled&quot;] then
&#9;&#9;objectValueSelect[&quot;Enabled&quot;] = false
&#9;&#9;objectValueSelect[&quot;Frame&quot;].Visible = true
&#9;&#9;objectValueSelect[&quot;Frame&quot;] = nil
&#9;&#9;objectValueSelect[&quot;Value&quot;] = nil
&#9;end
end
function on3dObjectValueButton1Up(mouse, guiMain)
&#9;local part = mouse.Target
&#9;if part ~= nil then
&#9;&#9;objectValueSelect[&quot;Value&quot;].Value = part
&#9;&#9;objectValueSelect[&quot;Enabled&quot;] = false
&#9;&#9;objectValueSelect[&quot;Frame&quot;].Visible = true
&#9;&#9;objectValueSelect[&quot;Frame&quot;] = nil
&#9;&#9;objectValueSelect[&quot;Value&quot;] = nil
&#9;end
end
function on3dObjectValueMouseMove(mouse, guiMain)
end
function setObjectButtonText(guiFrame, objectButton, objectValue)
&#9;if objectValueSelect[&quot;Enabled&quot;] and objectValue == objectValueSelect[&quot;Value&quot;] then
&#9;&#9;guiFrame.Visible = true
&#9;&#9;objectValueSelect[&quot;Enabled&quot;] = false
&#9;&#9;objectValueSelect[&quot;Value&quot;] = nil
&#9;end
&#9;if objectValue.Value ~= nil then
&#9;&#9;objectButton.Text = objectValue.Value.Name
&#9;else
&#9;&#9;objectButton.Text = &quot;[nil]&quot;
&#9;end
&#9;objectButton.BackgroundColor = buttonColor
end
function processObjectValue(value, playerGui, guiFrame)
&#9;local subFrame = sharedProcess(value.Name, guiFrame)
&#9;local objectButton = Instance.new(&quot;TextButton&quot;)
&#9;objectButton.FontSize = textSize
&#9;objectButton.Position = UDim2.new(0.5, 2, 0.0, 2)
&#9;objectButton.Size = UDim2.new(0.5, -4, 1.0, -4)
&#9;objectButton.BackgroundColor = BrickColor.White()
&#9;objectButton.TextColor = BrickColor.Black()
&#9;objectButton.Parent = subFrame
&#9;objectButton.AutoButtonColor = false
&#9;objectButton.MouseButton1Click:connect(function() onObjectValueMouseClick(guiFrame, value, objectButton) end)
&#9;objectButton.MouseEnter:connect(function() onObjectValueMouseEnter(value, objectButton) end)
&#9;objectButton.MouseLeave:connect(function() onObjectValueMouseLeave(value, objectButton) end)
&#9;valueConnections[#valueConnections+1] = value.Changed:connect(function(newObjectValue) setObjectButtonText(guiFrame, objectButton, value) end)&#9;
&#9;setObjectButtonText(guiFrame, objectButton, value)
&#9;return subFrame
end
function processValue(value, playerGui, guiFrame)
&#9;if constrained(value) then origValueMap[value.Name] = value.ConstrainedValue
&#9;else origValueMap[value.Name] = value.Value end
&#9;if #value:GetChildren() &gt; 0 and value:IsA(&quot;StringValue&quot;) then
&#9;&#9;return processEnumValue(value, guiFrame)
&#9;else
&#9;&#9;if value.className == &quot;BoolValue&quot; then
&#9;&#9;&#9;return processBoolValue(value, guiFrame)
&#9;&#9;elseif value.className == &quot;IntValue&quot; then
&#9;&#9;&#9;return processIntValue(value, guiFrame)
&#9;&#9;elseif value.className == &quot;NumberValue&quot; then
&#9;&#9;&#9;return processNumberValue(value, guiFrame)
&#9;&#9;elseif value.className == &quot;StringValue&quot; then
&#9;&#9;&#9;return processStringValue(value, guiFrame)
&#9;&#9;elseif value.className == &quot;ObjectValue&quot; then
&#9;&#9;&#9;return processObjectValue(value, playerGui, guiFrame)
&#9;&#9;elseif value.className == &quot;BrickColorValue&quot; then
&#9;&#9;&#9;return processBrickColorValue(value, guiFrame)
&#9;&#9;elseif value.className == &quot;IntConstrainedValue&quot; or value.className == &quot;DoubleConstrainedValue&quot; then
&#9;&#9;&#9;return processConstrainedNumberValue(value, guiFrame)
&#9;&#9;else
&#9;&#9;&#9;return nil
&#9;&#9;end
&#9;end
end
function killFrame(frame)
&#9;screen.Enabled = false
&#9;frame:remove()
end
function closeFrame(frame)
&#9;lastPart = nil
&#9;if frame.Parent == nil then return end
&#9;frame:TweenSizeAndPosition(UDim2.new(0,0,0,0),UDim2.new(0.5,0,0.5,0),Enum.EasingDirection.In,Enum.EasingStyle.Back,0.5, true, function() killFrame(frame) end)
end
function allowTween()
&#9;canTween = true
end
function openFrame(frame,size)
&#9;if not canTween then return end
&#9;canTween = false
&#9;screen.Enabled = true
&#9;frame.Size = UDim2.new(0,0,0,0)
&#9;frame.Position = UDim2.new(0.5,0,0.5,0)
&#9;frame:TweenSizeAndPosition(size,UDim2.new(0,0,0,0),Enum.EasingDirection.Out,Enum.EasingStyle.Back,0.5,true, function() allowTween() end)
end
function sharedMain(name, playerGui)
&#9;local parentFrame = Instance.new(&quot;Frame&quot;)
&#9;parentFrame.Style = Enum.FrameStyle.RobloxRound
&#9;parentFrame.Active = true
&#9;parentFrame.Name = &quot;MainFrame&quot;
&#9;parentFrame.Size = UDim2.new(1, 0, 1, 0)
&#9;parentFrame.BackgroundTransparency = 1
&#9;local titleLabel = Instance.new(&quot;TextLabel&quot;)
&#9;titleLabel.Name = &quot;TitleLabel&quot;
&#9;titleLabel.Font = Enum.Font.ArialBold
&#9;titleLabel.FontSize = textSize + 2
&#9;titleLabel.Size = UDim2.new(1.0, 0.0, 0.0, height)
&#9;titleLabel.TextColor = BrickColor.White()
&#9;titleLabel.BackgroundColor = BrickColor.new(&quot;Cool yellow&quot;)
&#9;titleLabel.BackgroundTransparency = 1
&#9;titleLabel.Text = name
&#9;titleLabel.Parent = parentFrame
&#9;local closeButton = Instance.new(&quot;TextButton&quot;)
&#9;closeButton.Name = &quot;CloseButton&quot;
&#9;closeButton.Style = Enum.ButtonStyle.RobloxButtonDefault
&#9;closeButton.Size = UDim2.new(0,20,0,20)
&#9;closeButton.Position = UDim2.new(1,-16,0,-5)
&#9;closeButton.Text = &quot;X&quot;
&#9;closeButton.TextColor3 = Color3.new(1,1,1)
&#9;closeButton.Font = Enum.Font.ArialBold
&#9;closeButton.FontSize = Enum.FontSize.Size18
&#9;closeButton.Parent = parentFrame
&#9;local closeCon = nil
&#9;closeCon = closeButton.MouseButton1Click:connect(function()
&#9;&#9;closeCon:disconnect()
&#9;&#9;removeBillboards()
&#9;&#9;screen.Enabled = false
&#9;&#9;cancelSelectionGui()
&#9;end)
&#9;local scrollFrame, scrollUpButton, scrollDownButton, recalculateFunction = RbxGui.CreateScrollingFrame()
&#9;gridRecalc = recalculateFunction
&#9;scrollFrame.Name = &quot;ValueContainer&quot;
&#9;scrollFrame.Size = UDim2.new(1,-17,1,-50)
&#9;scrollFrame.Position = UDim2.new(0,0,0,25)
&#9;scrollFrame.Parent = parentFrame
&#9;local changerCon = nil
&#9;delay(1,function()
&#9;&#9;if scrollFrame and scrollFrame.Parent then
&#9;&#9;&#9;changerCon = scrollFrame.Changed:connect(function(prop)
&#9;&#9;&#9;&#9;if prop == &quot;AbsoluteSize&quot; then
&#9;&#9;&#9;&#9;&#9;if scrollFrame.AbsoluteSize.Y &lt; 38 then
&#9;&#9;&#9;&#9;&#9;&#9;changerCon:disconnect()
&#9;&#9;&#9;&#9;&#9;&#9;closeFrame(parentFrame)
&#9;&#9;&#9;&#9;&#9;else
&#9;&#9;&#9;&#9;&#9;&#9;gridRecalc()
&#9;&#9;&#9;&#9;&#9;end
&#9;&#9;&#9;&#9;end
&#9;&#9;&#9;end)
&#9;&#9;end
&#9;end)
&#9;local dieCon
&#9;dieCon = scrollFrame.AncestryChanged:connect(function(child,parent)
&#9;&#9;if parent == nil then
&#9;&#9;&#9;dieCon:disconnect()
&#9;&#9;&#9;if changerCon then changerCon:disconnect() end
&#9;&#9;end
&#9;end)
&#9;local scrollButtonFrame = Instance.new(&quot;Frame&quot;)
&#9;scrollButtonFrame.Name = &quot;ScrollButtonFrame&quot;
&#9;scrollButtonFrame.Position = UDim2.new(1,-17,0,25)
&#9;scrollButtonFrame.Size = UDim2.new(0,17,1,-50)
&#9;scrollButtonFrame.BackgroundTransparency = 1
&#9;scrollButtonFrame.Parent = parentFrame
&#9;scrollUpButton.Parent = scrollButtonFrame
&#9;scrollDownButton.Parent = scrollButtonFrame
&#9;scrollDownButton.Position = UDim2.new(0,0,1,-17)
&#9;
&#9;return parentFrame
end
function sharedButtons(parentFrame, valueChildren)
&#9;local buttonFrame = Instance.new(&quot;Frame&quot;)
&#9;buttonFrame.Name = &quot;Buttons&quot;
&#9;buttonFrame.BackgroundTransparency = 1.0
&#9;buttonFrame.Size = UDim2.new(1.0, 0.0, 0.0, height)
&#9;buttonFrame.Position = UDim2.new(0.0, 0, 1, -25)
&#9;buttonFrame.Parent = parentFrame
&#9;valueChildren = valueChildren + 1
&#9;local okButton = Instance.new(&quot;TextButton&quot;)
&#9;okButton.FontSize = textSize
&#9;okButton.Name = &quot;OkButton&quot;
&#9;okButton.Font = Enum.Font.ArialBold
&#9;okButton.TextColor = BrickColor.White()
&#9;okButton.Style = Enum.ButtonStyle.RobloxButton
&#9;okButton.Text = &quot;Ok&quot;
&#9;okButton.Size = UDim2.new(.25, -4, 0.0, height + 5)
&#9;okButton.Position = UDim2.new(0.55, 2, 0.0, 2)
&#9;okButton.BackgroundColor = buttonColor
&#9;okButton.MouseButton1Click:connect(function() removeSelectionGui() end)
&#9;okButton.Parent = buttonFrame
&#9;local cancelButton = okButton:clone()
&#9;cancelButton.Name = &quot;cancelButton&quot;
&#9;cancelButton.Text = &quot;Cancel&quot;
&#9;cancelButton.Position = UDim2.new(0.200000003, 2, 0, 2)
&#9;cancelButton.MouseButton1Click:connect(function() cancelSelectionGui() end)
&#9;cancelButton.Parent = buttonFrame
end
function processVehicleSeat(vehicleSeat, playerGui, valueChildren)
&#9;local parentFrame = sharedMain(vehicleSeat.Name, playerGui)
&#9;lastVehicleSeat = vehicleSeat
&#9;local valueChildren = 1
&#9;local fields = {&quot;MaxSpeed&quot;, &quot;Steer&quot;, &quot;Torque&quot;, &quot;TurnSpeed&quot;}
&#9;for pos, field in pairs(fields) do
&#9;&#9;local newFrame = processPropertyValue(vehicleSeat, field, field, guiFrame)
&#9;&#9;if newFrame then
&#9;&#9;&#9;newFrame.Position = UDim2.new(0.0, 0, 0.0, (valueChildren*height) - height)
&#9;&#9;&#9;newFrame.Parent = parentFrame.ValueContainer
&#9;&#9;&#9;valueChildren = valueChildren + 1
&#9;&#9;end
&#9;end
&#9;sharedButtons(parentFrame, valueChildren)
&#9;return parentFrame
end
function processConfiguration(config, playerGui)
&#9;local parentFrame = sharedMain(config.Name, playerGui)
&#9;lastConfig = config
&#9;local valueChildren = 1
&#9;local children = config:GetChildren()
&#9;if children then
&#9;&#9;for pos, child in pairs(children) do
&#9;&#9;&#9;local newFrame = processValue(child, playerGui, parentFrame)
&#9;&#9;&#9;if newFrame then
&#9;&#9;&#9;&#9;newFrame.Position = UDim2.new(0.0, 0, 0.0, (valueChildren*height) - height)
&#9;&#9;&#9;&#9;newFrame.Parent = parentFrame.ValueContainer
&#9;&#9;&#9;&#9;valueChildren = valueChildren + 1
&#9;&#9;&#9;end
&#9;&#9;end
&#9;end
&#9;
&#9;sharedButtons(parentFrame, valueChildren)
&#9;return parentFrame
end
function on3dMouseMove(mouse, guiMain)
&#9;if mouse.Target and canSelectObject(mouse.Target) then
&#9;&#9;local part = mouse.Target
&#9;&#9;if part:IsA(&quot;VehicleSeat&quot;) then
&#9;&#9;&#9;foundPart = part
&#9;&#9;else
&#9;&#9;&#9;foundPart = findConfiguration(part)
&#9;&#9;end
&#9;&#9;if foundPart then
&#9;&#9;&#9;if objectValueSelect[&quot;HoverBox&quot;] then
&#9;&#9;&#9;&#9;local isModel, model = isInModel(part)
&#9;&#9;&#9;&#9;local adornee = part
&#9;&#9;&#9;&#9;if isModel then
&#9;&#9;&#9;&#9;&#9;adornee = model
&#9;&#9;&#9;&#9;end
&#9;&#9;&#9;&#9;objectValueSelect[&quot;HoverBox&quot;].Adornee = adornee
&#9;&#9;&#9;&#9;local billboard = getBillboard(adornee)
&#9;&#9;&#9;&#9;local configBadge = billboard:FindFirstChild(&quot;ConfigBadge&quot;,true)
&#9;&#9;&#9;&#9;if configBadge then
&#9;&#9;&#9;&#9;&#9;configBadge.Image = configIconOverImage
&#9;&#9;&#9;&#9;&#9;highlightedImage = configBadge
&#9;&#9;&#9;&#9;end
&#9;&#9;&#9;end
&#9;&#9;&#9;needsIconReset = true
&#9;&#9;else
&#9;&#9;&#9;if needsIconReset then
&#9;&#9;&#9;&#9;if objectValueSelect[&quot;HoverBox&quot;] then objectValueSelect[&quot;HoverBox&quot;].Adornee = nil end
&#9;&#9;&#9;&#9;needsIconReset = false
&#9;&#9;&#9;&#9;if highlightedImage then
&#9;&#9;&#9;&#9;&#9;highlightedImage.Image = configIconImage
&#9;&#9;&#9;&#9;end
&#9;&#9;&#9;end
&#9;&#9;end
&#9;else
&#9;&#9;if needsIconReset then
&#9;&#9;&#9;if objectValueSelect[&quot;HoverBox&quot;] then objectValueSelect[&quot;HoverBox&quot;].Adornee = nil end
&#9;&#9;&#9;needsIconReset = false
&#9;&#9;&#9;if highlightedImage then
&#9;&#9;&#9;&#9;highlightedImage.Image = configIconImage
&#9;&#9;&#9;end
&#9;&#9;end
&#9;end
&#9;if objectValueSelect[&quot;Enabled&quot;] then
&#9;&#9;on3dObjectValueMouseMove(mouse, guiMain)
&#9;end
end
function cancelSelectionGui()
&#9;lastPart = nil
&#9;if selectionGui ~= nil then
&#9;&#9;closeFrame(selectionGui)
&#9;&#9;selectionGui = nil
&#9;&#9;for pos, connection in pairs(valueConnections) do
&#9;&#9;&#9;connection:disconnect()
&#9;&#9;end
&#9;&#9;valueConnections = {}
&#9;end
&#9;showConfigurationAnnotations()
&#9;if lastConfig then
&#9;&#9;local configValues = lastConfig:GetChildren()
&#9;&#9;for i = 1, #configValues do
&#9;&#9;&#9;if origValueMap[configValues[i].Name] ~= nil then
&#9;&#9;&#9;&#9;if constrained(configValues[i]) then configValues[i].ConstrainedValue = origValueMap[configValues[i].Name]
&#9;&#9;&#9;&#9;else configValues[i].Value = origValueMap[configValues[i].Name] end
&#9;&#9;&#9;&#9;origValueMap[configValues[i].Name] = nil
&#9;&#9;&#9;end
&#9;&#9;end
&#9;elseif lastVehicleSeat then
&#9;&#9;lastVehicleSeat.MaxSpeed = origValueMap[&quot;MaxSpeed&quot;]
&#9;&#9;origValueMap[&quot;MaxSpeed&quot;] = nil
&#9;&#9;lastVehicleSeat.Steer = origValueMap[&quot;Steer&quot;]
&#9;&#9;origValueMap[&quot;Steer&quot;] = nil
&#9;&#9;lastVehicleSeat.Torque = origValueMap[&quot;Torque&quot;]
&#9;&#9;origValueMap[&quot;Torque&quot;] = nil
&#9;&#9;lastVehicleSeat.TurnSpeed = origValueMap[&quot;TurnSpeed&quot;]
&#9;&#9;origValueMap[&quot;TurnSpeed&quot;] = nil
&#9;end
end
function removeSelectionGui()
&#9;if selectionGui ~= nil then
&#9;&#9;closeFrame(selectionGui)
&#9;&#9;for pos, connection in pairs(valueConnections) do
&#9;&#9;&#9;connection:disconnect()
&#9;&#9;end
&#9;&#9;valueConnections = {}
&#9;end
&#9;if objectValueSelect[&quot;HoverBox&quot;] then objectValueSelect[&quot;HoverBox&quot;].Adornee = nil end
&#9;showConfigurationAnnotations()
&#9;if lastConfig then
&#9;&#9;local configValues = lastConfig:GetChildren()
&#9;&#9;for i = 1, #configValues do
&#9;&#9;&#9;if origValueMap[configValues[i].Name] ~= nil then
&#9;&#9;&#9;&#9;origValueMap[configValues[i].Name] = nil
&#9;&#9;&#9;end
&#9;&#9;end
&#9;end
end
function canSelectObject(part)
&#9;if isRestricted then
&#9;&#9;waitForChild(playerArea,&quot;PlayerArea&quot;)
&#9;&#9;if isRestricted and playerArea:FindFirstChild(&quot;PlayerArea&quot;) and part:IsDescendantOf(playerArea.PlayerArea) then
&#9;&#9;&#9;return part and not (part.Locked) and part:IsA(&quot;BasePart&quot;)
&#9;&#9;else
&#9;&#9;&#9;return false
&#9;&#9;end
&#9;end
&#9;return part and not (part.Locked) and part:IsA(&quot;BasePart&quot;)
end
local function findConfigInModel(model)
&#9;local children = model:GetChildren()
&#9;for i = 1, #children do
&#9;&#9;if children[i]:IsA(&quot;Configuration&quot;) or children[i]:IsA(&quot;VehicleSeat&quot;) then
&#9;&#9;&#9;return children[i]
&#9;&#9;end
&#9;end
&#9;for i = 1, #children do
&#9;&#9;if #children[i]:GetChildren() &gt; 0 then
&#9;&#9;&#9;local returnValue = findConfigInModel(children[i])
&#9;&#9;&#9;if returnValue ~= nil then
&#9;&#9;&#9;&#9;return returnValue
&#9;&#9;&#9;end
&#9;&#9;end
&#9;end
&#9;return nil
end
function findConfiguration(part)
&#9;local partInModel, model = isInModel(part)
&#9;if partInModel then
&#9;&#9;local isModelConfig = findConfigInModel(model)
&#9;&#9;return isModelConfig
&#9;else
&#9;&#9;local children = part:GetChildren() &#9;&#9;
&#9;&#9;if children then
&#9;&#9;&#9;for pos, child in pairs(children) do
&#9;&#9;&#9;&#9;if child:IsA(&quot;Configuration&quot;) or child:IsA(&quot;VehicleSeat&quot;) then
&#9;&#9;&#9;&#9;&#9;return child
&#9;&#9;&#9;&#9;end
&#9;&#9;&#9;end
&#9;&#9;end
&#9;end
&#9;return nil
end
function removeBillboards()
&#9;local guis = guiMain:GetChildren()
&#9;for i = 1, #guis do
&#9;&#9;if guis[i]:IsA(&quot;Frame&quot;) then
&#9;&#9;&#9;guis[i]:remove()
&#9;&#9;end
&#9;end
end
function on3dButton1Up(mouse, guiMain, playerGui)
&#9;if objectValueSelect[&quot;Enabled&quot;] then
&#9;&#9;on3dObjectValueButton1Up(mouse, guiMain)
&#9;&#9;return
&#9;elseif canSelectObject(mouse.Target) then
&#9;&#9;local part = mouse.Target
&#9;&#9;local foundPart = nil
&#9;&#9;if part:IsA(&quot;VehicleSeat&quot;) then
&#9;&#9;&#9;foundPart = part
&#9;&#9;else
&#9;&#9;&#9;foundPart = findConfiguration(part)
&#9;&#9;end
&#9;
&#9;&#9;if foundPart then
&#9;&#9;&#9;
&#9;&#9;&#9;if foundPart == lastPart then
&#9;&#9;&#9;&#9;return
&#9;&#9;&#9;end
&#9;&#9;&#9;lastPart = foundPart
&#9;&#9;&#9;removeBillboards()
&#9;&#9;&#9;screen.Enabled = true
&#9;&#9;&#9;if foundPart:IsA(&quot;Configuration&quot;) then
&#9;&#9;&#9;&#9;selectionGui = processConfiguration(foundPart, playerGui)
&#9;&#9;&#9;else
&#9;&#9;&#9;&#9;selectionGui = processVehicleSeat(foundPart, playerGui)&#9;
&#9;&#9;&#9;end
&#9;&#9;&#9;selectionGui.Parent = guiMain
&#9;&#9;&#9;openFrame(selectionGui, selectionGui.Size)
&#9;&#9;&#9;local hasModel, model = isInModel(part)
&#9;&#9;&#9;if hasModel then
&#9;&#9;&#9;&#9;screen.Adornee = model
&#9;&#9;&#9;else
&#9;&#9;&#9;&#9;screen.Adornee = part
&#9;&#9;&#9;end
&#9;&#9;&#9;if highlightedImage then
&#9;&#9;&#9;&#9;highlightedImage.Image = configIconImage
&#9;&#9;&#9;end
&#9;&#9;end
&#9;else
&#9;&#9;cancelSelectionGui()
&#9;end
end
function onEquippedLocal(mouse)
&#9;local character = script.Parent.Parent
&#9;player = game.Players:GetPlayerFromCharacter(character)
&#9;if player == nil then return end
&#9;if playerOwner.Value and playerOwner.Value ~= player then return end
&#9;playerOwner.Value = player
&#9;if isRestricted then
&#9;&#9;waitForChild(game.Workspace,&quot;BuildingAreas&quot;)
&#9;&#9;waitForChild(game.Workspace.BuildingAreas,&quot;Area1&quot;)
&#9;&#9;waitForChild(game.Workspace.BuildingAreas.Area1,&quot;Player&quot;)
&#9;&#9;local areas = game.Workspace.BuildingAreas:GetChildren()
&#9;&#9;for i = 1, #areas do
&#9;&#9;&#9;if areas[i]:FindFirstChild(&quot;Player&quot;) and areas[i].Player.Value == player.Name then
&#9;&#9;&#9;&#9;playerArea = areas[i]
&#9;&#9;&#9;&#9;break
&#9;&#9;&#9;end
&#9;&#9;end
&#9;&#9;waitForChild(playerArea,&quot;PlayerArea&quot;)
&#9;&#9;STATIC_BASE_PLATE = playerArea.PlayerArea
&#9;end
&#9;if not screen then
&#9;&#9;screen = Instance.new(&quot;BillboardGui&quot;)
&#9;&#9;screen.Name = &quot;ConfigGui&quot;
&#9;&#9;screen.Size = UDim2.new(0,360,0,180)
&#9;&#9;screen.Enabled = false
&#9;&#9;screen.Active = true
&#9;&#9;screen.Parent = player.PlayerGui
&#9;&#9;screen.AlwaysOnTop = true
&#9;&#9;guiMain = Instance.new(&quot;Frame&quot;)
&#9;&#9;guiMain.BackgroundTransparency = 1
&#9;&#9;guiMain.Size = UDim2.new(1,0,1,0)
&#9;&#9;guiMain.Parent = screen
&#9;else
&#9;&#9;removeBillboards()
&#9;&#9;lastPart = nil
&#9;&#9;screen.Parent = player.PlayerGui
&#9;end
&#9;setUpConfigurationService(guiMain)
&#9;showConfigurationAnnotations()
&#9;mouse.Icon = &quot;http://www.roblox.com/asset?id=66887593&quot;
&#9;mouse.Button1Up:connect(function() on3dButton1Up(mouse, guiMain, player.PlayerGui) end)
&#9;mouse.Move:connect(function() on3dMouseMove(mouse, guiMain) end)
&#9;objectValueSelect.HoverBox = Instance.new(&quot;SelectionBox&quot;)
&#9;objectValueSelect.HoverBox.Name = &quot;HoverBox&quot;
&#9;objectValueSelect.HoverBox.Color = BrickColor.new(&quot;Really blue&quot;)
&#9;objectValueSelect.HoverBox.Transparency = 0.5
&#9;objectValueSelect.HoverBox.Adornee = nil
&#9;objectValueSelect.HoverBox.Parent = player.PlayerGui;
end
function onUnequippedLocal()
&#9;local guiChildren = game.Players.LocalPlayer.PlayerGui:GetChildren()
&#9;for i = 1, #guiChildren do
&#9;&#9;if guiChildren[i]:IsA(&quot;BillboardGui&quot;) then
&#9;&#9;&#9;guiChildren[i].Parent = nil
&#9;&#9;end
&#9;end
&#9;destroyConfigurationService()
&#9;objectValueSelect.HoverBox:Remove()
&#9;if screen then
&#9;&#9;screen.Parent = nil
&#9;end
&#9;player = nil
&#9;hideConfigurationAnnotations()
&#9;objectValueSelect = {}
end
local configTable = {}
function createVisualAnnotation(config, guiMain)
&#9;local selection = Instance.new(&quot;SelectionBox&quot;)
&#9;selection.Name = &quot;Annotation&quot;
&#9;selection.Color = BrickColor.new(&quot;Really blue&quot;)
&#9;selection.Transparency = 0.5
&#9;selection.Parent = guiMain.Parent
&#9;return selection
end
function configurationParentChanged(data, part)
&#9;local isModel, model = isInModel(part)
&#9;if not isModel then
&#9;&#9;data[&quot;VisualAnnotation&quot;].Adornee = part
&#9;else
&#9;&#9;data[&quot;VisualAnnotation&quot;].Adornee = model
&#9;end
end
function showConfigurationAnnotations()
&#9;for config, data in pairs(configTable) do
&#9;&#9;data[&quot;VisualAnnotation&quot;].Visible = true
&#9;end
end
function hideConfigurationAnnotations()
&#9;for config, data in pairs(configTable) do
&#9;&#9;data[&quot;VisualAnnotation&quot;].Visible = false
&#9;end
end
local function isInMyArea(part)
&#9;if part.Parent == nil then return false end
&#9;if part.Parent:FindFirstChild(&quot;Player&quot;) and part.Parent.Player:IsA(&quot;StringValue&quot;) then
&#9;&#9;if part.Parent.Player.Value == player.Name then
&#9;&#9;&#9;return true
&#9;&#9;else
&#9;&#9;&#9;return false
&#9;&#9;end
&#9;elseif part.Parent == game.Workspace.BuildingAreas or part.Parent == game.Workspace then
&#9;&#9;return false
&#9;else
&#9;&#9;return isInMyArea(part.Parent)
&#9;end
end
function findBillboard(guiTable)
&#9;if not guiTable then return end
&#9;for i = 1, #guiTable do
&#9;&#9;if guiTable[i] and guiTable[i]:IsA(&quot;BillboardGui&quot;) then
&#9;&#9;&#9;return guiTable[i]
&#9;&#9;end
&#9;end
end
function getBillboard(adornee)
&#9;local guiKey = adornee
&#9;
&#9;local billboard = findBillboard(adornmentTable[guiKey])
&#9;if not billboard then
&#9;&#9;local screen = Instance.new(&quot;BillboardGui&quot;)
&#9;&#9;screen.Name = adornee.Name .. &quot;BadgeGUI&quot;
&#9;&#9;screen.Size = UDim2.new(1.5,0,1.5,0)
&#9;&#9;screen.Enabled = true
&#9;&#9;screen.Active = true
&#9;&#9;screen.AlwaysOnTop = true
&#9;&#9;screen.ExtentsOffset = Vector3.new(0,0,0)
&#9;&#9;screen.Adornee = adornee
&#9;&#9;screen.Parent = game.Players.LocalPlayer.PlayerGui
&#9;&#9;if not adornmentTable[guiKey] then
&#9;&#9;&#9;adornmentTable[guiKey] = {}
&#9;&#9;end
&#9;&#9;table.insert(adornmentTable[guiKey],screen)
&#9;&#9;return screen
&#9;end
&#9;return billboard
end
function hasBadge(adornee)
&#9;local screen = getBillboard(adornee)
&#9;if not screen then return false end
&#9;return screen:FindFirstChild(&quot;Badge&quot;,true)
end
function removeBadge(adornee)
&#9;local screen = getBillboard(adornee)
&#9;local badge = screen:FindFirstChild(&quot;ConfigBadge&quot;,true)
&#9;if badge then badge:remove() end
end
function giveConfigBadge(adornee)
&#9;local billboard = getBillboard(adornee)
&#9;local configBadge = Instance.new(&quot;ImageLabel&quot;)
&#9;configBadge.Name = &quot;ConfigBadge&quot;
&#9;configBadge.BackgroundTransparency = 1
&#9;configBadge.Image = configIconImage
&#9;configBadge.Size = UDim2.new(1,0,1,0)
&#9;configBadge.Parent = billboard
&#9;billboard.Parent = game.Players.LocalPlayer.PlayerGui
&#9;local badgeCon = configBadge.Changed:connect(function(prop)
&#9;&#9;if prop == &quot;AbsoluteSize&quot; then
&#9;&#9;&#9;configBadge.Visible = (configBadge.AbsoluteSize.X &gt; 10)
&#9;&#9;end
&#9;end)
&#9;local enterCon = configBadge.MouseEnter:connect(function()
&#9;&#9;configBadge.Image = configIconHoverImage
&#9;end)
&#9;local leaveCon = configBadge.MouseLeave:connect(function()
&#9;&#9;configBadge.Image = configIconImage
&#9;end)
&#9;local killCon = nil
&#9;killCon = configBadge.AncestryChanged:connect(function(child,parent)
&#9;&#9;if parent == nil then
&#9;&#9;&#9;killCon:disconnect()
&#9;&#9;&#9;badgeCon:disconnect()
&#9;&#9;&#9;enterCon:disconnect()
&#9;&#9;&#9;leaveCon:disconnect()
&#9;&#9;end
&#9;end)
end
function configurationAdded(config, guiMain)
&#9;if configTable[config] then
&#9;&#9;return
&#9;end
&#9;if isRestricted and not inBaseplate(config) then return end
&#9;
&#9;local data = {}
&#9;data.Configuration = config
&#9;data.VisualAnnotation = createVisualAnnotation(config, guiMain)
&#9;if config:IsA(&quot;Configuration&quot;) then
&#9;&#9;data.Connection = config.AncestryChanged:connect(function(child, newParent)
&#9;&#9;&#9;if child == config then
&#9;&#9;&#9;&#9;configurationParentChanged(data, newParent)
&#9;&#9;&#9;end
&#9;&#9;end)
&#9;&#9;configurationParentChanged(data, config.Parent)
&#9;else
&#9;&#9;configurationParentChanged(data, config)
&#9;end
&#9;local partInModel, model = isInModel(config.Parent)
&#9;if partInModel then
&#9;&#9;if not hasBadge(model) then
&#9;&#9;&#9;giveConfigBadge(model)
&#9;&#9;end
&#9;else
&#9;&#9;if not hasBadge(config.Parent) then
&#9;&#9;&#9;giveConfigBadge(config.Parent)
&#9;&#9;end
&#9;end
&#9;configTable[config] = data
end
function configurationRemoved(config)
&#9;local data = configTable[config]&#9;
&#9;if not(data) then
&#9;&#9;--I have no opinion about this
&#9;&#9;return
&#9;end
&#9;if data.Connection then
&#9;&#9;data.Connection:disconnect()
&#9;end
&#9;data.VisualAnnotation:Remove()
&#9;removeBadge(config.Parent)
&#9;
&#9;configTable[config] = nil
end
function findVehicleSeats(object, guiMain)
&#9;if object:IsA(&quot;VehicleSeat&quot;) then
&#9;&#9;configurationAdded(object, guiMain)
&#9;end
&#9;for index,child in pairs(object:GetChildren()) do
&#9;&#9;findVehicleSeats(child, guiMain)
&#9;end
end
function setUpConfigurationService(guiMain)
&#9;ServiceConnections = {}
&#9;local collectionService = game:GetService(&quot;CollectionService&quot;)
&#9;ServiceConnections[#ServiceConnections+1] = collectionService.ItemAdded:connect(function(instance) if instance:IsA(&quot;Configuration&quot;) then configurationAdded(instance, guiMain) end end)
&#9;ServiceConnections[#ServiceConnections+1] = collectionService.ItemRemoved:connect(function(instance) if instance:IsA(&quot;Configuration&quot;) then configurationRemoved(instance) end end)
&#9;local configs = collectionService:GetCollection(&quot;Configuration&quot;)
&#9;if configs then
&#9;&#9;for pos, config in pairs(configs) do
&#9;&#9;&#9;configurationAdded(config, guiMain)
&#9;&#9;end
&#9;end
&#9;ServiceConnections[#ServiceConnections+1] = game.workspace.DescendantAdded:connect(function(instance) if instance:IsA(&quot;VehicleSeat&quot;) then configurationAdded(instance, guiMain) end end)
&#9;ServiceConnections[#ServiceConnections+1] = game.workspace.DescendantRemoving:connect(function(instance) if instance:IsA(&quot;VehicleSeat&quot;) then configurationRemoved(instance) end end)
&#9;findVehicleSeats(game.workspace, guiMain)
end
function destroyConfigurationService()
&#9;for config, data in pairs(configTable) do
&#9;&#9;configurationRemoved(config)
&#9;end
&#9;for index, connection in pairs(ServiceConnections) do
&#9;&#9;connection:disconnect()
&#9;end
&#9;ServiceConnections = {}
end
Tool.Equipped:connect(onEquippedLocal)
Tool.Unequipped:connect(onUnequippedLocal)</ProtectedString>
</Properties>
</Item>
<Item class="ObjectValue" referent="RBX4">
<Properties>
<string name="Name">PlayerOwner</string>
<Ref name="Value">null</Ref>
</Properties>
</Item>
</Item>
</roblox>