https://1foreverhd.github.io/HDAdmin/projects/topbarplus/about/
Created
May 21, 2020 01:57
-
-
Save TheEpicFace007/0cd7d58e69f4d4204e1f53b3283fecaa to your computer and use it in GitHub Desktop.
TopBar+ for exploits
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- UTILITY | |
-- local Signal = require(4893141590) | |
-- local DirectoryService = require(4926442976) | |
-- read the docs here: https://1foreverhd.github.io/HDAdmin/projects/topbarplus/about/ | |
local __IS_TESTING = true | |
-- init | |
-- CREATE ICON UI | |
local topbarPlusGui = Instance.new("ScreenGui") | |
topbarPlusGui.Enabled = true | |
topbarPlusGui.DisplayOrder = 0 | |
topbarPlusGui.IgnoreGuiInset = true | |
topbarPlusGui.Name = "Topbar+" | |
if __IS_TESTING then | |
topbarPlusGui.Parent = game.Players.LocalPlayer.PlayerGui | |
topbarPlusGui.ResetOnSpawn = true | |
else | |
topbarPlusGui.Parent = game.CoreGui | |
end | |
local topbarContainer = Instance.new("Frame") | |
topbarContainer.BackgroundTransparency = 1 | |
topbarContainer.Name = "TopbarContainer" | |
topbarContainer.Position = UDim2.new(0, 0, 0, 0) | |
topbarContainer.Size = UDim2.new(1, 0, 0, 36) | |
topbarContainer.Visible = true | |
topbarContainer.ZIndex = 1 | |
topbarContainer.Parent = topbarPlusGui | |
local iconContainer = Instance.new("Frame") | |
iconContainer.BackgroundTransparency = 1 | |
iconContainer.Name = "_IconTemplate" | |
iconContainer.Position = UDim2.new(0, 104, 0, 4) | |
iconContainer.Size = UDim2.new(0, 32, 0, 32) | |
iconContainer.Visible = false | |
iconContainer.ZIndex = 1 | |
iconContainer.Parent = topbarContainer | |
local iconButton = Instance.new("ImageButton") | |
iconButton.BackgroundTransparency = 1 | |
iconButton.Name = "IconButton" | |
iconButton.Position = UDim2.new(0, 0, 0, 0) | |
iconButton.Size = UDim2.new(1, 0, 1, 0) | |
iconButton.Visible = true | |
iconButton.ZIndex = 2 | |
iconButton.Image = "rbxassetid://5027411759" | |
iconButton.ImageTransparency = 0.5 | |
iconButton.ImageColor3 = Color3.fromRGB(0, 0, 0) | |
iconButton.ScaleType = Enum.ScaleType.Stretch | |
iconButton.Parent = iconContainer | |
local iconImage = Instance.new("ImageLabel") | |
iconImage.BackgroundTransparency = 1 | |
iconImage.Name = "IconImage" | |
iconImage.AnchorPoint = Vector2.new(0.5, 0.5) | |
iconImage.Position = UDim2.new(0.5, 0, 0.5, 0) | |
iconImage.Size = UDim2.new(0, 20, 0, 20) | |
iconImage.Visible = true | |
iconImage.ZIndex = 3 | |
iconImage.ImageTransparency = 0 | |
iconImage.ImageColor3 = Color3.fromRGB(255, 255, 255) | |
iconImage.ScaleType = Enum.ScaleType.Fit | |
iconImage.Parent = iconButton | |
local notification = Instance.new("ImageLabel") | |
notification.BackgroundTransparency = 1 | |
notification.Name = "Notification" | |
notification.Position = UDim2.new(0.45, 0, 0, -2) | |
notification.Size = UDim2.new(1, 0, 0.7, 0) | |
notification.Visible = false | |
notification.ZIndex = 4 | |
notification.Image = "http://www.roblox.com/asset/?id=4871790969" | |
notification.ImageTransparency = 0 | |
notification.ImageColor3 = Color3.fromRGB(255, 255, 255) | |
notification.ScaleType = Enum.ScaleType.Fit | |
notification.Parent = iconButton | |
local amount = Instance.new("TextLabel") | |
amount.BackgroundTransparency = 1 | |
amount.Name = "Amount" | |
amount.Position = UDim2.new(0.25, 0, 0.15, 0) | |
amount.Size = UDim2.new(0.5, 0, 0.7, 0) | |
amount.Visible = true | |
amount.ZIndex = 5 | |
amount.Font = Enum.Font.Arial | |
amount.Text = "0" | |
amount.TextColor3 = Color3.fromRGB(31, 33, 35) | |
amount.TextScaled = true | |
amount.Parent = notification | |
-- signal library | |
-- Quenty's Signal Module, modified to include Disconnect method | |
local Signal = {} | |
Signal.__index = Signal | |
Signal.ClassName = "Signal" | |
function Signal.new() | |
local self = setmetatable({}, Signal) | |
self._bindableEvent = Instance.new("BindableEvent") | |
self._argData = nil | |
self._argCount = nil -- Prevent edge case of :Fire("A", nil) --> "A" instead of "A", nil | |
return self | |
end | |
function Signal:Fire(...) | |
self._argData = {...} | |
self._argCount = select("#", ...) | |
self._bindableEvent:Fire() | |
self._argData = nil | |
self._argCount = nil | |
end | |
function Signal:Connect(handler) | |
if not (type(handler) == "function") then | |
error(("connect(%s)"):format(typeof(handler)), 2) | |
end | |
return self._bindableEvent.Event:Connect(function() | |
handler(unpack(self._argData, 1, self._argCount)) | |
end) | |
end | |
function Signal:Wait() | |
self._bindableEvent.Event:Wait() | |
assert(self._argData, "Missing arg data, likely due to :TweenSize/Position corrupting threadrefs.") | |
return unpack(self._argData, 1, self._argCount) | |
end | |
function Signal:Destroy() | |
if self._bindableEvent then | |
self._bindableEvent:Destroy() | |
self._bindableEvent = nil | |
end | |
self._argData = nil | |
self._argCount = nil | |
end | |
function Signal:Disconnect() | |
self:Destroy() | |
end | |
-- icon.lua | |
-- LOCAL | |
local tweenService = game:GetService("TweenService") | |
local replicatedStorage = game:GetService("ReplicatedStorage") | |
local iconTemplate = topbarContainer["_IconTemplate"] | |
local Icon = {} | |
Icon.__index = Icon | |
-- CONSTRUCTOR | |
function Icon.new(name, imageId, order) | |
local self = {} | |
setmetatable(self, Icon) | |
local container = iconTemplate:Clone() | |
container.Name = name | |
container.Visible = true | |
local button = container.IconButton | |
self.objects = { | |
["container"] = container, | |
["button"] = button, | |
["image"] = button.IconImage, | |
["notification"] = button.Notification, | |
["amount"] = button.Notification.Amount | |
} | |
self.theme = { | |
-- TOGGLE EFFECT | |
["toggleTweenInfo"] = TweenInfo.new(0, Enum.EasingStyle.Quad, Enum.EasingDirection.Out), | |
-- OBJECT PROPERTIES | |
["container"] = { | |
selected = {}, | |
deselected = {} | |
}, | |
["button"] = { | |
selected = { | |
ImageColor3 = Color3.fromRGB(245, 245, 245), | |
ImageTransparency = 0.1 | |
}, | |
deselected = { | |
ImageColor3 = Color3.fromRGB(0, 0, 0), | |
ImageTransparency = 0.5 | |
} | |
}, | |
["image"] = { | |
selected = { | |
ImageColor3 = Color3.fromRGB(57, 60, 65), | |
}, | |
deselected = { | |
ImageColor3 = Color3.fromRGB(255, 255, 255), | |
} | |
}, | |
["notification"] = { | |
selected = {}, | |
deselected = {}, | |
}, | |
["amount"] = { | |
selected = {}, | |
deselected = {}, | |
}, | |
} | |
self.toggleStatus = "deselected" | |
self:applyThemeToAllObjects() | |
self.name = name | |
self.imageId = imageId or 0 | |
self:setImageSize(20) | |
self.order = order or 1 | |
self.enabled = true | |
self.totalNotifications = 0 | |
self.toggleFunction = function() end | |
self.hoverFunction = function() end | |
self.deselectWhenOtherIconSelected = true | |
self.fakeChatConnections = {} | |
self.updated = Signal.new() | |
self.selected = Signal.new() | |
self.deselected = Signal.new() | |
self.endNotifications = Signal.new() | |
--[[ | |
local hoverInputs = {"InputBegan", "InputEnded"} | |
local originalTransparency = button.ImageTransparency | |
self:setHoverFunction(function(inputName) | |
local hovering = inputName == "InputBegan" | |
button.ImageTransparency = (hovering and originalTransparency + 0.2) or (self.theme.button.selected.ImageTransparency or originalTransparency) | |
end) | |
for _, inputName in pairs(hoverInputs) do | |
button[inputName]:Connect(function(input) | |
if input.UserInputType == Enum.UserInputType.MouseMovement then | |
self.hoverFunction(inputName) | |
end | |
end) | |
end | |
--]] | |
button.MouseButton1Click:Connect(function() | |
if self.toggleStatus == "selected" then | |
self:deselect() | |
else | |
self:select() | |
end | |
end) | |
if imageId then | |
self:setImage(imageId) | |
end | |
container.Parent = topbarContainer | |
return self | |
end | |
-- METHODS | |
function Icon:setImage(imageId) | |
local textureId = (tonumber(imageId) and "http://www.roblox.com/asset/?id="..imageId) or imageId | |
self.imageId = textureId | |
self.objects.image.Image = textureId | |
self.theme.image = self.theme.image or {} | |
self.theme.image.selected = self.theme.image.selected or {} | |
self.theme.image.selected.Image = textureId | |
end | |
function Icon:setOrder(order) | |
self.order = tonumber(order) or 1 | |
self.updated:Fire() | |
end | |
function Icon:setImageSize(pixelsX, pixelsY) | |
pixelsX = tonumber(pixelsX) or self.imageSize | |
if not pixelsY then | |
pixelsY = pixelsX | |
end | |
self.imageSize = Vector2.new(pixelsX, pixelsY) | |
self.objects.image.Size = UDim2.new(0, pixelsX, 0, pixelsY) | |
end | |
function Icon:setEnabled(bool) | |
self.enabled = bool | |
self.objects.container.Visible = bool | |
self.updated:Fire() | |
end | |
function Icon:setBaseZIndex(baseValue) | |
local container = self.objects.container | |
local baseValue = tonumber(baseValue) or container.ZIndex | |
local difference = baseValue - container.ZIndex | |
if difference == 0 then | |
return "The baseValue is the same" | |
end | |
for _, object in pairs(self.objects) do | |
object.ZIndex = object.ZIndex + difference | |
end | |
end | |
function Icon:setToggleMenu(guiObject) | |
if not guiObject or not guiObject:IsA("GuiObject") then | |
guiObject = nil | |
end | |
self.toggleMenu = guiObject | |
end | |
function Icon:setToggleFunction(toggleFunction) | |
if type(toggleFunction) == "function" then | |
local oppositeToggleStatus = (toggleStatus == "selected" and "deselected") or "selected" | |
local oppositeGroup = self.theme[objectName][oppositeToggleStatus] | |
local group = self.theme[objectName][toggleStatus] | |
for key, value in pairs(propertiesTable) do | |
local oppositeKey = oppositeGroup[key] | |
if not oppositeKey then | |
oppositeGroup[key] = group[key] | |
end | |
group[key] = value | |
end | |
if toggleStatus == self.toggleStatus then | |
self:applyThemeToObject(objectName, toggleStatus) | |
end | |
end | |
for objectName, toggleDetails in pairs(themeDetails) do | |
parseDetails(objectName, toggleDetails) | |
end | |
end | |
function Icon:applyThemeToObject(objectName, toggleStatus) | |
local object = self.objects[objectName] | |
if object then | |
local propertiesTable = self.theme[objectName][(toggleStatus or self.toggleStatus)] | |
local toggleTweenInfo = self.theme.toggleTweenInfo | |
local invalidProperties = {"Image"} | |
local finalPropertiesTable = {} | |
for propName, propValue in pairs(propertiesTable) do | |
if table.find(invalidProperties, propName) then | |
object[propName] = propValue | |
else | |
finalPropertiesTable[propName] = propValue | |
end | |
end | |
tweenService:Create(object, toggleTweenInfo, finalPropertiesTable):Play() | |
end | |
end | |
function Icon:applyThemeToAllObjects(...) | |
for objectName, toggleDetails in pairs(self.theme) do | |
self:applyThemeToObject(objectName, ...) | |
end | |
end | |
function Icon:select() | |
self.toggleStatus = "selected" | |
self:applyThemeToAllObjects() | |
self.toggleFunction() | |
if self.toggleMenu then | |
self.toggleMenu.Visible = true | |
end | |
self.selected:Fire() | |
end | |
function Icon:deselect() | |
self.toggleStatus = "deselected" | |
self:applyThemeToAllObjects() | |
self.toggleFunction() | |
if self.toggleMenu then | |
self.toggleMenu.Visible = false | |
end | |
self.deselected:Fire() | |
end | |
function Icon:notify(clearNoticeEvent) | |
coroutine.wrap(function() | |
if not clearNoticeEvent then | |
clearNoticeEvent = self.deselected | |
end | |
self.totalNotifications = self.totalNotifications + 1 | |
self.objects.amount.Text = (self.totalNotifications < 100 and self.totalNotifications) or "99+" | |
self.objects.notification.Visible = true | |
local notifComplete = Signal.new() | |
local endEvent = self.endNotifications:Connect(function() | |
notifComplete:Fire() | |
end) | |
local customEvent = clearNoticeEvent:Connect(function() | |
notifComplete:Fire() | |
end) | |
notifComplete:Wait() | |
endEvent:Disconnect() | |
customEvent:Disconnect() | |
notifComplete:Disconnect() | |
self.totalNotifications = self.totalNotifications - 1 | |
if self.totalNotifications < 1 then | |
self.objects.notification.Visible = false | |
end | |
end)() | |
end | |
function Icon:clearNotifications() | |
self.endNotifications:Fire() | |
end | |
function Icon:clearFakeChatConnections() | |
for cName, connection in pairs(self.fakeChatConnections) do | |
connection:Disconnect() | |
self.fakeChatConnections[cName] = nil | |
end | |
end | |
function Icon:destroy() | |
self:clearNotifications() | |
self:clearFakeChatConnections() | |
self.objects.button:Destroy() | |
for signalName, signal in pairs(self) do | |
if type(signal) == "table" and signal.Destroy then | |
signal:Destroy() | |
end | |
end | |
end | |
-- icon controller | |
-- LOCAL | |
local starterGui = game:GetService("StarterGui") | |
local userInputService = game:GetService("UserInputService") | |
local players = game:GetService("Players") | |
local IconController = {} | |
local topbarIcons = {} | |
local errorStart = "Topbar+ | " | |
local fakeChatName = "_FakeChat" | |
local function deepCopy(original) | |
local copy = {} | |
for k, v in pairs(original) do | |
if type(v) == "table" then | |
v = deepCopy(v) | |
end | |
copy[k] = v | |
end | |
return copy | |
end | |
local function getChatMain() | |
return require(players.LocalPlayer.PlayerScripts:WaitForChild("ChatScript").ChatMain) | |
end | |
local function getTopbarPlusGui() | |
local player = game:GetService("Players").LocalPlayer | |
local playerGui = player.PlayerGui | |
local topbarPlusGui = playerGui:WaitForChild("Topbar+") | |
return topbarPlusGui | |
end | |
-- METHODS | |
function IconController:createIcon(name, imageId, order) | |
-- Verify data | |
local iconDetails = topbarIcons[name] | |
if iconDetails then | |
warn(("%sFailed to create Icon '%s': an icon already exists under that name."):format(errorStart, name)) | |
return false | |
end | |
-- Create and record icon | |
local icon = Icon.new(name, imageId, order) | |
iconDetails = {name = name, icon = icon, order = icon.order} | |
topbarIcons[name] = iconDetails | |
icon:setOrder(icon.order) | |
-- Events | |
local function updateIcon() | |
local iconDetails = topbarIcons[name] | |
if not iconDetails then | |
warn(("%sFailed to update Icon '%s': icon not found."):format(errorStart, name)) | |
return false | |
end | |
iconDetails.order = icon.order or 1 | |
local orderedIconDetails = {} | |
for name, details in pairs(topbarIcons) do | |
if details.icon.enabled == true then | |
table.insert(orderedIconDetails, details) | |
end | |
end | |
if #orderedIconDetails > 1 then | |
table.sort(orderedIconDetails, function(a,b) return a.order < b.order end) | |
end | |
local startPosition = 104 | |
local positionIncrement = 44 | |
if not starterGui:GetCoreGuiEnabled("Chat") then | |
startPosition = startPosition - positionIncrement | |
end | |
for i, details in pairs(orderedIconDetails) do | |
local container = details.icon.objects.container | |
local iconX = startPosition + (i-1)*positionIncrement | |
container.Position = UDim2.new(0, iconX, 0, 4) | |
end | |
return true | |
end | |
updateIcon() | |
icon.updated:Connect(function() | |
updateIcon() | |
end) | |
icon.selected:Connect(function() | |
local allIcons = self:getAllIcons() | |
for _, otherIcon in pairs(allIcons) do | |
if otherIcon ~= icon and otherIcon.deselectWhenOtherIconSelected and otherIcon.toggleStatus == "selected" then | |
otherIcon:deselect() | |
end | |
end | |
end) | |
return icon | |
end | |
function IconController:createFakeChat(theme) | |
local ChatMain = getChatMain() | |
local iconName = fakeChatName | |
local icon = self:getIcon(iconName) | |
local function displayChatBar(visibility) | |
icon.ignoreVisibilityStateChange = true | |
ChatMain.CoreGuiEnabled:fire(visibility) | |
ChatMain:SetVisible(visibility) | |
icon.ignoreVisibilityStateChange = nil | |
end | |
local function setIconEnabled(visibility) | |
icon.ignoreVisibilityStateChange = true | |
ChatMain.CoreGuiEnabled:fire(visibility) | |
icon:setEnabled(visibility) | |
starterGui:SetCoreGuiEnabled("Chat", false) | |
icon:deselect() | |
icon.updated:Fire() | |
icon.ignoreVisibilityStateChange = nil | |
end | |
if not icon then | |
icon = self:createIcon(iconName, "rbxasset://textures/ui/TopBar/chatOff.png", -1) | |
-- Open chat via Slash key | |
icon.fakeChatConnections["ChatInput"] = userInputService.InputEnded:connect(function(inputObject, gameProcessedEvent) | |
if gameProcessedEvent then | |
return "Another menu has priority" | |
elseif inputObject.KeyCode ~= Enum.KeyCode.Slash then | |
return "No relavent key pressed" | |
elseif ChatMain.IsFocused() then | |
return "Chat bar already open" | |
end | |
displayChatBar(true) | |
ChatMain:FocusChatBar(true) | |
icon:select() | |
end) | |
-- Keep when other icons selected | |
icon.deselectWhenOtherIconSelected = false | |
-- Mimic chat notifications | |
icon.fakeChatConnections["MessagesChanged"] = ChatMain.MessagesChanged:connect(function(messageCount) | |
if ChatMain:GetVisibility() == true then | |
return "ChatWindow was open" | |
end | |
icon:notify(icon.selected) | |
end) | |
-- Mimic visibility when StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Chat, state) is called | |
icon.fakeChatConnections["CoreGuiEnabled"] = ChatMain.CoreGuiEnabled:connect(function(newState) | |
if icon.ignoreVisibilityStateChange then | |
return "ignoreVisibilityStateChange enabled" | |
end | |
setIconEnabled(newState) | |
end) | |
end | |
theme = (theme and deepCopy(theme)) or {} | |
theme.image = theme.image or {} | |
theme.image.selected = theme.image.selected or {} | |
theme.image.selected.Image = "rbxasset://textures/ui/TopBar/chatOn.png" | |
icon:setTheme(theme) | |
icon:setImageSize(20) | |
icon:setToggleFunction(function() | |
local isSelected = icon.toggleStatus == "selected" | |
displayChatBar(isSelected) | |
end) | |
setIconEnabled(starterGui:GetCoreGuiEnabled("Chat")) | |
return icon | |
end | |
function IconController:removeFakeChat() | |
local icon = IconController:getIcon(fakeChatName) | |
local enabled = icon.enabled | |
icon:clearFakeChatConnections() | |
IconController:removeIcon(fakeChatName) | |
starterGui:SetCoreGuiEnabled("Chat", enabled) | |
end | |
function IconController:setTopbarEnabled(newState) | |
local topbarPlusGui = getTopbarPlusGui() | |
local topbarContainer = topbarPlusGui.TopbarContainer | |
topbarContainer.Visible = newState | |
end | |
function IconController:setDisplayOrder(value) | |
local topbarPlusGui = getTopbarPlusGui() | |
local value = tonumber(value) or topbarPlusGui.DisplayOrder | |
topbarPlusGui.DisplayOrder = value | |
end | |
function IconController:getIcon(name) | |
local iconDetails = topbarIcons[name] | |
if not iconDetails then | |
--warn(("%sFailed to get Icon '%s': icon not found."):format(errorStart, name)) | |
return false | |
end | |
return iconDetails.icon | |
end | |
function IconController:getAllIcons() | |
local allIcons = {} | |
for name, details in pairs(topbarIcons) do | |
table.insert(allIcons, details.icon) | |
end | |
return allIcons | |
end | |
function IconController:removeIcon(name) | |
local iconDetails = topbarIcons[name] | |
if not iconDetails then | |
warn(("%sFailed to remove Icon '%s': icon not found."):format(errorStart, name)) | |
return false | |
end | |
local icon = iconDetails.icon | |
icon:setEnabled(false) | |
icon:deselect() | |
icon.updated:Fire() | |
icon:destroy() | |
topbarIcons[name] = nil | |
return true | |
end | |
-- BEHAVIOUR | |
coroutine.wrap(function() | |
-- Mimic the enabling of the topbar when StarterGui:SetCore("TopbarEnabled", state) is called | |
local ChatMain = getChatMain() | |
ChatMain.CoreGuiEnabled:connect(function(newState) | |
local enabled = starterGui:GetCore("TopbarEnabled") | |
IconController:setTopbarEnabled(enabled) | |
local icons = IconController:getAllIcons() | |
for _, icon in pairs(icons) do | |
icon.updated:Fire() | |
end | |
end) | |
IconController:setTopbarEnabled(starterGui:GetCore("TopbarEnabled")) | |
end)() | |
-- actual script | |
infinite_yield = Icon.new("Infinite yield",5063637342,1) | |
infinite_yield.toggleFunction = function() loadstring(game:HttpGet('https://raw.githubusercontent.com/EdgeIY/infiniteyield/master/source'))() end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment