add gs
This commit is contained in:
+269
@@ -0,0 +1,269 @@
|
||||
--[[
|
||||
// FileName: ContextMenuGui.lua
|
||||
// Written by: TheGamer101
|
||||
// Description: Module for creating the context GUI.
|
||||
]]
|
||||
|
||||
-- CONSTANTS
|
||||
|
||||
local BG_TRANSPARENCY = 1
|
||||
local BG_COLOR = Color3.fromRGB(31, 31, 31)
|
||||
|
||||
local BOTTOM_SCREEN_PADDING_PERCENT = 0.02
|
||||
|
||||
local MAX_WIDTH = 250
|
||||
local MAX_HEIGHT = 300
|
||||
local MAX_WIDTH_PERCENT = 0.7
|
||||
local MAX_HEIGHT_PERCENT = 0.6
|
||||
|
||||
local PLAYER_ICON_SIZE_Y = 0.3
|
||||
|
||||
-- SERVICES
|
||||
local CoreGuiService = game:GetService("CoreGui")
|
||||
local GuiService = game:GetService("GuiService")
|
||||
|
||||
--- VARIABLES
|
||||
local RobloxGui = CoreGuiService:WaitForChild("RobloxGui")
|
||||
local CoreGuiModules = RobloxGui:WaitForChild("Modules")
|
||||
local SettingsModules = CoreGuiModules:WaitForChild("Settings")
|
||||
local AvatarMenuModules = CoreGuiModules:WaitForChild("AvatarContextMenu")
|
||||
local PlayerCarousel = nil
|
||||
local PlayerChangedEvent = Instance.new("BindableEvent")
|
||||
|
||||
--- Modules
|
||||
local ContextMenuUtil = require(AvatarMenuModules:WaitForChild("ContextMenuUtil"))
|
||||
local Utility = require(SettingsModules:WaitForChild("Utility"))
|
||||
|
||||
local ContextMenuGui = {}
|
||||
ContextMenuGui.__index = ContextMenuGui
|
||||
|
||||
-- PRIVATE METHODS
|
||||
|
||||
function ContextMenuGui:CreateContextMenuHolder(player)
|
||||
local contextMenuHolder = Instance.new("Frame")
|
||||
contextMenuHolder.Name = "AvatarContextMenu"
|
||||
contextMenuHolder.Position = UDim2.new(0, 0, 0, 0)
|
||||
contextMenuHolder.Size = UDim2.new(1, 0, 1, 0)
|
||||
contextMenuHolder.BackgroundTransparency = 1
|
||||
contextMenuHolder.Parent = RobloxGui
|
||||
return contextMenuHolder
|
||||
end
|
||||
|
||||
function ContextMenuGui:CreateLeaveMenuButton(frame)
|
||||
local function closeMenu()
|
||||
self.CloseMenuFunc()
|
||||
end
|
||||
local closeMenuButton = Instance.new("ImageButton")
|
||||
closeMenuButton.Name = "CloseMenuButton"
|
||||
closeMenuButton.BackgroundTransparency = 1
|
||||
closeMenuButton.AnchorPoint = Vector2.new(1, 0)
|
||||
closeMenuButton.Position = UDim2.new(1, -10, 0, 10)
|
||||
closeMenuButton.Size = UDim2.new(0.05, 0, 0.1, 0)
|
||||
closeMenuButton.Image = "rbxasset://textures/loading/cancelButton.png"
|
||||
closeMenuButton.Selectable = false
|
||||
closeMenuButton.Activated:Connect(closeMenu)
|
||||
|
||||
local aspectConstraint = Instance.new("UIAspectRatioConstraint")
|
||||
aspectConstraint.AspectType = Enum.AspectType.FitWithinMaxSize
|
||||
aspectConstraint.DominantAxis = Enum.DominantAxis.Height
|
||||
aspectConstraint.AspectRatio = 1
|
||||
aspectConstraint.Parent = closeMenuButton
|
||||
|
||||
closeMenuButton.Parent = frame
|
||||
|
||||
return closeMenuButton
|
||||
end
|
||||
|
||||
-- PUBLIC METHODS
|
||||
|
||||
local function listenToViewportChange(functionToFire)
|
||||
if functionToFire == nil then return end
|
||||
|
||||
local viewportChangedConnection = nil
|
||||
|
||||
local function updateCamera()
|
||||
local newCamera = workspace.CurrentCamera
|
||||
if viewportChangedConnection then
|
||||
viewportChangedConnection:Disconnect()
|
||||
end
|
||||
viewportChangedConnection = newCamera:GetPropertyChangedSignal('ViewportSize'):Connect(functionToFire)
|
||||
functionToFire()
|
||||
end
|
||||
|
||||
workspace:GetPropertyChangedSignal('CurrentCamera'):Connect(updateCamera)
|
||||
updateCamera()
|
||||
end
|
||||
|
||||
function ContextMenuGui:CreateMenuFrame()
|
||||
local contextMenuHolder = self:CreateContextMenuHolder()
|
||||
|
||||
local menu = Instance.new("ImageButton")
|
||||
menu.Name = "Menu"
|
||||
menu.Size = UDim2.new(0.95, 0, 0.9, 0)
|
||||
menu.Position = UDim2.new(0.5, 0, 1 - BOTTOM_SCREEN_PADDING_PERCENT, 0)
|
||||
menu.AnchorPoint = Vector2.new(0.5, 1)
|
||||
menu.BackgroundTransparency = 1
|
||||
menu.Selectable = false
|
||||
menu.Image = "rbxasset://textures/blackBkg_round.png"
|
||||
menu.ScaleType = Enum.ScaleType.Slice
|
||||
menu.SliceCenter = Rect.new(12,12,12,12)
|
||||
menu.Visible = false
|
||||
menu.Active = true
|
||||
menu.ClipsDescendants = true
|
||||
|
||||
GuiService:AddSelectionParent("AvatarContextMenuGroup", menu)
|
||||
|
||||
local aspectConstraint = Instance.new("UIAspectRatioConstraint")
|
||||
aspectConstraint.AspectType = Enum.AspectType.ScaleWithParentSize
|
||||
aspectConstraint.DominantAxis = Enum.DominantAxis.Height
|
||||
aspectConstraint.AspectRatio = 1.15
|
||||
aspectConstraint.Parent = menu
|
||||
|
||||
local function updateAspectRatioForViewport()
|
||||
local viewportSize = workspace.CurrentCamera.ViewportSize
|
||||
if viewportSize.x < viewportSize.y then
|
||||
aspectConstraint.DominantAxis = Enum.DominantAxis.Width
|
||||
else
|
||||
aspectConstraint.DominantAxis = Enum.DominantAxis.Height
|
||||
end
|
||||
end
|
||||
listenToViewportChange(updateAspectRatioForViewport)
|
||||
|
||||
local sizeConstraint = Instance.new("UISizeConstraint")
|
||||
sizeConstraint.MaxSize = Vector2.new(300,300)
|
||||
sizeConstraint.MinSize = Vector2.new(200,200)
|
||||
sizeConstraint.Parent = menu
|
||||
|
||||
local contentFrame = Instance.new("Frame")
|
||||
contentFrame.Name = "Content"
|
||||
contentFrame.Size = UDim2.new(1,0,1,0)
|
||||
contentFrame.BackgroundTransparency = 1
|
||||
contentFrame.Parent = menu
|
||||
|
||||
local contentListLayout = Instance.new("UIListLayout")
|
||||
contentListLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
|
||||
contentListLayout.VerticalAlignment = Enum.VerticalAlignment.Top
|
||||
contentListLayout.SortOrder = Enum.SortOrder.LayoutOrder
|
||||
contentListLayout.Parent = contentFrame
|
||||
|
||||
local contextActionList = Instance.new("ScrollingFrame")
|
||||
contextActionList.Name = "ContextActionList"
|
||||
contextActionList.AnchorPoint = Vector2.new(0.5,1)
|
||||
contextActionList.BackgroundColor3 = Color3.fromRGB(79,79,79)
|
||||
contextActionList.BorderSizePixel = 0
|
||||
contextActionList.LayoutOrder = 2
|
||||
contextActionList.Size = UDim2.new(1,-12,0.54,0)
|
||||
contextActionList.CanvasSize = UDim2.new(0,0,0,208)
|
||||
contextActionList.ScrollBarThickness = 4
|
||||
contextActionList.Selectable = false
|
||||
contextActionList.Parent = contentFrame
|
||||
|
||||
local contextActionListUIListLayout = Instance.new("UIListLayout")
|
||||
contextActionListUIListLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
|
||||
contextActionListUIListLayout.SortOrder = Enum.SortOrder.LayoutOrder
|
||||
contextActionListUIListLayout.VerticalAlignment = Enum.VerticalAlignment.Top
|
||||
|
||||
contextActionListUIListLayout:GetPropertyChangedSignal("AbsoluteContentSize"):Connect(function()
|
||||
contextActionList.CanvasSize = UDim2.new(0,0,0,contextActionListUIListLayout.AbsoluteContentSize.Y)
|
||||
end)
|
||||
|
||||
contextActionListUIListLayout.Parent = contextActionList
|
||||
|
||||
local nameTag = Instance.new("TextButton")
|
||||
nameTag.Name = "NameTag"
|
||||
nameTag.AnchorPoint = Vector2.new(0.5,1)
|
||||
nameTag.BackgroundColor3 = Color3.fromRGB(79,79,79)
|
||||
nameTag.AutoButtonColor = false
|
||||
nameTag.BorderSizePixel = 0
|
||||
nameTag.LayoutOrder = 1
|
||||
nameTag.Size = UDim2.new(1,-12,0.16,0)
|
||||
nameTag.Font = Enum.Font.SourceSansBold
|
||||
nameTag.Text = ""
|
||||
nameTag.TextColor3 = Color3.fromRGB(255,255,255)
|
||||
nameTag.TextSize = 24
|
||||
nameTag.TextXAlignment = Enum.TextXAlignment.Center
|
||||
nameTag.TextYAlignment = Enum.TextYAlignment.Center
|
||||
nameTag.Selectable = false
|
||||
nameTag.Parent = contentFrame
|
||||
|
||||
local underline = Instance.new("Frame")
|
||||
underline.Name = "Underline"
|
||||
underline.BackgroundColor3 = Color3.fromRGB(255,255,255)
|
||||
underline.AnchorPoint = Vector2.new(0,1)
|
||||
underline.BorderSizePixel = 0
|
||||
underline.Position = UDim2.new(0,0,1,0)
|
||||
underline.Size = UDim2.new(1,0,0,2)
|
||||
underline.Parent = nameTag
|
||||
|
||||
self:CreateLeaveMenuButton(menu)
|
||||
|
||||
menu.Parent = contextMenuHolder
|
||||
self.ContextMenuFrame = menu
|
||||
|
||||
return menu
|
||||
end
|
||||
|
||||
function ContextMenuGui:BuildPlayerCarousel(playersByProximity)
|
||||
if not PlayerCarousel then
|
||||
PlayerCarousel = require(AvatarMenuModules:WaitForChild("PlayerCarousel"))
|
||||
PlayerCarousel.rbxGui.Parent = self.ContextMenuFrame.Content
|
||||
end
|
||||
|
||||
PlayerCarousel:ClearPlayerEntries()
|
||||
|
||||
for i = 1, #playersByProximity do
|
||||
PlayerCarousel:CreatePlayerEntry(playersByProximity[i][1], playersByProximity[i][2])
|
||||
end
|
||||
|
||||
if #playersByProximity > 0 then
|
||||
self.ContextMenuFrame.Content.NameTag.Text = playersByProximity[1][1].Name
|
||||
end
|
||||
|
||||
PlayerCarousel.PlayerChanged:Connect(function(player)
|
||||
if player then
|
||||
self.ContextMenuFrame.Content.NameTag.Text = player.Name
|
||||
else
|
||||
self.ContextMenuFrame.Content.NameTag.Text = ""
|
||||
end
|
||||
PlayerChangedEvent:Fire(player)
|
||||
end)
|
||||
|
||||
end
|
||||
|
||||
function ContextMenuGui:GetBottomScreenPaddingConstant()
|
||||
return BOTTOM_SCREEN_PADDING_PERCENT
|
||||
end
|
||||
|
||||
function ContextMenuGui:SetCloseMenuFunc(closeMenuFunc)
|
||||
self.CloseMenuFunc = closeMenuFunc
|
||||
end
|
||||
|
||||
function ContextMenuGui:SwitchToPlayerEntry(player, dontTween)
|
||||
if not PlayerCarousel then return end
|
||||
PlayerCarousel:SwitchToPlayerEntry(player, dontTween)
|
||||
end
|
||||
|
||||
function ContextMenuGui:OffsetPlayerEntry(offset)
|
||||
if not PlayerCarousel then return end
|
||||
PlayerCarousel:OffsetPlayerEntry(offset)
|
||||
end
|
||||
|
||||
function ContextMenuGui:GetSelectedPlayer()
|
||||
if not PlayerCarousel then return nil end
|
||||
return PlayerCarousel:GetSelectedPlayer()
|
||||
end
|
||||
|
||||
function ContextMenuGui.new()
|
||||
local obj = setmetatable({}, ContextMenuGui)
|
||||
|
||||
obj.CloseMenuFunc = nil
|
||||
|
||||
obj.ContextMenuFrame = nil
|
||||
obj.LastSetPlayerIcon = nil
|
||||
|
||||
obj.SelectedPlayerChanged = PlayerChangedEvent.Event
|
||||
|
||||
return obj
|
||||
end
|
||||
|
||||
return ContextMenuGui.new()
|
||||
+314
@@ -0,0 +1,314 @@
|
||||
--[[
|
||||
// FileName: ContextMenuItems.lua
|
||||
// Written by: TheGamer101
|
||||
// Description: Module for creating the context menu items for the menu and doing the actions when they are clicked.
|
||||
]]
|
||||
|
||||
-- CONSTANTS
|
||||
local FRIEND_LAYOUT_ORDER = 1
|
||||
local CHAT_LAYOUT_ORDER = 3
|
||||
local WAVE_LAYOUT_ORDER = 4
|
||||
local CUSTOM_LAYOUT_ORDER = 20
|
||||
|
||||
local MENU_ITEM_SIZE_X = 0.96
|
||||
local MENU_ITEM_SIZE_Y = 0
|
||||
local MENU_ITEM_SIZE_Y_OFFSET = 52
|
||||
|
||||
local THUMBNAIL_URL = "https://www.roblox.com/Thumbs/Avatar.ashx?x=200&y=200&format=png&userId="
|
||||
local BUST_THUMBNAIL_URL = "https://www.roblox.com/bust-thumbnail/image?width=420&height=420&format=png&userId="
|
||||
|
||||
--- SERVICES
|
||||
local PlayersService = game:GetService("Players")
|
||||
local CoreGuiService = game:GetService("CoreGui")
|
||||
local StarterGui = game:GetService("StarterGui")
|
||||
local Chat = game:GetService("Chat")
|
||||
local RunService = game:GetService("RunService")
|
||||
local AnalyticsService = game:GetService("AnalyticsService")
|
||||
|
||||
-- MODULES
|
||||
local RobloxGui = CoreGuiService:WaitForChild("RobloxGui")
|
||||
local CoreGuiModules = RobloxGui:WaitForChild("Modules")
|
||||
local SettingsModules = CoreGuiModules:WaitForChild("Settings")
|
||||
local AvatarMenuModules = CoreGuiModules:WaitForChild("AvatarContextMenu")
|
||||
local SettingsPages = SettingsModules:WaitForChild("Pages")
|
||||
|
||||
local ContextMenuUtil = require(AvatarMenuModules:WaitForChild("ContextMenuUtil"))
|
||||
|
||||
local PromptCreator = require(CoreGuiModules:WaitForChild("PromptCreator"))
|
||||
local PlayerDropDownModule = require(CoreGuiModules:WaitForChild("PlayerDropDown"))
|
||||
local ReportAbuseMenu = require(SettingsPages:WaitForChild("ReportAbuseMenu"))
|
||||
|
||||
-- VARIABLES
|
||||
|
||||
local LocalPlayer = PlayersService.LocalPlayer
|
||||
while not LocalPlayer do
|
||||
PlayersService.PlayerAdded:wait()
|
||||
LocalPlayer = PlayersService.LocalPlayer
|
||||
end
|
||||
|
||||
local EnabledContextMenuItems = {
|
||||
[Enum.AvatarContextMenuOption.Chat] = true,
|
||||
[Enum.AvatarContextMenuOption.Friend] = true,
|
||||
[Enum.AvatarContextMenuOption.Emote] = true
|
||||
}
|
||||
local CustomContextMenuItems = {}
|
||||
|
||||
local BlockingUtility = PlayerDropDownModule:CreateBlockingUtility()
|
||||
|
||||
local ContextMenuItems = {}
|
||||
ContextMenuItems.__index = ContextMenuItems
|
||||
|
||||
-- PRIVATE METHODS
|
||||
function ContextMenuItems:ClearMenuItems()
|
||||
local children = self.MenuItemFrame:GetChildren()
|
||||
for i = 1, #children do
|
||||
if children[i]:IsA("GuiObject") then
|
||||
children[i]:Destroy()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ContextMenuItems:AddCustomAvatarMenuItem(menuOption, bindableEvent)
|
||||
CustomContextMenuItems[menuOption] = bindableEvent
|
||||
end
|
||||
|
||||
function ContextMenuItems:RemoveCustomAvatarMenuItem(menuOption)
|
||||
CustomContextMenuItems[menuOption] = nil
|
||||
end
|
||||
|
||||
function ContextMenuItems:IsContextAvatarEnumItem(enumItem)
|
||||
local enumItems = Enum.AvatarContextMenuOption:GetEnumItems()
|
||||
for i = 1, #enumItems do
|
||||
if enumItem == enumItems[i] then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function ContextMenuItems:EnableDefaultMenuItem(menuOption)
|
||||
EnabledContextMenuItems[menuOption] = true
|
||||
end
|
||||
|
||||
function ContextMenuItems:RemoveDefaultMenuItem(menuOption)
|
||||
EnabledContextMenuItems[menuOption] = false
|
||||
end
|
||||
|
||||
function ContextMenuItems:RegisterCoreMethods()
|
||||
local function addMenuItemFunc(args) --[[ menuOption, bindableEvent]]
|
||||
if type(args) == "table" then
|
||||
local name = ""
|
||||
if args[1] and type(args[1]) == "string" then
|
||||
name = args[1]
|
||||
else
|
||||
error("AddAvatarContextMenuOption first argument must be a table or Enum.AvatarContextMenuOption")
|
||||
end
|
||||
|
||||
if args[2] and typeof(args[2]) == "Instance" and args[2].ClassName == "BindableEvent" then
|
||||
self:AddCustomAvatarMenuItem(name, args[2])
|
||||
else
|
||||
error("AddAvatarContextMenuOption second table entry must be a BindableEvent")
|
||||
end
|
||||
|
||||
elseif typeof(args) == "EnumItem" then
|
||||
if self:IsContextAvatarEnumItem(args) then
|
||||
self:EnableDefaultMenuItem(args)
|
||||
else
|
||||
error("AddAvatarContextMenuOption given EnumItem is not valid")
|
||||
end
|
||||
else
|
||||
error("AddAvatarContextMenuOption first argument must be a table or Enum.AvatarContextMenuOption")
|
||||
end
|
||||
end
|
||||
StarterGui:RegisterSetCore("AddAvatarContextMenuOption", addMenuItemFunc)
|
||||
local function removeMenuItemFunc(menuOption)
|
||||
if type(menuOption) == "string" then
|
||||
self:RemoveCustomAvatarMenuItem(menuOption)
|
||||
elseif typeof(menuOption) == "EnumItem" then
|
||||
if self:IsContextAvatarEnumItem(menuOption) then
|
||||
self:RemoveDefaultMenuItem(menuOption)
|
||||
else
|
||||
error("RemoveAvatarContextMenuOption given EnumItem is not valid")
|
||||
end
|
||||
else
|
||||
error("RemoveAvatarContextMenuOption first argument must be a string or Enum.AvatarContextMenuOption")
|
||||
end
|
||||
end
|
||||
StarterGui:RegisterSetCore("RemoveAvatarContextMenuOption", removeMenuItemFunc)
|
||||
end
|
||||
|
||||
function ContextMenuItems:CreateCustomMenuItems()
|
||||
for buttonText, bindableEvent in pairs(CustomContextMenuItems) do
|
||||
AnalyticsService:TrackEvent("Game", "AvatarContextMenuCustomButton", "name: " .. tostring(buttonText))
|
||||
local function customButtonFunc()
|
||||
bindableEvent:Fire(self.SelectedPlayer)
|
||||
end
|
||||
local customButton = ContextMenuUtil:MakeStyledButton("CustomButton", buttonText, UDim2.new(MENU_ITEM_SIZE_X, 0, MENU_ITEM_SIZE_Y, MENU_ITEM_SIZE_Y_OFFSET), customButtonFunc)
|
||||
customButton.Name = "CustomButton"
|
||||
customButton.LayoutOrder = CUSTOM_LAYOUT_ORDER
|
||||
customButton.Parent = self.MenuItemFrame
|
||||
end
|
||||
end
|
||||
|
||||
-- PUBLIC METHODS
|
||||
|
||||
local addFriendString = "Add Friend"
|
||||
local friendsString = "Friends"
|
||||
local friendRequestPendingString = "Friend Request Pending"
|
||||
local acceptFriendRequestString = "Accept Friend Request"
|
||||
|
||||
local addFriendDisabledTransparency = 0.75
|
||||
local friendStatusChangedConn = nil
|
||||
function ContextMenuItems:CreateFriendButton(status)
|
||||
local friendLabel = self.MenuItemFrame:FindFirstChild("FriendStatus")
|
||||
if friendLabel then
|
||||
friendLabel:Destroy()
|
||||
friendLabel = nil
|
||||
end
|
||||
if friendStatusChangedConn then
|
||||
friendStatusChangedConn:disconnect()
|
||||
end
|
||||
local friendLabelText = nil
|
||||
|
||||
local addFriendFunc = function()
|
||||
if friendLabelText and friendLabel.Selectable then
|
||||
friendLabel.Selectable = false
|
||||
friendLabelText.TextTransparency = addFriendDisabledTransparency
|
||||
friendLabelText.Text = friendRequestPendingString
|
||||
AnalyticsService:ReportCounter("AvatarContextMenu-RequestFriendship")
|
||||
AnalyticsService:TrackEvent("Game", "RequestFriendship", "AvatarContextMenu")
|
||||
LocalPlayer:RequestFriendship(self.SelectedPlayer)
|
||||
end
|
||||
end
|
||||
|
||||
friendLabel, friendLabelText = ContextMenuUtil:MakeStyledButton("FriendStatus", addFriendString, UDim2.new(MENU_ITEM_SIZE_X, 0, MENU_ITEM_SIZE_Y, MENU_ITEM_SIZE_Y_OFFSET), addFriendFunc)
|
||||
|
||||
if status ~= Enum.FriendStatus.Friend then
|
||||
friendLabel.Selectable = true
|
||||
friendLabelText.TextTransparency = 0
|
||||
else
|
||||
friendLabel.Selectable = false
|
||||
friendLabelText.TextTransparency = addFriendDisabledTransparency
|
||||
friendLabelText.Text = friendsString
|
||||
end
|
||||
|
||||
friendStatusChangedConn = LocalPlayer.FriendStatusChanged:connect(function(player, friendStatus)
|
||||
if player == self.SelectedPlayer and friendLabelText then
|
||||
if not friendLabel.Selectable then
|
||||
if friendStatus == Enum.FriendStatus.Friend then
|
||||
friendLabelText.Text = friendsString
|
||||
end
|
||||
else
|
||||
if friendStatus == Enum.FriendStatus.FriendRequestReceived then
|
||||
friendLabelText.Text = acceptFriendRequestString
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
friendLabel.LayoutOrder = FRIEND_LAYOUT_ORDER
|
||||
friendLabel.Parent = self.MenuItemFrame
|
||||
end
|
||||
|
||||
function ContextMenuItems:UpdateFriendButton(status)
|
||||
local friendLabel = self.MenuItemFrame:FindFirstChild("FriendStatus")
|
||||
if friendLabel then
|
||||
self:CreateFriendButton(status)
|
||||
end
|
||||
end
|
||||
|
||||
function ContextMenuItems:CreateEmoteButton()
|
||||
local function wave()
|
||||
if self.CloseMenuFunc then self:CloseMenuFunc() end
|
||||
|
||||
AnalyticsService:ReportCounter("AvatarContextMenu-Wave")
|
||||
AnalyticsService:TrackEvent("Game", "AvatarContextMenuWave", "placeId: " .. tostring(game.PlaceId))
|
||||
|
||||
PlayersService:Chat("/e wave")
|
||||
end
|
||||
|
||||
local waveButton = self.MenuItemFrame:FindFirstChild("Wave")
|
||||
if not waveButton then
|
||||
waveButton = ContextMenuUtil:MakeStyledButton("Wave", "Wave", UDim2.new(MENU_ITEM_SIZE_X, 0, MENU_ITEM_SIZE_Y, MENU_ITEM_SIZE_Y_OFFSET), wave)
|
||||
waveButton.LayoutOrder = WAVE_LAYOUT_ORDER
|
||||
waveButton.Parent = self.MenuItemFrame
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function ContextMenuItems:CreateChatButton()
|
||||
local function chatFunc()
|
||||
if self.CloseMenuFunc then self:CloseMenuFunc() end
|
||||
|
||||
AnalyticsService:ReportCounter("AvatarContextMenu-Chat")
|
||||
AnalyticsService:TrackEvent("Game", "AvatarContextMenuChat", "placeId: " .. tostring(game.PlaceId))
|
||||
|
||||
-- todo: need a proper api to set up text in the chat bar
|
||||
local ChatBar = nil
|
||||
pcall(function() ChatBar = LocalPlayer.PlayerGui.Chat.Frame.ChatBarParentFrame.Frame.BoxFrame.Frame.ChatBar end)
|
||||
if ChatBar then
|
||||
ChatBar.Text = "/w " .. self.SelectedPlayer.Name
|
||||
end
|
||||
|
||||
local ChatModule = require(RobloxGui.Modules.ChatSelector)
|
||||
ChatModule:SetVisible(true)
|
||||
ChatModule:FocusChatBar()
|
||||
end
|
||||
|
||||
local chatButton = self.MenuItemFrame:FindFirstChild("ChatStatus")
|
||||
if not chatButton then
|
||||
chatButton = ContextMenuUtil:MakeStyledButton("ChatStatus", "Chat", UDim2.new(MENU_ITEM_SIZE_X, 0, MENU_ITEM_SIZE_Y, MENU_ITEM_SIZE_Y_OFFSET), chatFunc)
|
||||
chatButton.LayoutOrder = CHAT_LAYOUT_ORDER
|
||||
end
|
||||
|
||||
local success, canLocalUserChat = pcall(function() return Chat:CanUserChatAsync(LocalPlayer.UserId) end)
|
||||
local canChat = success and (RunService:IsStudio() or canLocalUserChat)
|
||||
|
||||
if canChat then
|
||||
chatButton.Parent = self.MenuItemFrame
|
||||
else
|
||||
chatButton.Parent = nil
|
||||
end
|
||||
end
|
||||
|
||||
function ContextMenuItems:BuildContextMenuItems(player)
|
||||
if not player then return end
|
||||
|
||||
local friendStatus = ContextMenuUtil:GetFriendStatus(player)
|
||||
local isBlocked = BlockingUtility:IsPlayerBlockedByUserId(player.UserId)
|
||||
local isMuted = BlockingUtility:IsPlayerMutedByUserId(player.UserId)
|
||||
self:ClearMenuItems()
|
||||
self:SetSelectedPlayer(player)
|
||||
if EnabledContextMenuItems[Enum.AvatarContextMenuOption.Friend] then
|
||||
self:CreateFriendButton(friendStatus)
|
||||
end
|
||||
if EnabledContextMenuItems[Enum.AvatarContextMenuOption.Chat] then
|
||||
self:CreateChatButton()
|
||||
end
|
||||
if EnabledContextMenuItems[Enum.AvatarContextMenuOption.Emote] then
|
||||
self:CreateEmoteButton()
|
||||
end
|
||||
|
||||
self:CreateCustomMenuItems()
|
||||
end
|
||||
|
||||
function ContextMenuItems:SetSelectedPlayer(selectedPlayer)
|
||||
self.SelectedPlayer = selectedPlayer
|
||||
end
|
||||
|
||||
function ContextMenuItems:SetCloseMenuFunc(closeMenuFunc)
|
||||
self.CloseMenuFunc = closeMenuFunc
|
||||
end
|
||||
|
||||
function ContextMenuItems.new(menuItemFrame)
|
||||
local obj = setmetatable({}, ContextMenuItems)
|
||||
|
||||
obj.MenuItemFrame = menuItemFrame
|
||||
obj.SelectedPlayer = nil
|
||||
|
||||
obj:RegisterCoreMethods()
|
||||
|
||||
return obj
|
||||
end
|
||||
|
||||
return ContextMenuItems
|
||||
+278
@@ -0,0 +1,278 @@
|
||||
--[[
|
||||
// FileName: ContextMenuUtil.lua
|
||||
// Written by: TheGamer101
|
||||
// Description: Module for utility funcitons of the avatar context menu.
|
||||
]]
|
||||
|
||||
--[[
|
||||
// FileName: ContextMenuGui.lua
|
||||
// Written by: TheGamer101
|
||||
// Description: Module for creating the context GUI.
|
||||
]]
|
||||
|
||||
--- CONSTANTS
|
||||
|
||||
local STOP_MOVEMENT_ACTION_NAME = "AvatarContextMenuStopInput"
|
||||
local MAX_THUMBNAIL_WAIT_TIME = 2
|
||||
local MAX_THUMBNAIL_RETRIES = 4
|
||||
|
||||
--- SERVICES
|
||||
local CoreGuiService = game:GetService("CoreGui")
|
||||
local PlayersService = game:GetService("Players")
|
||||
local ContextActionService = game:GetService("ContextActionService")
|
||||
local GuiService = game:GetService("GuiService")
|
||||
local UserInputService = game:GetService("UserInputService")
|
||||
|
||||
--- VARIABLES
|
||||
local RobloxGui = CoreGuiService:WaitForChild("RobloxGui")
|
||||
|
||||
local LocalPlayer = PlayersService.LocalPlayer
|
||||
while not LocalPlayer do
|
||||
PlayersService.PlayerAdded:wait()
|
||||
LocalPlayer = PlayersService.LocalPlayer
|
||||
end
|
||||
|
||||
local ContextMenuUtil = {}
|
||||
ContextMenuUtil.__index = ContextMenuUtil
|
||||
|
||||
-- PUBLIC METHODS
|
||||
|
||||
function ContextMenuUtil:GetHeadshotForPlayer(player)
|
||||
if self.HeadShotUrlCache[player] ~= nil and self.HeadShotUrlCache[player] ~= "" then
|
||||
return self.HeadShotUrlCache[player]
|
||||
end
|
||||
if self.HeadShotUrlCache[player] == nil then
|
||||
-- Mark that we are getting a headshot for this player.
|
||||
self.HeadShotUrlCache[player] = ""
|
||||
end
|
||||
|
||||
local startTime = tick()
|
||||
local headshotUrl, isFinal = PlayersService:GetUserThumbnailAsync(player.UserId, Enum.ThumbnailType.HeadShot, Enum.ThumbnailSize.Size180x180)
|
||||
|
||||
if not isFinal then
|
||||
for i = 0, MAX_THUMBNAIL_RETRIES do
|
||||
headshotUrl, isFinal = PlayersService:GetUserThumbnailAsync(player.UserId, Enum.ThumbnailType.HeadShot, Enum.ThumbnailSize.Size180x180)
|
||||
if isFinal then
|
||||
break
|
||||
end
|
||||
wait(i ^ 2)
|
||||
end
|
||||
end
|
||||
self.HeadShotUrlCache[player] = headshotUrl
|
||||
|
||||
return headshotUrl
|
||||
end
|
||||
|
||||
function ContextMenuUtil:HasOrGettingHeadShot(player)
|
||||
return self.HeadShotUrlCache[player] ~= nil
|
||||
end
|
||||
|
||||
function ContextMenuUtil:FindPlayerFromPart(part)
|
||||
if part and part.Parent then
|
||||
local possibleCharacter = part
|
||||
while possibleCharacter and not possibleCharacter:IsA("Model") do
|
||||
possibleCharacter = possibleCharacter.Parent
|
||||
end
|
||||
if possibleCharacter then
|
||||
return PlayersService:GetPlayerFromCharacter(possibleCharacter)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function ContextMenuUtil:GetPlayerPosition(player)
|
||||
if player.Character then
|
||||
local hrp = player.Character:FindFirstChild("HumanoidRootPart")
|
||||
if hrp then
|
||||
return hrp.Position
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local playerMovementEnabled = true
|
||||
|
||||
function ContextMenuUtil:DisablePlayerMovement()
|
||||
if not playerMovementEnabled then return end
|
||||
playerMovementEnabled = false
|
||||
|
||||
local noOpFunc = function(actionName, actionState)
|
||||
if actionState == Enum.UserInputState.End then
|
||||
return Enum.ContextActionResult.Pass
|
||||
end
|
||||
return Enum.ContextActionResult.Sink
|
||||
end
|
||||
|
||||
ContextActionService:BindCoreAction(STOP_MOVEMENT_ACTION_NAME, noOpFunc, false,
|
||||
Enum.PlayerActions.CharacterForward,
|
||||
Enum.PlayerActions.CharacterBackward,
|
||||
Enum.PlayerActions.CharacterLeft,
|
||||
Enum.PlayerActions.CharacterRight,
|
||||
Enum.PlayerActions.CharacterJump,
|
||||
Enum.UserInputType.Gamepad1, Enum.UserInputType.Gamepad2, Enum.UserInputType.Gamepad3, Enum.UserInputType.Gamepad4
|
||||
)
|
||||
end
|
||||
|
||||
function ContextMenuUtil:EnablePlayerMovement()
|
||||
if playerMovementEnabled then return end
|
||||
playerMovementEnabled = true
|
||||
|
||||
ContextActionService:UnbindCoreAction(STOP_MOVEMENT_ACTION_NAME)
|
||||
end
|
||||
|
||||
function ContextMenuUtil:GetFriendStatus(player)
|
||||
local success, result = pcall(function()
|
||||
-- NOTE: Core script only
|
||||
return LocalPlayer:GetFriendStatus(player)
|
||||
end)
|
||||
if success then
|
||||
return result
|
||||
else
|
||||
return Enum.FriendStatus.NotFriend
|
||||
end
|
||||
end
|
||||
|
||||
local SelectionOverrideObject = Instance.new("ImageLabel")
|
||||
SelectionOverrideObject.Image = ""
|
||||
SelectionOverrideObject.BackgroundTransparency = 1
|
||||
|
||||
local function MakeDefaultButton(name, size, clickFunc)
|
||||
|
||||
local button = Instance.new("ImageButton")
|
||||
button.Name = name .. "Button"
|
||||
button.Image = ""
|
||||
button.ScaleType = Enum.ScaleType.Slice
|
||||
button.SliceCenter = Rect.new(8,6,46,44)
|
||||
button.AutoButtonColor = false
|
||||
button.BackgroundTransparency = 1
|
||||
button.Size = size
|
||||
button.ZIndex = 2
|
||||
button.SelectionImageObject = SelectionOverrideObject
|
||||
button.BorderSizePixel = 0
|
||||
|
||||
local underline = Instance.new("Frame")
|
||||
underline.Name = "Underline"
|
||||
underline.BackgroundColor3 = Color3.fromRGB(137,137,137)
|
||||
underline.AnchorPoint = Vector2.new(0.5,1)
|
||||
underline.BorderSizePixel = 0
|
||||
underline.Position = UDim2.new(0.5,0,1,0)
|
||||
underline.Size = UDim2.new(0.95,0,0,1)
|
||||
underline.Parent = button
|
||||
|
||||
if clickFunc then
|
||||
button.MouseButton1Click:Connect(function()
|
||||
clickFunc(UserInputService:GetLastInputType())
|
||||
end)
|
||||
end
|
||||
|
||||
local function isPointerInput(inputObject)
|
||||
return inputObject.UserInputType == Enum.UserInputType.MouseMovement or inputObject.UserInputType == Enum.UserInputType.Touch
|
||||
end
|
||||
|
||||
local function selectButton()
|
||||
button.BackgroundTransparency = 0.5
|
||||
end
|
||||
|
||||
local function deselectButton()
|
||||
button.BackgroundTransparency = 1
|
||||
end
|
||||
|
||||
button.InputBegan:Connect(function(inputObject)
|
||||
if button.Selectable and isPointerInput(inputObject) then
|
||||
selectButton()
|
||||
inputObject:GetPropertyChangedSignal("UserInputState"):connect(function()
|
||||
if inputObject.UserInputState == Enum.UserInputState.End then
|
||||
deselectButton()
|
||||
end
|
||||
end)
|
||||
end
|
||||
end)
|
||||
button.InputEnded:Connect(function(inputObject)
|
||||
if button.Selectable and GuiService.SelectedCoreObject ~= button and isPointerInput(inputObject) then
|
||||
deselectButton()
|
||||
end
|
||||
end)
|
||||
|
||||
button.SelectionGained:Connect(function()
|
||||
selectButton()
|
||||
end)
|
||||
button.SelectionLost:Connect(function()
|
||||
deselectButton()
|
||||
end)
|
||||
|
||||
local guiServiceCon = GuiService.Changed:Connect(function(prop)
|
||||
if prop ~= "SelectedCoreObject" then return end
|
||||
|
||||
if GuiService.SelectedCoreObject == nil or GuiService.SelectedCoreObject ~= button then
|
||||
deselectButton()
|
||||
return
|
||||
end
|
||||
|
||||
if button.Selectable then
|
||||
selectButton()
|
||||
end
|
||||
end)
|
||||
|
||||
return button
|
||||
end
|
||||
|
||||
local function getViewportSize()
|
||||
while not workspace.CurrentCamera do
|
||||
workspace.Changed:wait()
|
||||
end
|
||||
|
||||
-- ViewportSize is initally set to 1, 1 in Camera.cpp constructor.
|
||||
-- Also check against 0, 0 incase this is changed in the future.
|
||||
while workspace.CurrentCamera.ViewportSize == Vector2.new(0,0) or
|
||||
workspace.CurrentCamera.ViewportSize == Vector2.new(1,1) do
|
||||
workspace.CurrentCamera.Changed:wait()
|
||||
end
|
||||
|
||||
return workspace.CurrentCamera.ViewportSize
|
||||
end
|
||||
|
||||
local function isSmallTouchScreen()
|
||||
local viewportSize = getViewportSize()
|
||||
return UserInputService.TouchEnabled and (viewportSize.Y < 500 or viewportSize.X < 700)
|
||||
end
|
||||
|
||||
function ContextMenuUtil:MakeStyledButton(name, text, size, clickFunc)
|
||||
local button = MakeDefaultButton(name, size, clickFunc)
|
||||
|
||||
local textLabel = Instance.new("TextLabel")
|
||||
textLabel.Name = name .. "TextLabel"
|
||||
textLabel.BackgroundTransparency = 1
|
||||
textLabel.BorderSizePixel = 0
|
||||
textLabel.Size = UDim2.new(1, 0, 1, -8)
|
||||
textLabel.Position = UDim2.new(0,0,0,0)
|
||||
textLabel.TextColor3 = Color3.fromRGB(255,255,255)
|
||||
textLabel.TextYAlignment = Enum.TextYAlignment.Center
|
||||
textLabel.Font = Enum.Font.SourceSansLight
|
||||
textLabel.TextSize = 24
|
||||
textLabel.Text = text
|
||||
textLabel.TextScaled = true
|
||||
textLabel.TextWrapped = true
|
||||
textLabel.ZIndex = 2
|
||||
textLabel.Parent = button
|
||||
|
||||
local constraint = Instance.new("UITextSizeConstraint",textLabel)
|
||||
|
||||
if isSmallTouchScreen() then
|
||||
textLabel.TextSize = 18
|
||||
elseif GuiService:IsTenFootInterface() then
|
||||
textLabel.TextSize = 36
|
||||
end
|
||||
constraint.MaxTextSize = textLabel.TextSize
|
||||
|
||||
return button, textLabel
|
||||
end
|
||||
|
||||
function ContextMenuUtil.new()
|
||||
local obj = setmetatable({}, ContextMenuUtil)
|
||||
|
||||
obj.HeadShotUrlCache = {}
|
||||
|
||||
return obj
|
||||
end
|
||||
|
||||
return ContextMenuUtil.new()
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
--[[
|
||||
// FileName: PlayerCarousel.lua
|
||||
// Written by: darthskrill
|
||||
// Description: Module for building the UI for the player selection carousel
|
||||
]]
|
||||
|
||||
local PlayerCarousel = {}
|
||||
PlayerCarousel.__index = PlayerCarousel
|
||||
|
||||
-- SERVICES
|
||||
local GuiService = game:GetService("GuiService")
|
||||
local CoreGuiService = game:GetService("CoreGui")
|
||||
local TweenService = game:GetService("TweenService")
|
||||
local UserInputService = game:GetService("UserInputService")
|
||||
|
||||
-- CONSTANTS
|
||||
local BACKGROUND_SELECTED_COLOR = Color3.fromRGB(0,162,255)
|
||||
local BACKGROUND_DEFAULT_COLOR = Color3.fromRGB(0,0,0)
|
||||
local PAGE_LAYOUT_TWEEN_TIME = 0.25
|
||||
|
||||
-- VARIABLES
|
||||
local RobloxGui = CoreGuiService:WaitForChild("RobloxGui")
|
||||
local CoreGuiModules = RobloxGui:WaitForChild("Modules")
|
||||
local AvatarMenuModules = CoreGuiModules:WaitForChild("AvatarContextMenu")
|
||||
local selectedPlayer = nil
|
||||
local uiPageLayout = nil
|
||||
local playerChangedEvent = nil
|
||||
local buttonToPlayerMap = {}
|
||||
local playerToButtonMap = {}
|
||||
|
||||
local function CreateMenuCarousel()
|
||||
local playerSelection = Instance.new("Frame")
|
||||
playerSelection.Name = "PlayerCarousel"
|
||||
playerSelection.AnchorPoint = Vector2.new(0.5, 0.5)
|
||||
playerSelection.BackgroundTransparency = 1
|
||||
playerSelection.Position = UDim2.new(0.5,0,0.5,0)
|
||||
playerSelection.Size = UDim2.new(1, 0, 0.28, 0)
|
||||
playerSelection.ClipsDescendants = true
|
||||
|
||||
local innerFrame = Instance.new("Frame")
|
||||
innerFrame.Name = "InnerFrame"
|
||||
innerFrame.AnchorPoint = Vector2.new(0.5, 0.5)
|
||||
innerFrame.BackgroundTransparency = 1
|
||||
innerFrame.Position = UDim2.new(0.5, 0, 0.5, 0)
|
||||
innerFrame.Size = UDim2.new(0.8, 0, 1, 0)
|
||||
innerFrame.ClipsDescendants = true
|
||||
innerFrame.Active = true
|
||||
innerFrame.Parent = playerSelection
|
||||
|
||||
selectedPlayer = Instance.new("Frame")
|
||||
selectedPlayer.Name = "SelectedPlayer"
|
||||
selectedPlayer.AnchorPoint = Vector2.new(0.5, 0.5)
|
||||
selectedPlayer.BackgroundTransparency = 1
|
||||
selectedPlayer.Position = UDim2.new(0.5, 0, 0.5, 0)
|
||||
selectedPlayer.Size = UDim2.new(0, 100, 1, -10)
|
||||
selectedPlayer.Parent = innerFrame
|
||||
|
||||
uiPageLayout = Instance.new("UIPageLayout")
|
||||
uiPageLayout.EasingDirection = Enum.EasingDirection.Out
|
||||
uiPageLayout.EasingStyle = Enum.EasingStyle.Quad
|
||||
uiPageLayout.Padding = UDim.new(0, 5)
|
||||
uiPageLayout.TweenTime = PAGE_LAYOUT_TWEEN_TIME
|
||||
uiPageLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
|
||||
uiPageLayout.VerticalAlignment = Enum.VerticalAlignment.Center
|
||||
uiPageLayout.TouchInputEnabled = false
|
||||
uiPageLayout.SortOrder = Enum.SortOrder.LayoutOrder
|
||||
|
||||
local aspectRatioConstraint = Instance.new("UIAspectRatioConstraint")
|
||||
aspectRatioConstraint.DominantAxis = Enum.DominantAxis.Height
|
||||
aspectRatioConstraint.Parent = selectedPlayer
|
||||
|
||||
playerChangedEvent = Instance.new("BindableEvent")
|
||||
playerChangedEvent.Name = "PlayerChanged"
|
||||
|
||||
uiPageLayout:GetPropertyChangedSignal("CurrentPage"):Connect(function()
|
||||
if uiPageLayout.CurrentPage then uiPageLayout.CurrentPage.BackgroundColor3 = BACKGROUND_DEFAULT_COLOR end
|
||||
if GuiService.SelectedCoreObject and GuiService.SelectedCoreObject.Parent == uiPageLayout.Parent then
|
||||
GuiService.SelectedCoreObject.BackgroundColor3 = BACKGROUND_SELECTED_COLOR
|
||||
end
|
||||
GuiService.SelectedCoreObject = uiPageLayout.CurrentPage
|
||||
if uiPageLayout.CurrentPage then playerChangedEvent:Fire(buttonToPlayerMap[uiPageLayout.CurrentPage]) end
|
||||
end)
|
||||
uiPageLayout.Parent = selectedPlayer
|
||||
|
||||
local nextButton = Instance.new("ImageButton")
|
||||
nextButton.Name = "NextButton"
|
||||
nextButton.Image = "rbxassetid://471630112"
|
||||
nextButton.BackgroundTransparency = 1
|
||||
nextButton.AnchorPoint = Vector2.new(1,0.5)
|
||||
nextButton.Position = UDim2.new(1,-5,0.5,0)
|
||||
nextButton.Size = UDim2.new(0.3,0,0.3,0)
|
||||
nextButton.Selectable = false
|
||||
nextButton.Parent = playerSelection
|
||||
|
||||
local aspectRatioConstraint = Instance.new("UIAspectRatioConstraint")
|
||||
aspectRatioConstraint.DominantAxis = Enum.DominantAxis.Width
|
||||
aspectRatioConstraint.Parent = nextButton
|
||||
|
||||
local prevButton = nextButton:Clone()
|
||||
prevButton.Name = "PrevButton"
|
||||
prevButton.AnchorPoint = Vector2.new(0, 0.5)
|
||||
prevButton.Position = UDim2.new(0, 5, 0.5, 0)
|
||||
prevButton.Rotation = 180
|
||||
prevButton.Selectable = false
|
||||
prevButton.Parent = playerSelection
|
||||
|
||||
local function moveChangePage(goToNext)
|
||||
if goToNext then
|
||||
uiPageLayout:Next()
|
||||
else
|
||||
uiPageLayout:Previous()
|
||||
end
|
||||
end
|
||||
|
||||
nextButton.MouseButton1Click:Connect(function() moveChangePage(true) end)
|
||||
prevButton.MouseButton1Click:Connect(function() moveChangePage(false) end)
|
||||
|
||||
local defaultChildrenSize = 3 -- aspectRatioConstraint, PageLayout, first button in pagelayout
|
||||
|
||||
local function checkButtonVisibility()
|
||||
local lastInputIsTouch = UserInputService:GetLastInputType() == Enum.UserInputType.Touch
|
||||
prevButton.Visible = not lastInputIsTouch and (#selectedPlayer:GetChildren() > defaultChildrenSize)
|
||||
nextButton.Visible = not lastInputIsTouch and (#selectedPlayer:GetChildren() > defaultChildrenSize)
|
||||
end
|
||||
checkButtonVisibility()
|
||||
UserInputService.LastInputTypeChanged:Connect(checkButtonVisibility)
|
||||
|
||||
return playerSelection
|
||||
end
|
||||
|
||||
function PlayerCarousel:ClearPlayerEntries()
|
||||
for button, player in pairs(buttonToPlayerMap) do
|
||||
button:Destroy()
|
||||
end
|
||||
|
||||
buttonToPlayerMap = {}
|
||||
playerToButtonMap = {}
|
||||
end
|
||||
|
||||
function PlayerCarousel:CreatePlayerEntry(player, distanceToLocalPlayer)
|
||||
local playerButton = playerToButtonMap[player]
|
||||
if playerButton then
|
||||
playerButton.LayoutOrder = distanceToLocalPlayer
|
||||
return
|
||||
end
|
||||
|
||||
local button = Instance.new("ImageButton")
|
||||
button.Name = player.Name
|
||||
button.BorderSizePixel = 0
|
||||
button.LayoutOrder = distanceToLocalPlayer
|
||||
button.BackgroundColor3 = Color3.fromRGB(0,0,0)
|
||||
button.BackgroundTransparency = 0
|
||||
button.Size = UDim2.new(1, 0, 1, 0)
|
||||
|
||||
button.SelectionLost:connect(function() button.BackgroundColor3 = BACKGROUND_DEFAULT_COLOR end)
|
||||
button.SelectionGained:connect(function() button.BackgroundColor3 = BACKGROUND_SELECTED_COLOR end)
|
||||
|
||||
local tweenStyle = TweenInfo.new(1, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut, -1, true)
|
||||
local buttonLoadingTween = TweenService:Create(button, tweenStyle, {BackgroundTransparency = 1, BackgroundColor3 = Color3.fromRGB(255,255,255)})
|
||||
buttonLoadingTween:Play()
|
||||
|
||||
buttonToPlayerMap[button] = player
|
||||
playerToButtonMap[player] = button
|
||||
|
||||
button.MouseButton1Click:Connect(function()
|
||||
uiPageLayout:JumpTo(button)
|
||||
end)
|
||||
|
||||
button.Parent = selectedPlayer
|
||||
|
||||
spawn(function()
|
||||
local ContextMenuUtil = require(AvatarMenuModules:WaitForChild("ContextMenuUtil"))
|
||||
button.Image = ContextMenuUtil:GetHeadshotForPlayer(player)
|
||||
buttonLoadingTween:Cancel()
|
||||
buttonLoadingTween = nil
|
||||
button.BackgroundTransparency = 0
|
||||
if button == GuiService.SelectedCoreObject then
|
||||
button.BackgroundColor3 = BACKGROUND_SELECTED_COLOR
|
||||
else
|
||||
button.BackgroundColor3 = BACKGROUND_DEFAULT_COLOR
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function PlayerCarousel:SwitchToPlayerEntry(player, dontTween)
|
||||
if not player then return end
|
||||
|
||||
local button = playerToButtonMap[player]
|
||||
if not button then
|
||||
self:CreatePlayerEntry(player, 0)
|
||||
button = playerToButtonMap[player]
|
||||
end
|
||||
|
||||
if dontTween then
|
||||
uiPageLayout.TweenTime = 0
|
||||
end
|
||||
uiPageLayout:JumpTo(button)
|
||||
spawn(function()
|
||||
uiPageLayout.TweenTime = PAGE_LAYOUT_TWEEN_TIME
|
||||
end)
|
||||
end
|
||||
|
||||
function PlayerCarousel:OffsetPlayerEntry(offset)
|
||||
if offset == 0 then return end
|
||||
|
||||
if offset > 0 then
|
||||
uiPageLayout:Next()
|
||||
else
|
||||
uiPageLayout:Previous()
|
||||
end
|
||||
end
|
||||
|
||||
function PlayerCarousel:GetSelectedPlayer()
|
||||
return buttonToPlayerMap[uiPageLayout.CurrentPage]
|
||||
end
|
||||
|
||||
function PlayerCarousel.new()
|
||||
local obj = setmetatable({}, PlayerCarousel)
|
||||
|
||||
obj.rbxGui = CreateMenuCarousel()
|
||||
obj.PlayerChanged = playerChangedEvent.Event
|
||||
|
||||
return obj
|
||||
end
|
||||
|
||||
return PlayerCarousel.new()
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
--[[
|
||||
// FileName: SelectedCharacterIndicator.lua
|
||||
// Written by: TheGamer101
|
||||
// Description: Module for rendering an effect for the selected character .
|
||||
]]
|
||||
|
||||
local SelectedCharacterIndicator = {}
|
||||
SelectedCharacterIndicator.__index = SelectedCharacterIndicator
|
||||
|
||||
local RunService = game:GetService("RunService")
|
||||
|
||||
local RENDER_ARROW_CONTEXT_ACTION = "ContextActionMenuRenderArrow"
|
||||
|
||||
local CurrentCamera = workspace.CurrentCamera
|
||||
|
||||
function ApplyArrow(character)
|
||||
local baseModel = Instance.new("Model")
|
||||
baseModel.Name = "ContextMenuArrow"
|
||||
baseModel.Parent = CurrentCamera
|
||||
|
||||
local humanoid = character:FindFirstChildOfClass("Humanoid")
|
||||
if humanoid == nil then
|
||||
humanoid = character:WaitForChild("Humanoid", 15)
|
||||
if humanoid == nil then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local torso = character:WaitForChild("HumanoidRootPart")
|
||||
|
||||
local arrowPart = game:GetService("InsertService"):LoadLocalAsset("rbxasset://models/AvatarContextMenu/AvatarContextArrow.rbxm")
|
||||
arrowPart.Anchored = true
|
||||
arrowPart.Transparency = 0
|
||||
arrowPart.CanCollide = false
|
||||
arrowPart.Parent = baseModel
|
||||
|
||||
local arrowTween = game:GetService("TweenService"):Create(arrowPart,
|
||||
TweenInfo.new(4, Enum.EasingStyle.Linear, Enum.EasingDirection.Out, -1, false),
|
||||
{Orientation=Vector3.new(0,360,180)})
|
||||
arrowTween:Play()
|
||||
|
||||
local function update()
|
||||
arrowPart.Position = torso.Position + Vector3.new(0, 5, 0)
|
||||
end
|
||||
|
||||
local isKilled = false
|
||||
local function kill()
|
||||
if isKilled then
|
||||
return
|
||||
end
|
||||
isKilled = true
|
||||
baseModel:Destroy()
|
||||
arrowTween:Destroy()
|
||||
RunService:UnbindFromRenderStep(RENDER_ARROW_CONTEXT_ACTION)
|
||||
end
|
||||
|
||||
humanoid.Died:Connect(kill)
|
||||
character.AncestryChanged:Connect(kill)
|
||||
RunService:BindToRenderStep(RENDER_ARROW_CONTEXT_ACTION, Enum.RenderPriority.Camera.Value + 1 , update)
|
||||
baseModel.Parent = CurrentCamera
|
||||
|
||||
return kill
|
||||
end
|
||||
|
||||
function SelectedCharacterIndicator:ChangeSelectedPlayer(selectedPlayer)
|
||||
coroutine.wrap(function()
|
||||
if self.SelectedPlayer then
|
||||
self.SelectedPlayer = nil
|
||||
self.CharacterAddedConn:Disconnect()
|
||||
self.CharacterAddedConn = nil
|
||||
if self.KillOldRenderFunction then
|
||||
self.KillOldRenderFunction()
|
||||
self.KillOldRenderFunction = nil
|
||||
end
|
||||
end
|
||||
|
||||
if selectedPlayer then
|
||||
self.SelectedPlayer = selectedPlayer
|
||||
self.CharacterAddedConn = selectedPlayer.CharacterAdded:Connect(function(character)
|
||||
if self.KillOldRenderFunction then
|
||||
self.KillOldRenderFunction()
|
||||
end
|
||||
self.KillOldRenderFunction = ApplyArrow(character)
|
||||
end)
|
||||
if selectedPlayer.Character then
|
||||
self.KillOldRenderFunction = ApplyArrow(selectedPlayer.Character)
|
||||
end
|
||||
end
|
||||
end)()
|
||||
end
|
||||
|
||||
function SelectedCharacterIndicator.new()
|
||||
local obj = setmetatable({}, SelectedCharacterIndicator)
|
||||
|
||||
obj.KillOldRenderFunction = nil
|
||||
obj.SelectedPlayer = nil
|
||||
obj.CharacterAddedConn = nil
|
||||
|
||||
return obj
|
||||
end
|
||||
|
||||
return SelectedCharacterIndicator.new()
|
||||
Reference in New Issue
Block a user