mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-04 20:57:49 +00:00
1009 lines
28 KiB
Lua
1009 lines
28 KiB
Lua
local on = false
|
|
local showingWires = false
|
|
local allWires = {}
|
|
|
|
---------------
|
|
--PLUGIN SETUP-
|
|
---------------
|
|
self = PluginManager():CreatePlugin()
|
|
self.Deactivation:connect(function () Off() end)
|
|
toolbar = self:CreateToolbar("Wiring")
|
|
toolbarbutton = toolbar:CreateButton("", "Hook up CustomEvent and CustomEventReceivers", "wiring.png")
|
|
toolbarbutton.Click:connect(function()
|
|
if on then
|
|
Off()
|
|
else
|
|
On()
|
|
end
|
|
end)
|
|
allWiresButton = toolbar:CreateButton("", "Show current connections", "showWires.png")
|
|
allWiresButton.Click:connect(function()
|
|
if showingWires then
|
|
hideAllWires()
|
|
else
|
|
showAllWires()
|
|
end
|
|
end)
|
|
|
|
local g = nil
|
|
local indicatorArrow = nil
|
|
local indicatorBox = nil
|
|
local storedTerminal = nil
|
|
local wires = {}
|
|
local WHITE_COLOR = Color3.new(1, 1, 1)
|
|
local BASE_WIRE_COLOR = BrickColor.new("Really black")
|
|
local BASE_WIRE_RADIUS = 0.0625
|
|
local HOVER_WIRE_COLOR = BrickColor.new("Really red")
|
|
local HOVER_WIRE_RADIUS = 0.125
|
|
local SOURCE_BUTTON_TEXT_COLOR = Color3.new(1, .5, 0)
|
|
local SOURCE_BUTTON_ICON_TEXTURE = "http://www.watrbx.wtf/asset/?id=55130296"
|
|
local SOURCE_BUTTON_ICON_HOVER_TEXTURE = "http://www.watrbx.wtf/asset/?id=56953981"
|
|
local SINK_BUTTON_TEXT_COLOR = Color3.new(0, 1, 0)
|
|
local SINK_BUTTON_ICON_TEXTURE = "http://www.watrbx.wtf/asset/?id=55130274"
|
|
local SINK_BUTTON_ICON_HOVER_TEXTURE = "http://www.watrbx.wtf/asset/?id=56953950"
|
|
local SELECT_CONNECTION = nil
|
|
local DOWN_ARROW_TEXTURE = "http://www.watrbx.wtf/asset/?id=48972653"
|
|
local SOURCE_BADGE_TEXTURE = "http://www.watrbx.wtf/asset/?id=60730993"
|
|
local SINK_BADGE_TEXTURE = "http://www.watrbx.wtf/asset/?id=61334830"
|
|
local PENDING_LEAVE_CALLBACK = nil
|
|
local receiverTable = {}
|
|
local eventTable = {}
|
|
local adornmentTable = {}
|
|
local receiverBadgeCount = {}
|
|
local eventBadgeCount = {}
|
|
|
|
self:GetMouse().Button1Down:connect(function ()
|
|
local target = self:GetMouse().Target
|
|
if target ~= nil then
|
|
while target.Parent ~= game.Workspace do
|
|
target = target.Parent
|
|
end
|
|
end
|
|
game.Selection:Set({target})
|
|
end)
|
|
self:GetMouse().KeyDown:connect(function (key)
|
|
if string.byte(key) == 27 then
|
|
game.Selection:Set({})
|
|
end
|
|
end)
|
|
|
|
function getIndicator()
|
|
if indicatorArrow == nil then
|
|
indicatorArrow = Instance.new("BillboardGui", game:GetService("CoreGui"))
|
|
indicatorArrow.Active = true
|
|
indicatorArrow.AlwaysOnTop = true
|
|
indicatorArrow.Size = UDim2.new(4, 0, 4, 0)
|
|
indicatorArrow.StudsOffset = Vector3.new(0, 2, 0)
|
|
|
|
local frame = Instance.new("Frame", indicatorArrow)
|
|
frame.Active = true
|
|
frame.BackgroundTransparency = 1
|
|
frame.Size = UDim2.new(1, 0, 1, 0)
|
|
|
|
local arrow = Instance.new("ImageLabel", frame)
|
|
arrow.BackgroundTransparency = 1
|
|
arrow.Image = DOWN_ARROW_TEXTURE
|
|
arrow.Size = UDim2.new(1, 0, 1, 0)
|
|
end
|
|
return indicatorArrow
|
|
end
|
|
|
|
function getIndicatorBox()
|
|
if indicatorBox == nil then
|
|
indicatorBox = Instance.new("SelectionBox", game:GetService("CoreGui"))
|
|
indicatorBox.Color = BrickColor.new("New Yeller")
|
|
indicatorBox.Adornee = nil
|
|
end
|
|
return indicatorBox
|
|
end
|
|
|
|
function refreshScreenGui()
|
|
if g ~= nil then
|
|
g:Remove()
|
|
end
|
|
for idx, wire in ipairs(wires) do
|
|
wire:Remove()
|
|
end
|
|
g = Instance.new("ScreenGui", game:GetService("CoreGui"))
|
|
|
|
getIndicator().Adornee = nil
|
|
getIndicatorBox().Adornee = nil
|
|
|
|
if storedTerminal ~= nil then
|
|
handleStoredTerminal(g)
|
|
end
|
|
|
|
selected = game.Selection:Get()
|
|
if #selected == 0 then
|
|
return
|
|
elseif #selected > 1 then
|
|
handleContainer(g, selected)
|
|
elseif selected[1]:IsA("CustomEvent") then
|
|
handleTerminal(g, selected[1], function(customEvent) return customEvent:GetAttachedReceivers() end)
|
|
getIndicatorBox().Adornee = selected.Parent
|
|
elseif selected[1]:IsA("CustomEventReceiver") then
|
|
handleTerminal(g, selected[1], function(customEventReceiver) return { customEventReceiver.Source } end)
|
|
getIndicatorBox().Adornee = selected.Parent
|
|
elseif selected[1] ~= game.Workspace then
|
|
handleContainer(g, selected)
|
|
end
|
|
end
|
|
|
|
function On()
|
|
RbxGui = LoadLibrary("RbxGui")
|
|
|
|
setUpConfigurationService()
|
|
|
|
self:Activate(true)
|
|
SELECT_CONNECTION = game.Selection.SelectionChanged:connect(refreshScreenGui)
|
|
refreshScreenGui()
|
|
|
|
toolbarbutton:SetActive(true)
|
|
on = true
|
|
end
|
|
|
|
function Off()
|
|
destroyConfigurationService()
|
|
|
|
storedTerminal = nil
|
|
if g ~= nil then
|
|
g:Remove()
|
|
g = nil
|
|
end
|
|
for idx, wire in ipairs(wires) do
|
|
wire:Remove()
|
|
end
|
|
wires = {}
|
|
SELECT_CONNECTION:disconnect()
|
|
getIndicator().Adornee = nil
|
|
|
|
toolbarbutton:SetActive(false)
|
|
on = false
|
|
end
|
|
|
|
function IsChildOfWorkspace(instance)
|
|
return instance ~= nil and (instance == game.Workspace or IsChildOfWorkspace(instance.Parent))
|
|
end
|
|
|
|
function findModel(part)
|
|
local origPart = part
|
|
while part ~= nil do
|
|
if part.className == "Model" then
|
|
return part
|
|
elseif part.Name == "Workspace" or part.Name == "game" then
|
|
return origPart
|
|
end
|
|
part = part.Parent
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
----------------------------------------------------------
|
|
-- Left Side Popup when CustomEvent/Receiver is selected
|
|
|
|
function applyTextSize(label, text)
|
|
label.Size = UDim2.new(0, label.TextBounds.x, 0, label.TextBounds.y)
|
|
end
|
|
|
|
function handleConnect(terminal)
|
|
if storedTerminal == nil then
|
|
storedTerminal = terminal
|
|
return
|
|
else
|
|
local storedIsSource = storedTerminal:IsA("CustomEvent")
|
|
local newIsSource = terminal:IsA("CustomEvent")
|
|
if storedIsSource and not newIsSource then
|
|
terminal.Source = storedTerminal
|
|
storedTerminal = nil
|
|
game:GetService("ChangeHistoryService"):SetWaypoint("Wiring")
|
|
elseif not storedIsSource and newIsSource then
|
|
storedTerminal.Source = terminal
|
|
storedTerminal = nil
|
|
game:GetService("ChangeHistoryService"):SetWaypoint("Wiring")
|
|
else
|
|
storedTerminal = terminal
|
|
end
|
|
end
|
|
end
|
|
|
|
function disconnectHelper(terminal1, terminal2)
|
|
if terminal1:IsA("CustomEvent") then
|
|
terminal2.Source = nil
|
|
else
|
|
terminal1.Source = nil
|
|
end
|
|
game:GetService("ChangeHistoryService"):SetWaypoint("Disconnect wiring")
|
|
end
|
|
|
|
function createModelLine(frame, yOffset, terminal)
|
|
local model = findParentUnderWorkspace(terminal)
|
|
|
|
local button = Instance.new("TextButton", frame)
|
|
button.Text = "Top parent: " .. model.Name
|
|
button.Font = Enum.Font.Arial
|
|
button.FontSize = Enum.FontSize.Size14
|
|
button.BackgroundTransparency = .5
|
|
button.TextColor3 = WHITE_COLOR
|
|
button.BorderSizePixel = 0
|
|
applyTextSize(button)
|
|
button.Position = UDim2.new(0, 0, 0, yOffset)
|
|
button.MouseButton1Click:connect(function () game.Selection:Set({model}) end)
|
|
|
|
return button
|
|
end
|
|
|
|
function createParentLine(frame, yOffset, terminal)
|
|
local parent = terminal.Parent
|
|
|
|
local button = Instance.new("TextButton", frame)
|
|
button.Text = "Parent: " .. parent.Name
|
|
button.Font = Enum.Font.Arial
|
|
button.FontSize = Enum.FontSize.Size14
|
|
button.BackgroundTransparency = .5
|
|
button.TextColor3 = WHITE_COLOR
|
|
button.BorderSizePixel = 0
|
|
applyTextSize(button)
|
|
button.Position = UDim2.new(0, 0, 0, yOffset)
|
|
button.MouseButton1Click:connect(function () game.Selection:Set({parent}) end)
|
|
|
|
return button
|
|
end
|
|
|
|
function createTerminalElement(type, frame, font, yOffset, terminal, dontShowParent)
|
|
local button = Instance.new(type, frame)
|
|
|
|
local icon = Instance.new("ImageLabel", button)
|
|
icon.Position = UDim2.new(0, 0, 0, -8)
|
|
icon.Size = UDim2.new(0, 35, 0 , 35)
|
|
icon.BackgroundTransparency = 1
|
|
|
|
if dontShowParent then
|
|
button.Text = terminal.Name
|
|
else
|
|
button.Text = terminal.Name .. " (" .. terminal.Parent.Name .. ")"
|
|
end
|
|
button.TextXAlignment = 1 -- right
|
|
button.Font = font
|
|
button.FontSize = Enum.FontSize.Size18
|
|
button.BorderSizePixel = 0
|
|
button.BackgroundTransparency = .5
|
|
applyTextSize(button)
|
|
button.Position = UDim2.new(0, 0, 0, yOffset)
|
|
|
|
if terminal:IsA("CustomEvent") then
|
|
button.TextColor3 = SOURCE_BUTTON_TEXT_COLOR
|
|
icon.Image = SOURCE_BUTTON_ICON_TEXTURE
|
|
else
|
|
button.TextColor3 = SINK_BUTTON_TEXT_COLOR
|
|
icon.Image = SINK_BUTTON_ICON_TEXTURE
|
|
end
|
|
|
|
button.Size = UDim2.new(0, button.Size.X.Offset + 35 + 10, 0, button.Size.Y.Offset)
|
|
|
|
return button
|
|
end
|
|
|
|
function createTextLabelHeader(labelParent, yOffset, text)
|
|
local label = Instance.new("TextLabel", labelParent)
|
|
label.Text = text
|
|
label.Font = Enum.Font.ArialBold
|
|
label.FontSize = Enum.FontSize.Size18
|
|
label.TextColor3 = WHITE_COLOR
|
|
label.BorderSizePixel = 0
|
|
label.BackgroundTransparency = 1
|
|
label.Position = UDim2.new(0, 0, 0, yOffset)
|
|
applyTextSize(label)
|
|
return label
|
|
end
|
|
|
|
function createTextLabel(labelParent, yOffset, childName, parentName)
|
|
local label = Instance.new("TextButton", labelParent)
|
|
label.Text = childName .. " (" .. parentName .. ")"
|
|
label.Font = Enum.Font.Arial
|
|
label.FontSize = Enum.FontSize.Size18
|
|
label.TextColor3 = WHITE_COLOR
|
|
label.BorderSizePixel = 0
|
|
label.BackgroundTransparency = .5
|
|
-- label.Position = UDim2.new(0, 0, 0, yOffset)
|
|
applyTextSize(label)
|
|
return label
|
|
end
|
|
|
|
function createDisconnectButton(frame, xOffset, yOffset, rcb)
|
|
local button = Instance.new("TextButton", frame)
|
|
button.Text = "Disconnect"
|
|
button.Font = Enum.Font.ArialBold
|
|
button.FontSize = Enum.FontSize.Size18
|
|
button.TextColor3 = WHITE_COLOR
|
|
applyTextSize(button)
|
|
button.BorderSizePixel = 0
|
|
button.BackgroundTransparency = 0.5
|
|
button.Position = UDim2.new(1, -button.Size.X.Offset - 2, 0, 0)
|
|
button.MouseButton1Click:connect(rcb)
|
|
return button
|
|
end
|
|
|
|
function createWire(terminal1, terminal2)
|
|
local from = nil
|
|
local to = nil
|
|
if terminal1:IsA("CustomEvent") then
|
|
from = terminal1.Parent
|
|
to = terminal2.Parent
|
|
else
|
|
from = terminal2.Parent
|
|
to = terminal1.Parent
|
|
end
|
|
|
|
local wire = Instance.new("FloorWire", game:GetService("CoreGui"))
|
|
wire.From = from
|
|
wire.To = to
|
|
wire.Color = BASE_WIRE_COLOR
|
|
wire.WireRadius = BASE_WIRE_RADIUS
|
|
table.insert(wires, wire)
|
|
|
|
if showingWires then
|
|
local wireCopy = Instance.new("FloorWire", game:GetService("CoreGui"))
|
|
wireCopy.From = wire.From
|
|
wireCopy.To = wire.To
|
|
wireCopy.Color = wire.Color
|
|
wireCopy.WireRadius = wire.WireRadius
|
|
table.insert(allWires, wireCopy)
|
|
end
|
|
return wire
|
|
end
|
|
|
|
function createNoneLabel(frame, yOffset)
|
|
local label = Instance.new("TextLabel", frame)
|
|
label.Text = "-- none --"
|
|
label.Font = Enum.Font.Arial
|
|
label.FontSize = Enum.FontSize.Size18
|
|
label.TextColor3 = WHITE_COLOR
|
|
label.BorderSizePixel = 0
|
|
label.BackgroundTransparency = 1
|
|
label.Position = UDim2.new(0, 0, 0, yOffset)
|
|
applyTextSize(label)
|
|
return label
|
|
end
|
|
|
|
function createConnectButton(frame, yOffset, terminal)
|
|
local button = Instance.new("TextButton", frame)
|
|
|
|
if storedTerminal == nil then
|
|
button.Text = "Add Connection"
|
|
else
|
|
local storedIsSource = storedTerminal:IsA("CustomEvent")
|
|
local terminalIsSource = terminal:IsA("CustomEvent")
|
|
if storedIsSource ~= terminalIsSource then
|
|
button.Text = "Connect to " .. storedTerminal.Name .. " (" .. storedTerminal.Parent.Name .. ")"
|
|
else
|
|
button.Text = "Add Connection"
|
|
end
|
|
end
|
|
button.Font = Enum.Font.ArialBold
|
|
button.FontSize = Enum.FontSize.Size18
|
|
button.TextColor3 = WHITE_COLOR
|
|
applyTextSize(button)
|
|
button.BorderSizePixel = 0
|
|
button.BackgroundTransparency = 0.5
|
|
button.Position = UDim2.new(0, 0, 0, yOffset)
|
|
|
|
return button
|
|
end
|
|
|
|
function handleTerminal(screenGui, terminal, getAttached)
|
|
local frame = Instance.new("Frame", screenGui)
|
|
frame.Style = Enum.FrameStyle.RobloxRound
|
|
frame.Visible = true
|
|
local yOffset = 0
|
|
local maxX = 0
|
|
|
|
local title = createTerminalElement("TextLabel", frame, Enum.Font.ArialBold, yOffset, terminal, true)
|
|
title.BackgroundTransparency = 1
|
|
yOffset = yOffset + title.Size.Y.Offset + 2
|
|
maxX = math.max(maxX, title.Size.X.Offset)
|
|
|
|
local modelLine = createModelLine(frame, yOffset, terminal)
|
|
yOffset = yOffset + modelLine.Size.Y.Offset + 2
|
|
maxX = math.max(maxX, modelLine.Size.X.Offset)
|
|
|
|
local parentLine = createParentLine(frame, yOffset, terminal)
|
|
yOffset = yOffset + parentLine.Size.Y.Offset + 12.5
|
|
maxX = math.max(maxX, parentLine.Size.X.Offset)
|
|
|
|
local header = createTextLabelHeader(frame, yOffset, "Connections")
|
|
yOffset = yOffset + header.Size.Y.Offset + 3
|
|
maxX = math.max(maxX, header.Size.X.Offset)
|
|
|
|
local attached = getAttached(terminal)
|
|
|
|
local scrollHolder = Instance.new("Frame", frame)
|
|
local scrollYOffset = 0
|
|
local scrollFrame, scrollUp, scrollDown, recalculateScroll = RbxGui.CreateScrollingFrame()
|
|
scrollFrame.Parent = scrollHolder
|
|
scrollUp.Parent = scrollHolder
|
|
scrollDown.Parent = scrollHolder
|
|
for idx, other in ipairs(attached) do
|
|
if IsChildOfWorkspace(other) then
|
|
local rowFrame = Instance.new("Frame", scrollFrame)
|
|
rowFrame.BackgroundTransparency = 1
|
|
rowFrame.BorderSizePixel = 0
|
|
|
|
local label = createTextLabel(rowFrame, scrollYOffset, other.Name, other.Parent.Name)
|
|
label.MouseButton1Click:connect(function () game.Selection:Set({other}) end)
|
|
label.MouseEnter:connect(function() getIndicator().Adornee = other.Parent end)
|
|
label.MouseLeave:connect(function() getIndicator().Adornee = nil end)
|
|
|
|
local button = createDisconnectButton(rowFrame, label.Size.X.Offset, scrollYOffset,
|
|
function()
|
|
disconnectHelper(terminal, other)
|
|
refreshScreenGui()
|
|
end)
|
|
local wire = createWire(terminal, other)
|
|
label.MouseEnter:connect(function() wire.WireRadius = HOVER_WIRE_RADIUS end)
|
|
label.MouseLeave:connect(function() wire.WireRadius = BASE_WIRE_RADIUS end)
|
|
button.MouseEnter:connect(function()
|
|
wire.Color = HOVER_WIRE_COLOR
|
|
wire.WireRadius = HOVER_WIRE_RADIUS
|
|
end)
|
|
button.MouseLeave:connect(function()
|
|
wire.Color = BASE_WIRE_COLOR
|
|
wire.WireRadius = BASE_WIRE_RADIUS
|
|
end)
|
|
|
|
rowFrame.Size = UDim2.new(1, 0, 0, label.Size.Y.Offset + 5)
|
|
scrollYOffset = scrollYOffset + rowFrame.Size.Y.Offset
|
|
maxX = math.max(maxX, label.Size.X.Offset + 3 + button.Size.X.Offset)
|
|
end
|
|
end
|
|
|
|
if #attached == 0 then
|
|
local label = createNoneLabel(frame, yOffset)
|
|
scrollYOffset = scrollYOffset + label.Size.Y.Offset + 3
|
|
maxX = math.max(maxX, label.Size.X.Offset)
|
|
end
|
|
|
|
if #attached < 4 then
|
|
scrollUp.Visible = false
|
|
scrollDown.Visible = false
|
|
end
|
|
|
|
scrollFrame.Size = UDim2.new(1, -scrollUp.Size.X.Offset, 1, 0)
|
|
scrollUp.Position = UDim2.new(1, -scrollUp.Size.X.Offset, 0, 0)
|
|
scrollDown.Position = UDim2.new(1, -scrollDown.Size.X.Offset, 1, -scrollDown.Size.Y.Offset)
|
|
scrollHolder.Position = UDim2.new(0, 0, 0, yOffset)
|
|
scrollHolder.Size = UDim2.new(1, 0, 0, math.min(70, scrollYOffset))
|
|
|
|
scrollHolder.BackgroundTransparency = 1
|
|
scrollHolder.BorderSizePixel = 0
|
|
scrollFrame.BackgroundTransparency = 1
|
|
scrollFrame.BorderSizePixel = 0
|
|
|
|
-- give room for scroll bars
|
|
maxX = maxX + scrollUp.Size.X.Offset + 3
|
|
yOffset = yOffset + scrollHolder.Size.Y.Offset
|
|
|
|
-- add another gap before the connect button
|
|
yOffset = yOffset + 12.5
|
|
local connect = createConnectButton(frame, yOffset, terminal)
|
|
connect.MouseButton1Click:connect(function ()
|
|
handleConnect(terminal)
|
|
refreshScreenGui()
|
|
end)
|
|
maxX = math.max(maxX, connect.Size.X.Offset)
|
|
|
|
|
|
frame.Size = UDim2.new(0, maxX + 17.5, 0, yOffset + connect.Size.Y.Offset + 17.5)
|
|
recalculateScroll()
|
|
frame.BackgroundTransparency = 0.5
|
|
delay(0, function()
|
|
local etime = time() + 10
|
|
while time() < etime do
|
|
recalculateScroll()
|
|
wait(.5)
|
|
end
|
|
end)
|
|
|
|
end
|
|
|
|
--------------------------------------------------
|
|
-- Left Side Popup when non-terminal is selected
|
|
|
|
function collectTerminalsHelper(root, terminals)
|
|
if root:IsA("CustomEvent") or root:IsA("CustomEventReceiver") then
|
|
table.insert(terminals, root)
|
|
end
|
|
for idx, child in ipairs(root:GetChildren()) do
|
|
collectTerminals(child, terminals)
|
|
end
|
|
end
|
|
|
|
function collectTerminals(root, terminals)
|
|
collectTerminalsHelper(root, terminals)
|
|
table.sort(terminals, function (item1, item2)
|
|
local item1IsSource = item1:IsA("CustomEvent")
|
|
local item2IsSource = item2:IsA("CustomEvent")
|
|
if item1IsSource and not item2IsSource then
|
|
return true
|
|
elseif item2IsSource and not item1IsSource then
|
|
return false
|
|
else
|
|
return item1.Name < item2.Name
|
|
end
|
|
end)
|
|
end
|
|
|
|
function handleContainer(screenGui, root)
|
|
local frame = Instance.new("Frame", screenGui)
|
|
frame.Style = Enum.FrameStyle.RobloxRound
|
|
frame.Visible = true
|
|
local yOffset = 0
|
|
local maxX = 0
|
|
|
|
local header = createTextLabelHeader(frame, yOffset, "Custom Events and Receivers")
|
|
yOffset = yOffset + header.Size.Y.Offset + 3
|
|
maxX = header.Size.X.Offset
|
|
|
|
local terminals = {}
|
|
for idx, sel in ipairs(root) do
|
|
if sel ~= game.Workspace then
|
|
collectTerminals(sel, terminals)
|
|
end
|
|
end
|
|
|
|
local scrollHolder = Instance.new("Frame", frame)
|
|
scrollHolder.BackgroundTransparency = 1
|
|
scrollHolder.BorderSizePixel = 0
|
|
local scrollFrame, scrollUp, scrollDown, recalculateScroll = RbxGui.CreateScrollingFrame()
|
|
scrollFrame.BackgroundTransparency = 1
|
|
scrollFrame.BorderSizePixel = 0
|
|
scrollFrame.Parent = scrollHolder
|
|
scrollUp.Parent = scrollHolder
|
|
scrollDown.Parent = scrollHolder
|
|
scrollHolder.Position = UDim2.new(0, 0, 0, yOffset)
|
|
|
|
for idx, terminal in ipairs(terminals) do
|
|
local button = createTerminalElement("TextButton", frame, Enum.Font.Arial, yOffset, terminal)
|
|
button.MouseButton1Click:connect(function ()
|
|
game.Selection:Set({terminal})
|
|
end)
|
|
button.MouseEnter:connect(function () getIndicator().Adornee = terminal.Parent end)
|
|
button.MouseLeave:connect(function () getIndicator().Adornee = nil end)
|
|
yOffset = yOffset + button.Size.Y.Offset + 3
|
|
maxX = math.max(maxX, button.Size.X.Offset)
|
|
end
|
|
|
|
if #terminals == 0 then
|
|
local label = createNoneLabel(frame, yOffset)
|
|
yOffset = yOffset + label.Size.Y.Offset + 3
|
|
maxX = math.max(maxX, label.Size.X.Offset)
|
|
end
|
|
|
|
if #terminals < 2 then
|
|
scrollUp.Visible = false
|
|
scrollDown.Visible = false
|
|
end
|
|
|
|
scrollFrame.Size = UDim2.new(1, -scrollUp.Size.X.Offset, 1, 0)
|
|
scrollUp.Position = UDim2.new(1, -scrollUp.Size.X.Offset, 0, 0)
|
|
scrollDown.Position = UDim2.new(1, -scrollDown.Size.X.Offset, 1, -scrollDown.Size.Y.Offset)
|
|
scrollHolder.Size = UDim2.new(1, 0, 0, yOffset - (header.Size.Y.Offset + 3))
|
|
recalculateScroll()
|
|
maxX = maxX + scrollUp.Size.X.Offset
|
|
|
|
frame.Size = UDim2.new(0, maxX + 17.5, 0, yOffset + 17.5)
|
|
frame.BackgroundTransparency = 0.5
|
|
end
|
|
|
|
----------------------------------------------------------
|
|
-- Right side gui when connecting a CustomEvent/Receiver
|
|
|
|
function findParentUnderWorkspace(instance)
|
|
while instance.Parent ~= game.Workspace and instance.Parent ~= nil do
|
|
instance = instance.Parent
|
|
end
|
|
return instance
|
|
end
|
|
|
|
function createCancelButton(frame, yOffset)
|
|
local button = Instance.new("TextButton", frame)
|
|
button.Text = "Cancel"
|
|
button.Font = Enum.Font.ArialBold
|
|
button.FontSize = Enum.FontSize.Size18
|
|
button.TextColor3 = WHITE_COLOR
|
|
applyTextSize(button)
|
|
button.BorderSizePixel = 0
|
|
button.BackgroundTransparency = 0.5
|
|
button.Position = UDim2.new(1, -button.Size.X.Offset, 0, yOffset)
|
|
button.MouseButton1Click:connect(function ()
|
|
storedTerminal = nil
|
|
refreshScreenGui()
|
|
end)
|
|
return button
|
|
end
|
|
|
|
function handleStoredTerminal(screenGui)
|
|
if storedTerminal == nil then return end
|
|
|
|
local frame = Instance.new("Frame", screenGui)
|
|
frame.Style = Enum.FrameStyle.RobloxRound
|
|
frame.Visible = true
|
|
local yOffset = 0
|
|
local maxX = 0
|
|
|
|
local terminalButton = createTerminalElement("TextButton", frame, Enum.Font.Arial, yOffset, storedTerminal)
|
|
terminalButton.MouseButton1Click:connect(function () game.Selection:Set({storedTerminal}) end)
|
|
yOffset = yOffset + terminalButton.Size.Y.Offset + 3
|
|
maxX = math.max(maxX, terminalButton.Size.X.Offset)
|
|
|
|
local cancelButton = createCancelButton(frame, yOffset)
|
|
yOffset = yOffset + cancelButton.Size.Y.Offset
|
|
maxX = math.max(maxX, cancelButton.Size.X.Offset)
|
|
|
|
frame.Size = UDim2.new(0, maxX + 17.5, 0, yOffset + 17.5)
|
|
frame.Position = UDim2.new(1, -frame.Size.X.Offset, 0, 0)
|
|
frame.BackgroundTransparency = 0.5
|
|
end
|
|
|
|
------------------------
|
|
-- Show/Hide All Wires
|
|
function showWiresHelper(terminal, othersFunc, completedTerminals)
|
|
local terminalIsSource = terminal:IsA("CustomEvent")
|
|
for idx, other in ipairs(othersFunc(terminal)) do
|
|
if completedTerminals[other] == nil and IsChildOfWorkspace(other) then
|
|
local wire = Instance.new("FloorWire", game:GetService("CoreGui"))
|
|
if terminalIsSource then
|
|
wire.From = terminal.Parent
|
|
wire.To = other.Parent
|
|
else
|
|
wire.From = other.Parent
|
|
wire.To = terminal.Parent
|
|
end
|
|
wire.Color = BASE_WIRE_COLOR
|
|
wire.WireRadius = BASE_WIRE_RADIUS
|
|
table.insert(allWires, wire)
|
|
end
|
|
end
|
|
completedTerminals[terminal] = true
|
|
end
|
|
|
|
|
|
function showAllWires()
|
|
allWiresButton:SetActive(true)
|
|
terminals = {}
|
|
collectTerminals(game.Workspace, terminals)
|
|
|
|
local completedTerminals = {}
|
|
for idx, terminal in ipairs(terminals) do
|
|
local othersFunc = nil
|
|
if terminal:IsA("CustomEvent") then
|
|
othersFunc = function (source) return source:GetAttachedReceivers() end
|
|
elseif terminal:IsA("CustomEventReceiver") then
|
|
othersFunc = function (sink) return { sink.Source } end
|
|
end
|
|
if othersFunc ~= nil then
|
|
showWiresHelper(terminal, othersFunc, completedTerminals)
|
|
end
|
|
end
|
|
showingWires = true
|
|
end
|
|
|
|
function hideAllWires()
|
|
allWiresButton:SetActive(false)
|
|
for idx, wire in ipairs(allWires) do
|
|
wire:Remove()
|
|
end
|
|
allWires = {}
|
|
showingWires = false
|
|
end
|
|
|
|
function refreshAllWires()
|
|
hideAllWires()
|
|
showAllWires()
|
|
end
|
|
|
|
game.DescendantAdded:connect(function (newChild)
|
|
if newChild:IsA("CustomEvent") or newChild:IsA("CustomEventReceiver") then
|
|
-- refresh screen gui now, because we may be showing the parent dialog
|
|
if on then refreshScreenGui() end
|
|
|
|
-- Attach a listener to the terminal to refresh Guis when properties changed.
|
|
-- This will catch re-wiring because connection changes show up as property
|
|
-- changes as well.
|
|
newChild.Changed:connect(function()
|
|
if on then
|
|
if showingWires then
|
|
hideAllWires()
|
|
showAllWires()
|
|
end
|
|
refreshScreenGui()
|
|
end
|
|
end)
|
|
|
|
end
|
|
end)
|
|
|
|
game.DescendantRemoving:connect(function (removed)
|
|
-- when a descendant is removed, refresh the screen gui
|
|
if on and (removed:IsA("CustomEvent") or removed:IsA("CustomEventReceiver")) then
|
|
refreshScreenGui()
|
|
end
|
|
end)
|
|
|
|
|
|
function findBillboard(guiTable)
|
|
if not guiTable then return end
|
|
|
|
for i = 1, #guiTable do
|
|
if guiTable[i] and guiTable[i]:IsA("BillboardGui") then
|
|
return guiTable[i]
|
|
end
|
|
end
|
|
end
|
|
|
|
function getBillboard(adornee)
|
|
local guiKey = adornee
|
|
|
|
|
|
local billboard = findBillboard(adornmentTable[guiKey])
|
|
if not billboard then
|
|
local screen = Instance.new("BillboardGui")
|
|
screen.Name = adornee.Name .. "BadgeGUI"
|
|
screen.Size = UDim2.new(1.5,0,1.5,0)
|
|
screen.Enabled = true
|
|
screen.Active = true
|
|
screen.AlwaysOnTop = true
|
|
screen.ExtentsOffset = Vector3.new(0,0,0)
|
|
screen.Adornee = adornee
|
|
screen.Parent = game:GetService("CoreGui")
|
|
|
|
if not adornmentTable[guiKey] then return end
|
|
table.insert(adornmentTable[guiKey],screen)
|
|
|
|
local badgeFrame = Instance.new("Frame")
|
|
badgeFrame.Name = "BadgeFrame"
|
|
badgeFrame.Size = UDim2.new(2,0,1,0)
|
|
badgeFrame.Position = UDim2.new(-0.5,0,0,0)
|
|
badgeFrame.BackgroundTransparency = 1
|
|
badgeFrame.Parent = screen
|
|
|
|
return screen
|
|
end
|
|
|
|
return billboard
|
|
end
|
|
|
|
function repositionBadges(badgeFrame)
|
|
local badges = badgeFrame:GetChildren()
|
|
if #badges == 1 then
|
|
badges[1].Position = UDim2.new(0.25,0,0,0)
|
|
elseif #badges == 2 then
|
|
badges[1].Position = UDim2.new(0,0,0,0)
|
|
badges[2].Position = UDim2.new(0.5,0,0)
|
|
end
|
|
end
|
|
|
|
function hasBadge(adornee, type)
|
|
local screen = getBillboard(adornee)
|
|
return screen:FindFirstChild(type .. "Badge",true)
|
|
end
|
|
|
|
function removeBadge(adornee, type)
|
|
local screen = getBillboard(adornee)
|
|
local badge = screen:FindFirstChild(type .. "Badge",true)
|
|
if badge then badge:remove() end
|
|
end
|
|
|
|
function createBadge(adornee,type)
|
|
local screen = getBillboard(adornee)
|
|
|
|
local wiringBadge = Instance.new("ImageLabel")
|
|
wiringBadge.Name = type .. "Badge"
|
|
wiringBadge.BackgroundTransparency = 1
|
|
if type == "Receiver" then
|
|
wiringBadge.Image = SOURCE_BADGE_TEXTURE
|
|
else
|
|
wiringBadge.Image = SINK_BADGE_TEXTURE
|
|
end
|
|
|
|
wiringBadge.Position = UDim2.new(0.25,0,0,0)
|
|
wiringBadge.Size = UDim2.new(0.5,0,1,0)
|
|
wiringBadge.Parent = screen.BadgeFrame
|
|
wiringBadge.Changed:connect(function(prop)
|
|
if prop == "AbsoluteSize" then
|
|
if wiringBadge.AbsoluteSize.X < 10 then
|
|
wiringBadge.Visible = false
|
|
else
|
|
wiringBadge.Visible = true
|
|
end
|
|
end
|
|
end)
|
|
|
|
repositionBadges(screen.BadgeFrame)
|
|
end
|
|
|
|
function upAdorneeCount(adornee,type)
|
|
local typeLower = string.lower(type)
|
|
if typeLower == "receiver" then
|
|
if not receiverBadgeCount[adornee] then
|
|
receiverBadgeCount[adornee] = 1
|
|
else
|
|
receiverBadgeCount[adornee] = receiverBadgeCount[adornee] + 1
|
|
end
|
|
elseif typeLower == "event" then
|
|
if not eventBadgeCount[adornee] then
|
|
eventBadgeCount[adornee] = 1
|
|
else
|
|
eventBadgeCount[adornee] = eventBadgeCount[adornee] + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
function downAdorneeCount(adornee,type)
|
|
local typeLower = string.lower(type)
|
|
if typeLower == "receiver" then
|
|
if receiverBadgeCount[adornee] then
|
|
receiverBadgeCount[adornee] = receiverBadgeCount[adornee] - 1
|
|
if receiverBadgeCount[adornee] < 1 then
|
|
receiverBadgeCount[adornee] = nil
|
|
end
|
|
end
|
|
elseif typeLower == "event" then
|
|
if eventBadgeCount[adornee] then
|
|
eventBadgeCount[adornee] = eventBadgeCount[adornee] - 1
|
|
if eventBadgeCount[adornee] < 1 then
|
|
eventBadgeCount[adornee] = nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function createAdornment(adornee,adornColor,type)
|
|
upAdorneeCount(adornee,type)
|
|
|
|
if receiverBadgeCount[adornee] == 1 or eventBadgeCount[adornee] == 1 then
|
|
local box = Instance.new("SelectionBox")
|
|
box.Color = adornColor
|
|
box.Name = adornee.Name .. "Selection" .. tostring(type)
|
|
box.Adornee = adornee
|
|
box.Transparency = 0.5
|
|
box.Parent = game:GetService("CoreGui")
|
|
if not adornmentTable[adornee] then
|
|
adornmentTable[adornee] = {}
|
|
end
|
|
|
|
table.insert(adornmentTable[adornee],box)
|
|
|
|
if not hasBadge(adornee,type) then
|
|
createBadge(adornee,type)
|
|
end
|
|
end
|
|
end
|
|
|
|
function doRemoveAdornment(adornee, type)
|
|
local key = adornee
|
|
if not adornmentTable[key] then return end
|
|
for i = 1, #adornmentTable[key] do
|
|
if adornmentTable[key] and adornmentTable[key][i] then
|
|
if string.find(adornmentTable[key][i].Name,type) then
|
|
adornmentTable[key][i]:remove()
|
|
adornmentTable[key][i] = nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function removeAdornment(adornee, type)
|
|
downAdorneeCount(adornee,type)
|
|
|
|
if type == "Receiver" then
|
|
if not receiverBadgeCount[adornee]then
|
|
removeBadge(adornee, type)
|
|
doRemoveAdornment(adornee, type)
|
|
end
|
|
elseif type == "Event" then
|
|
if not eventBadgeCount[adornee] then
|
|
removeBadge(adornee, type)
|
|
doRemoveAdornment(adornee, type)
|
|
end
|
|
end
|
|
end
|
|
|
|
function eventReceiverAdded(receiver,wirePartCount)
|
|
if isRestricted then
|
|
if not inBaseplate(receiver) then return wirePartCount end
|
|
end
|
|
receiverTable[receiver] = findModel(receiver.Parent)
|
|
createAdornment(receiverTable[receiver], BrickColor.new("Lime green"), "Receiver")
|
|
|
|
if wirePartCount then
|
|
return wirePartCount + 1
|
|
else
|
|
return 0
|
|
end
|
|
|
|
end
|
|
|
|
function eventAdded(event,wirePartCount)
|
|
if isRestricted then
|
|
if not inBaseplate(event) then return wirePartCount end
|
|
end
|
|
eventTable[event] = findModel(event.Parent)
|
|
createAdornment(eventTable[event], BrickColor.new("Bright orange"), "Event")
|
|
|
|
if wirePartCount then
|
|
return wirePartCount + 1
|
|
else
|
|
return 0
|
|
end
|
|
end
|
|
|
|
function eventReceiverRemoved(receiver)
|
|
if not receiverTable[receiver] then return end
|
|
|
|
removeAdornment(receiverTable[receiver],"Receiver")
|
|
receiverTable[receiver] = nil
|
|
end
|
|
|
|
function eventRemoved(event)
|
|
if not eventTable[event] then return end
|
|
|
|
removeAdornment(eventTable[event], "Event")
|
|
eventTable[event] = nil
|
|
end
|
|
|
|
function setUpConfigurationService()
|
|
local wirePartCount = 0
|
|
ServiceConnections = {}
|
|
local collectionService = game:GetService("CollectionService")
|
|
|
|
-- first lets check if anything already exists
|
|
local receivers = collectionService:GetCollection("CustomEventReceiver")
|
|
if receivers then
|
|
for pos, receiver in pairs(receivers) do
|
|
wirePartCount = eventReceiverAdded(receiver, wirePartCount)
|
|
end
|
|
end
|
|
|
|
local events = collectionService:GetCollection("CustomEvent")
|
|
if events then
|
|
for pos, event in pairs(events) do
|
|
wirePartCount = eventAdded(event, wirePartCount)
|
|
end
|
|
end
|
|
|
|
-- Now lets listen for any future additions/removals
|
|
ServiceConnections[#ServiceConnections+1] = collectionService.ItemAdded:connect(function(instance)
|
|
if instance:IsA("CustomEventReceiver") then
|
|
eventReceiverAdded(instance)
|
|
elseif instance:IsA("CustomEvent") then
|
|
eventAdded(instance)
|
|
end
|
|
end)
|
|
ServiceConnections[#ServiceConnections+1] = collectionService.ItemRemoved:connect(function(instance)
|
|
if instance:IsA("CustomEventReceiver") then
|
|
eventReceiverRemoved(instance)
|
|
elseif instance:IsA("CustomEvent") then
|
|
eventRemoved(instance)
|
|
end
|
|
end)
|
|
|
|
return wirePartCount
|
|
end
|
|
|
|
function destroyConfigurationService()
|
|
-- first lets destroy the collection service
|
|
for index, connection in pairs(ServiceConnections) do
|
|
connection:disconnect()
|
|
end
|
|
ServiceConnections = {}
|
|
|
|
-- now lets remove all of our collection service objects that were generated
|
|
for event, object in pairs(eventTable) do
|
|
eventRemoved(event)
|
|
end
|
|
for eventReceiver, object in pairs(receiverTable) do
|
|
eventReceiverRemoved(eventReceiver)
|
|
end
|
|
end
|