1660 lines
43 KiB
Lua
1660 lines
43 KiB
Lua
--[[
|
|
// FileName: Topbar.lua
|
|
// Written by: SolarCrane
|
|
// Description: Code for lua side Top Menu items in ROBLOX.
|
|
]]
|
|
|
|
|
|
--[[ CONSTANTS ]]
|
|
|
|
local TOPBAR_THICKNESS = 36
|
|
local USERNAME_CONTAINER_WIDTH = 170
|
|
local COLUMN_WIDTH = 75
|
|
local NAME_LEADERBOARD_SEP_WIDTH = 2
|
|
|
|
local ITEM_SPACING = 0
|
|
local VR_ITEM_SPACING = 3
|
|
|
|
local FONT_COLOR = Color3.new(1,1,1)
|
|
local TOPBAR_BACKGROUND_COLOR = Color3.new(31/255,31/255,31/255)
|
|
local TOPBAR_OPAQUE_TRANSPARENCY = 0
|
|
local TOPBAR_TRANSLUCENT_TRANSPARENCY = 0.5
|
|
|
|
local HEALTH_BACKGROUND_COLOR = Color3.new(228/255, 236/255, 246/255)
|
|
local HEALTH_RED_COLOR = Color3.new(255/255, 28/255, 0/255)
|
|
local HEALTH_YELLOW_COLOR = Color3.new(250/255, 235/255, 0)
|
|
local HEALTH_GREEN_COLOR = Color3.new(27/255, 252/255, 107/255)
|
|
|
|
local HEALTH_PERCANTAGE_FOR_OVERLAY = 5 / 100
|
|
|
|
local HURT_OVERLAY_IMAGE = "http://www.roblox.com/asset/?id=34854607"
|
|
|
|
local DEBOUNCE_TIME = 0.25
|
|
|
|
--[[ END OF CONSTANTS ]]
|
|
|
|
--[[ FFLAG VALUES ]]
|
|
|
|
local defeatableTopbarSuccess, defeatableTopbarFlagValue = pcall(function() return settings():GetFFlag("EnableSetCoreTopbarEnabled") end)
|
|
local defeatableTopbar = (defeatableTopbarSuccess and defeatableTopbarFlagValue == true)
|
|
|
|
local vr3dGuisSuccess, vr3dGuisFlagValue = pcall(function() return settings():GetFFlag("RenderUserGuiIn3DSpace") end)
|
|
local vr3dGuis = (vr3dGuisSuccess and vr3dGuisFlagValue == true)
|
|
|
|
--[[ END OF FFLAG VALUES ]]
|
|
|
|
|
|
--[[ SERVICES ]]
|
|
|
|
local CoreGuiService = game:GetService('CoreGui')
|
|
local PlayersService = game:GetService('Players')
|
|
local GuiService = game:GetService('GuiService')
|
|
local InputService = game:GetService('UserInputService')
|
|
local StarterGui = game:GetService('StarterGui')
|
|
local ContextActionService = game:GetService("ContextActionService")
|
|
local RunService = game:GetService('RunService')
|
|
local TextService = game:GetService('TextService')
|
|
|
|
--[[ END OF SERVICES ]]
|
|
|
|
|
|
local topbarEnabled = true
|
|
local topbarEnabledChangedEvent = Instance.new('BindableEvent')
|
|
|
|
local settingsActive = false
|
|
|
|
local GameSettings = UserSettings().GameSettings
|
|
local Player = PlayersService.LocalPlayer
|
|
while Player == nil do
|
|
wait()
|
|
Player = PlayersService.LocalPlayer
|
|
end
|
|
|
|
local GuiRoot = CoreGuiService:WaitForChild('RobloxGui')
|
|
local TenFootInterface = require(GuiRoot.Modules.TenFootInterface)
|
|
local isTenFootInterface = TenFootInterface:IsEnabled()
|
|
|
|
local Panel3D = require(GuiRoot.Modules.VR.Panel3D)
|
|
local Topbar3DPanel = Panel3D.Get("Topbar3D")
|
|
|
|
local Util = {}
|
|
do
|
|
-- Check if we are running on a touch device
|
|
function Util.IsTouchDevice()
|
|
return InputService.TouchEnabled
|
|
end
|
|
|
|
function Util.Create(instanceType)
|
|
return function(data)
|
|
local obj = Instance.new(instanceType)
|
|
for k, v in pairs(data) do
|
|
if type(k) == 'number' then
|
|
v.Parent = obj
|
|
else
|
|
obj[k] = v
|
|
end
|
|
end
|
|
return obj
|
|
end
|
|
end
|
|
|
|
function Util.Clamp(low, high, input)
|
|
return math.max(low, math.min(high, input))
|
|
end
|
|
|
|
function Util.DisconnectEvent(conn)
|
|
if conn then
|
|
conn:disconnect()
|
|
end
|
|
return nil
|
|
end
|
|
|
|
function Util.SetGUIInsetBounds(x1, y1, x2, y2)
|
|
GuiService:SetGlobalGuiInset(x1, y1, x2, y2)
|
|
if GuiRoot:FindFirstChild("GuiInsetChanged") then
|
|
GuiRoot.GuiInsetChanged:Fire(x1, y1, x2, y2)
|
|
end
|
|
end
|
|
|
|
local humanoidCache = {}
|
|
function Util.FindPlayerHumanoid(player)
|
|
local character = player and player.Character
|
|
if character then
|
|
local resultHumanoid = humanoidCache[player]
|
|
if resultHumanoid and resultHumanoid.Parent == character then
|
|
return resultHumanoid
|
|
else
|
|
humanoidCache[player] = nil -- Bust Old Cache
|
|
for _, child in pairs(character:GetChildren()) do
|
|
if child:IsA('Humanoid') then
|
|
humanoidCache[player] = child
|
|
return child
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local selectionRing = Util.Create "ImageLabel" {
|
|
Name = "SelectionRing",
|
|
Position = UDim2.new(0.5, -23, 0.5, -23),
|
|
Size = UDim2.new(0, 46, 0, 46),
|
|
BackgroundTransparency = 1,
|
|
Image = "rbxasset://textures/ui/menu/buttonHover.png"
|
|
}
|
|
|
|
local function CreateTopBar()
|
|
local this = {}
|
|
|
|
local playerGuiChangedConn = nil
|
|
|
|
local topbarContainer = Util.Create'Frame'{
|
|
Name = "TopBarContainer";
|
|
Size = UDim2.new(1, 0, 0, TOPBAR_THICKNESS);
|
|
Position = UDim2.new(0, 0, 0, -TOPBAR_THICKNESS);
|
|
BackgroundTransparency = TOPBAR_OPAQUE_TRANSPARENCY;
|
|
BackgroundColor3 = TOPBAR_BACKGROUND_COLOR;
|
|
BorderSizePixel = 0;
|
|
Active = true;
|
|
Parent = GuiRoot;
|
|
};
|
|
|
|
local topbarShadow = Util.Create'ImageLabel'{
|
|
Name = "TopBarShadow";
|
|
Size = UDim2.new(1, 0, 0, 3);
|
|
Position = UDim2.new(0, 0, 1, 0);
|
|
Image = "rbxasset://textures/ui/TopBar/dropshadow.png";
|
|
BackgroundTransparency = 1;
|
|
Active = false;
|
|
Visible = false;
|
|
Parent = topbarContainer;
|
|
};
|
|
|
|
local function ComputeTransparency()
|
|
if not topbarEnabled then
|
|
return 1
|
|
end
|
|
|
|
local playerGui = Player:FindFirstChild('PlayerGui')
|
|
if playerGui then
|
|
return playerGui:GetTopbarTransparency()
|
|
end
|
|
|
|
return TOPBAR_TRANSLUCENT_TRANSPARENCY
|
|
end
|
|
|
|
function this:UpdateBackgroundTransparency()
|
|
if settingsActive and not VREnabled then
|
|
topbarContainer.BackgroundTransparency = TOPBAR_OPAQUE_TRANSPARENCY
|
|
topbarShadow.Visible = false
|
|
else
|
|
topbarContainer.BackgroundTransparency = ComputeTransparency()
|
|
topbarShadow.Visible = (topbarContainer.BackgroundTransparency == 0)
|
|
end
|
|
end
|
|
|
|
function this:GetInstance()
|
|
return topbarContainer
|
|
end
|
|
|
|
spawn(function()
|
|
local playerGui = Player:WaitForChild('PlayerGui')
|
|
playerGuiChangedConn = Util.DisconnectEvent(playerGuiChangedConn)
|
|
pcall(function()
|
|
playerGuiChangedConn = playerGui.TopbarTransparencyChangedSignal:connect(this.UpdateBackgroundTransparency)
|
|
end)
|
|
this:UpdateBackgroundTransparency()
|
|
end)
|
|
|
|
return this
|
|
end
|
|
|
|
|
|
local BarAlignmentEnum =
|
|
{
|
|
Right = 0;
|
|
Left = 1;
|
|
Middle = 2;
|
|
}
|
|
|
|
local function CreateMenuBar(barAlignment)
|
|
local this = {}
|
|
local thickness = TOPBAR_THICKNESS
|
|
local alignment = barAlignment or BarAlignmentEnum.Right
|
|
local items = {}
|
|
local propertyChangedConnections = {}
|
|
local dock = nil
|
|
|
|
function this:ArrangeItems()
|
|
local totalWidth = 0
|
|
|
|
local spacing = ITEM_SPACING
|
|
if InputService.VREnabled then
|
|
spacing = VR_ITEM_SPACING
|
|
end
|
|
|
|
for i, item in ipairs(items) do
|
|
local width = item:GetWidth()
|
|
|
|
if alignment == BarAlignmentEnum.Left then
|
|
item.Position = UDim2.new(0, totalWidth, 0, 0)
|
|
elseif alignment == BarAlignmentEnum.Right then
|
|
item.Position = UDim2.new(1, -totalWidth - width, 0, 0)
|
|
end
|
|
|
|
if i ~= #items then
|
|
width = width + spacing
|
|
end
|
|
|
|
totalWidth = totalWidth + width
|
|
end
|
|
|
|
if alignment == BarAlignmentEnum.Middle then
|
|
local currentX = -totalWidth / 2
|
|
for _, item in ipairs(items) do
|
|
item.Position = UDim2.new(0, currentX, 0, 0)
|
|
|
|
currentX = currentX + item:GetWidth() + spacing
|
|
end
|
|
end
|
|
|
|
return totalWidth
|
|
end
|
|
|
|
function this:GetThickness()
|
|
return thickness
|
|
end
|
|
|
|
function this:GetNumberOfItems()
|
|
return #items
|
|
end
|
|
|
|
function this:SetDock(newDock)
|
|
dock = newDock
|
|
for _, item in pairs(items) do
|
|
item.Parent = dock
|
|
end
|
|
end
|
|
|
|
function this:IndexOfItem(searchItem)
|
|
for index, item in pairs(items) do
|
|
if item == searchItem then
|
|
return index
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
function this:ItemAtIndex(index)
|
|
return items[index]
|
|
end
|
|
|
|
function this:GetItems()
|
|
return items
|
|
end
|
|
|
|
function this:AddItem(item, index)
|
|
local numItems = self:GetNumberOfItems()
|
|
index = Util.Clamp(1, numItems + 1, (index or numItems + 1))
|
|
|
|
local alreadyFoundIndex = self:IndexOfItem(item)
|
|
if alreadyFoundIndex then
|
|
return item, index
|
|
end
|
|
|
|
table.insert(items, index, item)
|
|
Util.DisconnectEvent(propertyChangedConnections[item])
|
|
propertyChangedConnections[item] = item.Changed:connect(function(property)
|
|
if property == 'AbsoluteSize' then
|
|
self:ArrangeItems()
|
|
end
|
|
end)
|
|
self:ArrangeItems()
|
|
|
|
if dock then
|
|
item.Parent = dock
|
|
end
|
|
|
|
return item, index
|
|
end
|
|
|
|
function this:RemoveItem(item)
|
|
local index = self:IndexOfItem(item)
|
|
if index then
|
|
local removedItem = table.remove(items, index)
|
|
|
|
removedItem.Parent = nil
|
|
Util.DisconnectEvent(propertyChangedConnections[removedItem])
|
|
|
|
self:ArrangeItems()
|
|
return removedItem, index
|
|
end
|
|
end
|
|
|
|
|
|
return this
|
|
end
|
|
|
|
local function Create3DMenuBar(barAlignment, threeDPanel)
|
|
local this = CreateMenuBar(barAlignment)
|
|
|
|
local superArrangeItems = this.ArrangeItems
|
|
function this:ArrangeItems()
|
|
local totalWidth = superArrangeItems(self)
|
|
if threeDPanel then
|
|
threeDPanel:ResizePixels(totalWidth, 120)
|
|
end
|
|
for _, v in pairs(this:GetItems()) do
|
|
v:UpdateHoverText()
|
|
end
|
|
return totalWidth
|
|
end
|
|
|
|
function this:CloseAllExcept(item)
|
|
for _, v in pairs(this:GetItems()) do
|
|
if v ~= item then
|
|
v:SetActive(false)
|
|
end
|
|
end
|
|
end
|
|
|
|
return this
|
|
end
|
|
|
|
|
|
local function CreateMenuItem(origInstance)
|
|
local this = {}
|
|
local instance = origInstance
|
|
|
|
function this:SetInstance(newInstance)
|
|
if not instance then
|
|
instance = newInstance
|
|
else
|
|
print("Trying to set an Instance of a Menu Item that already has an instance; doing nothing.")
|
|
end
|
|
end
|
|
|
|
function this:GetWidth()
|
|
return self.Size.X.Offset
|
|
end
|
|
|
|
-- We are extending a regular instance.
|
|
do
|
|
local mt =
|
|
{
|
|
__index = function (t, k)
|
|
return instance[k]
|
|
end;
|
|
|
|
__newindex = function (t, k, v)
|
|
--if instance[k] ~= nil then
|
|
instance[k] = v
|
|
--else
|
|
-- rawset(t, k, v)
|
|
--end
|
|
end;
|
|
}
|
|
setmetatable(this, mt)
|
|
end
|
|
|
|
return this
|
|
end
|
|
|
|
local function Create3DMenuItem()
|
|
local menuItem = {}
|
|
|
|
local backgroundButton = Util.Create 'ImageButton' {
|
|
Name = "ButtonBackground",
|
|
Size = UDim2.new(0, 52, 0, 52),
|
|
|
|
BackgroundTransparency = 1,
|
|
SelectionImageObject = selectionRing:Clone(),
|
|
|
|
ClipsDescendants = false
|
|
}
|
|
|
|
local isActive = false
|
|
|
|
function menuItem:SetActive(active)
|
|
isActive = active
|
|
if active then
|
|
backgroundButton.Image = "rbxasset://textures/ui/menu/buttonActive.png"
|
|
else
|
|
backgroundButton.Image = "rbxasset://textures/ui/menu/buttonBackground.png"
|
|
end
|
|
backgroundButton.SelectionImageObject.Visible = not active
|
|
end
|
|
|
|
function menuItem:GetWidth()
|
|
return backgroundButton.AbsoluteSize.X
|
|
end
|
|
|
|
function menuItem:GetInstance()
|
|
return backgroundButton
|
|
end
|
|
|
|
local function setTransparency(parent, transparency)
|
|
if parent:IsA("ImageLabel") or parent:IsA("ImageButton") then
|
|
parent.ImageTransparency = transparency
|
|
elseif parent:IsA("TextLabel") or parent:IsA("TextButton") then
|
|
parent.TextTransparency = transparency
|
|
end
|
|
for _, v in pairs(parent:GetChildren()) do
|
|
if v:IsA("GuiObject") then
|
|
setTransparency(v, transparency)
|
|
end
|
|
end
|
|
end
|
|
function menuItem:SetTransparency(transparency)
|
|
setTransparency(backgroundButton, transparency)
|
|
end
|
|
|
|
menuItem:SetActive(false)
|
|
|
|
local hoverTextFrame = Util.Create 'Frame' {
|
|
Name = "ButtonHoverText",
|
|
BackgroundTransparency = 1,
|
|
BorderSizePixel = 0,
|
|
|
|
Position = UDim2.new(0.5, -45, 0, 55),
|
|
Size = UDim2.new(0, 90, 0, 60),
|
|
|
|
Visible = false,
|
|
Parent = backgroundButton
|
|
}
|
|
local hoverMid = Util.Create 'ImageLabel' {
|
|
Name = "HoverMid",
|
|
BackgroundTransparency = 1,
|
|
|
|
Image = "rbxasset://textures/ui/Menu/hoverPopupMid.png",
|
|
|
|
Position = UDim2.new(0.5, -12, 0, 0),
|
|
Size = UDim2.new(0, 24, 1, 0),
|
|
Parent = hoverTextFrame
|
|
}
|
|
local hoverLeft = Util.Create 'ImageLabel' {
|
|
Name = "HoverLeft",
|
|
BackgroundTransparency = 1,
|
|
|
|
Image = "rbxasset://textures/ui/Menu/hoverPopupLeft.png",
|
|
|
|
Position = UDim2.new(0, 0, 0, 0),
|
|
Size = UDim2.new(0.5, -12, 1, 0),
|
|
ScaleType = Enum.ScaleType.Slice,
|
|
SliceCenter = Rect.new(1, 1, 33, 59),
|
|
Parent = hoverTextFrame
|
|
}
|
|
local hoverRight = Util.Create 'ImageLabel' {
|
|
Name = "HoverRight",
|
|
BackgroundTransparency = 1,
|
|
|
|
Image = "rbxasset://textures/ui/Menu/hoverPopupRight.png",
|
|
|
|
Position = UDim2.new(0.5, 12, 0, 0),
|
|
Size = UDim2.new(0.5, -12, 1, 0),
|
|
ScaleType = Enum.ScaleType.Slice,
|
|
SliceCenter = Rect.new(0, 1, 32, 59),
|
|
Parent = hoverTextFrame
|
|
}
|
|
|
|
local hoverTextLabel = Util.Create 'TextLabel' {
|
|
Name = "ButtonHoverTextLabel",
|
|
BackgroundTransparency = 1,
|
|
|
|
Font = Enum.Font.SourceSansBold,
|
|
FontSize = Enum.FontSize.Size24,
|
|
Text = "",
|
|
TextColor3 = Color3.new(1, 1, 1),
|
|
|
|
Position = UDim2.new(0, 0, 0, 8),
|
|
Size = UDim2.new(1, 0, 1, -5),
|
|
|
|
Parent = hoverTextFrame
|
|
}
|
|
|
|
function menuItem:SetHoverText(text)
|
|
hoverTextLabel.Text = text
|
|
local textSize = TextService:GetTextSize(
|
|
hoverTextLabel.Text,
|
|
24,
|
|
hoverTextLabel.Font,
|
|
Vector2.new(1000, 10000))
|
|
local frameWidth = textSize.x + 20
|
|
hoverTextFrame.Position = UDim2.new(0.5, -frameWidth / 2, 0, 55)
|
|
hoverTextFrame.Size = UDim2.new(0, frameWidth, 0, 60)
|
|
end
|
|
|
|
backgroundButton.SelectionGained:connect(function()
|
|
hoverTextFrame.Visible = true
|
|
end)
|
|
backgroundButton.SelectionLost:connect(function()
|
|
hoverTextFrame.Visible = false
|
|
end)
|
|
|
|
function menuItem:UpdateHoverText()
|
|
self:SetHoverText(hoverTextLabel.Text)
|
|
end
|
|
|
|
setmetatable(menuItem, {
|
|
__index = function(t, k)
|
|
return backgroundButton[k]
|
|
end,
|
|
__newindex = function(t, k, v)
|
|
backgroundButton[k] = v
|
|
end
|
|
})
|
|
|
|
return menuItem
|
|
end
|
|
|
|
local function createNormalHealthBar()
|
|
local container = Util.Create'ImageButton'
|
|
{
|
|
Name = "NameHealthContainer";
|
|
Size = UDim2.new(0, USERNAME_CONTAINER_WIDTH, 1, 0);
|
|
AutoButtonColor = false;
|
|
Image = "";
|
|
BackgroundTransparency = 1;
|
|
}
|
|
|
|
local username = Util.Create'TextLabel'{
|
|
Name = "Username";
|
|
Text = Player.Name;
|
|
Size = UDim2.new(1, -14, 0, 22);
|
|
Position = UDim2.new(0, 7, 0, 0);
|
|
Font = Enum.Font.SourceSansBold;
|
|
FontSize = Enum.FontSize.Size14;
|
|
BackgroundTransparency = 1;
|
|
TextColor3 = FONT_COLOR;
|
|
TextYAlignment = Enum.TextYAlignment.Bottom;
|
|
TextXAlignment = Enum.TextXAlignment.Left;
|
|
Parent = container;
|
|
};
|
|
|
|
local healthContainer = Util.Create'Frame'{
|
|
Name = "HealthContainer";
|
|
Size = UDim2.new(1, -14, 0, 3);
|
|
Position = UDim2.new(0, 7, 1, -9);
|
|
BorderSizePixel = 0;
|
|
BackgroundColor3 = HEALTH_BACKGROUND_COLOR;
|
|
Parent = container;
|
|
};
|
|
|
|
local healthFill = Util.Create'Frame'{
|
|
Name = "HealthFill";
|
|
Size = UDim2.new(1, 0, 1, 0);
|
|
BorderSizePixel = 0;
|
|
BackgroundColor3 = HEALTH_GREEN_COLOR;
|
|
Parent = healthContainer;
|
|
};
|
|
|
|
return container, username, healthContainer, healthFill
|
|
end
|
|
|
|
----- HEALTH -----
|
|
local function CreateUsernameHealthMenuItem()
|
|
|
|
local container, username, healthContainer, healthFill = nil
|
|
|
|
if isTenFootInterface then
|
|
container, username, healthContainer, healthFill = TenFootInterface:CreateHealthBar()
|
|
else
|
|
container, username, healthContainer, healthFill = createNormalHealthBar()
|
|
end
|
|
|
|
local hurtOverlay = Util.Create'ImageLabel'
|
|
{
|
|
Name = "HurtOverlay";
|
|
BackgroundTransparency = 1;
|
|
Image = HURT_OVERLAY_IMAGE;
|
|
Position = UDim2.new(-10,0,-10,0);
|
|
Size = UDim2.new(20,0,20,0);
|
|
Visible = false;
|
|
Parent = GuiRoot;
|
|
};
|
|
|
|
local this = CreateMenuItem(container)
|
|
|
|
--- EVENTS ---
|
|
local humanoidChangedConn, childAddedConn, childRemovedConn = nil
|
|
--------------
|
|
|
|
local function AnimateHurtOverlay()
|
|
if hurtOverlay and not VREnabled then
|
|
local newSize = UDim2.new(20, 0, 20, 0)
|
|
local newPos = UDim2.new(-10, 0, -10, 0)
|
|
|
|
if hurtOverlay:IsDescendantOf(game) then
|
|
-- stop any tweens on overlay
|
|
hurtOverlay:TweenSizeAndPosition(newSize, newPos, Enum.EasingDirection.Out, Enum.EasingStyle.Linear, 0, true, function()
|
|
-- show the gui
|
|
hurtOverlay.Size = UDim2.new(1,0,1,0)
|
|
hurtOverlay.Position = UDim2.new(0,0,0,0)
|
|
hurtOverlay.Visible = true
|
|
-- now tween the hide
|
|
if hurtOverlay:IsDescendantOf(game) then
|
|
hurtOverlay:TweenSizeAndPosition(newSize, newPos, Enum.EasingDirection.Out, Enum.EasingStyle.Quad, 10, false, function()
|
|
hurtOverlay.Visible = false
|
|
end)
|
|
else
|
|
hurtOverlay.Size = newSize
|
|
hurtOverlay.Position = newPos
|
|
end
|
|
end)
|
|
end
|
|
end
|
|
end
|
|
|
|
local healthColorToPosition = {
|
|
[Vector3.new(HEALTH_RED_COLOR.r, HEALTH_RED_COLOR.g, HEALTH_RED_COLOR.b)] = 0.1;
|
|
[Vector3.new(HEALTH_YELLOW_COLOR.r, HEALTH_YELLOW_COLOR.g, HEALTH_YELLOW_COLOR.b)] = 0.5;
|
|
[Vector3.new(HEALTH_GREEN_COLOR.r, HEALTH_GREEN_COLOR.g, HEALTH_GREEN_COLOR.b)] = 0.8;
|
|
}
|
|
local min = 0.1
|
|
local minColor = HEALTH_RED_COLOR
|
|
local max = 0.8
|
|
local maxColor = HEALTH_GREEN_COLOR
|
|
|
|
local function HealthbarColorTransferFunction(healthPercent)
|
|
if healthPercent < min then
|
|
return minColor
|
|
elseif healthPercent > max then
|
|
return maxColor
|
|
end
|
|
|
|
-- Shepard's Interpolation
|
|
local numeratorSum = Vector3.new(0,0,0)
|
|
local denominatorSum = 0
|
|
for colorSampleValue, samplePoint in pairs(healthColorToPosition) do
|
|
local distance = healthPercent - samplePoint
|
|
if distance == 0 then
|
|
-- If we are exactly on an existing sample value then we don't need to interpolate
|
|
return Color3.new(colorSampleValue.x, colorSampleValue.y, colorSampleValue.z)
|
|
else
|
|
local wi = 1 / (distance*distance)
|
|
numeratorSum = numeratorSum + wi * colorSampleValue
|
|
denominatorSum = denominatorSum + wi
|
|
end
|
|
end
|
|
local result = numeratorSum / denominatorSum
|
|
return Color3.new(result.x, result.y, result.z)
|
|
end
|
|
|
|
local function OnHumanoidAdded(humanoid)
|
|
local lastHealth = humanoid.Health
|
|
local function OnHumanoidHealthChanged(health)
|
|
if humanoid then
|
|
local healthDelta = lastHealth - health
|
|
local healthPercent = health / humanoid.MaxHealth
|
|
if humanoid.MaxHealth <= 0 then
|
|
healthPercent = 0
|
|
end
|
|
healthPercent = Util.Clamp(0, 1, healthPercent)
|
|
local healthColor = HealthbarColorTransferFunction(healthPercent)
|
|
local thresholdForHurtOverlay = humanoid.MaxHealth * HEALTH_PERCANTAGE_FOR_OVERLAY
|
|
|
|
if healthDelta >= thresholdForHurtOverlay and health ~= humanoid.MaxHealth and game.StarterGui:GetCoreGuiEnabled("Health") == true then
|
|
AnimateHurtOverlay()
|
|
end
|
|
|
|
healthFill.Size = UDim2.new(healthPercent, 0, 1, 0)
|
|
healthFill.BackgroundColor3 = healthColor
|
|
|
|
lastHealth = health
|
|
end
|
|
end
|
|
Util.DisconnectEvent(humanoidChangedConn)
|
|
humanoidChangedConn = humanoid.HealthChanged:connect(OnHumanoidHealthChanged)
|
|
OnHumanoidHealthChanged(lastHealth)
|
|
end
|
|
|
|
local function OnCharacterAdded(character)
|
|
local humanoid = Util.FindPlayerHumanoid(Player)
|
|
if humanoid then
|
|
OnHumanoidAdded(humanoid)
|
|
end
|
|
|
|
local function onChildAddedOrRemoved()
|
|
local tempHumanoid = Util.FindPlayerHumanoid(Player)
|
|
if tempHumanoid and tempHumanoid ~= humanoid then
|
|
humanoid = tempHumanoid
|
|
OnHumanoidAdded(humanoid)
|
|
end
|
|
end
|
|
Util.DisconnectEvent(childAddedConn)
|
|
Util.DisconnectEvent(childRemovedConn)
|
|
childAddedConn = character.ChildAdded:connect(onChildAddedOrRemoved)
|
|
childRemovedConn = character.ChildRemoved:connect(onChildAddedOrRemoved)
|
|
end
|
|
|
|
rawset(this, "SetHealthbarEnabled",
|
|
function(self, enabled)
|
|
healthContainer.Visible = enabled
|
|
if enabled then
|
|
username.Size = UDim2.new(1, -14, 0, 22);
|
|
username.TextYAlignment = Enum.TextYAlignment.Bottom;
|
|
else
|
|
username.Size = UDim2.new(1, -14, 1, 0);
|
|
username.TextYAlignment = Enum.TextYAlignment.Center;
|
|
end
|
|
end)
|
|
|
|
rawset(this, "SetNameVisible",
|
|
function(self, visible)
|
|
username.Visible = visible
|
|
end)
|
|
|
|
-- Don't need to disconnect this one because we never reconnect it.
|
|
Player.CharacterAdded:connect(OnCharacterAdded)
|
|
if Player.Character then
|
|
OnCharacterAdded(Player.Character)
|
|
end
|
|
|
|
local PlayerlistModule = require(GuiRoot.Modules.PlayerlistModule)
|
|
container.MouseButton1Click:connect(function()
|
|
if topbarEnabled then
|
|
PlayerlistModule.ToggleVisibility()
|
|
end
|
|
end)
|
|
|
|
return this
|
|
end
|
|
----- END OF HEALTH -----
|
|
|
|
----- LEADERSTATS -----
|
|
local function CreateLeaderstatsMenuItem()
|
|
local PlayerlistModule = require(GuiRoot.Modules.PlayerlistModule)
|
|
|
|
local leaderstatsContainer = Util.Create'ImageButton'
|
|
{
|
|
Name = "LeaderstatsContainer";
|
|
Size = UDim2.new(0, 0, 1, 0);
|
|
AutoButtonColor = false;
|
|
Image = "";
|
|
BackgroundTransparency = 1;
|
|
};
|
|
|
|
local this = CreateMenuItem(leaderstatsContainer)
|
|
local columns = {}
|
|
|
|
rawset(this, "SetColumns",
|
|
function(self, columnsList)
|
|
-- Should we handle is the screen dimensions change and it is no longer a small touch device after we set columns?
|
|
local isSmallTouchDevice = Util.IsTouchDevice() and GuiService:GetScreenResolution().Y < 500
|
|
local numColumns = #columnsList
|
|
|
|
-- Destroy old columns
|
|
for _, oldColumn in pairs(columns) do
|
|
oldColumn:Destroy()
|
|
end
|
|
columns = {}
|
|
-- End destroy old columns
|
|
local count = 0
|
|
for index, columnData in pairs(columnsList) do -- i = 1, numColumns do
|
|
if not isSmallTouchDevice or index <= 1 then
|
|
local columnName = columnData.Name
|
|
local columnValue = columnData.Text
|
|
|
|
local columnframe = Util.Create'Frame'
|
|
{
|
|
Name = "Column" .. tostring(index);
|
|
Size = UDim2.new(0, COLUMN_WIDTH + (index == numColumns and 0 or NAME_LEADERBOARD_SEP_WIDTH), 1, 0);
|
|
Position = UDim2.new(0, NAME_LEADERBOARD_SEP_WIDTH + (COLUMN_WIDTH + NAME_LEADERBOARD_SEP_WIDTH) * (index-1), 0, 0);
|
|
BackgroundTransparency = 1;
|
|
Parent = leaderstatsContainer;
|
|
|
|
Util.Create'TextLabel'
|
|
{
|
|
Name = "ColumnName";
|
|
Text = columnName;
|
|
Size = UDim2.new(1, 0, 0, 10);
|
|
Position = UDim2.new(0, 0, 0, 4);
|
|
Font = Enum.Font.SourceSans;
|
|
FontSize = Enum.FontSize.Size14;
|
|
BorderSizePixel = 0;
|
|
BackgroundTransparency = 1;
|
|
TextColor3 = FONT_COLOR;
|
|
TextYAlignment = Enum.TextYAlignment.Center;
|
|
TextXAlignment = Enum.TextXAlignment.Center;
|
|
};
|
|
|
|
Util.Create'TextLabel'
|
|
{
|
|
Name = "ColumnValue";
|
|
Text = columnValue;
|
|
Size = UDim2.new(1, 0, 0, 10);
|
|
Position = UDim2.new(0, 0, 0, 19);
|
|
Font = Enum.Font.SourceSansBold;
|
|
FontSize = Enum.FontSize.Size14;
|
|
BorderSizePixel = 0;
|
|
BackgroundTransparency = 1;
|
|
TextColor3 = FONT_COLOR;
|
|
TextYAlignment = Enum.TextYAlignment.Center;
|
|
TextXAlignment = Enum.TextXAlignment.Center;
|
|
};
|
|
};
|
|
columns[columnName] = columnframe
|
|
count = count + 1
|
|
end
|
|
end
|
|
leaderstatsContainer.Size = UDim2.new(0, COLUMN_WIDTH * count + NAME_LEADERBOARD_SEP_WIDTH * count, 1, 0)
|
|
end)
|
|
|
|
rawset(this, "UpdateColumnValue",
|
|
function(self, columnName, value)
|
|
local column = columns[columnName]
|
|
local columnValue = column and column:FindFirstChild('ColumnValue')
|
|
if columnValue then
|
|
columnValue.Text = tostring(value)
|
|
end
|
|
end)
|
|
|
|
topbarEnabledChangedEvent.Event:connect(function()
|
|
PlayerlistModule.TopbarEnabledChanged(topbarEnabled)
|
|
end)
|
|
|
|
this:SetColumns(PlayerlistModule.GetStats())
|
|
PlayerlistModule.OnLeaderstatsChanged.Event:connect(function(newStatColumns)
|
|
this:SetColumns(newStatColumns)
|
|
end)
|
|
|
|
PlayerlistModule.OnStatChanged.Event:connect(function(statName, statValueAsString)
|
|
this:UpdateColumnValue(statName, statValueAsString)
|
|
end)
|
|
|
|
leaderstatsContainer.MouseButton1Click:connect(function()
|
|
if topbarEnabled then
|
|
PlayerlistModule.ToggleVisibility()
|
|
end
|
|
end)
|
|
|
|
return this
|
|
end
|
|
----- END OF LEADERSTATS -----
|
|
|
|
--- SETTINGS ---
|
|
local function CreateSettingsIcon(topBarInstance)
|
|
local MenuModule = require(game.CoreGui.RobloxGui.Modules.Settings.SettingsHub)
|
|
|
|
local settingsIconButton = Util.Create'ImageButton'
|
|
{
|
|
Name = "Settings";
|
|
Size = UDim2.new(0, 50, 0, TOPBAR_THICKNESS);
|
|
Image = "";
|
|
AutoButtonColor = false;
|
|
BackgroundTransparency = 1;
|
|
}
|
|
|
|
local settingsIconImage = Util.Create'ImageLabel'
|
|
{
|
|
Name = "SettingsIcon";
|
|
Size = UDim2.new(0, 32, 0, 25);
|
|
Position = UDim2.new(0.5, -16, 0.5, -12);
|
|
BackgroundTransparency = 1;
|
|
Image = "rbxasset://textures/ui/Menu/Hamburger.png";
|
|
Parent = settingsIconButton;
|
|
};
|
|
|
|
local function UpdateHamburgerIcon()
|
|
if settingsActive then
|
|
settingsIconImage.Image = "rbxasset://textures/ui/Menu/HamburgerDown.png";
|
|
else
|
|
settingsIconImage.Image = "rbxasset://textures/ui/Menu/Hamburger.png";
|
|
end
|
|
end
|
|
|
|
local function toggleSettings()
|
|
if settingsActive == false then
|
|
settingsActive = true
|
|
else
|
|
settingsActive = false
|
|
end
|
|
|
|
MenuModule:ToggleVisibility()
|
|
UpdateHamburgerIcon()
|
|
|
|
return settingsActive
|
|
end
|
|
|
|
settingsIconButton.MouseButton1Click:connect(function() toggleSettings() end)
|
|
|
|
MenuModule.SettingsShowSignal:connect(function(active)
|
|
settingsActive = active
|
|
topBarInstance:UpdateBackgroundTransparency()
|
|
UpdateHamburgerIcon()
|
|
end)
|
|
|
|
local menuItem = CreateMenuItem(settingsIconButton)
|
|
|
|
rawset(menuItem, "SetTransparency", function(self, transparency)
|
|
settingsIconImage.ImageTransparency = transparency
|
|
end)
|
|
rawset(menuItem, "SetImage", function(self, image)
|
|
settingsIconImage.Image = image
|
|
end)
|
|
rawset(menuItem, "SetSettingsActive", function(self, active)
|
|
settingsActive = active
|
|
MenuModule:ToggleVisibility(settingsActive)
|
|
UpdateHamburgerIcon()
|
|
|
|
return settingsActive
|
|
end)
|
|
|
|
return menuItem
|
|
end
|
|
|
|
local function Create3DSettingsIcon(topBarInstance, panel, menubar)
|
|
local MenuModule = require(game.CoreGui.RobloxGui.Modules.Settings.SettingsHub)
|
|
local menuItem = Create3DMenuItem()
|
|
menuItem:SetHoverText("Settings")
|
|
|
|
local icon = Util.Create "ImageLabel" {
|
|
Parent = menuItem:GetInstance(),
|
|
|
|
Position = UDim2.new(0.5, -15, 0.5, -11),
|
|
Size = UDim2.new(0, 30, 0, 22),
|
|
|
|
BackgroundTransparency = 1,
|
|
|
|
Image = "rbxasset://textures/ui/Menu/hamburger3D.png"
|
|
}
|
|
|
|
menuItem.MouseButton1Click:connect(function()
|
|
MenuModule:SetVisibility(true)
|
|
menubar:CloseAllExcept(menuItem)
|
|
end)
|
|
|
|
local settingsPanel = Panel3D.Get("SettingsMenu")
|
|
function settingsPanel:OnVisibilityChanged(visible)
|
|
menuItem:SetActive(visible)
|
|
end
|
|
|
|
return menuItem
|
|
end
|
|
|
|
------------
|
|
|
|
--- CHAT ---
|
|
local function CreateUnreadMessagesNotifier(ChatModule)
|
|
local chatActive = false
|
|
local lastMessageCount = 0
|
|
|
|
local chatCounter = Util.Create'ImageLabel'
|
|
{
|
|
Name = "ChatCounter";
|
|
Size = UDim2.new(0, 18, 0, 18);
|
|
Position = UDim2.new(1, -12, 0, -4);
|
|
BackgroundTransparency = 1;
|
|
Image = "rbxasset://textures/ui/Chat/MessageCounter.png";
|
|
Visible = false;
|
|
};
|
|
|
|
local chatCountText = Util.Create'TextLabel'
|
|
{
|
|
Name = "ChatCounterText";
|
|
Text = '';
|
|
Size = UDim2.new(0, 13, 0, 9);
|
|
Position = UDim2.new(0.5, -7, 0.5, -7);
|
|
Font = Enum.Font.SourceSansBold;
|
|
FontSize = Enum.FontSize.Size14;
|
|
BorderSizePixel = 0;
|
|
BackgroundTransparency = 1;
|
|
TextColor3 = FONT_COLOR;
|
|
TextYAlignment = Enum.TextYAlignment.Center;
|
|
TextXAlignment = Enum.TextXAlignment.Center;
|
|
Parent = chatCounter;
|
|
};
|
|
|
|
local function OnUnreadMessagesChanged(count)
|
|
if chatActive then
|
|
lastMessageCount = count
|
|
end
|
|
local unreadCount = count - lastMessageCount
|
|
|
|
if unreadCount <= 0 then
|
|
chatCountText.Text = ""
|
|
chatCounter.Visible = false
|
|
else
|
|
if unreadCount < 100 then
|
|
chatCountText.Text = tostring(unreadCount)
|
|
else
|
|
chatCountText.Text = "!"
|
|
end
|
|
chatCounter.Visible = true
|
|
end
|
|
end
|
|
|
|
local function onChatStateChanged(visible)
|
|
chatActive = visible
|
|
if ChatModule then
|
|
OnUnreadMessagesChanged(ChatModule:GetMessageCount())
|
|
end
|
|
end
|
|
|
|
|
|
if ChatModule then
|
|
if ChatModule.VisibilityStateChanged then
|
|
ChatModule.VisibilityStateChanged:connect(onChatStateChanged)
|
|
end
|
|
if ChatModule.MessagesChanged then
|
|
ChatModule.MessagesChanged:connect(OnUnreadMessagesChanged)
|
|
end
|
|
|
|
onChatStateChanged(ChatModule:GetVisibility())
|
|
OnUnreadMessagesChanged(ChatModule:GetMessageCount())
|
|
end
|
|
|
|
return chatCounter
|
|
end
|
|
|
|
local function CreateChatIcon()
|
|
local chatEnabled = game:GetService("UserInputService"):GetPlatform() ~= Enum.Platform.XBoxOne
|
|
if not chatEnabled then return end
|
|
|
|
local ChatModule = require(GuiRoot.Modules.Chat)
|
|
|
|
local bubbleChatIsOn = not PlayersService.ClassicChat and PlayersService.BubbleChat
|
|
local debounce = 0
|
|
|
|
local chatIconButton = Util.Create'ImageButton'
|
|
{
|
|
Name = "Chat";
|
|
Size = UDim2.new(0, 50, 0, TOPBAR_THICKNESS);
|
|
Image = "";
|
|
AutoButtonColor = false;
|
|
BackgroundTransparency = 1;
|
|
};
|
|
|
|
local chatIconImage = Util.Create'ImageLabel'
|
|
{
|
|
Name = "ChatIcon";
|
|
Size = UDim2.new(0, 28, 0, 27);
|
|
Position = UDim2.new(0.5, -14, 0.5, -13);
|
|
BackgroundTransparency = 1;
|
|
Image = "rbxasset://textures/ui/Chat/Chat.png";
|
|
Parent = chatIconButton;
|
|
};
|
|
if not Util.IsTouchDevice() then
|
|
local chatCounter = CreateUnreadMessagesNotifier(ChatModule)
|
|
chatCounter.Parent = chatIconImage;
|
|
end
|
|
|
|
local function updateIcon(down)
|
|
if down then
|
|
chatIconImage.Image = "rbxasset://textures/ui/Chat/ChatDown.png";
|
|
else
|
|
chatIconImage.Image = "rbxasset://textures/ui/Chat/Chat.png";
|
|
end
|
|
end
|
|
|
|
local function onChatStateChanged(visible)
|
|
if not Util.IsTouchDevice() then
|
|
updateIcon(visible)
|
|
end
|
|
end
|
|
|
|
local function toggleChat()
|
|
if InputService.VREnabled then
|
|
ChatModule:ToggleVisibility()
|
|
elseif Util.IsTouchDevice() or bubbleChatIsOn then
|
|
if debounce + DEBOUNCE_TIME < tick() then
|
|
if Util.IsTouchDevice() then
|
|
ChatModule:SetVisible(true)
|
|
end
|
|
ChatModule:FocusChatBar()
|
|
end
|
|
else
|
|
ChatModule:ToggleVisibility()
|
|
end
|
|
end
|
|
|
|
topbarEnabledChangedEvent.Event:connect(function()
|
|
ChatModule:TopbarEnabledChanged(topbarEnabled)
|
|
end)
|
|
|
|
chatIconButton.MouseButton1Click:connect(function()
|
|
toggleChat()
|
|
end)
|
|
|
|
if Util.IsTouchDevice() or bubbleChatIsOn then
|
|
if ChatModule.ChatBarFocusChanged then
|
|
ChatModule.ChatBarFocusChanged:connect(function(isFocused)
|
|
updateIcon(isFocused)
|
|
debounce = tick()
|
|
end)
|
|
end
|
|
updateIcon(false)
|
|
end
|
|
|
|
if ChatModule.VisibilityStateChanged then
|
|
ChatModule.VisibilityStateChanged:connect(onChatStateChanged)
|
|
end
|
|
onChatStateChanged(ChatModule:GetVisibility())
|
|
|
|
if not (Util.IsTouchDevice() or InputService.VREnabled) then
|
|
ChatModule:SetVisible(true)
|
|
end
|
|
|
|
local menuItem = CreateMenuItem(chatIconButton)
|
|
|
|
rawset(menuItem, "ToggleChat", function(self)
|
|
toggleChat()
|
|
end)
|
|
rawset(menuItem, "SetTransparency", function(self, transparency)
|
|
chatIconImage.ImageTransparency = transparency
|
|
end)
|
|
rawset(menuItem, "SetImage", function(self, newImage)
|
|
chatIconImage.Image = newImage
|
|
end)
|
|
|
|
return menuItem
|
|
end
|
|
|
|
local function CreateMobileHideChatIcon()
|
|
local ChatModule = require(GuiRoot.Modules.Chat)
|
|
|
|
local chatHideIconButton = Util.Create'ImageButton'
|
|
{
|
|
Name = "ChatVisible";
|
|
Size = UDim2.new(0, 50, 0, TOPBAR_THICKNESS);
|
|
Image = "";
|
|
AutoButtonColor = false;
|
|
BackgroundTransparency = 1;
|
|
};
|
|
|
|
local chatIconImage = Util.Create'ImageLabel'
|
|
{
|
|
Name = "ChatVisibleIcon";
|
|
Size = UDim2.new(0, 28, 0, 27);
|
|
Position = UDim2.new(0.5, -14, 0.5, -13);
|
|
BackgroundTransparency = 1;
|
|
Image = "rbxasset://textures/ui/Chat/ToggleChat.png";
|
|
Parent = chatHideIconButton;
|
|
};
|
|
|
|
local unreadMessageNotifier = CreateUnreadMessagesNotifier(ChatModule)
|
|
unreadMessageNotifier.Parent = chatIconImage
|
|
|
|
local function updateIcon(down)
|
|
if down then
|
|
chatIconImage.Image = "rbxasset://textures/ui/Chat/ToggleChatDown.png";
|
|
else
|
|
chatIconImage.Image = "rbxasset://textures/ui/Chat/ToggleChat.png";
|
|
end
|
|
end
|
|
|
|
local function toggleChat()
|
|
ChatModule:ToggleVisibility()
|
|
end
|
|
|
|
local function onChatStateChanged(visible)
|
|
updateIcon(visible)
|
|
end
|
|
|
|
chatHideIconButton.MouseButton1Click:connect(function()
|
|
toggleChat()
|
|
end)
|
|
|
|
if ChatModule.VisibilityStateChanged then
|
|
ChatModule.VisibilityStateChanged:connect(onChatStateChanged)
|
|
end
|
|
onChatStateChanged(ChatModule:GetVisibility())
|
|
|
|
return CreateMenuItem(chatHideIconButton)
|
|
end
|
|
|
|
|
|
local function Create3DChatIcon(topBarInstance, panel, menubar)
|
|
local chatEnabled = game:GetService("UserInputService"):GetPlatform() ~= Enum.Platform.XBoxOne
|
|
if not chatEnabled then return end
|
|
|
|
local ChatModule = require(GuiRoot.Modules.Chat)
|
|
|
|
local menuItem = Create3DMenuItem()
|
|
menuItem:SetHoverText("Chat")
|
|
|
|
local icon = Util.Create "ImageLabel" {
|
|
Parent = menuItem:GetInstance(),
|
|
|
|
Position = UDim2.new(0.5, -14, 0.5, -12),
|
|
Size = UDim2.new(0, 28, 0, 28),
|
|
|
|
BackgroundTransparency = 1,
|
|
|
|
Image = "rbxasset://textures/ui/Chat/Chat.png"
|
|
}
|
|
|
|
menuItem.MouseButton1Click:connect(function()
|
|
ChatModule:SetVisible(not ChatModule:GetVisibility())
|
|
if ChatModule:GetVisibility() then
|
|
ChatModule:FocusChatBar()
|
|
end
|
|
menubar:CloseAllExcept(menuItem)
|
|
end)
|
|
|
|
local closedEventConn = nil
|
|
local function OnVREnabled(prop)
|
|
if prop == 'VREnabled' then
|
|
if closedEventConn then
|
|
closedEventConn:disconnect()
|
|
closedEventConn = nil
|
|
end
|
|
if InputService.VREnabled then
|
|
local VirtualKeyboardModule = require(GuiRoot.Modules.VR.VirtualKeyboard)
|
|
closedEventConn = VirtualKeyboardModule.ClosedEvent:connect(function()
|
|
if ChatModule:IsFocused(true) then
|
|
ChatModule:SetVisible(false)
|
|
end
|
|
end)
|
|
end
|
|
end
|
|
end
|
|
InputService.Changed:connect(OnVREnabled)
|
|
spawn(function() OnVREnabled("VREnabled") end)
|
|
|
|
|
|
local chatPanel = Panel3D.Get("Chat")
|
|
function chatPanel:OnVisibilityChanged(visible)
|
|
menuItem:SetActive(visible)
|
|
end
|
|
|
|
return menuItem
|
|
end
|
|
|
|
local function Create3DUserGuiToggleIcon(topBarInstance, panel, menubar)
|
|
local menuItem = Create3DMenuItem()
|
|
menuItem:SetHoverText("2D UI")
|
|
|
|
local icon = Util.Create "ImageLabel" {
|
|
Parent = menuItem:GetInstance(),
|
|
|
|
Position = UDim2.new(0.5, -14, 0.5, -14),
|
|
Size = UDim2.new(0, 28, 0, 28),
|
|
|
|
BackgroundTransparency = 1,
|
|
|
|
Image = "rbxasset://textures/ui/VR/toggle2D.png"
|
|
}
|
|
|
|
local userGuiPanel = Panel3D.Get("UserGui")
|
|
userGuiPanel:SetType(Panel3D.Type.Fixed)
|
|
userGuiPanel:ResizePixels(300, 125)
|
|
userGuiPanel:SetVisible(false, false)
|
|
|
|
menuItem.MouseButton1Click:connect(function()
|
|
if InputService.VREnabled then
|
|
userGuiPanel:SetVisible(not userGuiPanel.isVisible, false)
|
|
end
|
|
end)
|
|
|
|
function userGuiPanel:OnVisibilityChanged(visible)
|
|
if visible then
|
|
local headLook = Panel3D.GetHeadLookXZ(true)
|
|
userGuiPanel.localCF = headLook * CFrame.Angles(math.rad(5), 0, 0) * CFrame.new(0, 0, 5)
|
|
end
|
|
menuItem:SetActive(visible)
|
|
local success, msg = pcall(function()
|
|
CoreGuiService:SetUserGuiRendering(true, visible and userGuiPanel:GetPart() or nil, Enum.NormalId.Front)
|
|
end)
|
|
end
|
|
|
|
local function OnVREnabled(prop)
|
|
if prop == 'VREnabled' then
|
|
local guiPart = nil
|
|
if InputService.VREnabled then
|
|
if userGuiPanel.isVisible then
|
|
guiPart = userGuiPanel:GetPart()
|
|
end
|
|
else
|
|
userGuiPanel:SetVisible(false, false)
|
|
end
|
|
local success, msg = pcall(function()
|
|
CoreGuiService:SetUserGuiRendering(InputService.VREnabled, guiPart, Enum.NormalId.Front)
|
|
end)
|
|
end
|
|
end
|
|
InputService.Changed:connect(OnVREnabled)
|
|
spawn(function() OnVREnabled("VREnabled") end)
|
|
|
|
return menuItem
|
|
end
|
|
|
|
-----------
|
|
|
|
--- Backpack ---
|
|
local function CreateBackpackIcon()
|
|
local BackpackModule = require(GuiRoot.Modules.BackpackScript)
|
|
|
|
local backpackIconButton = Util.Create'ImageButton'
|
|
{
|
|
Name = "Backpack";
|
|
Size = UDim2.new(0, 50, 0, TOPBAR_THICKNESS);
|
|
Image = "";
|
|
AutoButtonColor = false;
|
|
BackgroundTransparency = 1;
|
|
};
|
|
|
|
local backpackIconImage = Util.Create'ImageLabel'
|
|
{
|
|
Name = "BackpackIcon";
|
|
Size = UDim2.new(0, 22, 0, 28);
|
|
Position = UDim2.new(0.5, -11, 0.5, -14);
|
|
BackgroundTransparency = 1;
|
|
Image = "rbxasset://textures/ui/Backpack/Backpack.png";
|
|
Parent = backpackIconButton;
|
|
};
|
|
|
|
local function onBackpackStateChanged(open)
|
|
if open then
|
|
backpackIconImage.Image = "rbxasset://textures/ui/Backpack/Backpack_Down.png";
|
|
else
|
|
backpackIconImage.Image = "rbxasset://textures/ui/Backpack/Backpack.png";
|
|
end
|
|
end
|
|
|
|
BackpackModule.StateChanged.Event:connect(onBackpackStateChanged)
|
|
|
|
local function toggleBackpack()
|
|
BackpackModule:OpenClose()
|
|
end
|
|
|
|
topbarEnabledChangedEvent.Event:connect(function()
|
|
BackpackModule:TopbarEnabledChanged(topbarEnabled)
|
|
end)
|
|
|
|
backpackIconButton.MouseButton1Click:connect(function()
|
|
BackpackModule:OpenClose()
|
|
end)
|
|
|
|
return CreateMenuItem(backpackIconButton)
|
|
end
|
|
--------------
|
|
|
|
----- Stop Recording --
|
|
local function CreateStopRecordIcon()
|
|
local stopRecordIconButton = Util.Create'ImageButton'
|
|
{
|
|
Name = "StopRecording";
|
|
Size = UDim2.new(0, 50, 0, TOPBAR_THICKNESS);
|
|
Image = "";
|
|
Visible = true;
|
|
BackgroundTransparency = 1;
|
|
};
|
|
stopRecordIconButton:SetVerb("RecordToggle")
|
|
|
|
local stopRecordIconLabel = Util.Create'ImageLabel'
|
|
{
|
|
Name = "StopRecordingIcon";
|
|
Size = UDim2.new(0, 28, 0, 28);
|
|
Position = UDim2.new(0.5, -14, 0.5, -14);
|
|
BackgroundTransparency = 1;
|
|
Image = "rbxasset://textures/ui/RecordDown.png";
|
|
Parent = stopRecordIconButton;
|
|
};
|
|
|
|
return CreateMenuItem(stopRecordIconButton)
|
|
end
|
|
-----------------------
|
|
|
|
local TopBar = CreateTopBar()
|
|
local LeftMenubar = CreateMenuBar(BarAlignmentEnum.Left)
|
|
local RightMenubar = CreateMenuBar(BarAlignmentEnum.Right)
|
|
local ThreeDMenubar = Create3DMenuBar(BarAlignmentEnum.Left, Topbar3DPanel)
|
|
|
|
local settingsIcon = CreateSettingsIcon(TopBar)
|
|
local mobileShowChatIcon = Util.IsTouchDevice() and CreateMobileHideChatIcon() or nil
|
|
local chatIcon = CreateChatIcon()
|
|
local backpackIcon = CreateBackpackIcon()
|
|
local stopRecordingIcon = CreateStopRecordIcon()
|
|
|
|
local leaderstatsMenuItem = CreateLeaderstatsMenuItem()
|
|
local nameAndHealthMenuItem = CreateUsernameHealthMenuItem()
|
|
|
|
local settingsIcon3D = Create3DSettingsIcon(TopBar, Topbar3DPanel, ThreeDMenubar)
|
|
local chatIcon3D = Create3DChatIcon(TopBar, Topbar3DPanel, ThreeDMenubar)
|
|
local userGuiIcon3D = Create3DUserGuiToggleIcon(TopBar, Topbar3DPanel, ThreeDMenubar)
|
|
|
|
local LEFT_ITEM_ORDER = {}
|
|
local RIGHT_ITEM_ORDER = {}
|
|
local THREE_D_ITEM_ORDER = {}
|
|
|
|
|
|
-- Set Item Orders
|
|
if settingsIcon then
|
|
LEFT_ITEM_ORDER[settingsIcon] = 1
|
|
end
|
|
if mobileShowChatIcon then
|
|
LEFT_ITEM_ORDER[mobileShowChatIcon] = 2
|
|
end
|
|
if chatIcon then
|
|
LEFT_ITEM_ORDER[chatIcon] = 3
|
|
end
|
|
if backpackIcon then
|
|
LEFT_ITEM_ORDER[backpackIcon] = 4
|
|
end
|
|
if stopRecordingIcon then
|
|
LEFT_ITEM_ORDER[stopRecordingIcon] = 5
|
|
end
|
|
|
|
if leaderstatsMenuItem then
|
|
RIGHT_ITEM_ORDER[leaderstatsMenuItem] = 1
|
|
end
|
|
if nameAndHealthMenuItem and not isTenFootInterface then
|
|
RIGHT_ITEM_ORDER[nameAndHealthMenuItem] = 2
|
|
end
|
|
|
|
if settingsIcon3D then
|
|
THREE_D_ITEM_ORDER[settingsIcon3D] = 1
|
|
end
|
|
if chatIcon3D then
|
|
THREE_D_ITEM_ORDER[chatIcon3D] = 2
|
|
end
|
|
if userGuiIcon3D then
|
|
THREE_D_ITEM_ORDER[userGuiIcon3D] = 3
|
|
end
|
|
|
|
-------------------------
|
|
|
|
|
|
local function AddItemInOrder(Bar, Item, ItemOrder)
|
|
local index = 1
|
|
while ItemOrder[Bar:ItemAtIndex(index)] and ItemOrder[Bar:ItemAtIndex(index)] < ItemOrder[Item] do
|
|
index = index + 1
|
|
end
|
|
Bar:AddItem(Item, index)
|
|
end
|
|
|
|
local function OnCoreGuiChanged(coreGuiType, coreGuiEnabled)
|
|
local enabled = coreGuiEnabled and topbarEnabled
|
|
if coreGuiType == Enum.CoreGuiType.PlayerList or coreGuiType == Enum.CoreGuiType.All then
|
|
if leaderstatsMenuItem then
|
|
if enabled then
|
|
AddItemInOrder(RightMenubar, leaderstatsMenuItem, RIGHT_ITEM_ORDER)
|
|
else
|
|
RightMenubar:RemoveItem(leaderstatsMenuItem)
|
|
end
|
|
end
|
|
end
|
|
if coreGuiType == Enum.CoreGuiType.Health or coreGuiType == Enum.CoreGuiType.All then
|
|
if nameAndHealthMenuItem then
|
|
nameAndHealthMenuItem:SetHealthbarEnabled(enabled)
|
|
end
|
|
end
|
|
if coreGuiType == Enum.CoreGuiType.Backpack or coreGuiType == Enum.CoreGuiType.All then
|
|
if backpackIcon then
|
|
if enabled then
|
|
AddItemInOrder(LeftMenubar, backpackIcon, LEFT_ITEM_ORDER)
|
|
else
|
|
LeftMenubar:RemoveItem(backpackIcon)
|
|
end
|
|
end
|
|
end
|
|
if coreGuiType == Enum.CoreGuiType.Chat or coreGuiType == Enum.CoreGuiType.All then
|
|
local showTopbarChatIcon = enabled and Player.ChatMode == Enum.ChatMode.TextAndMenu
|
|
local showThree3DChatIcon = coreGuiEnabled and InputService.VREnabled and Player.ChatMode == Enum.ChatMode.TextAndMenu
|
|
|
|
if showThree3DChatIcon then
|
|
if chatIcon3D then
|
|
AddItemInOrder(ThreeDMenubar, chatIcon3D, THREE_D_ITEM_ORDER)
|
|
end
|
|
else
|
|
if chatIcon3D then
|
|
ThreeDMenubar:RemoveItem(chatIcon3D)
|
|
end
|
|
end
|
|
if showTopbarChatIcon then
|
|
if chatIcon then
|
|
AddItemInOrder(LeftMenubar, chatIcon, LEFT_ITEM_ORDER)
|
|
end
|
|
if mobileShowChatIcon and PlayersService.ClassicChat then
|
|
AddItemInOrder(LeftMenubar, mobileShowChatIcon, LEFT_ITEM_ORDER)
|
|
end
|
|
else
|
|
if chatIcon then
|
|
LeftMenubar:RemoveItem(chatIcon)
|
|
end
|
|
if mobileShowChatIcon then
|
|
LeftMenubar:RemoveItem(mobileShowChatIcon)
|
|
end
|
|
end
|
|
end
|
|
|
|
if nameAndHealthMenuItem then
|
|
local playerListOn = StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.PlayerList)
|
|
local healthbarOn = StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Health)
|
|
-- Left-align the player's name if either playerlist or healthbar is shown
|
|
nameAndHealthMenuItem:SetNameVisible((playerListOn or healthbarOn) and topbarEnabled)
|
|
end
|
|
end
|
|
|
|
|
|
TopBar:UpdateBackgroundTransparency()
|
|
|
|
LeftMenubar:SetDock(TopBar:GetInstance())
|
|
RightMenubar:SetDock(TopBar:GetInstance())
|
|
ThreeDMenubar:SetDock(Topbar3DPanel:GetGUI())
|
|
|
|
|
|
if not isTenFootInterface then
|
|
Util.SetGUIInsetBounds(0, TOPBAR_THICKNESS, 0, 0)
|
|
end
|
|
|
|
if settingsIcon then
|
|
AddItemInOrder(LeftMenubar, settingsIcon, LEFT_ITEM_ORDER)
|
|
end
|
|
if nameAndHealthMenuItem and topbarEnabled and not isTenFootInterface then
|
|
AddItemInOrder(RightMenubar, nameAndHealthMenuItem, RIGHT_ITEM_ORDER)
|
|
end
|
|
|
|
if userGuiIcon3D and vr3dGuis then
|
|
local function FindScreenGuiChild(object)
|
|
for _, child in pairs(object:GetChildren()) do
|
|
if child:IsA('ScreenGui') then
|
|
return child
|
|
end
|
|
end
|
|
end
|
|
|
|
local function onPlayerGuiAdded(playerGui)
|
|
playerGui.ChildAdded:connect(function(child)
|
|
if FindScreenGuiChild(playerGui) then
|
|
AddItemInOrder(ThreeDMenubar, userGuiIcon3D, THREE_D_ITEM_ORDER)
|
|
end
|
|
end)
|
|
playerGui.ChildRemoved:connect(function(child)
|
|
if child:IsA('ScreenGui') and not FindScreenGuiChild(playerGui) then
|
|
ThreeDMenubar:RemoveItem(userGuiIcon3D)
|
|
end
|
|
end)
|
|
if FindScreenGuiChild(playerGui) then
|
|
AddItemInOrder(ThreeDMenubar, userGuiIcon3D, THREE_D_ITEM_ORDER)
|
|
end
|
|
end
|
|
Player.ChildAdded:connect(function(child)
|
|
if child:IsA('PlayerGui') then
|
|
onPlayerGuiAdded(child)
|
|
end
|
|
end)
|
|
if Player:FindFirstChild('PlayerGui') then
|
|
onPlayerGuiAdded(Player:FindFirstChild('PlayerGui'))
|
|
end
|
|
end
|
|
|
|
|
|
local function MoveHamburgerTo3D()
|
|
Topbar3DPanel:SetType(Panel3D.Type.Fixed)
|
|
Topbar3DPanel:LinkTo("Backpack")
|
|
Topbar3DPanel:SetVisible(true)
|
|
|
|
local backpackPanel = Panel3D.Get("Backpack")
|
|
local panelLocalCF = CFrame.Angles(math.rad(5), 0, 0) * CFrame.new(0, -1.625, 0) * CFrame.Angles(math.rad(5), 0, 0)
|
|
function Topbar3DPanel:PreUpdate(cameraCF, cameraRenderCF, userHeadCF, lookRay)
|
|
local panelOriginCF = backpackPanel.localCF or CFrame.new()
|
|
self.localCF = panelOriginCF * panelLocalCF
|
|
end
|
|
|
|
function Topbar3DPanel:OnUpdate()
|
|
for _, item in pairs(ThreeDMenubar:GetItems()) do
|
|
item:SetTransparency(self.transparency)
|
|
end
|
|
end
|
|
|
|
LeftMenubar:RemoveItem(settingsIcon)
|
|
AddItemInOrder(ThreeDMenubar, settingsIcon3D, THREE_D_ITEM_ORDER)
|
|
end
|
|
|
|
local gameOptions = settings():FindFirstChild("Game Options")
|
|
if gameOptions and not isTenFootInterface then
|
|
local success, result = pcall(function()
|
|
gameOptions.VideoRecordingChangeRequest:connect(function(recording)
|
|
if recording and topbarEnabled then
|
|
AddItemInOrder(LeftMenubar, stopRecordingIcon, LEFT_ITEM_ORDER)
|
|
else
|
|
LeftMenubar:RemoveItem(stopRecordingIcon)
|
|
end
|
|
end)
|
|
end)
|
|
end
|
|
|
|
local function topBarEnabledChanged()
|
|
topbarEnabledChangedEvent:Fire(topbarEnabled)
|
|
TopBar:UpdateBackgroundTransparency()
|
|
for _, enumItem in pairs(Enum.CoreGuiType:GetEnumItems()) do
|
|
-- The All enum will be false if any of the coreguis are false
|
|
-- therefore by force updating it we are clobbering the previous sets
|
|
if enumItem ~= Enum.CoreGuiType.All then
|
|
OnCoreGuiChanged(enumItem, StarterGui:GetCoreGuiEnabled(enumItem))
|
|
end
|
|
end
|
|
end
|
|
|
|
local UISChanged;
|
|
local function OnVREnabled(prop)
|
|
if prop == "VREnabled" and InputService.VREnabled then
|
|
VREnabled = true
|
|
topbarEnabled = false
|
|
MoveHamburgerTo3D()
|
|
topBarEnabledChanged()
|
|
if UISChanged then
|
|
UISChanged:disconnect()
|
|
UISChanged = nil
|
|
end
|
|
end
|
|
end
|
|
UISChanged = InputService.Changed:connect(OnVREnabled)
|
|
OnVREnabled("VREnabled")
|
|
|
|
if defeatableTopbar then
|
|
StarterGui:RegisterSetCore("TopbarEnabled", function(enabled)
|
|
if type(enabled) == "boolean" then
|
|
topbarEnabled = enabled
|
|
topBarEnabledChanged()
|
|
end
|
|
end)
|
|
end
|
|
|
|
-- Hook-up coregui changing
|
|
StarterGui.CoreGuiChangedSignal:connect(OnCoreGuiChanged)
|
|
topBarEnabledChanged()
|