mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-06 13:47:48 +00:00
GEEKING
This commit is contained in:
@@ -0,0 +1,657 @@
|
||||
--[[
|
||||
// FileName: BubbleChat.lua
|
||||
// Written by: jeditkacheff
|
||||
// Description: Code for rendering bubble chat
|
||||
]]
|
||||
|
||||
--[[ SERVICES ]]
|
||||
local RunService = game:GetService('RunService')
|
||||
local CoreGuiService = game:GetService('CoreGui')
|
||||
local PlayersService = game:GetService('Players')
|
||||
local ChatService = game:GetService("Chat")
|
||||
local TextService = game:GetService("TextService")
|
||||
local GameOptions = settings()["Game Options"]
|
||||
--[[ END OF SERVICES ]]
|
||||
|
||||
|
||||
while PlayersService.LocalPlayer == nil do PlayersService.ChildAdded:wait() end
|
||||
local GuiRoot = CoreGuiService:WaitForChild('RobloxGui')
|
||||
local playerDropDownModule = require(GuiRoot.Modules:WaitForChild("PlayerDropDown"))
|
||||
local blockingUtility = playerDropDownModule:CreateBlockingUtility()
|
||||
|
||||
|
||||
--[[ SCRIPT VARIABLES ]]
|
||||
local CHAT_BUBBLE_FONT = Enum.Font.SourceSans
|
||||
local CHAT_BUBBLE_FONT_SIZE = Enum.FontSize.Size24 -- if you change CHAT_BUBBLE_FONT_SIZE_INT please change this to match
|
||||
local CHAT_BUBBLE_FONT_SIZE_INT = 24 -- if you change CHAT_BUBBLE_FONT_SIZE please change this to match
|
||||
local CHAT_BUBBLE_LINE_HEIGHT = CHAT_BUBBLE_FONT_SIZE_INT + 10
|
||||
local CHAT_BUBBLE_TAIL_HEIGHT = 14
|
||||
local CHAT_BUBBLE_WIDTH_PADDING = 30
|
||||
local CHAT_BUBBLE_FADE_SPEED = 1.5
|
||||
|
||||
local BILLBOARD_MAX_WIDTH = 400
|
||||
local BILLBOARD_MAX_HEIGHT = 250 --This limits the number of bubble chats that you see above characters
|
||||
|
||||
local ELIPSES = "..."
|
||||
local CchMaxChatMessageLength = 128 -- max chat message length, including null terminator and elipses.
|
||||
local CchMaxChatMessageLengthExclusive = CchMaxChatMessageLength - string.len(ELIPSES) - 1
|
||||
|
||||
local NEAR_BUBBLE_DISTANCE = 65 --previously 45
|
||||
local MAX_BUBBLE_DISTANCE = 100 --previously 80
|
||||
|
||||
--[[ END OF SCRIPT VARIABLES ]]
|
||||
|
||||
|
||||
-- [[ SCRIPT ENUMS ]]
|
||||
local ChatType = { PLAYER_CHAT = "pChat",
|
||||
PLAYER_TEAM_CHAT = "pChatTeam",
|
||||
PLAYER_WHISPER_CHAT = "pChatWhisper",
|
||||
GAME_MESSAGE= "gMessage",
|
||||
PLAYER_GAME_CHAT = "pGame",
|
||||
BOT_CHAT = "bChat" }
|
||||
|
||||
local BubbleColor = { WHITE = "dub",
|
||||
BLUE = "blu",
|
||||
GREEN = "gre",
|
||||
RED = "red" }
|
||||
|
||||
--[[ END OF SCRIPT ENUMS ]]
|
||||
|
||||
|
||||
|
||||
--[[ FUNCTIONS ]]
|
||||
|
||||
local function lerpLength(msg, min, max)
|
||||
return min + (max-min) * math.min(string.len(msg)/75.0, 1.0)
|
||||
end
|
||||
|
||||
local function createFifo()
|
||||
local this = {}
|
||||
this.data = {}
|
||||
|
||||
local emptyEvent = Instance.new("BindableEvent")
|
||||
this.Emptied = emptyEvent.Event
|
||||
|
||||
function this:Size()
|
||||
return #this.data
|
||||
end
|
||||
|
||||
function this:Empty()
|
||||
return this:Size() <= 0
|
||||
end
|
||||
|
||||
function this:PopFront()
|
||||
table.remove(this.data, 1)
|
||||
if this:Empty() then emptyEvent:Fire() end
|
||||
end
|
||||
|
||||
function this:Front()
|
||||
return this.data[1]
|
||||
end
|
||||
|
||||
function this:Get(index)
|
||||
return this.data[index]
|
||||
end
|
||||
|
||||
function this:PushBack(value)
|
||||
table.insert(this.data, value)
|
||||
end
|
||||
|
||||
function this:GetData()
|
||||
return this.data
|
||||
end
|
||||
|
||||
return this
|
||||
end
|
||||
|
||||
local function createCharacterChats()
|
||||
local this = {}
|
||||
|
||||
this.Fifo = createFifo()
|
||||
this.BillboardGui = nil
|
||||
|
||||
return this
|
||||
end
|
||||
|
||||
local function createMap()
|
||||
local this = {}
|
||||
this.data = {}
|
||||
local count = 0
|
||||
|
||||
function this:Size()
|
||||
return count
|
||||
end
|
||||
|
||||
function this:Erase(key)
|
||||
if this.data[key] then count = count - 1 end
|
||||
this.data[key] = nil
|
||||
end
|
||||
|
||||
function this:Set(key, value)
|
||||
this.data[key] = value
|
||||
if value then count = count + 1 end
|
||||
end
|
||||
|
||||
function this:Get(key)
|
||||
if not this.data[key] then
|
||||
this.data[key] = createCharacterChats()
|
||||
local emptiedCon = nil
|
||||
emptiedCon = this.data[key].Fifo.Emptied:connect(function()
|
||||
emptiedCon:disconnect()
|
||||
this:Erase(key)
|
||||
end)
|
||||
end
|
||||
return this.data[key]
|
||||
end
|
||||
|
||||
function this:GetData()
|
||||
return this.data
|
||||
end
|
||||
|
||||
return this
|
||||
end
|
||||
|
||||
local function createChatLine(chatType, message, bubbleColor, isLocalPlayer)
|
||||
local this = {}
|
||||
|
||||
function this:ComputeBubbleLifetime(msg, isSelf)
|
||||
if isSelf then
|
||||
return lerpLength(msg,8,15)
|
||||
else
|
||||
return lerpLength(msg,12,20)
|
||||
end
|
||||
end
|
||||
|
||||
function this:IsPlayerChat()
|
||||
if not this.ChatType then return false end
|
||||
|
||||
if this.ChatType == ChatType.PLAYER_CHAT or
|
||||
this.ChatType == ChatType.PLAYER_WHISPER_CHAT or
|
||||
this.ChatType == ChatType.PLAYER_TEAM_CHAT then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
this.ChatType = chatType
|
||||
this.Origin = nil
|
||||
this.RenderBubble = nil
|
||||
this.Message = message
|
||||
this.BubbleDieDelay = this:ComputeBubbleLifetime(message, isLocalPlayer)
|
||||
this.BubbleColor = bubbleColor
|
||||
this.IsLocalPlayer = isLocalPlayer
|
||||
|
||||
return this
|
||||
end
|
||||
|
||||
local function createPlayerChatLine(chatType, player, message, isLocalPlayer)
|
||||
local this = createChatLine(chatType, message, BubbleColor.WHITE, isLocalPlayer)
|
||||
|
||||
if player then
|
||||
this.User = player.Name
|
||||
this.Origin = player.Character
|
||||
end
|
||||
|
||||
return this
|
||||
end
|
||||
|
||||
local function createGameChatLine(origin, message, isLocalPlayer, bubbleColor)
|
||||
local this = createChatLine(origin and ChatType.PLAYER_GAME_CHAT or ChatType.BOT_CHAT, message, bubbleColor, isLocalPlayer)
|
||||
this.Origin = origin
|
||||
|
||||
return this
|
||||
end
|
||||
|
||||
function createChatBubbleMain(filePrefix, sliceRect)
|
||||
local chatBubbleMain = Instance.new("ImageLabel")
|
||||
chatBubbleMain.Name = "ChatBubble"
|
||||
chatBubbleMain.ScaleType = Enum.ScaleType.Slice
|
||||
chatBubbleMain.SliceCenter = sliceRect
|
||||
chatBubbleMain.Image = "rbxasset://textures/" .. tostring(filePrefix) .. ".png"
|
||||
chatBubbleMain.BackgroundTransparency = 1
|
||||
chatBubbleMain.BorderSizePixel = 0
|
||||
chatBubbleMain.Size = UDim2.new(1.0, 0, 1.0, 0)
|
||||
chatBubbleMain.Position = UDim2.new(0,0,0,0)
|
||||
|
||||
return chatBubbleMain
|
||||
end
|
||||
|
||||
function createChatBubbleTail(position, size)
|
||||
local chatBubbleTail = Instance.new("ImageLabel")
|
||||
chatBubbleTail.Name = "ChatBubbleTail"
|
||||
chatBubbleTail.Image = "rbxasset://textures/ui/dialog_tail.png"
|
||||
chatBubbleTail.BackgroundTransparency = 1
|
||||
chatBubbleTail.BorderSizePixel = 0
|
||||
chatBubbleTail.Position = position
|
||||
chatBubbleTail.Size = size
|
||||
|
||||
return chatBubbleTail
|
||||
end
|
||||
|
||||
function createChatBubbleWithTail(filePrefix, position, size, sliceRect)
|
||||
local chatBubbleMain = createChatBubbleMain(filePrefix, sliceRect)
|
||||
|
||||
local chatBubbleTail = createChatBubbleTail(position, size)
|
||||
chatBubbleTail.Parent = chatBubbleMain
|
||||
|
||||
return chatBubbleMain
|
||||
end
|
||||
|
||||
function createScaledChatBubbleWithTail(filePrefix, frameScaleSize, position, sliceRect)
|
||||
local chatBubbleMain = createChatBubbleMain(filePrefix, sliceRect)
|
||||
|
||||
local frame = Instance.new("Frame")
|
||||
frame.Name = "ChatBubbleTailFrame"
|
||||
frame.BackgroundTransparency = 1
|
||||
frame.SizeConstraint = Enum.SizeConstraint.RelativeXX
|
||||
frame.Position = UDim2.new(0.5, 0, 1, 0)
|
||||
frame.Size = UDim2.new(frameScaleSize, 0, frameScaleSize, 0)
|
||||
frame.Parent = chatBubbleMain
|
||||
|
||||
local chatBubbleTail = createChatBubbleTail(position, UDim2.new(1,0,0.5,0))
|
||||
chatBubbleTail.Parent = frame
|
||||
|
||||
return chatBubbleMain
|
||||
end
|
||||
|
||||
function createChatImposter(filePrefix, dotDotDot, yOffset)
|
||||
local result = Instance.new("ImageLabel")
|
||||
result.Name = "DialogPlaceholder"
|
||||
result.Image = "rbxasset://textures/" .. tostring(filePrefix) .. ".png"
|
||||
result.BackgroundTransparency = 1
|
||||
result.BorderSizePixel = 0
|
||||
result.Position = UDim2.new(0, 0, -1.25, 0)
|
||||
result.Size = UDim2.new(1, 0, 1, 0)
|
||||
|
||||
local image = Instance.new("ImageLabel")
|
||||
image.Name = "DotDotDot"
|
||||
image.Image = "rbxasset://textures/" .. tostring(dotDotDot) .. ".png"
|
||||
image.BackgroundTransparency = 1
|
||||
image.BorderSizePixel = 0
|
||||
image.Position = UDim2.new(0.001, 0, yOffset, 0)
|
||||
image.Size = UDim2.new(1, 0, 0.7, 0)
|
||||
image.Parent = result
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
local function createChatOutput()
|
||||
|
||||
local this = {}
|
||||
this.ChatBubble = {}
|
||||
this.ChatBubbleWithTail = {}
|
||||
this.ScalingChatBubbleWithTail = {}
|
||||
this.CharacterSortedMsg = createMap()
|
||||
|
||||
-- init chat bubble tables
|
||||
local function initChatBubbleType(chatBubbleType, fileName, imposterFileName, isInset, sliceRect)
|
||||
this.ChatBubble[chatBubbleType] = createChatBubbleMain(fileName, sliceRect)
|
||||
this.ChatBubbleWithTail[chatBubbleType] = createChatBubbleWithTail(fileName, UDim2.new(0.5, -CHAT_BUBBLE_TAIL_HEIGHT, 1, isInset and -1 or 0), UDim2.new(0, 30, 0, CHAT_BUBBLE_TAIL_HEIGHT), sliceRect)
|
||||
this.ScalingChatBubbleWithTail[chatBubbleType] = createScaledChatBubbleWithTail(fileName, 0.5, UDim2.new(-0.5, 0, 0, isInset and -1 or 0), sliceRect)
|
||||
end
|
||||
|
||||
initChatBubbleType(BubbleColor.WHITE, "ui/dialog_white", "ui/chatBubble_white_notify_bkg", false, Rect.new(5,5,15,15))
|
||||
initChatBubbleType(BubbleColor.BLUE, "ui/dialog_blue", "ui/chatBubble_blue_notify_bkg", true, Rect.new(7,7,33,33))
|
||||
initChatBubbleType(BubbleColor.RED, "ui/dialog_red", "ui/chatBubble_red_notify_bkg", true, Rect.new(7,7,33,33))
|
||||
initChatBubbleType(BubbleColor.GREEN, "ui/dialog_green", "ui/chatBubble_green_notify_bkg", true, Rect.new(7,7,33,33))
|
||||
|
||||
function this:SanitizeChatLine(msg)
|
||||
if string.len(msg) > CchMaxChatMessageLengthExclusive then
|
||||
return string.sub(msg, 1, CchMaxChatMessageLengthExclusive + string.len(ELIPSES))
|
||||
else
|
||||
return msg
|
||||
end
|
||||
end
|
||||
|
||||
local function createBillboardInstance(adornee)
|
||||
local billboardGui = Instance.new("BillboardGui")
|
||||
billboardGui.Adornee = adornee
|
||||
billboardGui.RobloxLocked = true
|
||||
billboardGui.Size = UDim2.new(0,BILLBOARD_MAX_WIDTH,0,BILLBOARD_MAX_HEIGHT)
|
||||
billboardGui.StudsOffset = Vector3.new(0, 1.5, 2)
|
||||
billboardGui.Parent = CoreGuiService
|
||||
|
||||
local billboardFrame = Instance.new("Frame")
|
||||
billboardFrame.Name = "BillboardFrame"
|
||||
billboardFrame.Size = UDim2.new(1,0,1,0)
|
||||
billboardFrame.Position = UDim2.new(0,0,-0.5,0)
|
||||
billboardFrame.BackgroundTransparency = 1
|
||||
billboardFrame.Parent = billboardGui
|
||||
|
||||
local billboardChildRemovedCon = nil
|
||||
billboardChildRemovedCon = billboardFrame.ChildRemoved:connect(function()
|
||||
if #billboardFrame:GetChildren() <= 1 then
|
||||
billboardChildRemovedCon:disconnect()
|
||||
billboardGui:Destroy()
|
||||
end
|
||||
end)
|
||||
|
||||
this:CreateSmallTalkBubble(BubbleColor.WHITE).Parent = billboardFrame
|
||||
|
||||
return billboardGui
|
||||
end
|
||||
|
||||
function this:CreateBillboardGuiHelper(instance, onlyCharacter)
|
||||
if not this.CharacterSortedMsg:Get(instance)["BillboardGui"] then
|
||||
if not onlyCharacter then
|
||||
if instance:IsA("Part") then
|
||||
-- Create a new billboardGui object attached to this player
|
||||
local billboardGui = createBillboardInstance(instance)
|
||||
this.CharacterSortedMsg:Get(instance)["BillboardGui"] = billboardGui
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if instance:IsA("Model") then
|
||||
local head = instance:FindFirstChild("Head")
|
||||
if head and head:IsA("Part") then
|
||||
-- Create a new billboardGui object attached to this player
|
||||
local billboardGui = createBillboardInstance(head)
|
||||
this.CharacterSortedMsg:Get(instance)["BillboardGui"] = billboardGui
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function distanceToBubbleOrigin(origin)
|
||||
if not origin then return 100000 end
|
||||
|
||||
return (origin.Position - game.Workspace.CurrentCamera.CoordinateFrame.p).magnitude
|
||||
end
|
||||
|
||||
local function isPartOfLocalPlayer(adornee)
|
||||
if adornee and PlayersService.LocalPlayer.Character then
|
||||
return adornee:IsDescendantOf(PlayersService.LocalPlayer.Character)
|
||||
end
|
||||
end
|
||||
|
||||
function this:SetBillboardLODNear(billboardGui)
|
||||
local isLocalPlayer = isPartOfLocalPlayer(billboardGui.Adornee)
|
||||
billboardGui.Size = UDim2.new(0, BILLBOARD_MAX_WIDTH, 0, BILLBOARD_MAX_HEIGHT)
|
||||
billboardGui.StudsOffset = Vector3.new(0, isLocalPlayer and 1.5 or 2.5, isLocalPlayer and 2 or 0)
|
||||
billboardGui.Enabled = true
|
||||
local billChildren = billboardGui.BillboardFrame:GetChildren()
|
||||
for i = 1, #billChildren do
|
||||
billChildren[i].Visible = true
|
||||
end
|
||||
billboardGui.BillboardFrame.SmallTalkBubble.Visible = false
|
||||
end
|
||||
|
||||
function this:SetBillboardLODDistant(billboardGui)
|
||||
local isLocalPlayer = isPartOfLocalPlayer(billboardGui.Adornee)
|
||||
billboardGui.Size = UDim2.new(4,0,3,0)
|
||||
billboardGui.StudsOffset = Vector3.new(0, 3, isLocalPlayer and 2 or 0)
|
||||
billboardGui.Enabled = true
|
||||
local billChildren = billboardGui.BillboardFrame:GetChildren()
|
||||
for i = 1, #billChildren do
|
||||
billChildren[i].Visible = false
|
||||
end
|
||||
billboardGui.BillboardFrame.SmallTalkBubble.Visible = true
|
||||
end
|
||||
|
||||
function this:SetBillboardLODVeryFar(billboardGui)
|
||||
billboardGui.Enabled = false
|
||||
end
|
||||
|
||||
function this:SetBillboardGuiLOD(billboardGui, origin)
|
||||
if not origin then return end
|
||||
|
||||
if origin:IsA("Model") then
|
||||
local head = origin:FindFirstChild("Head")
|
||||
if not head then origin = origin.PrimaryPart
|
||||
else origin = head end
|
||||
end
|
||||
|
||||
local bubbleDistance = distanceToBubbleOrigin(origin)
|
||||
|
||||
if bubbleDistance < NEAR_BUBBLE_DISTANCE then
|
||||
this:SetBillboardLODNear(billboardGui)
|
||||
elseif bubbleDistance >= NEAR_BUBBLE_DISTANCE and bubbleDistance < MAX_BUBBLE_DISTANCE then
|
||||
this:SetBillboardLODDistant(billboardGui)
|
||||
else
|
||||
this:SetBillboardLODVeryFar(billboardGui)
|
||||
end
|
||||
end
|
||||
|
||||
function this:CameraCFrameChanged()
|
||||
for index, value in pairs(this.CharacterSortedMsg:GetData()) do
|
||||
local playerBillboardGui = value["BillboardGui"]
|
||||
if playerBillboardGui then this:SetBillboardGuiLOD(playerBillboardGui, index) end
|
||||
end
|
||||
end
|
||||
|
||||
function this:CreateBubbleText(message)
|
||||
local bubbleText = Instance.new("TextLabel")
|
||||
bubbleText.Name = "BubbleText"
|
||||
bubbleText.BackgroundTransparency = 1
|
||||
bubbleText.Position = UDim2.new(0,CHAT_BUBBLE_WIDTH_PADDING/2,0,0)
|
||||
bubbleText.Size = UDim2.new(1,-CHAT_BUBBLE_WIDTH_PADDING,1,0)
|
||||
bubbleText.Font = CHAT_BUBBLE_FONT
|
||||
bubbleText.TextWrapped = true
|
||||
bubbleText.FontSize = CHAT_BUBBLE_FONT_SIZE
|
||||
bubbleText.Text = message
|
||||
bubbleText.Visible = false
|
||||
|
||||
return bubbleText
|
||||
end
|
||||
|
||||
function this:CreateSmallTalkBubble(chatBubbleType)
|
||||
local smallTalkBubble = this.ScalingChatBubbleWithTail[chatBubbleType]:Clone()
|
||||
smallTalkBubble.Name = "SmallTalkBubble"
|
||||
smallTalkBubble.Position = UDim2.new(0,0,1,-40)
|
||||
smallTalkBubble.Visible = false
|
||||
local text = this:CreateBubbleText("...")
|
||||
text.TextScaled = true
|
||||
text.TextWrapped = false
|
||||
text.Visible = true
|
||||
text.Parent = smallTalkBubble
|
||||
|
||||
return smallTalkBubble
|
||||
end
|
||||
|
||||
function this:UpdateChatLinesForOrigin(origin, currentBubbleYPos)
|
||||
local bubbleQueue = this.CharacterSortedMsg:Get(origin).Fifo
|
||||
local bubbleQueueSize = bubbleQueue:Size()
|
||||
local bubbleQueueData = bubbleQueue:GetData()
|
||||
if #bubbleQueueData <= 1 then return end
|
||||
|
||||
for index = (#bubbleQueueData - 1), 1, -1 do
|
||||
local value = bubbleQueueData[index]
|
||||
local bubble = value.RenderBubble
|
||||
if not bubble then return end
|
||||
local bubblePos = bubbleQueueSize - index + 1
|
||||
|
||||
if bubblePos > 1 then
|
||||
local tail = bubble:FindFirstChild("ChatBubbleTail")
|
||||
if tail then tail:Destroy() end
|
||||
local bubbleText = bubble:FindFirstChild("BubbleText")
|
||||
if bubbleText then bubbleText.TextTransparency = 0.5 end
|
||||
end
|
||||
|
||||
local udimValue = UDim2.new( bubble.Position.X.Scale, bubble.Position.X.Offset,
|
||||
1, currentBubbleYPos - bubble.Size.Y.Offset - CHAT_BUBBLE_TAIL_HEIGHT )
|
||||
bubble:TweenPosition(udimValue, Enum.EasingDirection.Out, Enum.EasingStyle.Bounce, 0.1, true)
|
||||
currentBubbleYPos = currentBubbleYPos - bubble.Size.Y.Offset - CHAT_BUBBLE_TAIL_HEIGHT
|
||||
end
|
||||
end
|
||||
|
||||
function this:DestroyBubble(bubbleQueue, bubbleToDestroy)
|
||||
if not bubbleQueue then return end
|
||||
if bubbleQueue:Empty() then return end
|
||||
|
||||
local bubble = bubbleQueue:Front().RenderBubble
|
||||
if not bubble then
|
||||
bubbleQueue:PopFront()
|
||||
return
|
||||
end
|
||||
|
||||
spawn(function()
|
||||
while bubbleQueue:Front().RenderBubble ~= bubbleToDestroy do
|
||||
wait()
|
||||
end
|
||||
|
||||
bubble = bubbleQueue:Front().RenderBubble
|
||||
|
||||
local timeBetween = 0
|
||||
local bubbleText = bubble:FindFirstChild("BubbleText")
|
||||
local bubbleTail = bubble:FindFirstChild("ChatBubbleTail")
|
||||
|
||||
while bubble and bubble.ImageTransparency < 1 do
|
||||
timeBetween = wait()
|
||||
if bubble then
|
||||
local fadeAmount = timeBetween * CHAT_BUBBLE_FADE_SPEED
|
||||
bubble.ImageTransparency = bubble.ImageTransparency + fadeAmount
|
||||
if bubbleText then bubbleText.TextTransparency = bubbleText.TextTransparency + fadeAmount end
|
||||
if bubbleTail then bubbleTail.ImageTransparency = bubbleTail.ImageTransparency + fadeAmount end
|
||||
end
|
||||
end
|
||||
|
||||
if bubble then
|
||||
bubble:Destroy()
|
||||
bubbleQueue:PopFront()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function this:CreateChatLineRender(instance, line, onlyCharacter, fifo)
|
||||
if not this.CharacterSortedMsg:Get(instance)["BillboardGui"] then
|
||||
this:CreateBillboardGuiHelper(instance, onlyCharacter)
|
||||
end
|
||||
|
||||
local billboardGui = this.CharacterSortedMsg:Get(instance)["BillboardGui"]
|
||||
local chatBubbleRender = this.ChatBubbleWithTail[line.BubbleColor]:Clone()
|
||||
chatBubbleRender.Visible = false
|
||||
local bubbleText = this:CreateBubbleText(line.Message)
|
||||
|
||||
bubbleText.Parent = chatBubbleRender
|
||||
chatBubbleRender.Parent = billboardGui.BillboardFrame
|
||||
|
||||
line.RenderBubble = chatBubbleRender
|
||||
|
||||
local currentTextBounds = TextService:GetTextSize(bubbleText.Text, CHAT_BUBBLE_FONT_SIZE_INT, CHAT_BUBBLE_FONT,
|
||||
Vector2.new(BILLBOARD_MAX_WIDTH, BILLBOARD_MAX_HEIGHT))
|
||||
local bubbleWidthScale = math.max((currentTextBounds.x + CHAT_BUBBLE_WIDTH_PADDING)/BILLBOARD_MAX_WIDTH, 0.1)
|
||||
local numOflines = (currentTextBounds.y/CHAT_BUBBLE_FONT_SIZE_INT)
|
||||
|
||||
-- prep chat bubble for tween
|
||||
chatBubbleRender.Size = UDim2.new(0,0,0,0)
|
||||
chatBubbleRender.Position = UDim2.new(0.5,0,1,0)
|
||||
|
||||
local newChatBubbleOffsetSizeY = numOflines * CHAT_BUBBLE_LINE_HEIGHT
|
||||
|
||||
chatBubbleRender:TweenSizeAndPosition(UDim2.new(bubbleWidthScale, 0, 0, newChatBubbleOffsetSizeY),
|
||||
UDim2.new( (1-bubbleWidthScale)/2, 0, 1, -newChatBubbleOffsetSizeY),
|
||||
Enum.EasingDirection.Out, Enum.EasingStyle.Elastic, 0.1, true,
|
||||
function() bubbleText.Visible = true end)
|
||||
|
||||
-- todo: remove when over max bubbles
|
||||
this:SetBillboardGuiLOD(billboardGui, line.Origin)
|
||||
this:UpdateChatLinesForOrigin(line.Origin, -newChatBubbleOffsetSizeY)
|
||||
|
||||
delay(line.BubbleDieDelay, function()
|
||||
this:DestroyBubble(fifo, chatBubbleRender)
|
||||
end)
|
||||
end
|
||||
|
||||
local testLabel = Instance.new('TextLabel')
|
||||
function isLabelTextAllowed(message)
|
||||
--There exists an internal filter that filters out some profanity. It does this silently if you try to set text of an object.
|
||||
--Here we check if the message is going to be filtered by applying it and comparing it.
|
||||
testLabel.Text = message
|
||||
return (testLabel.Text == message)
|
||||
end
|
||||
|
||||
function this:OnPlayerChatMessage(chatType, sourcePlayer, message, targetPlayer)
|
||||
if not this:BubbleChatEnabled() then return end
|
||||
|
||||
-- eliminate display of commands
|
||||
if string.sub(message, 1, 1) == '/' then return end
|
||||
|
||||
local localPlayer = PlayersService.LocalPlayer
|
||||
local fromOthers = localPlayer ~= nil and sourcePlayer ~= localPlayer
|
||||
|
||||
-- annihilate chats made by blocked or muted players
|
||||
if blockingUtility:IsPlayerBlockedByUserId(sourcePlayer.userId) or blockingUtility:IsPlayerMutedByUserId(sourcePlayer.userId) then return end
|
||||
|
||||
-- remove messages that are filtered from the default gui text filter
|
||||
if not isLabelTextAllowed(message) then return end
|
||||
|
||||
local luaChatType = ChatType.PLAYER_CHAT
|
||||
if chatType == Enum.PlayerChatType.Team then
|
||||
luaChatType = ChatType.PLAYER_TEAM_CHAT
|
||||
elseif chatType == Enum.PlayerChatType.All then
|
||||
luaChatType = ChatType.PLAYER_GAME_CHAT
|
||||
elseif chatType == Enum.PlayerChatType.Whisper then
|
||||
luaChatType = ChatType.PLAYER_WHISPER_CHAT
|
||||
end
|
||||
|
||||
local safeMessage = this:SanitizeChatLine(message)
|
||||
|
||||
local line = createPlayerChatLine(chatType, sourcePlayer, safeMessage, not fromOthers)
|
||||
|
||||
local fifo = this.CharacterSortedMsg:Get(line.Origin).Fifo
|
||||
fifo:PushBack(line)
|
||||
|
||||
if sourcePlayer then
|
||||
--Game chat (badges) won't show up here
|
||||
this:CreateChatLineRender(sourcePlayer.Character, line, true, fifo)
|
||||
end
|
||||
end
|
||||
|
||||
function this:OnGameChatMessage(origin, message, color)
|
||||
if not this:BubbleChatEnabled() then return end
|
||||
|
||||
local localPlayer = PlayersService.LocalPlayer
|
||||
local fromOthers = localPlayer ~= nil and (localPlayer.Character ~= origin)
|
||||
|
||||
local bubbleColor = BubbleColor.WHITE
|
||||
|
||||
if color == Enum.ChatColor.Blue then bubbleColor = BubbleColor.BLUE
|
||||
elseif color == Enum.ChatColor.Green then bubbleColor = BubbleColor.GREEN
|
||||
elseif color == Enum.ChatColor.Red then bubbleColor = BubbleColor.RED end
|
||||
|
||||
local safeMessage = this:SanitizeChatLine(message)
|
||||
local line = createGameChatLine(origin, safeMessage, not fromOthers, bubbleColor)
|
||||
|
||||
this.CharacterSortedMsg:Get(line.Origin).Fifo:PushBack(line)
|
||||
this:CreateChatLineRender(origin, line, false, this.CharacterSortedMsg:Get(line.Origin).Fifo)
|
||||
end
|
||||
|
||||
function this:BubbleChatEnabled()
|
||||
return PlayersService.BubbleChat
|
||||
end
|
||||
|
||||
function this:CameraChanged(prop)
|
||||
if prop == "CoordinateFrame" then
|
||||
this:CameraCFrameChanged()
|
||||
end
|
||||
end
|
||||
|
||||
-- setup to datamodel connections
|
||||
PlayersService.PlayerChatted:connect(function(chatType, player, message, targetPlayer) this:OnPlayerChatMessage(chatType, player, message, targetPlayer) end)
|
||||
ChatService.Chatted:connect(function(origin, message, color) this:OnGameChatMessage(origin, message, color) end)
|
||||
|
||||
local cameraChangedCon = nil
|
||||
if game.Workspace.CurrentCamera then
|
||||
cameraChangedCon = game.Workspace.CurrentCamera.Changed:connect(function(prop) this:CameraChanged(prop) end)
|
||||
end
|
||||
game.Workspace.Changed:connect(function(prop)
|
||||
if prop == "CurrentCamera" then
|
||||
if cameraChangedCon then cameraChangedCon:disconnect() end
|
||||
if game.Workspace.CurrentCamera then
|
||||
cameraChangedCon = game.Workspace.CurrentCamera.Changed:connect(function(prop) this:CameraChanged(prop) end)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
local isClient = false
|
||||
local success = pcall(function() isClient = game:GetService("RunService"):IsClient()end)
|
||||
|
||||
-- init only if we have a simulation going
|
||||
if isClient or not success then
|
||||
createChatOutput()
|
||||
end
|
||||
@@ -0,0 +1,174 @@
|
||||
-- Responsible for giving out tools in personal servers
|
||||
|
||||
-- first, lets see if buildTools have already been created
|
||||
-- create the object in ReplicatedStorage if not
|
||||
local container = game:GetService("ReplicatedStorage")
|
||||
local toolsArray = container:FindFirstChild("BuildToolsModel")
|
||||
local ownerArray = container:FindFirstChild("OwnerToolsModel")
|
||||
local hasBuildTools = false
|
||||
|
||||
local function waitForProperty(instance, name)
|
||||
while not instance[name] do
|
||||
instance.Changed:wait()
|
||||
end
|
||||
end
|
||||
|
||||
waitForProperty(game:GetService("Players"),"LocalPlayer")
|
||||
waitForProperty(game:GetService("Players").LocalPlayer,"userId")
|
||||
|
||||
local player = game:GetService("Players").LocalPlayer
|
||||
if not player then
|
||||
script:Destroy()
|
||||
return
|
||||
end
|
||||
|
||||
function getIds(idTable, assetTable)
|
||||
for i = 1, #idTable do
|
||||
local model = Game:GetService("InsertService"):LoadAsset(idTable[i])
|
||||
if model then
|
||||
local children = model:GetChildren()
|
||||
for i = 1, #children do
|
||||
if children[i]:IsA("Tool") then
|
||||
table.insert(assetTable,children[i])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function storeInContainer(modelName, assetTable)
|
||||
local model = Instance.new("Model")
|
||||
model.Archivable = false
|
||||
model.Name = modelName
|
||||
|
||||
for i = 1, #assetTable do
|
||||
assetTable[i].Parent = model
|
||||
end
|
||||
|
||||
if not container:FindFirstChild(modelName) then -- no one beat us to it, we get to insert
|
||||
model.Parent = container
|
||||
end
|
||||
end
|
||||
|
||||
if not toolsArray then -- no one has made build tools yet, we get to!
|
||||
local buildToolIds = {}
|
||||
local ownerToolIds = {}
|
||||
|
||||
local BaseUrl = game:GetService("ContentProvider").BaseUrl:lower()
|
||||
|
||||
if BaseUrl:find("www.watrbx.wtf") or BaseUrl:find("gametest1") then
|
||||
table.insert(buildToolIds,73089166) -- PartSelectionTool
|
||||
table.insert(buildToolIds,73089190) -- DeleteTool
|
||||
table.insert(buildToolIds,73089204) -- CloneTool
|
||||
table.insert(buildToolIds,73089214) -- RotateTool
|
||||
table.insert(buildToolIds,73089229) -- RecentPartTool
|
||||
table.insert(buildToolIds,73089239) -- ConfigTool
|
||||
table.insert(buildToolIds,73089259) -- WiringTool
|
||||
elseif BaseUrl:find("gametest2") then
|
||||
table.insert(buildToolIds,70353315) -- PartSelectionTool
|
||||
table.insert(buildToolIds,70353317) -- DeleteTool
|
||||
table.insert(buildToolIds,70353314) -- CloneTool
|
||||
table.insert(buildToolIds,70353318) -- RotateTool
|
||||
table.insert(buildToolIds,70353316) -- RecentPartTool
|
||||
table.insert(buildToolIds,70353319) -- ConfigTool
|
||||
table.insert(buildToolIds,70353320) -- WiringTool
|
||||
end
|
||||
|
||||
table.insert(buildToolIds,58921588) -- ClassicTool
|
||||
table.insert(ownerToolIds, 65347268) -- OwnerCameraTool
|
||||
|
||||
-- next, create array of our tools
|
||||
local buildTools = {}
|
||||
local ownerTools = {}
|
||||
|
||||
getIds(buildToolIds, buildTools)
|
||||
getIds(ownerToolIds, ownerTools)
|
||||
|
||||
storeInContainer("BuildToolsModel",buildTools)
|
||||
storeInContainer("OwnerToolsModel",ownerTools)
|
||||
|
||||
toolsArray = container:FindFirstChild("BuildToolsModel")
|
||||
ownerArray = container:FindFirstChild("OwnerToolsModel")
|
||||
end
|
||||
|
||||
local localBuildTools = {}
|
||||
|
||||
function giveBuildTools()
|
||||
if not hasBuildTools then
|
||||
hasBuildTools = true
|
||||
local theTools = toolsArray:GetChildren()
|
||||
for i = 1, #theTools do
|
||||
local toolClone = theTools[i]:Clone()
|
||||
if toolClone then
|
||||
toolClone.Parent = player:FindFirstChild("Backpack")
|
||||
table.insert(localBuildTools,toolClone)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function giveOwnerTools()
|
||||
local theOwnerTools = ownerArray:GetChildren()
|
||||
for i = 1, #theOwnerTools do
|
||||
local ownerToolClone = theOwnerTools[i]:Clone()
|
||||
if ownerToolClone then
|
||||
ownerToolClone.Parent = player:FindFirstChild("Backpack")
|
||||
table.insert(localBuildTools,ownerToolClone)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function removeBuildTools()
|
||||
if not hasBuildTools then return end
|
||||
hasBuildTools = false
|
||||
for k,v in pairs(localBuildTools) do
|
||||
v:Destroy()
|
||||
end localBuildTools = {}
|
||||
end
|
||||
|
||||
if player.HasBuildTools then
|
||||
giveBuildTools()
|
||||
end
|
||||
if player.PersonalServerRank >= 255 then
|
||||
giveOwnerTools()
|
||||
end
|
||||
|
||||
local debounce = false
|
||||
player.Changed:connect(function(prop)
|
||||
if prop == "HasBuildTools" then
|
||||
while debounce do
|
||||
wait(0.5)
|
||||
end
|
||||
|
||||
debounce = true
|
||||
|
||||
if player.HasBuildTools then
|
||||
giveBuildTools()
|
||||
else
|
||||
removeBuildTools()
|
||||
end
|
||||
|
||||
if player.PersonalServerRank >= 255 then
|
||||
giveOwnerTools()
|
||||
end
|
||||
|
||||
debounce = false
|
||||
elseif prop == "PersonalServerRank" then
|
||||
if player.PersonalServerRank >= 255 then
|
||||
giveOwnerTools()
|
||||
elseif player.PersonalServerRank <= 0 then
|
||||
player:Kick() -- you're banned, goodbye!
|
||||
Game:SetMessage("You're banned from this PBS")
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
player.CharacterAdded:connect(function()
|
||||
hasBuildTools = false
|
||||
if player.HasBuildTools then
|
||||
giveBuildTools()
|
||||
end
|
||||
if player.PersonalServerRank >= 255 then
|
||||
giveOwnerTools()
|
||||
end
|
||||
end)
|
||||
@@ -0,0 +1,214 @@
|
||||
-- This script is responsible for loading in all build tools for build mode
|
||||
|
||||
-- Script Globals
|
||||
local buildTools = {}
|
||||
local currentTools = {}
|
||||
|
||||
local BaseUrl = game:GetService("ContentProvider").BaseUrl:lower()
|
||||
|
||||
if BaseUrl:find("www.watrbx.wtf") or BaseUrl:find("gametest1") then
|
||||
DeleteToolID = 73089190
|
||||
PartSelectionID = 73089166
|
||||
CloneToolID = 73089204
|
||||
RotateToolID = 73089214
|
||||
ConfigToolID = 73089239
|
||||
WiringToolID = 73089259
|
||||
classicToolID = 58921588
|
||||
elseif BaseUrl:find("gametest2") then
|
||||
DeleteToolID = 70353317
|
||||
PartSelectionID = 70353315
|
||||
CloneToolID = 70353314
|
||||
RotateToolID = 70353318
|
||||
ConfigToolID = 70353319
|
||||
WiringToolID = 70353320
|
||||
classicToolID = 58921588
|
||||
end
|
||||
|
||||
local player = nil
|
||||
local backpack = nil
|
||||
|
||||
-- Basic Functions
|
||||
local function waitForProperty(instance, name)
|
||||
while not instance[name] do
|
||||
instance.Changed:wait()
|
||||
end
|
||||
end
|
||||
|
||||
local function waitForChild(instance, name)
|
||||
while not instance:FindFirstChild(name) do
|
||||
instance.ChildAdded:wait()
|
||||
end
|
||||
end
|
||||
|
||||
waitForProperty(game:GetService("Players"),"LocalPlayer")
|
||||
waitForProperty(game:GetService("Players").LocalPlayer,"userId")
|
||||
|
||||
-- we aren't in a true build mode session, don't give build tools and delete this script
|
||||
if game:GetService("Players").LocalPlayer.userId < 1 then
|
||||
script:Destroy()
|
||||
return -- this is probably not necessesary, doing it just in case
|
||||
end
|
||||
|
||||
-- Functions
|
||||
function getLatestPlayer()
|
||||
waitForProperty(game:GetService("Players"),"LocalPlayer")
|
||||
player = game:GetService("Players").LocalPlayer
|
||||
waitForChild(player,"Backpack")
|
||||
backpack = player.Backpack
|
||||
end
|
||||
|
||||
function waitForCharacterLoad()
|
||||
|
||||
local startTick = tick()
|
||||
|
||||
local playerLoaded = false
|
||||
|
||||
local success = pcall(function() playerLoaded = player.AppearanceDidLoad end) --TODO: remove pcall once this in client on prod
|
||||
if not success then return false end
|
||||
|
||||
while not playerLoaded do
|
||||
player.Changed:wait()
|
||||
playerLoaded = player.AppearanceDidLoad
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function showBuildToolsTutorial()
|
||||
local tutorialKey = "BuildToolsTutorial"
|
||||
if UserSettings().GameSettings:GetTutorialState(tutorialKey) == true then return end --already have shown tutorial
|
||||
|
||||
local RbxGui = LoadLibrary("RbxGui")
|
||||
|
||||
local frame, showTutorial, dismissTutorial, gotoPage = RbxGui.CreateTutorial("Build", tutorialKey, false)
|
||||
local firstPage = RbxGui.CreateImageTutorialPage(" ", "http://www.watrbx.wtf/asset/?id=59162193", 359, 296, function() dismissTutorial() end, true)
|
||||
|
||||
RbxGui.AddTutorialPage(frame, firstPage)
|
||||
frame.Parent = game:GetService("CoreGui"):FindFirstChild("RobloxGui")
|
||||
|
||||
game:GetService("GuiService"):AddCenterDialog(frame, Enum.CenterDialogType.UnsolicitedDialog,
|
||||
--showFunction
|
||||
function()
|
||||
frame.Visible = true
|
||||
showTutorial()
|
||||
end,
|
||||
--hideFunction
|
||||
function()
|
||||
frame.Visible = false
|
||||
end
|
||||
)
|
||||
|
||||
wait(1)
|
||||
showTutorial()
|
||||
end
|
||||
|
||||
function clearLoadout()
|
||||
currentTools = {}
|
||||
|
||||
local backpackChildren = game:GetService("Players").LocalPlayer.Backpack:GetChildren()
|
||||
for i = 1, #backpackChildren do
|
||||
if backpackChildren[i]:IsA("Tool") or backpackChildren[i]:IsA("HopperBin") then
|
||||
table.insert(currentTools,backpackChildren[i])
|
||||
end
|
||||
end
|
||||
|
||||
if game:GetService("Players").LocalPlayer["Character"] then
|
||||
local characterChildren = game:GetService("Players").LocalPlayer.Character:GetChildren()
|
||||
for i = 1, #characterChildren do
|
||||
if characterChildren[i]:IsA("Tool") or characterChildren[i]:IsA("HopperBin") then
|
||||
table.insert(currentTools,characterChildren[i])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for i = 1, #currentTools do
|
||||
currentTools[i].Parent = nil
|
||||
end
|
||||
end
|
||||
|
||||
function giveToolsBack()
|
||||
for i = 1, #currentTools do
|
||||
currentTools[i].Parent = game:GetService("Players").LocalPlayer.Backpack
|
||||
end
|
||||
end
|
||||
|
||||
function backpackHasTool(tool)
|
||||
local backpackChildren = backpack:GetChildren()
|
||||
for i = 1, #backpackChildren do
|
||||
if backpackChildren[i] == tool then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function getToolAssetID(assetID)
|
||||
local newTool = game:GetService("InsertService"):LoadAsset(assetID)
|
||||
local toolChildren = newTool:GetChildren()
|
||||
for i = 1, #toolChildren do
|
||||
if toolChildren[i]:IsA("Tool") then
|
||||
return toolChildren[i]
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- remove legacy identifiers
|
||||
-- todo: determine if we still need this
|
||||
function removeBuildToolTag(tool)
|
||||
if tool:FindFirstChild("RobloxBuildTool") then
|
||||
tool.RobloxBuildTool:Destroy()
|
||||
end
|
||||
end
|
||||
|
||||
function giveAssetId(assetID,toolName)
|
||||
local theTool = getToolAssetID(assetID,toolName)
|
||||
if theTool and not backpackHasTool(theTool) then
|
||||
removeBuildToolTag(theTool)
|
||||
theTool.Parent = backpack
|
||||
table.insert(buildTools,theTool)
|
||||
end
|
||||
end
|
||||
|
||||
function loadBuildTools()
|
||||
giveAssetId(PartSelectionID)
|
||||
giveAssetId(DeleteToolID)
|
||||
giveAssetId(CloneToolID)
|
||||
giveAssetId(RotateToolID)
|
||||
giveAssetId(WiringToolID)
|
||||
giveAssetId(ConfigToolID)
|
||||
|
||||
-- deprecated tools
|
||||
giveAssetId(classicToolID)
|
||||
end
|
||||
|
||||
function givePlayerBuildTools()
|
||||
getLatestPlayer()
|
||||
|
||||
clearLoadout()
|
||||
|
||||
loadBuildTools()
|
||||
|
||||
giveToolsBack()
|
||||
end
|
||||
|
||||
function takePlayerBuildTools()
|
||||
for k,v in ipairs(buildTools) do
|
||||
v.Parent = nil
|
||||
end
|
||||
buildTools = {}
|
||||
end
|
||||
|
||||
|
||||
-- Script start
|
||||
getLatestPlayer()
|
||||
waitForCharacterLoad()
|
||||
givePlayerBuildTools()
|
||||
|
||||
-- If player dies, we make sure to give them build tools again
|
||||
player.CharacterAdded:connect(function()
|
||||
takePlayerBuildTools()
|
||||
givePlayerBuildTools()
|
||||
end)
|
||||
|
||||
showBuildToolsTutorial()
|
||||
@@ -0,0 +1,206 @@
|
||||
-- Personal Server Script
|
||||
|
||||
-----------------
|
||||
--| Constants |--
|
||||
-----------------
|
||||
|
||||
local CHANGES_PER_PLAYER = 100 -- Saving also occurs every time the number of edits reaches this number times the number of players
|
||||
local SAVE_CHECK_INTERVAL = 1800 -- should be set in seconds, this is how long we wait to force a save, as long as at least one change has been made
|
||||
local MIN_SAVE_TIME = 900 -- At least this many seconds will pass before saving again
|
||||
|
||||
-----------------
|
||||
--| Variables |--
|
||||
-----------------
|
||||
|
||||
local ContentProviderService = game:GetService('ContentProvider')
|
||||
local PlayersService = game:GetService('Players')
|
||||
local RunService = game:GetService("RunService")
|
||||
|
||||
local StartingPlayerRanks = {}
|
||||
local RbxUtil = nil
|
||||
|
||||
local LastSaveTime = 0
|
||||
local ChangeCount = 0
|
||||
local TryingToSave = false
|
||||
local NumberOfChangesBeforeSaveAbsolute = CHANGES_PER_PLAYER
|
||||
local GameRunning = true
|
||||
local WaitingToSave = false
|
||||
|
||||
local PlaceId = game.PlaceId
|
||||
local Url = ContentProviderService.BaseUrl
|
||||
local UrlBase = Url:match('^http://www\.(.-)/?$') -- Turns "http://www.gametest1.pizzaboxer.fun/" into "gametest1.pizzaboxer.fun"
|
||||
local ApiProxyUrl = 'https://api.' .. UrlBase
|
||||
local DataFarmProtocol = 'http'
|
||||
local DataFarmUsesHttpsFlagExists, DataFarmUsesHttpsFlagValue = pcall(function () return settings():GetFFlag("DataFarmUsesHttps") end)
|
||||
if DataFarmUsesHttpsFlagExists and DataFarmUsesHttpsFlagValue then
|
||||
DataFarmProtocol = 'https'
|
||||
end
|
||||
local DataFarmUrl = DataFarmProtocol .. '://data.' .. UrlBase
|
||||
|
||||
-----------------
|
||||
--| Functions |--
|
||||
-----------------
|
||||
|
||||
function GetRbxUtil()
|
||||
if not RbxUtil then
|
||||
RbxUtil = LoadLibrary("RbxUtility")
|
||||
end
|
||||
return RbxUtil
|
||||
end
|
||||
|
||||
-- Checks the full hierarchy of an instance for archivability
|
||||
local function IsArchivable(instance)
|
||||
if instance == workspace then
|
||||
return true
|
||||
elseif not instance.Archivable then
|
||||
return false
|
||||
else
|
||||
return IsArchivable(instance.Parent)
|
||||
end
|
||||
end
|
||||
|
||||
local function UpdateSaveOnChangeAmount()
|
||||
local players = PlayersService:GetPlayers()
|
||||
NumberOfChangesBeforeSaveAbsolute = #players * CHANGES_PER_PLAYER
|
||||
end
|
||||
|
||||
local function OnPlayerAdded(player)
|
||||
if player:IsA('Player') then
|
||||
|
||||
local getRankUrl = ApiProxyUrl .. '/RoleSets/GetRoleSetForUser?placeId=' .. tostring(PlaceId) .. '&userId=' .. tostring(player.userId)
|
||||
local serverRankTable = nil
|
||||
pcall(function()
|
||||
serverRankTable = GetRbxUtil().DecodeJSON(game:HttpGetAsync(getRankUrl))
|
||||
end)
|
||||
|
||||
local playerRank = 0
|
||||
if serverRankTable and type(serverRankTable) == 'table' then
|
||||
for k, v in pairs(serverRankTable) do
|
||||
if k == "data" then
|
||||
if v["Rank"] then
|
||||
playerRank = v["Rank"]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
player.PersonalServerRank = playerRank
|
||||
StartingPlayerRanks[player] = playerRank
|
||||
|
||||
UpdateSaveOnChangeAmount()
|
||||
end
|
||||
end
|
||||
|
||||
local function OnPlayerRemoved(player)
|
||||
if player:IsA('Player') then
|
||||
UpdateSaveOnChangeAmount()
|
||||
|
||||
if StartingPlayerRanks[player] then
|
||||
local playerRank = player.PersonalServerRank
|
||||
if StartingPlayerRanks[player] ~= playerRank then -- Don't need to make web call if rank is the same
|
||||
local setRankUrl = ApiProxyUrl .. '/RoleSets/PrivilegedSetUserRoleSetRank?placeId=' .. tostring(PlaceId) .. '&userId=' .. tostring(player.userId) .. '&newRank=' .. tostring(playerRank)
|
||||
ypcall(function() game:HttpPostAsync(setRankUrl, 'SetPersonalServerRank') end)
|
||||
end
|
||||
StartingPlayerRanks[player] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function DoSave()
|
||||
if GameRunning then
|
||||
ChangeCount = 0
|
||||
LastSaveTime = tick()
|
||||
game:ServerSave()
|
||||
end
|
||||
end
|
||||
|
||||
local function TrySave()
|
||||
if not TryingToSave then
|
||||
TryingToSave = true
|
||||
|
||||
local now = tick()
|
||||
|
||||
if now - LastSaveTime >= MIN_SAVE_TIME then
|
||||
DoSave()
|
||||
elseif not WaitingToSave then -- Save after cooldown
|
||||
WaitingToSave = true
|
||||
delay(LastSaveTime + MIN_SAVE_TIME - now, function()
|
||||
DoSave()
|
||||
WaitingToSave = false
|
||||
end)
|
||||
end
|
||||
|
||||
TryingToSave = false
|
||||
end
|
||||
end
|
||||
|
||||
-- Save based on number of edits to workspace
|
||||
local function OnEdit(descendant)
|
||||
if IsArchivable(descendant) then
|
||||
ChangeCount = ChangeCount + 1
|
||||
if ChangeCount >= NumberOfChangesBeforeSaveAbsolute then
|
||||
TrySave()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Make sure we save every interval regardless of number of edits, so long as there is one
|
||||
local function CheckForSaveOnInterval()
|
||||
while true do
|
||||
wait(SAVE_CHECK_INTERVAL)
|
||||
|
||||
if tick() - LastSaveTime >= SAVE_CHECK_INTERVAL and ChangeCount > 0 then
|
||||
TrySave()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--------------------
|
||||
--| Script Logic |--
|
||||
--------------------
|
||||
|
||||
game:WaitForChild('Workspace')
|
||||
|
||||
pcall(function()
|
||||
game.IsPersonalServer = true
|
||||
|
||||
if not workspace:FindFirstChild("PSVariable") then
|
||||
local psVar = Instance.new("BoolValue")
|
||||
psVar.Name = "PSVariable"
|
||||
psVar.Archivable = false
|
||||
psVar.Parent = workspace
|
||||
end
|
||||
end)
|
||||
|
||||
PlayersService.PlayerAdded:connect(OnPlayerAdded)
|
||||
PlayersService.ChildRemoved:connect(OnPlayerRemoved)
|
||||
for _, player in pairs(PlayersService:GetPlayers()) do
|
||||
OnPlayerAdded(player)
|
||||
end
|
||||
|
||||
local useSubdomainsFlagExists, useSubdomainsFlagValue = pcall(function () return settings():GetFFlag("UseNewSubdomainsInCoreScripts") end)
|
||||
local saveUrlBase = Url
|
||||
if(useSubdomainsFlagExists and useSubdomainsFlagValue and DataFarmUrl~=nil) then
|
||||
saveUrlBase = DataFarmUrl
|
||||
end
|
||||
|
||||
if saveUrlBase~=nil then
|
||||
game:SetServerSaveUrl(saveUrlBase .. "/Data/AutoSave.ashx?assetId=" .. PlaceId)
|
||||
end
|
||||
|
||||
if pcall(function()
|
||||
game.Close:connect(
|
||||
function()
|
||||
GameRunning = false
|
||||
game:ServerSave()
|
||||
end)
|
||||
end) == false then
|
||||
print("!Error in Game.Close:connect")
|
||||
end
|
||||
|
||||
RunService:Run()
|
||||
|
||||
game:GetService("Workspace").DescendantAdded:connect(OnEdit)
|
||||
game:GetService("Workspace").DescendantRemoving:connect(OnEdit)
|
||||
|
||||
spawn(CheckForSaveOnInterval)
|
||||
@@ -0,0 +1,268 @@
|
||||
-- ContextActionTouch.lua
|
||||
-- Copyright ROBLOX 2014, created by Ben Tkacheff
|
||||
-- this script controls ui and firing of lua functions that are bound in ContextActionService for touch inputs
|
||||
-- Essentially a user can bind a lua function to a key code, input type (mousebutton1 etc.) and this
|
||||
|
||||
-- Variables
|
||||
local contextActionService = game:GetService("ContextActionService")
|
||||
local userInputService = game:GetService("UserInputService")
|
||||
local isTouchDevice = userInputService.TouchEnabled
|
||||
local functionTable = {}
|
||||
local buttonVector = {}
|
||||
local buttonScreenGui = nil
|
||||
local buttonFrame = nil
|
||||
|
||||
local ContextDownImage = "http://www.watrbx.wtf/asset/?id=97166756"
|
||||
local ContextUpImage = "http://www.watrbx.wtf/asset/?id=97166444"
|
||||
|
||||
local oldTouches = {}
|
||||
|
||||
local buttonPositionTable = {
|
||||
[1] = UDim2.new(0,123,0,70),
|
||||
[2] = UDim2.new(0,30,0,60),
|
||||
[3] = UDim2.new(0,180,0,160),
|
||||
[4] = UDim2.new(0,85,0,-25),
|
||||
[5] = UDim2.new(0,185,0,-25),
|
||||
[6] = UDim2.new(0,185,0,260),
|
||||
[7] = UDim2.new(0,216,0,65)
|
||||
}
|
||||
local maxButtons = #buttonPositionTable
|
||||
|
||||
-- Preload images
|
||||
game:GetService("ContentProvider"):Preload(ContextDownImage)
|
||||
game:GetService("ContentProvider"):Preload(ContextUpImage)
|
||||
|
||||
repeat wait() until game:GetService("Players").LocalPlayer
|
||||
|
||||
local localPlayer = game:GetService("Players").LocalPlayer
|
||||
|
||||
function createContextActionGui()
|
||||
if not buttonScreenGui and isTouchDevice then
|
||||
buttonScreenGui = Instance.new("ScreenGui")
|
||||
buttonScreenGui.Name = "ContextActionGui"
|
||||
|
||||
buttonFrame = Instance.new("Frame")
|
||||
buttonFrame.BackgroundTransparency = 1
|
||||
buttonFrame.Size = UDim2.new(0.3,0,0.5,0)
|
||||
buttonFrame.Position = UDim2.new(0.7,0,0.5,0)
|
||||
buttonFrame.Name = "ContextButtonFrame"
|
||||
buttonFrame.Parent = buttonScreenGui
|
||||
|
||||
buttonFrame.Visible = not userInputService.ModalEnabled
|
||||
userInputService.Changed:connect(function(property)
|
||||
if property == "ModalEnabled" then
|
||||
buttonFrame.Visible = not userInputService.ModalEnabled
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
-- functions
|
||||
function setButtonSizeAndPosition(object)
|
||||
local buttonSize = 55
|
||||
local xOffset = 10
|
||||
local yOffset = 95
|
||||
|
||||
-- todo: better way to determine mobile sized screens
|
||||
local onSmallScreen = (game:GetService("CoreGui").RobloxGui.AbsoluteSize.X < 600)
|
||||
if not onSmallScreen then
|
||||
buttonSize = 85
|
||||
xOffset = 40
|
||||
end
|
||||
|
||||
object.Size = UDim2.new(0,buttonSize,0,buttonSize)
|
||||
end
|
||||
|
||||
function contextButtonDown(button, inputObject, actionName)
|
||||
if inputObject.UserInputType == Enum.UserInputType.Touch then
|
||||
button.Image = ContextDownImage
|
||||
contextActionService:CallFunction(actionName, Enum.UserInputState.Begin, inputObject)
|
||||
end
|
||||
end
|
||||
|
||||
function contextButtonMoved(button, inputObject, actionName)
|
||||
if inputObject.UserInputType == Enum.UserInputType.Touch then
|
||||
button.Image = ContextDownImage
|
||||
contextActionService:CallFunction(actionName, Enum.UserInputState.Change, inputObject)
|
||||
end
|
||||
end
|
||||
|
||||
function contextButtonUp(button, inputObject, actionName)
|
||||
button.Image = ContextUpImage
|
||||
if inputObject.UserInputType == Enum.UserInputType.Touch and inputObject.UserInputState == Enum.UserInputState.End then
|
||||
contextActionService:CallFunction(actionName, Enum.UserInputState.End, inputObject)
|
||||
end
|
||||
end
|
||||
|
||||
function isSmallScreenDevice()
|
||||
return game:GetService("GuiService"):GetScreenResolution().y <= 320
|
||||
end
|
||||
|
||||
|
||||
function createNewButton(actionName, functionInfoTable)
|
||||
local contextButton = Instance.new("ImageButton")
|
||||
contextButton.Name = "ContextActionButton"
|
||||
contextButton.BackgroundTransparency = 1
|
||||
contextButton.Size = UDim2.new(0,90,0,90)
|
||||
contextButton.Active = true
|
||||
if isSmallScreenDevice() then
|
||||
contextButton.Size = UDim2.new(0,70,0,70)
|
||||
end
|
||||
contextButton.Image = ContextUpImage
|
||||
contextButton.Parent = buttonFrame
|
||||
|
||||
local currentButtonTouch = nil
|
||||
|
||||
userInputService.InputEnded:connect(function ( inputObject )
|
||||
oldTouches[inputObject] = nil
|
||||
end)
|
||||
contextButton.InputBegan:connect(function(inputObject)
|
||||
if oldTouches[inputObject] then return end
|
||||
|
||||
if inputObject.UserInputState == Enum.UserInputState.Begin and currentButtonTouch == nil then
|
||||
currentButtonTouch = inputObject
|
||||
contextButtonDown(contextButton, inputObject, actionName)
|
||||
end
|
||||
end)
|
||||
contextButton.InputChanged:connect(function(inputObject)
|
||||
if oldTouches[inputObject] then return end
|
||||
if currentButtonTouch ~= inputObject then return end
|
||||
|
||||
contextButtonMoved(contextButton, inputObject, actionName)
|
||||
end)
|
||||
contextButton.InputEnded:connect(function(inputObject)
|
||||
if oldTouches[inputObject] then return end
|
||||
if currentButtonTouch ~= inputObject then return end
|
||||
|
||||
currentButtonTouch = nil
|
||||
oldTouches[inputObject] = true
|
||||
contextButtonUp(contextButton, inputObject, actionName)
|
||||
end)
|
||||
|
||||
local actionIcon = Instance.new("ImageLabel")
|
||||
actionIcon.Name = "ActionIcon"
|
||||
actionIcon.Position = UDim2.new(0.175, 0, 0.175, 0)
|
||||
actionIcon.Size = UDim2.new(0.65, 0, 0.65, 0)
|
||||
actionIcon.BackgroundTransparency = 1
|
||||
if functionInfoTable["image"] and type(functionInfoTable["image"]) == "string" then
|
||||
actionIcon.Image = functionInfoTable["image"]
|
||||
end
|
||||
actionIcon.Parent = contextButton
|
||||
|
||||
local actionTitle = Instance.new("TextLabel")
|
||||
actionTitle.Name = "ActionTitle"
|
||||
actionTitle.Size = UDim2.new(1,0,1,0)
|
||||
actionTitle.BackgroundTransparency = 1
|
||||
actionTitle.Font = Enum.Font.SourceSansBold
|
||||
actionTitle.TextColor3 = Color3.new(1,1,1)
|
||||
actionTitle.TextStrokeTransparency = 0
|
||||
actionTitle.FontSize = Enum.FontSize.Size18
|
||||
actionTitle.TextWrapped = true
|
||||
actionTitle.Text = ""
|
||||
if functionInfoTable["title"] and type(functionInfoTable["title"]) == "string" then
|
||||
actionTitle.Text = functionInfoTable["title"]
|
||||
end
|
||||
actionTitle.Parent = contextButton
|
||||
|
||||
return contextButton
|
||||
end
|
||||
|
||||
function createButton( actionName, functionInfoTable )
|
||||
local button = createNewButton(actionName, functionInfoTable)
|
||||
|
||||
local position = nil
|
||||
for i = 1,#buttonVector do
|
||||
if buttonVector[i] == "empty" then
|
||||
position = i
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not position then
|
||||
position = #buttonVector + 1
|
||||
end
|
||||
|
||||
if position > maxButtons then
|
||||
return -- todo: let user know we have too many buttons already?
|
||||
end
|
||||
|
||||
buttonVector[position] = button
|
||||
functionTable[actionName]["button"] = button
|
||||
|
||||
button.Position = buttonPositionTable[position]
|
||||
button.Parent = buttonFrame
|
||||
|
||||
if buttonScreenGui and buttonScreenGui.Parent == nil then
|
||||
buttonScreenGui.Parent = localPlayer.PlayerGui
|
||||
end
|
||||
end
|
||||
|
||||
function removeAction(actionName)
|
||||
if not functionTable[actionName] then return end
|
||||
|
||||
local actionButton = functionTable[actionName]["button"]
|
||||
|
||||
if actionButton then
|
||||
actionButton.Parent = nil
|
||||
|
||||
for i = 1,#buttonVector do
|
||||
if buttonVector[i] == actionButton then
|
||||
buttonVector[i] = "empty"
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
actionButton:Destroy()
|
||||
end
|
||||
|
||||
functionTable[actionName] = nil
|
||||
end
|
||||
|
||||
function addAction(actionName,createTouchButton,functionInfoTable)
|
||||
if functionTable[actionName] then
|
||||
removeAction(actionName)
|
||||
end
|
||||
functionTable[actionName] = {functionInfoTable}
|
||||
if createTouchButton and isTouchDevice then
|
||||
createContextActionGui()
|
||||
createButton(actionName, functionInfoTable)
|
||||
end
|
||||
end
|
||||
|
||||
-- Connections
|
||||
contextActionService.BoundActionChanged:connect( function(actionName, changeName, changeTable)
|
||||
if functionTable[actionName] and changeTable then
|
||||
local button = functionTable[actionName]["button"]
|
||||
if button then
|
||||
if changeName == "image" then
|
||||
button.ActionIcon.Image = changeTable[changeName]
|
||||
elseif changeName == "title" then
|
||||
button.ActionTitle.Text = changeTable[changeName]
|
||||
elseif changeName == "description" then
|
||||
-- todo: add description to menu
|
||||
elseif changeName == "position" then
|
||||
button.Position = changeTable[changeName]
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
contextActionService.BoundActionAdded:connect( function(actionName, createTouchButton, functionInfoTable)
|
||||
addAction(actionName, createTouchButton, functionInfoTable)
|
||||
end)
|
||||
|
||||
contextActionService.BoundActionRemoved:connect( function(actionName, functionInfoTable)
|
||||
removeAction(actionName)
|
||||
end)
|
||||
|
||||
contextActionService.GetActionButtonEvent:connect( function(actionName)
|
||||
if functionTable[actionName] then
|
||||
contextActionService:FireActionButtonFoundSignal(actionName, functionTable[actionName]["button"])
|
||||
end
|
||||
end)
|
||||
|
||||
-- make sure any bound data before we setup connections is handled
|
||||
local boundActions = contextActionService:GetAllBoundActionInfo()
|
||||
for actionName, actionData in pairs(boundActions) do
|
||||
addAction(actionName,actionData["createTouchButton"],actionData)
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,652 @@
|
||||
--[[
|
||||
Filename: GamepadMenu.lua
|
||||
Written by: jeditkacheff
|
||||
Version 1.1
|
||||
Description: Controls the radial menu that appears when pressing menu button on gamepad
|
||||
--]]
|
||||
|
||||
--[[ SERVICES ]]
|
||||
local GuiService = game:GetService('GuiService')
|
||||
local CoreGuiService = game:GetService('CoreGui')
|
||||
local InputService = game:GetService('UserInputService')
|
||||
local ContextActionService = game:GetService('ContextActionService')
|
||||
local HttpService = game:GetService('HttpService')
|
||||
local StarterGui = game:GetService('StarterGui')
|
||||
local GuiRoot = CoreGuiService:WaitForChild('RobloxGui')
|
||||
--[[ END OF SERVICES ]]
|
||||
|
||||
--[[ MODULES ]]
|
||||
local tenFootInterface = require(GuiRoot.Modules.TenFootInterface)
|
||||
local utility = require(GuiRoot.Modules.Settings.Utility)
|
||||
local recordPage = require(GuiRoot.Modules.Settings.Pages.Record)
|
||||
|
||||
--[[ VARIABLES ]]
|
||||
local gamepadSettingsFrame = nil
|
||||
local isVisible = false
|
||||
local smallScreen = utility:IsSmallTouchScreen()
|
||||
local isTenFootInterface = tenFootInterface:IsEnabled()
|
||||
local radialButtons = {}
|
||||
local lastInputChangedCon = nil
|
||||
|
||||
local function getButtonForCoreGuiType(coreGuiType)
|
||||
if coreGuiType == Enum.CoreGuiType.All then
|
||||
return radialButtons
|
||||
else
|
||||
for button, table in pairs(radialButtons) do
|
||||
if table["CoreGuiType"] == coreGuiType then
|
||||
return button
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
local function getImagesForSlot(slot)
|
||||
if slot == 1 then return "rbxasset://textures/ui/Settings/Radial/Top.png", "rbxasset://textures/ui/Settings/Radial/TopSelected.png",
|
||||
"rbxasset://textures/ui/Settings/Radial/Menu.png",
|
||||
UDim2.new(0.5,-26,0,18), UDim2.new(0,52,0,41),
|
||||
UDim2.new(0,150,0,100), UDim2.new(0.5,-75,0,0)
|
||||
elseif slot == 2 then return "rbxasset://textures/ui/Settings/Radial/TopRight.png", "rbxasset://textures/ui/Settings/Radial/TopRightSelected.png",
|
||||
"rbxasset://textures/ui/Settings/Radial/PlayerList.png",
|
||||
UDim2.new(1,-90,0,90), UDim2.new(0,52,0,52),
|
||||
UDim2.new(0,108,0,150), UDim2.new(1,-110,0,50)
|
||||
elseif slot == 3 then return "rbxasset://textures/ui/Settings/Radial/BottomRight.png", "rbxasset://textures/ui/Settings/Radial/BottomRightSelected.png",
|
||||
"rbxasset://textures/ui/Settings/Radial/Alert.png",
|
||||
UDim2.new(1,-85,1,-150), UDim2.new(0,42,0,58),
|
||||
UDim2.new(0,120,0,150), UDim2.new(1,-120,1,-200)
|
||||
elseif slot == 4 then return "rbxasset://textures/ui/Settings/Radial/Bottom.png", "rbxasset://textures/ui/Settings/Radial/BottomSelected.png",
|
||||
"rbxasset://textures/ui/Settings/Radial/Leave.png",
|
||||
UDim2.new(0.5,-20,1,-62), UDim2.new(0,55,0,46),
|
||||
UDim2.new(0,150,0,100), UDim2.new(0.5,-75,1,-100)
|
||||
elseif slot == 5 then return "rbxasset://textures/ui/Settings/Radial/BottomLeft.png", "rbxasset://textures/ui/Settings/Radial/BottomLeftSelected.png",
|
||||
"rbxasset://textures/ui/Settings/Radial/Backpack.png",
|
||||
UDim2.new(0,40,1,-150), UDim2.new(0,44,0,56),
|
||||
UDim2.new(0,110,0,150), UDim2.new(0,0,0,205)
|
||||
elseif slot == 6 then return "rbxasset://textures/ui/Settings/Radial/TopLeft.png", "rbxasset://textures/ui/Settings/Radial/TopLeftSelected.png",
|
||||
"rbxasset://textures/ui/Settings/Radial/Chat.png",
|
||||
UDim2.new(0,35,0,100), UDim2.new(0,56,0,53),
|
||||
UDim2.new(0,110,0,150), UDim2.new(0,0,0,50)
|
||||
end
|
||||
|
||||
return "", "", UDim2.new(0,0,0,0), UDim2.new(0,0,0,0)
|
||||
end
|
||||
|
||||
local function setSelectedRadialButton(selectedObject)
|
||||
for button, buttonTable in pairs(radialButtons) do
|
||||
local isVisible = (button == selectedObject)
|
||||
button:FindFirstChild("Selected").Visible = isVisible
|
||||
button:FindFirstChild("RadialLabel").Visible = isVisible
|
||||
end
|
||||
end
|
||||
|
||||
local function activateSelectedRadialButton()
|
||||
for button, buttonTable in pairs(radialButtons) do
|
||||
if button:FindFirstChild("Selected").Visible then
|
||||
buttonTable["Function"]()
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function setButtonEnabled(button, enabled)
|
||||
if radialButtons[button]["Disabled"] == not enabled then return end
|
||||
|
||||
if button:FindFirstChild("Selected").Visible == true then
|
||||
setSelectedRadialButton(nil)
|
||||
end
|
||||
|
||||
if enabled then
|
||||
button.Image = string.gsub(button.Image, "rbxasset://textures/ui/Settings/Radial/Empty", "rbxasset://textures/ui/Settings/Radial/")
|
||||
button.ImageTransparency = 0
|
||||
button.RadialIcon.ImageTransparency = 0
|
||||
else
|
||||
button.Image = string.gsub(button.Image, "rbxasset://textures/ui/Settings/Radial/", "rbxasset://textures/ui/Settings/Radial/Empty")
|
||||
button.ImageTransparency = 0
|
||||
button.RadialIcon.ImageTransparency = 1
|
||||
end
|
||||
|
||||
radialButtons[button]["Disabled"] = not enabled
|
||||
end
|
||||
|
||||
local emptySelectedImageObject = utility:Create'ImageLabel'
|
||||
{
|
||||
BackgroundTransparency = 1,
|
||||
Size = UDim2.new(1,0,1,0),
|
||||
Image = ""
|
||||
};
|
||||
|
||||
local function createRadialButton(name, text, slot, disabled, coreGuiType, activateFunc)
|
||||
local slotImage, selectedSlotImage, slotIcon,
|
||||
slotIconPosition, slotIconSize, mouseFrameSize, mouseFramePos = getImagesForSlot(slot)
|
||||
|
||||
local radialButton = utility:Create'ImageButton'
|
||||
{
|
||||
Name = name,
|
||||
Position = UDim2.new(0,0,0,0),
|
||||
Size = UDim2.new(1,0,1,0),
|
||||
BackgroundTransparency = 1,
|
||||
Image = slotImage,
|
||||
ZIndex = 2,
|
||||
SelectionImageObject = emptySelectedImageObject,
|
||||
Parent = gamepadSettingsFrame
|
||||
};
|
||||
if disabled then
|
||||
radialButton.Image = string.gsub(radialButton.Image, "rbxasset://textures/ui/Settings/Radial/", "rbxasset://textures/ui/Settings/Radial/Empty")
|
||||
end
|
||||
|
||||
local selectedRadial = utility:Create'ImageLabel'
|
||||
{
|
||||
Name = "Selected",
|
||||
Position = UDim2.new(0,0,0,0),
|
||||
Size = UDim2.new(1,0,1,0),
|
||||
BackgroundTransparency = 1,
|
||||
Image = selectedSlotImage,
|
||||
ZIndex = 2,
|
||||
Visible = false,
|
||||
Parent = radialButton
|
||||
};
|
||||
|
||||
local radialIcon = utility:Create'ImageLabel'
|
||||
{
|
||||
Name = "RadialIcon",
|
||||
Position = slotIconPosition,
|
||||
Size = slotIconSize,
|
||||
BackgroundTransparency = 1,
|
||||
Image = slotIcon,
|
||||
ZIndex = 3,
|
||||
ImageTransparency = disabled and 1 or 0,
|
||||
Parent = radialButton
|
||||
};
|
||||
|
||||
local nameLabel = utility:Create'TextLabel'
|
||||
{
|
||||
|
||||
Size = UDim2.new(0,220,0,50),
|
||||
Position = UDim2.new(0.5, -110, 0.5, -25),
|
||||
BackgroundTransparency = 1,
|
||||
Text = text,
|
||||
Font = Enum.Font.SourceSansBold,
|
||||
FontSize = Enum.FontSize.Size14,
|
||||
TextColor3 = Color3.new(1,1,1),
|
||||
Name = "RadialLabel",
|
||||
Visible = false,
|
||||
ZIndex = 2,
|
||||
Parent = radialButton
|
||||
};
|
||||
if not smallScreen then
|
||||
nameLabel.FontSize = Enum.FontSize.Size36
|
||||
nameLabel.Size = UDim2.new(nameLabel.Size.X.Scale, nameLabel.Size.X.Offset, nameLabel.Size.Y.Scale, nameLabel.Size.Y.Offset + 4)
|
||||
end
|
||||
local nameBackgroundImage = utility:Create'ImageLabel'
|
||||
{
|
||||
Name = text .. "BackgroundImage",
|
||||
Size = UDim2.new(1,0,1,0),
|
||||
Position = UDim2.new(0,0,0,2),
|
||||
BackgroundTransparency = 1,
|
||||
Image = "rbxasset://textures/ui/Settings/Radial/RadialLabel@2x.png",
|
||||
ScaleType = Enum.ScaleType.Slice,
|
||||
SliceCenter = Rect.new(24,4,130,42),
|
||||
ZIndex = 2,
|
||||
Parent = nameLabel
|
||||
};
|
||||
|
||||
local mouseFrame = utility:Create'ImageButton'
|
||||
{
|
||||
Name = "MouseFrame",
|
||||
Position = mouseFramePos,
|
||||
Size = mouseFrameSize,
|
||||
ZIndex = 3,
|
||||
BackgroundTransparency = 1,
|
||||
SelectionImageObject = emptySelectedImageObject,
|
||||
Parent = radialButton
|
||||
};
|
||||
|
||||
mouseFrame.MouseEnter:connect(function()
|
||||
if not radialButtons[radialButton]["Disabled"] then
|
||||
setSelectedRadialButton(radialButton)
|
||||
end
|
||||
end)
|
||||
mouseFrame.MouseLeave:connect(function()
|
||||
setSelectedRadialButton(nil)
|
||||
end)
|
||||
|
||||
mouseFrame.MouseButton1Click:connect(function()
|
||||
if selectedRadial.Visible then
|
||||
activateFunc()
|
||||
end
|
||||
end)
|
||||
|
||||
radialButtons[radialButton] = {["Function"] = activateFunc, ["Disabled"] = disabled, ["CoreGuiType"] = coreGuiType}
|
||||
|
||||
return radialButton
|
||||
end
|
||||
|
||||
local function createGamepadMenuGui()
|
||||
gamepadSettingsFrame = utility:Create'Frame'
|
||||
{
|
||||
Name = "GamepadSettingsFrame",
|
||||
Position = UDim2.new(0.5,-51,0.5,-51),
|
||||
BackgroundTransparency = 1,
|
||||
BorderSizePixel = 0,
|
||||
Size = UDim2.new(0,102,0,102),
|
||||
Visible = false,
|
||||
Parent = GuiRoot
|
||||
};
|
||||
|
||||
---------------------------------
|
||||
-------- Settings Menu ----------
|
||||
local settingsFunc = function()
|
||||
toggleCoreGuiRadial(true)
|
||||
local MenuModule = require(GuiRoot.Modules.Settings.SettingsHub)
|
||||
MenuModule:SetVisibility(true, nil, nil, true)
|
||||
end
|
||||
local settingsRadial = createRadialButton("Settings", "Settings", 1, false, nil, settingsFunc)
|
||||
settingsRadial.Parent = gamepadSettingsFrame
|
||||
|
||||
---------------------------------
|
||||
-------- Player List ------------
|
||||
local playerListFunc = function()
|
||||
toggleCoreGuiRadial(true)
|
||||
local PlayerListModule = require(GuiRoot.Modules.PlayerlistModule)
|
||||
if not PlayerListModule:IsOpen() then
|
||||
PlayerListModule:ToggleVisibility()
|
||||
end
|
||||
end
|
||||
local playerListRadial = createRadialButton("PlayerList", "Player List", 2, not StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.PlayerList), Enum.CoreGuiType.PlayerList, playerListFunc)
|
||||
playerListRadial.Parent = gamepadSettingsFrame
|
||||
|
||||
---------------------------------
|
||||
-------- Notifications ----------
|
||||
local gamepadNotifications = Instance.new("BindableEvent")
|
||||
gamepadNotifications.Name = "GamepadNotifications"
|
||||
gamepadNotifications.Parent = script
|
||||
local notificationsFunc = function()
|
||||
toggleCoreGuiRadial()
|
||||
gamepadNotifications:Fire(true)
|
||||
end
|
||||
local notificationsRadial = createRadialButton("Notifications", "Notifications", 3, false, nil, notificationsFunc)
|
||||
if isTenFootInterface then
|
||||
setButtonEnabled(notificationsRadial, false)
|
||||
end
|
||||
notificationsRadial.Parent = gamepadSettingsFrame
|
||||
|
||||
---------------------------------
|
||||
---------- Leave Game -----------
|
||||
local leaveGameFunc = function()
|
||||
toggleCoreGuiRadial(true)
|
||||
local MenuModule = require(GuiRoot.Modules.Settings.SettingsHub)
|
||||
MenuModule:SetVisibility(true, false, require(GuiRoot.Modules.Settings.Pages.LeaveGame), true)
|
||||
end
|
||||
local leaveGameRadial = createRadialButton("LeaveGame", "Leave Game", 4, false, nil, leaveGameFunc)
|
||||
leaveGameRadial.Parent = gamepadSettingsFrame
|
||||
|
||||
---------------------------------
|
||||
---------- Backpack -------------
|
||||
local backpackFunc = function()
|
||||
toggleCoreGuiRadial(true)
|
||||
local BackpackModule = require(GuiRoot.Modules.BackpackScript)
|
||||
BackpackModule:OpenClose()
|
||||
end
|
||||
local backpackRadial = createRadialButton("Backpack", "Backpack", 5, not StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Backpack), Enum.CoreGuiType.Backpack, backpackFunc)
|
||||
backpackRadial.Parent = gamepadSettingsFrame
|
||||
|
||||
---------------------------------
|
||||
------------ Chat ---------------
|
||||
local chatFunc = function()
|
||||
toggleCoreGuiRadial()
|
||||
local ChatModule = require(GuiRoot.Modules.Chat)
|
||||
ChatModule:ToggleVisibility()
|
||||
end
|
||||
local chatRadial = createRadialButton("Chat", "Chat", 6, not StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Chat), Enum.CoreGuiType.Chat, chatFunc)
|
||||
if isTenFootInterface then
|
||||
setButtonEnabled(chatRadial, false)
|
||||
end
|
||||
chatRadial.Parent = gamepadSettingsFrame
|
||||
|
||||
|
||||
---------------------------------
|
||||
--------- Close Button ----------
|
||||
local closeHintImage = utility:Create'ImageLabel'
|
||||
{
|
||||
Name = "CloseHint",
|
||||
Position = UDim2.new(1,10,1,10),
|
||||
Size = UDim2.new(0,60,0,60),
|
||||
BackgroundTransparency = 1,
|
||||
Image = "rbxasset://textures/ui/Settings/Help/BButtonDark.png",
|
||||
Parent = gamepadSettingsFrame
|
||||
}
|
||||
if isTenFootInterface then
|
||||
closeHintImage.Image = "rbxasset://textures/ui/Settings/Help/BButtonDark@2x.png"
|
||||
closeHintImage.Size = UDim2.new(0,90,0,90)
|
||||
end
|
||||
|
||||
local closeHintText = utility:Create'TextLabel'
|
||||
{
|
||||
Name = "closeHintText",
|
||||
Position = UDim2.new(1,10,0.5,-12),
|
||||
Size = UDim2.new(0,43,0,24),
|
||||
Font = Enum.Font.SourceSansBold,
|
||||
FontSize = Enum.FontSize.Size24,
|
||||
BackgroundTransparency = 1,
|
||||
Text = "Back",
|
||||
TextColor3 = Color3.new(1,1,1),
|
||||
TextXAlignment = Enum.TextXAlignment.Left,
|
||||
Parent = closeHintImage
|
||||
}
|
||||
if isTenFootInterface then
|
||||
closeHintText.FontSize = Enum.FontSize.Size36
|
||||
end
|
||||
|
||||
------------------------------------------
|
||||
--------- Stop Recording Button ----------
|
||||
--todo: enable this when recording is not a verb
|
||||
--[[local stopRecordingImage = utility:Create'ImageLabel'
|
||||
{
|
||||
Name = "StopRecordingHint",
|
||||
Position = UDim2.new(0,-100,1,10),
|
||||
Size = UDim2.new(0,61,0,61),
|
||||
BackgroundTransparency = 1,
|
||||
Image = "rbxasset://textures/ui/Settings/Help/YButtonDark.png",
|
||||
Visible = recordPage:IsRecording(),
|
||||
Parent = gamepadSettingsFrame
|
||||
}
|
||||
local stopRecordingText = utility:Create'TextLabel'
|
||||
{
|
||||
Name = "stopRecordingHintText",
|
||||
Position = UDim2.new(1,10,0.5,-12),
|
||||
Size = UDim2.new(0,43,0,24),
|
||||
Font = Enum.Font.SourceSansBold,
|
||||
FontSize = Enum.FontSize.Size24,
|
||||
BackgroundTransparency = 1,
|
||||
Text = "Stop Recording",
|
||||
TextColor3 = Color3.new(1,1,1),
|
||||
TextXAlignment = Enum.TextXAlignment.Left,
|
||||
Parent = stopRecordingImage
|
||||
}
|
||||
|
||||
recordPage.RecordingChanged:connect(function(isRecording)
|
||||
stopRecordingImage.Visible = isRecording
|
||||
end)]]
|
||||
|
||||
GuiService:AddSelectionParent(HttpService:GenerateGUID(false), gamepadSettingsFrame)
|
||||
|
||||
gamepadSettingsFrame.Changed:connect(function(prop)
|
||||
if prop == "Visible" then
|
||||
if not gamepadSettingsFrame.Visible then
|
||||
unbindAllRadialActions()
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local function isCoreGuiDisabled()
|
||||
for _, enumItem in pairs(Enum.CoreGuiType:GetEnumItems()) do
|
||||
if StarterGui:GetCoreGuiEnabled(enumItem) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function setupGamepadControls()
|
||||
local freezeControllerActionName = "doNothingAction"
|
||||
local radialSelectActionName = "RadialSelectAction"
|
||||
local thumbstick2RadialActionName = "Thumbstick2RadialAction"
|
||||
local radialCancelActionName = "RadialSelectCancel"
|
||||
local radialAcceptActionName = "RadialSelectAccept"
|
||||
local toggleMenuActionName = "RBXToggleMenuAction"
|
||||
|
||||
local noOpFunc = function() end
|
||||
local doGamepadMenuButton = nil
|
||||
|
||||
function unbindAllRadialActions()
|
||||
local success = pcall(function() GuiService.CoreGuiNavigationEnabled = true end)
|
||||
if not success then
|
||||
GuiService.GuiNavigationEnabled = true
|
||||
end
|
||||
|
||||
ContextActionService:UnbindCoreAction(radialSelectActionName)
|
||||
ContextActionService:UnbindCoreAction(radialCancelActionName)
|
||||
ContextActionService:UnbindCoreAction(radialAcceptActionName)
|
||||
ContextActionService:UnbindCoreAction(freezeControllerActionName)
|
||||
ContextActionService:UnbindCoreAction(thumbstick2RadialActionName)
|
||||
end
|
||||
|
||||
local radialButtonLayout = { PlayerList = {
|
||||
Range = { Begin = 36,
|
||||
End = 96
|
||||
}
|
||||
},
|
||||
Notifications = {
|
||||
Range = { Begin = 96,
|
||||
End = 156
|
||||
}
|
||||
},
|
||||
LeaveGame = {
|
||||
Range = { Begin = 156,
|
||||
End = 216
|
||||
}
|
||||
},
|
||||
Backpack = {
|
||||
Range = { Begin = 216,
|
||||
End = 276
|
||||
}
|
||||
},
|
||||
Chat = {
|
||||
Range = { Begin = 276,
|
||||
End = 336
|
||||
}
|
||||
},
|
||||
Settings = {
|
||||
Range = { Begin = 336,
|
||||
End = 36
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
local function getSelectedObjectFromAngle(angle, depth)
|
||||
local closest = nil
|
||||
local closestDistance = 30 -- threshold of 30 for selecting the closest radial button
|
||||
for radialKey, buttonLayout in pairs(radialButtonLayout) do
|
||||
if radialButtons[gamepadSettingsFrame[radialKey]]["Disabled"] == false then
|
||||
--Check for exact match
|
||||
if buttonLayout.Range.Begin < buttonLayout.Range.End then
|
||||
if angle > buttonLayout.Range.Begin and angle <= buttonLayout.Range.End then
|
||||
return gamepadSettingsFrame[radialKey]
|
||||
end
|
||||
else
|
||||
if angle > buttonLayout.Range.Begin or angle <= buttonLayout.Range.End then
|
||||
return gamepadSettingsFrame[radialKey]
|
||||
end
|
||||
end
|
||||
--Check if this is the closest button so far
|
||||
local distanceBegin = math.min(math.abs((buttonLayout.Range.Begin + 360) - angle), math.abs(buttonLayout.Range.Begin - angle))
|
||||
local distanceEnd = math.min(math.abs((buttonLayout.Range.End + 360) - angle), math.abs(buttonLayout.Range.End - angle))
|
||||
local distance = math.min(distanceBegin, distanceEnd)
|
||||
if distance < closestDistance then
|
||||
closestDistance = distance
|
||||
closest = gamepadSettingsFrame[radialKey]
|
||||
end
|
||||
end
|
||||
end
|
||||
return closest
|
||||
end
|
||||
|
||||
local radialSelect = function(name, state, input)
|
||||
local inputVector = Vector2.new(0,0)
|
||||
|
||||
if input.KeyCode == Enum.KeyCode.Thumbstick1 then
|
||||
inputVector = Vector2.new(input.Position.x, input.Position.y)
|
||||
end
|
||||
|
||||
local selectedObject = nil
|
||||
|
||||
if inputVector.magnitude > 0.8 then
|
||||
|
||||
local angle = math.atan2(inputVector.X, inputVector.Y) * 180 / math.pi
|
||||
if angle < 0 then
|
||||
angle = angle + 360
|
||||
end
|
||||
|
||||
selectedObject = getSelectedObjectFromAngle(angle)
|
||||
|
||||
setSelectedRadialButton(selectedObject)
|
||||
end
|
||||
end
|
||||
|
||||
local radialSelectAccept = function(name, state, input)
|
||||
if gamepadSettingsFrame.Visible and state == Enum.UserInputState.Begin then
|
||||
activateSelectedRadialButton()
|
||||
end
|
||||
end
|
||||
|
||||
local radialSelectCancel = function(name, state, input)
|
||||
if gamepadSettingsFrame.Visible and state == Enum.UserInputState.Begin then
|
||||
toggleCoreGuiRadial()
|
||||
end
|
||||
end
|
||||
|
||||
function setVisibility()
|
||||
local children = gamepadSettingsFrame:GetChildren()
|
||||
for i = 1, #children do
|
||||
if children[i]:FindFirstChild("RadialIcon") then
|
||||
children[i].RadialIcon.Visible = isVisible
|
||||
end
|
||||
if children[i]:FindFirstChild("RadialLabel") and not isVisible then
|
||||
children[i].RadialLabel.Visible = isVisible
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function setOverrideMouseIconBehavior()
|
||||
pcall(function()
|
||||
if InputService:GetLastInputType() == Enum.UserInputType.Gamepad1 then
|
||||
InputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.ForceHide
|
||||
else
|
||||
InputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.ForceShow
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function toggleCoreGuiRadial(goingToSettings)
|
||||
isVisible = not gamepadSettingsFrame.Visible
|
||||
|
||||
setVisibility()
|
||||
|
||||
if isVisible then
|
||||
setOverrideMouseIconBehavior()
|
||||
pcall(function() lastInputChangedCon = InputService.LastInputTypeChanged:connect(setOverrideMouseIconBehavior) end)
|
||||
|
||||
gamepadSettingsFrame.Visible = isVisible
|
||||
|
||||
local settingsChildren = gamepadSettingsFrame:GetChildren()
|
||||
for i = 1, #settingsChildren do
|
||||
if settingsChildren[i]:IsA("GuiButton") then
|
||||
utility:TweenProperty(settingsChildren[i], "ImageTransparency", 1, 0, 0.1, utility:GetEaseOutQuad(), nil)
|
||||
end
|
||||
end
|
||||
gamepadSettingsFrame:TweenSizeAndPosition(UDim2.new(0,408,0,408), UDim2.new(0.5,-204,0.5,-204),
|
||||
Enum.EasingDirection.Out, Enum.EasingStyle.Back, 0.18, true,
|
||||
function()
|
||||
setVisibility()
|
||||
end)
|
||||
else
|
||||
if lastInputChangedCon ~= nil then
|
||||
lastInputChangedCon:disconnect()
|
||||
lastInputChangedCon = nil
|
||||
end
|
||||
pcall(function() InputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.None end)
|
||||
|
||||
local settingsChildren = gamepadSettingsFrame:GetChildren()
|
||||
for i = 1, #settingsChildren do
|
||||
if settingsChildren[i]:IsA("GuiButton") then
|
||||
utility:TweenProperty(settingsChildren[i], "ImageTransparency", 0, 1, 0.1, utility:GetEaseOutQuad(), nil)
|
||||
end
|
||||
end
|
||||
gamepadSettingsFrame:TweenSizeAndPosition(UDim2.new(0,102,0,102), UDim2.new(0.5,-51,0.5,-51),
|
||||
Enum.EasingDirection.Out, Enum.EasingStyle.Sine, 0.1, true,
|
||||
function()
|
||||
if not goingToSettings and not isVisible then GuiService:SetMenuIsOpen(false) end
|
||||
gamepadSettingsFrame.Visible = isVisible
|
||||
end)
|
||||
end
|
||||
|
||||
if isVisible then
|
||||
setSelectedRadialButton(nil)
|
||||
|
||||
local success = pcall(function() GuiService.CoreGuiNavigationEnabled = false end)
|
||||
if not success then
|
||||
GuiService.GuiNavigationEnabled = false
|
||||
end
|
||||
|
||||
GuiService:SetMenuIsOpen(true)
|
||||
|
||||
ContextActionService:BindCoreAction(freezeControllerActionName, noOpFunc, false, Enum.UserInputType.Gamepad1)
|
||||
ContextActionService:BindCoreAction(radialAcceptActionName, radialSelectAccept, false, Enum.KeyCode.ButtonA)
|
||||
ContextActionService:BindCoreAction(radialCancelActionName, radialSelectCancel, false, Enum.KeyCode.ButtonB)
|
||||
ContextActionService:BindCoreAction(radialSelectActionName, radialSelect, false, Enum.KeyCode.Thumbstick1)
|
||||
ContextActionService:BindCoreAction(thumbstick2RadialActionName, noOpFunc, false, Enum.KeyCode.Thumbstick2)
|
||||
ContextActionService:BindCoreAction(toggleMenuActionName, doGamepadMenuButton, false, Enum.KeyCode.ButtonStart)
|
||||
else
|
||||
unbindAllRadialActions()
|
||||
end
|
||||
|
||||
return gamepadSettingsFrame.Visible
|
||||
end
|
||||
|
||||
doGamepadMenuButton = function(name, state, input)
|
||||
if state ~= Enum.UserInputState.Begin then return end
|
||||
|
||||
if not toggleCoreGuiRadial() then
|
||||
unbindAllRadialActions()
|
||||
end
|
||||
end
|
||||
|
||||
if InputService:GetGamepadConnected(Enum.UserInputType.Gamepad1) then
|
||||
createGamepadMenuGui()
|
||||
else
|
||||
InputService.GamepadConnected:connect(function(gamepadEnum)
|
||||
if gamepadEnum == Enum.UserInputType.Gamepad1 then
|
||||
createGamepadMenuGui()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local function setRadialButtonEnabled(coreGuiType, enabled)
|
||||
local returnValue = getButtonForCoreGuiType(coreGuiType)
|
||||
if not returnValue then return end
|
||||
|
||||
local buttonsToDisable = {}
|
||||
if type(returnValue) == "table" then
|
||||
for button, buttonTable in pairs(returnValue) do
|
||||
if buttonTable["CoreGuiType"] then
|
||||
if isTenFootInterface and buttonTable["CoreGuiType"] == Enum.CoreGuiType.Chat then
|
||||
else
|
||||
buttonsToDisable[#buttonsToDisable + 1] = button
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if isTenFootInterface and returnValue.Name == "Chat" then
|
||||
else
|
||||
buttonsToDisable[1] = returnValue
|
||||
end
|
||||
end
|
||||
|
||||
for i = 1, #buttonsToDisable do
|
||||
local button = buttonsToDisable[i]
|
||||
setButtonEnabled(button, enabled)
|
||||
end
|
||||
end
|
||||
StarterGui.CoreGuiChangedSignal:connect(setRadialButtonEnabled)
|
||||
|
||||
ContextActionService:BindCoreAction(toggleMenuActionName, doGamepadMenuButton, false, Enum.KeyCode.ButtonStart)
|
||||
end
|
||||
|
||||
-- hook up gamepad stuff
|
||||
setupGamepadControls()
|
||||
@@ -0,0 +1,316 @@
|
||||
--[[
|
||||
This script controls the gui the player sees in regards to his or her health.
|
||||
Can be turned with Game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Health,false)
|
||||
Copyright ROBLOX 2014. Written by Ben Tkacheff.
|
||||
--]]
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Initialize/Variables
|
||||
while not game do
|
||||
wait(1/60)
|
||||
end
|
||||
while not game:GetService("Players") do
|
||||
wait(1/60)
|
||||
end
|
||||
|
||||
local useCoreHealthBar = false
|
||||
local success = pcall(function() useCoreHealthBar = game:GetService("Players"):GetUseCoreScriptHealthBar() end)
|
||||
if not success or not useCoreHealthBar then
|
||||
return
|
||||
end
|
||||
|
||||
local currentHumanoid = nil
|
||||
|
||||
local HealthGui = nil
|
||||
local lastHealth = 100
|
||||
local HealthPercentageForOverlay = 5
|
||||
local maxBarTweenTime = 0.3
|
||||
local greenColor = Color3.new(0.2, 1, 0.2)
|
||||
local redColor = Color3.new(1, 0.2, 0.2)
|
||||
local yellowColor = Color3.new(1, 1, 0.2)
|
||||
|
||||
local guiEnabled = false
|
||||
local healthChangedConnection = nil
|
||||
local humanoidDiedConnection = nil
|
||||
local characterAddedConnection = nil
|
||||
|
||||
local greenBarImage = "rbxasset://textures/ui/Health-BKG-Center.png"
|
||||
local greenBarImageLeft = "rbxasset://textures/ui/Health-BKG-Left-Cap.png"
|
||||
local greenBarImageRight = "rbxasset://textures/ui/Health-BKG-Right-Cap.png"
|
||||
local hurtOverlayImage = "http://www.watrbx.wtf/asset/?id=34854607"
|
||||
|
||||
game:GetService("ContentProvider"):Preload(greenBarImage)
|
||||
game:GetService("ContentProvider"):Preload(hurtOverlayImage)
|
||||
|
||||
while not game:GetService("Players").LocalPlayer do
|
||||
wait(1/60)
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Functions
|
||||
|
||||
local capHeight = 15
|
||||
local capWidth = 7
|
||||
|
||||
function CreateGui()
|
||||
if HealthGui and #HealthGui:GetChildren() > 0 then
|
||||
HealthGui.Parent = game:GetService("CoreGui").RobloxGui
|
||||
return
|
||||
end
|
||||
|
||||
local hurtOverlay = Instance.new("ImageLabel")
|
||||
hurtOverlay.Name = "HurtOverlay"
|
||||
hurtOverlay.BackgroundTransparency = 1
|
||||
hurtOverlay.Image = hurtOverlayImage
|
||||
hurtOverlay.Position = UDim2.new(-10,0,-10,0)
|
||||
hurtOverlay.Size = UDim2.new(20,0,20,0)
|
||||
hurtOverlay.Visible = false
|
||||
hurtOverlay.Parent = HealthGui
|
||||
|
||||
local healthFrame = Instance.new("Frame")
|
||||
healthFrame.Name = "HealthFrame"
|
||||
healthFrame.BackgroundTransparency = 1
|
||||
healthFrame.BackgroundColor3 = Color3.new(1,1,1)
|
||||
healthFrame.BorderColor3 = Color3.new(0,0,0)
|
||||
healthFrame.BorderSizePixel = 0
|
||||
healthFrame.Position = UDim2.new(0.5,-85,1,-20)
|
||||
healthFrame.Size = UDim2.new(0,170,0,capHeight)
|
||||
healthFrame.Parent = HealthGui
|
||||
|
||||
|
||||
local healthBarBackCenter = Instance.new("ImageLabel")
|
||||
healthBarBackCenter.Name = "healthBarBackCenter"
|
||||
healthBarBackCenter.BackgroundTransparency = 1
|
||||
healthBarBackCenter.Image = greenBarImage
|
||||
healthBarBackCenter.Size = UDim2.new(1,-capWidth*2,1,0)
|
||||
healthBarBackCenter.Position = UDim2.new(0,capWidth,0,0)
|
||||
healthBarBackCenter.Parent = healthFrame
|
||||
healthBarBackCenter.ImageColor3 = Color3.new(1,1,1)
|
||||
|
||||
local healthBarBackLeft = Instance.new("ImageLabel")
|
||||
healthBarBackLeft.Name = "healthBarBackLeft"
|
||||
healthBarBackLeft.BackgroundTransparency = 1
|
||||
healthBarBackLeft.Image = greenBarImageLeft
|
||||
healthBarBackLeft.Size = UDim2.new(0,capWidth,1,0)
|
||||
healthBarBackLeft.Position = UDim2.new(0,0,0,0)
|
||||
healthBarBackLeft.Parent = healthFrame
|
||||
healthBarBackLeft.ImageColor3 = Color3.new(1,1,1)
|
||||
|
||||
local healthBarBackRight = Instance.new("ImageLabel")
|
||||
healthBarBackRight.Name = "healthBarBackRight"
|
||||
healthBarBackRight.BackgroundTransparency = 1
|
||||
healthBarBackRight.Image = greenBarImageRight
|
||||
healthBarBackRight.Size = UDim2.new(0,capWidth,1,0)
|
||||
healthBarBackRight.Position = UDim2.new(1,-capWidth,0,0)
|
||||
healthBarBackRight.Parent = healthFrame
|
||||
healthBarBackRight.ImageColor3 = Color3.new(1,1,1)
|
||||
|
||||
|
||||
local healthBar = Instance.new("Frame")
|
||||
healthBar.Name = "HealthBar"
|
||||
healthBar.BackgroundTransparency = 1
|
||||
healthBar.BackgroundColor3 = Color3.new(1,1,1)
|
||||
healthBar.BorderColor3 = Color3.new(0,0,0)
|
||||
healthBar.BorderSizePixel = 0
|
||||
healthBar.ClipsDescendants = true
|
||||
healthBar.Position = UDim2.new(0, 0, 0, 0)
|
||||
healthBar.Size = UDim2.new(1,0,1,0)
|
||||
healthBar.Parent = healthFrame
|
||||
|
||||
|
||||
local healthBarCenter = Instance.new("ImageLabel")
|
||||
healthBarCenter.Name = "healthBarCenter"
|
||||
healthBarCenter.BackgroundTransparency = 1
|
||||
healthBarCenter.Image = greenBarImage
|
||||
healthBarCenter.Size = UDim2.new(1,-capWidth*2,1,0)
|
||||
healthBarCenter.Position = UDim2.new(0,capWidth,0,0)
|
||||
healthBarCenter.Parent = healthBar
|
||||
healthBarCenter.ImageColor3 = greenColor
|
||||
|
||||
local healthBarLeft = Instance.new("ImageLabel")
|
||||
healthBarLeft.Name = "healthBarLeft"
|
||||
healthBarLeft.BackgroundTransparency = 1
|
||||
healthBarLeft.Image = greenBarImageLeft
|
||||
healthBarLeft.Size = UDim2.new(0,capWidth,1,0)
|
||||
healthBarLeft.Position = UDim2.new(0,0,0,0)
|
||||
healthBarLeft.Parent = healthBar
|
||||
healthBarLeft.ImageColor3 = greenColor
|
||||
|
||||
local healthBarRight = Instance.new("ImageLabel")
|
||||
healthBarRight.Name = "healthBarRight"
|
||||
healthBarRight.BackgroundTransparency = 1
|
||||
healthBarRight.Image = greenBarImageRight
|
||||
healthBarRight.Size = UDim2.new(0,capWidth,1,0)
|
||||
healthBarRight.Position = UDim2.new(1,-capWidth,0,0)
|
||||
healthBarRight.Parent = healthBar
|
||||
healthBarRight.ImageColor3 = greenColor
|
||||
|
||||
HealthGui.Parent = game:GetService("CoreGui").RobloxGui
|
||||
end
|
||||
|
||||
function UpdateGui(health)
|
||||
if not HealthGui then return end
|
||||
|
||||
local healthFrame = HealthGui:FindFirstChild("HealthFrame")
|
||||
if not healthFrame then return end
|
||||
|
||||
local healthBar = healthFrame:FindFirstChild("HealthBar")
|
||||
if not healthBar then return end
|
||||
|
||||
-- If more than 1/4 health, bar = green. Else, bar = red.
|
||||
local percentHealth = (health/currentHumanoid.MaxHealth)
|
||||
if percentHealth ~= percentHealth then
|
||||
percentHealth = 1
|
||||
healthBar.healthBarCenter.ImageColor3 = yellowColor
|
||||
healthBar.healthBarRight.ImageColor3 = yellowColor
|
||||
healthBar.healthBarLeft.ImageColor3 = yellowColor
|
||||
elseif percentHealth > 0.25 then
|
||||
healthBar.healthBarCenter.ImageColor3 = greenColor
|
||||
healthBar.healthBarRight.ImageColor3 = greenColor
|
||||
healthBar.healthBarLeft.ImageColor3 = greenColor
|
||||
else
|
||||
healthBar.healthBarCenter.ImageColor3 = redColor
|
||||
healthBar.healthBarRight.ImageColor3 = redColor
|
||||
healthBar.healthBarLeft.ImageColor3 = redColor
|
||||
end
|
||||
|
||||
local width = (health / currentHumanoid.MaxHealth)
|
||||
width = math.max(math.min(width,1),0) -- make sure width is between 0 and 1
|
||||
if width ~= width then width = 1 end
|
||||
|
||||
local healthDelta = lastHealth - health
|
||||
lastHealth = health
|
||||
|
||||
local percentOfTotalHealth = math.abs(healthDelta/currentHumanoid.MaxHealth)
|
||||
percentOfTotalHealth = math.max(math.min(percentOfTotalHealth,1),0) -- make sure percentOfTotalHealth is between 0 and 1
|
||||
if percentOfTotalHealth ~= percentOfTotalHealth then percentOfTotalHealth = 1 end
|
||||
|
||||
local newHealthSize = UDim2.new(width,0,1,0)
|
||||
|
||||
healthBar.Size = newHealthSize
|
||||
|
||||
local sizeX = healthBar.AbsoluteSize.X
|
||||
if sizeX < capWidth then
|
||||
healthBar.healthBarCenter.Visible = false
|
||||
healthBar.healthBarRight.Visible = false
|
||||
elseif sizeX < (2*capWidth + 1) then
|
||||
healthBar.healthBarCenter.Visible = true
|
||||
healthBar.healthBarCenter.Size = UDim2.new(0,sizeX - capWidth,1,0)
|
||||
healthBar.healthBarRight.Visible = false
|
||||
else
|
||||
healthBar.healthBarCenter.Visible = true
|
||||
healthBar.healthBarCenter.Size = UDim2.new(1,-capWidth*2,1,0)
|
||||
healthBar.healthBarRight.Visible = true
|
||||
end
|
||||
|
||||
local thresholdForHurtOverlay = currentHumanoid.MaxHealth * (HealthPercentageForOverlay/100)
|
||||
|
||||
if healthDelta >= thresholdForHurtOverlay and guiEnabled then
|
||||
AnimateHurtOverlay()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function AnimateHurtOverlay()
|
||||
if not HealthGui then return end
|
||||
|
||||
local overlay = HealthGui:FindFirstChild("HurtOverlay")
|
||||
if not overlay then return end
|
||||
|
||||
local newSize = UDim2.new(20, 0, 20, 0)
|
||||
local newPos = UDim2.new(-10, 0, -10, 0)
|
||||
|
||||
if overlay:IsDescendantOf(game) then
|
||||
-- stop any tweens on overlay
|
||||
overlay:TweenSizeAndPosition(newSize,newPos,Enum.EasingDirection.Out,Enum.EasingStyle.Linear,0,true,function()
|
||||
|
||||
-- show the gui
|
||||
overlay.Size = UDim2.new(1,0,1,0)
|
||||
overlay.Position = UDim2.new(0,0,0,0)
|
||||
overlay.Visible = true
|
||||
|
||||
-- now tween the hide
|
||||
if overlay:IsDescendantOf(game) then
|
||||
overlay:TweenSizeAndPosition(newSize,newPos,Enum.EasingDirection.Out,Enum.EasingStyle.Quad,10,false,function()
|
||||
overlay.Visible = false
|
||||
end)
|
||||
else
|
||||
overlay.Size = newSize
|
||||
overlay.Position = newPos
|
||||
end
|
||||
end)
|
||||
else
|
||||
overlay.Size = newSize
|
||||
overlay.Position = newPos
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function humanoidDied()
|
||||
UpdateGui(0)
|
||||
end
|
||||
|
||||
function disconnectPlayerConnections()
|
||||
if characterAddedConnection then characterAddedConnection:disconnect() end
|
||||
if humanoidDiedConnection then humanoidDiedConnection:disconnect() end
|
||||
if healthChangedConnection then healthChangedConnection:disconnect() end
|
||||
end
|
||||
|
||||
function newPlayerCharacter()
|
||||
disconnectPlayerConnections()
|
||||
startGui()
|
||||
end
|
||||
|
||||
function startGui()
|
||||
characterAddedConnection = game:GetService("Players").LocalPlayer.CharacterAdded:connect(newPlayerCharacter)
|
||||
|
||||
local character = game:GetService("Players").LocalPlayer.Character
|
||||
if not character then
|
||||
return
|
||||
end
|
||||
|
||||
currentHumanoid = character:WaitForChild("Humanoid")
|
||||
if not currentHumanoid then
|
||||
return
|
||||
end
|
||||
|
||||
if not game:GetService("StarterGui"):GetCoreGuiEnabled(Enum.CoreGuiType.Health) then
|
||||
return
|
||||
end
|
||||
|
||||
healthChangedConnection = currentHumanoid.HealthChanged:connect(UpdateGui)
|
||||
humanoidDiedConnection = currentHumanoid.Died:connect(humanoidDied)
|
||||
UpdateGui(currentHumanoid.Health)
|
||||
|
||||
CreateGui()
|
||||
end
|
||||
|
||||
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Start Script
|
||||
|
||||
HealthGui = Instance.new("Frame")
|
||||
HealthGui.Name = "HealthGui"
|
||||
HealthGui.BackgroundTransparency = 1
|
||||
HealthGui.Size = UDim2.new(1,0,1,0)
|
||||
|
||||
game:GetService("StarterGui").CoreGuiChangedSignal:connect(function(coreGuiType,enabled)
|
||||
if coreGuiType == Enum.CoreGuiType.Health or coreGuiType == Enum.CoreGuiType.All then
|
||||
if guiEnabled and not enabled then
|
||||
if HealthGui then
|
||||
HealthGui.Parent = nil
|
||||
end
|
||||
disconnectPlayerConnections()
|
||||
elseif not guiEnabled and enabled then
|
||||
startGui()
|
||||
end
|
||||
|
||||
guiEnabled = enabled
|
||||
end
|
||||
end)
|
||||
|
||||
if game:GetService("StarterGui"):GetCoreGuiEnabled(Enum.CoreGuiType.Health) then
|
||||
guiEnabled = true
|
||||
startGui()
|
||||
end
|
||||
@@ -0,0 +1,729 @@
|
||||
local PURPOSE_DATA = {
|
||||
[Enum.DialogPurpose.Quest] = {"rbxasset://textures/DialogQuest.png", Vector2.new(10, 34)},
|
||||
[Enum.DialogPurpose.Help] = {"rbxasset://textures/DialogHelp.png", Vector2.new(20, 35)},
|
||||
[Enum.DialogPurpose.Shop] = {"rbxasset://textures/ui/DialogShop.png", Vector2.new(22, 43)},
|
||||
}
|
||||
local TEXT_HEIGHT = 24 -- Pixel height of one row
|
||||
local FONT_SIZE = Enum.FontSize.Size24
|
||||
local BAR_THICKNESS = 6
|
||||
local STYLE_PADDING = 17
|
||||
local CHOICE_PADDING = 6 * 2 -- (Added to vertical height)
|
||||
local PROMPT_SIZE = Vector2.new(80, 90)
|
||||
local FRAME_WIDTH = 350
|
||||
|
||||
local WIDTH_BONUS = (STYLE_PADDING * 2) - BAR_THICKNESS
|
||||
local XPOS_OFFSET = -(STYLE_PADDING - BAR_THICKNESS)
|
||||
|
||||
local contextActionService = game:GetService("ContextActionService")
|
||||
local guiService = game:GetService("GuiService")
|
||||
local YPOS_OFFSET = -math.floor(STYLE_PADDING / 2)
|
||||
local usingGamepad = false
|
||||
|
||||
function setUsingGamepad(input, processed)
|
||||
if input.UserInputType == Enum.UserInputType.Gamepad1 or input.UserInputType == Enum.UserInputType.Gamepad2 or
|
||||
input.UserInputType == Enum.UserInputType.Gamepad3 or input.UserInputType == Enum.UserInputType.Gamepad4 then
|
||||
usingGamepad = true
|
||||
else
|
||||
usingGamepad = false
|
||||
end
|
||||
end
|
||||
|
||||
game:GetService("UserInputService").InputBegan:connect(setUsingGamepad)
|
||||
game:GetService("UserInputService").InputChanged:connect(setUsingGamepad)
|
||||
|
||||
function waitForProperty(instance, name)
|
||||
while not instance[name] do
|
||||
instance.Changed:wait()
|
||||
end
|
||||
end
|
||||
|
||||
function waitForChild(instance, name)
|
||||
while not instance:FindFirstChild(name) do
|
||||
instance.ChildAdded:wait()
|
||||
end
|
||||
end
|
||||
|
||||
local filteringEnabledFixFlagSuccess, filteringEnabledFixFlagValue = pcall(function() return settings():GetFFlag("FilteringEnabledDialogFix") end)
|
||||
local filterEnabledFixActive = (filteringEnabledFixFlagSuccess and filteringEnabledFixFlagValue)
|
||||
|
||||
local goodbyeChoiceActiveFlagSuccess, goodbyeChoiceActiveFlagValue = pcall(function() return settings():GetFFlag("GoodbyeChoiceActiveProperty") end)
|
||||
local goodbyeChoiceActiveFlag = (goodbyeChoiceActiveFlagSuccess and goodbyeChoiceActiveFlagValue)
|
||||
|
||||
local mainFrame
|
||||
local choices = {}
|
||||
local lastChoice
|
||||
local choiceMap = {}
|
||||
local currentConversationDialog
|
||||
local currentConversationPartner
|
||||
local currentAbortDialogScript
|
||||
|
||||
local coroutineMap = {}
|
||||
local currentDialogTimeoutCoroutine = nil
|
||||
|
||||
local tooFarAwayMessage = "You are too far away to chat!"
|
||||
local tooFarAwaySize = 300
|
||||
local characterWanderedOffMessage = "Chat ended because you walked away"
|
||||
local characterWanderedOffSize = 350
|
||||
local conversationTimedOut = "Chat ended because you didn't reply"
|
||||
local conversationTimedOutSize = 350
|
||||
|
||||
local RobloxReplicatedStorage = game:GetService('RobloxReplicatedStorage')
|
||||
local setDialogInUseEvent = RobloxReplicatedStorage:WaitForChild("SetDialogInUse")
|
||||
|
||||
local player
|
||||
local screenGui
|
||||
local chatNotificationGui
|
||||
local messageDialog
|
||||
local timeoutScript
|
||||
local reenableDialogScript
|
||||
local dialogMap = {}
|
||||
local dialogConnections = {}
|
||||
local touchControlGui = nil
|
||||
|
||||
local gui = nil
|
||||
waitForChild(game,"CoreGui")
|
||||
waitForChild(game:GetService("CoreGui"),"RobloxGui")
|
||||
|
||||
game:GetService("CoreGui").RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface")
|
||||
local isTenFootInterface = require(game:GetService("CoreGui").RobloxGui.Modules.TenFootInterface):IsEnabled()
|
||||
local utility = require(game:GetService("CoreGui").RobloxGui.Modules.Settings.Utility)
|
||||
local isSmallTouchScreen = utility:IsSmallTouchScreen()
|
||||
|
||||
if isTenFootInterface then
|
||||
FONT_SIZE = Enum.FontSize.Size36
|
||||
TEXT_HEIGHT = 36
|
||||
FRAME_WIDTH = 500
|
||||
elseif isSmallTouchScreen then
|
||||
FONT_SIZE = Enum.FontSize.Size14
|
||||
TEXT_HEIGHT = 14
|
||||
FRAME_WIDTH = 250
|
||||
end
|
||||
|
||||
if game:GetService("CoreGui").RobloxGui:FindFirstChild("ControlFrame") then
|
||||
gui = game:GetService("CoreGui").RobloxGui.ControlFrame
|
||||
else
|
||||
gui = game:GetService("CoreGui").RobloxGui
|
||||
end
|
||||
local touchEnabled = game:GetService("UserInputService").TouchEnabled
|
||||
|
||||
function currentTone()
|
||||
if currentConversationDialog then
|
||||
return currentConversationDialog.Tone
|
||||
else
|
||||
return Enum.DialogTone.Neutral
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function createChatNotificationGui()
|
||||
chatNotificationGui = Instance.new("BillboardGui")
|
||||
chatNotificationGui.Name = "ChatNotificationGui"
|
||||
|
||||
chatNotificationGui.ExtentsOffset = Vector3.new(0,1,0)
|
||||
chatNotificationGui.Size = UDim2.new(PROMPT_SIZE.X / 31.5, 0, PROMPT_SIZE.Y / 31.5, 0)
|
||||
chatNotificationGui.SizeOffset = Vector2.new(0,0)
|
||||
chatNotificationGui.StudsOffset = Vector3.new(0, 3.7, 0)
|
||||
chatNotificationGui.Enabled = true
|
||||
chatNotificationGui.RobloxLocked = true
|
||||
chatNotificationGui.Active = true
|
||||
|
||||
local button = Instance.new("ImageButton")
|
||||
button.Name = "Background"
|
||||
button.Active = false
|
||||
button.BackgroundTransparency = 1
|
||||
button.Position = UDim2.new(0, 0, 0, 0)
|
||||
button.Size = UDim2.new(1, 0, 1, 0)
|
||||
button.Image = ""
|
||||
button.RobloxLocked = true
|
||||
button.Parent = chatNotificationGui
|
||||
|
||||
local icon = Instance.new("ImageLabel")
|
||||
icon.Name = "Icon"
|
||||
icon.Position = UDim2.new(0, 0, 0, 0)
|
||||
icon.Size = UDim2.new(1, 0, 1, 0)
|
||||
icon.Image = ""
|
||||
icon.BackgroundTransparency = 1
|
||||
icon.RobloxLocked = true
|
||||
icon.Parent = button
|
||||
|
||||
local activationButton = Instance.new("ImageLabel")
|
||||
activationButton.Name = "ActivationButton"
|
||||
activationButton.Position = UDim2.new(-0.3, 0, -0.4, 0)
|
||||
activationButton.Size = UDim2.new(.8, 0, .8*(PROMPT_SIZE.X/PROMPT_SIZE.Y), 0)
|
||||
activationButton.Image = "rbxasset://textures/ui/Settings/Help/XButtonDark.png"
|
||||
activationButton.BackgroundTransparency = 1
|
||||
activationButton.Visible = false
|
||||
activationButton.RobloxLocked = true
|
||||
activationButton.Parent = button
|
||||
end
|
||||
|
||||
function getChatColor(tone)
|
||||
if tone == Enum.DialogTone.Neutral then
|
||||
return Enum.ChatColor.Blue
|
||||
elseif tone == Enum.DialogTone.Friendly then
|
||||
return Enum.ChatColor.Green
|
||||
elseif tone == Enum.DialogTone.Enemy then
|
||||
return Enum.ChatColor.Red
|
||||
end
|
||||
end
|
||||
|
||||
function styleChoices()
|
||||
for _, obj in pairs(choices) do
|
||||
obj.BackgroundTransparency = 1
|
||||
end
|
||||
lastChoice.BackgroundTransparency = 1
|
||||
end
|
||||
|
||||
function styleMainFrame(tone)
|
||||
if tone == Enum.DialogTone.Neutral then
|
||||
mainFrame.Style = Enum.FrameStyle.ChatBlue
|
||||
elseif tone == Enum.DialogTone.Friendly then
|
||||
mainFrame.Style = Enum.FrameStyle.ChatGreen
|
||||
elseif tone == Enum.DialogTone.Enemy then
|
||||
mainFrame.Style = Enum.FrameStyle.ChatRed
|
||||
end
|
||||
|
||||
styleChoices()
|
||||
end
|
||||
function setChatNotificationTone(gui, purpose, tone)
|
||||
if tone == Enum.DialogTone.Neutral then
|
||||
gui.Background.Image = "rbxasset://textures/ui/chatBubble_blue_notify_bkg.png"
|
||||
elseif tone == Enum.DialogTone.Friendly then
|
||||
gui.Background.Image = "rbxasset://textures/ui/chatBubble_green_notify_bkg.png"
|
||||
elseif tone == Enum.DialogTone.Enemy then
|
||||
gui.Background.Image = "rbxasset://textures/ui/chatBubble_red_notify_bkg.png"
|
||||
end
|
||||
|
||||
local newIcon, size = unpack(PURPOSE_DATA[purpose])
|
||||
local relativeSize = size / PROMPT_SIZE
|
||||
gui.Background.Icon.Size = UDim2.new(relativeSize.X, 0, relativeSize.Y, 0)
|
||||
gui.Background.Icon.Position = UDim2.new(0.5 - (relativeSize.X / 2), 0, 0.4 - (relativeSize.Y / 2), 0)
|
||||
gui.Background.Icon.Image = newIcon
|
||||
end
|
||||
|
||||
function createMessageDialog()
|
||||
messageDialog = Instance.new("Frame");
|
||||
messageDialog.Name = "DialogScriptMessage"
|
||||
messageDialog.Style = Enum.FrameStyle.Custom
|
||||
messageDialog.BackgroundTransparency = 0.5
|
||||
messageDialog.BackgroundColor3 = Color3.new(31/255, 31/255, 31/255)
|
||||
messageDialog.Visible = false
|
||||
|
||||
local text = Instance.new("TextLabel")
|
||||
text.Name = "Text"
|
||||
text.Position = UDim2.new(0,0,0,-1)
|
||||
text.Size = UDim2.new(1,0,1,0)
|
||||
text.FontSize = Enum.FontSize.Size14
|
||||
text.BackgroundTransparency = 1
|
||||
text.TextColor3 = Color3.new(1,1,1)
|
||||
text.RobloxLocked = true
|
||||
text.Parent = messageDialog
|
||||
end
|
||||
|
||||
function showMessage(msg, size)
|
||||
messageDialog.Text.Text = msg
|
||||
messageDialog.Size = UDim2.new(0,size,0,40)
|
||||
messageDialog.Position = UDim2.new(0.5, -size/2, 0.5, -40)
|
||||
messageDialog.Visible = true
|
||||
wait(2)
|
||||
messageDialog.Visible = false
|
||||
end
|
||||
|
||||
function variableDelay(str)
|
||||
local length = math.min(string.len(str), 100)
|
||||
wait(0.75 + ((length/75) * 1.5))
|
||||
end
|
||||
|
||||
function resetColor(frame)
|
||||
frame.BackgroundTransparency = 1
|
||||
end
|
||||
|
||||
function wanderDialog()
|
||||
mainFrame.Visible = false
|
||||
endDialog()
|
||||
showMessage(characterWanderedOffMessage, characterWanderedOffSize)
|
||||
end
|
||||
|
||||
function timeoutDialog()
|
||||
mainFrame.Visible = false
|
||||
endDialog()
|
||||
showMessage(conversationTimedOut, conversationTimedOutSize)
|
||||
end
|
||||
|
||||
function normalEndDialog()
|
||||
endDialog()
|
||||
end
|
||||
|
||||
function endDialog()
|
||||
if filterEnabledFixActive then
|
||||
if currentDialogTimeoutCoroutine then
|
||||
coroutineMap[currentDialogTimeoutCoroutine] = false
|
||||
currentDialogTimeoutCoroutine = nil
|
||||
end
|
||||
else
|
||||
if currentAbortDialogScript then
|
||||
currentAbortDialogScript:Destroy()
|
||||
currentAbortDialogScript = nil
|
||||
end
|
||||
end
|
||||
|
||||
local dialog = currentConversationDialog
|
||||
currentConversationDialog = nil
|
||||
if dialog and dialog.InUse then
|
||||
if filterEnabledFixActive then
|
||||
spawn(function()
|
||||
wait(5)
|
||||
setDialogInUseEvent:FireServer(dialog, false)
|
||||
end)
|
||||
else
|
||||
local reenableScript = reenableDialogScript:Clone()
|
||||
reenableScript.Archivable = false
|
||||
reenableScript.Disabled = false
|
||||
reenableScript.Parent = dialog
|
||||
end
|
||||
end
|
||||
|
||||
for dialog, gui in pairs(dialogMap) do
|
||||
if dialog and gui then
|
||||
gui.Enabled = not dialog.InUse
|
||||
end
|
||||
end
|
||||
|
||||
contextActionService:UnbindCoreAction("Nothing")
|
||||
currentConversationPartner = nil
|
||||
|
||||
if touchControlGui then
|
||||
touchControlGui.Visible = true
|
||||
end
|
||||
end
|
||||
|
||||
function sanitizeMessage(msg)
|
||||
if string.len(msg) == 0 then
|
||||
return "..."
|
||||
else
|
||||
return msg
|
||||
end
|
||||
end
|
||||
|
||||
function selectChoice(choice)
|
||||
renewKillswitch(currentConversationDialog)
|
||||
|
||||
--First hide the Gui
|
||||
mainFrame.Visible = false
|
||||
if choice == lastChoice then
|
||||
game:GetService("Chat"):Chat(game:GetService("Players").LocalPlayer.Character, lastChoice.UserPrompt.Text, getChatColor(currentTone()))
|
||||
|
||||
normalEndDialog()
|
||||
else
|
||||
local dialogChoice = choiceMap[choice]
|
||||
|
||||
game:GetService("Chat"):Chat(game:GetService("Players").LocalPlayer.Character, sanitizeMessage(dialogChoice.UserDialog), getChatColor(currentTone()))
|
||||
wait(1)
|
||||
currentConversationDialog:SignalDialogChoiceSelected(player, dialogChoice)
|
||||
game:GetService("Chat"):Chat(currentConversationPartner, sanitizeMessage(dialogChoice.ResponseDialog), getChatColor(currentTone()))
|
||||
|
||||
variableDelay(dialogChoice.ResponseDialog)
|
||||
presentDialogChoices(currentConversationPartner, dialogChoice:GetChildren(), dialogChoice)
|
||||
end
|
||||
end
|
||||
|
||||
function newChoice()
|
||||
local dummyFrame = Instance.new("Frame")
|
||||
dummyFrame.Visible = false
|
||||
|
||||
local frame = Instance.new("TextButton")
|
||||
frame.BackgroundColor3 = Color3.new(227/255, 227/255, 227/255)
|
||||
frame.BackgroundTransparency = 1
|
||||
frame.AutoButtonColor = false
|
||||
frame.BorderSizePixel = 0
|
||||
frame.Text = ""
|
||||
frame.MouseEnter:connect(function() frame.BackgroundTransparency = 0 end)
|
||||
frame.MouseLeave:connect(function() frame.BackgroundTransparency = 1 end)
|
||||
frame.SelectionImageObject = dummyFrame
|
||||
frame.MouseButton1Click:connect(function() selectChoice(frame) end)
|
||||
frame.RobloxLocked = true
|
||||
|
||||
local prompt = Instance.new("TextLabel")
|
||||
prompt.Name = "UserPrompt"
|
||||
prompt.BackgroundTransparency = 1
|
||||
prompt.Font = Enum.Font.SourceSans
|
||||
prompt.FontSize = FONT_SIZE
|
||||
prompt.Position = UDim2.new(0, 40, 0, 0)
|
||||
prompt.Size = UDim2.new(1, -32-40, 1, 0)
|
||||
prompt.TextXAlignment = Enum.TextXAlignment.Left
|
||||
prompt.TextYAlignment = Enum.TextYAlignment.Center
|
||||
prompt.TextWrap = true
|
||||
prompt.RobloxLocked = true
|
||||
prompt.Parent = frame
|
||||
|
||||
local selectionButton = Instance.new("ImageLabel")
|
||||
selectionButton.Name = "RBXchatDialogSelectionButton"
|
||||
selectionButton.Position = UDim2.new(0, 0, 0.5, -33/2)
|
||||
selectionButton.Size = UDim2.new(0, 33, 0, 33)
|
||||
selectionButton.Image = "rbxasset://textures/ui/Settings/Help/AButtonLightSmall.png"
|
||||
selectionButton.BackgroundTransparency = 1
|
||||
selectionButton.Visible = false
|
||||
selectionButton.RobloxLocked = true
|
||||
selectionButton.Parent = frame
|
||||
|
||||
return frame
|
||||
end
|
||||
function initialize(parent)
|
||||
choices[1] = newChoice()
|
||||
choices[2] = newChoice()
|
||||
choices[3] = newChoice()
|
||||
choices[4] = newChoice()
|
||||
|
||||
lastChoice = newChoice()
|
||||
lastChoice.UserPrompt.Text = "Goodbye!"
|
||||
lastChoice.Size = UDim2.new(1, WIDTH_BONUS, 0, TEXT_HEIGHT + CHOICE_PADDING)
|
||||
|
||||
mainFrame = Instance.new("Frame")
|
||||
mainFrame.Name = "UserDialogArea"
|
||||
mainFrame.Size = UDim2.new(0, FRAME_WIDTH, 0, 200)
|
||||
mainFrame.Style = Enum.FrameStyle.ChatBlue
|
||||
mainFrame.Visible = false
|
||||
|
||||
for n, obj in pairs(choices) do
|
||||
obj.RobloxLocked = true
|
||||
obj.Parent = mainFrame
|
||||
end
|
||||
|
||||
lastChoice.RobloxLocked = true
|
||||
lastChoice.Parent = mainFrame
|
||||
|
||||
mainFrame.RobloxLocked = true
|
||||
mainFrame.Parent = parent
|
||||
end
|
||||
|
||||
function presentDialogChoices(talkingPart, dialogChoices, parentDialog)
|
||||
if not currentConversationDialog then
|
||||
return
|
||||
end
|
||||
|
||||
currentConversationPartner = talkingPart
|
||||
sortedDialogChoices = {}
|
||||
for n, obj in pairs(dialogChoices) do
|
||||
if obj:IsA("DialogChoice") then
|
||||
table.insert(sortedDialogChoices, obj)
|
||||
end
|
||||
end
|
||||
table.sort(sortedDialogChoices, function(a,b) return a.Name < b.Name end)
|
||||
|
||||
if #sortedDialogChoices == 0 then
|
||||
normalEndDialog()
|
||||
return
|
||||
end
|
||||
|
||||
local pos = 1
|
||||
local yPosition = 0
|
||||
choiceMap = {}
|
||||
for n, obj in pairs(choices) do
|
||||
obj.Visible = false
|
||||
end
|
||||
|
||||
for n, obj in pairs(sortedDialogChoices) do
|
||||
if pos <= #choices then
|
||||
--3 lines is the maximum, set it to that temporarily
|
||||
choices[pos].Size = UDim2.new(1, WIDTH_BONUS, 0, TEXT_HEIGHT * 3)
|
||||
choices[pos].UserPrompt.Text = obj.UserDialog
|
||||
local height = (math.ceil(choices[pos].UserPrompt.TextBounds.Y / TEXT_HEIGHT) * TEXT_HEIGHT) + CHOICE_PADDING
|
||||
|
||||
choices[pos].Position = UDim2.new(0, XPOS_OFFSET, 0, YPOS_OFFSET + yPosition)
|
||||
choices[pos].Size = UDim2.new(1, WIDTH_BONUS, 0, height)
|
||||
choices[pos].Visible = true
|
||||
|
||||
choiceMap[choices[pos]] = obj
|
||||
|
||||
yPosition = yPosition + height + 1 -- The +1 makes highlights not overlap
|
||||
pos = pos + 1
|
||||
end
|
||||
end
|
||||
|
||||
lastChoice.Size = UDim2.new(1, WIDTH_BONUS, 0, TEXT_HEIGHT * 3)
|
||||
lastChoice.UserPrompt.Text = parentDialog.GoodbyeDialog == "" and "Goodbye!" or parentDialog.GoodbyeDialog
|
||||
local height = (math.ceil(lastChoice.UserPrompt.TextBounds.Y / TEXT_HEIGHT) * TEXT_HEIGHT) + CHOICE_PADDING
|
||||
lastChoice.Size = UDim2.new(1, WIDTH_BONUS, 0, height)
|
||||
lastChoice.Position = UDim2.new(0, XPOS_OFFSET, 0, YPOS_OFFSET + yPosition)
|
||||
lastChoice.Visible = true
|
||||
|
||||
if goodbyeChoiceActiveFlag and not parentDialog.GoodbyeChoiceActive then
|
||||
lastChoice.Visible = false
|
||||
mainFrame.Size = UDim2.new(0, FRAME_WIDTH, 0, yPosition + (STYLE_PADDING * 2) + (YPOS_OFFSET * 2))
|
||||
else
|
||||
mainFrame.Size = UDim2.new(0, FRAME_WIDTH, 0, yPosition + lastChoice.AbsoluteSize.Y + (STYLE_PADDING * 2) + (YPOS_OFFSET * 2))
|
||||
end
|
||||
|
||||
mainFrame.Position = UDim2.new(0,20,1.0, -mainFrame.Size.Y.Offset-20)
|
||||
if isSmallTouchScreen then
|
||||
local touchScreenGui = game.Players.LocalPlayer.PlayerGui:FindFirstChild("TouchGui")
|
||||
if touchScreenGui then
|
||||
touchControlGui = touchScreenGui:FindFirstChild("TouchControlFrame")
|
||||
if touchControlGui then
|
||||
touchControlGui.Visible = false
|
||||
end
|
||||
end
|
||||
mainFrame.Position = UDim2.new(0,10,1.0, -mainFrame.Size.Y.Offset)
|
||||
end
|
||||
styleMainFrame(currentTone())
|
||||
mainFrame.Visible = true
|
||||
|
||||
if usingGamepad then
|
||||
Game:GetService("GuiService").SelectedCoreObject = choices[1]
|
||||
end
|
||||
end
|
||||
|
||||
function doDialog(dialog)
|
||||
if dialog.InUse then
|
||||
return
|
||||
else
|
||||
dialog.InUse = true
|
||||
if filterEnabledFixActive then
|
||||
setDialogInUseEvent:FireServer(dialog, true)
|
||||
end
|
||||
end
|
||||
|
||||
currentConversationDialog = dialog
|
||||
game:GetService("Chat"):Chat(dialog.Parent, dialog.InitialPrompt, getChatColor(dialog.Tone))
|
||||
variableDelay(dialog.InitialPrompt)
|
||||
|
||||
presentDialogChoices(dialog.Parent, dialog:GetChildren(), dialog)
|
||||
end
|
||||
|
||||
function renewKillswitch(dialog)
|
||||
if filterEnabledFixActive then
|
||||
if currentDialogTimeoutCoroutine then
|
||||
coroutineMap[currentDialogTimeoutCoroutine] = false
|
||||
currentDialogTimeoutCoroutine = nil
|
||||
end
|
||||
else
|
||||
if currentAbortDialogScript then
|
||||
currentAbortDialogScript:Destroy()
|
||||
currentAbortDialogScript = nil
|
||||
end
|
||||
end
|
||||
|
||||
if filterEnabledFixActive then
|
||||
currentDialogTimeoutCoroutine = coroutine.create(function(thisCoroutine)
|
||||
wait(15)
|
||||
if thisCoroutine ~= nil then
|
||||
if coroutineMap[thisCoroutine] == nil then
|
||||
setDialogInUseEvent:FireServer(dialog, false)
|
||||
end
|
||||
coroutineMap[thisCoroutine] = nil
|
||||
end
|
||||
end)
|
||||
coroutine.resume(currentDialogTimeoutCoroutine, currentDialogTimeoutCoroutine)
|
||||
else
|
||||
currentAbortDialogScript = timeoutScript:Clone()
|
||||
currentAbortDialogScript.Archivable = false
|
||||
currentAbortDialogScript.Disabled = false
|
||||
currentAbortDialogScript.Parent = dialog
|
||||
end
|
||||
end
|
||||
|
||||
function checkForLeaveArea()
|
||||
while currentConversationDialog do
|
||||
if currentConversationDialog.Parent and (player:DistanceFromCharacter(currentConversationDialog.Parent.Position) >= currentConversationDialog.ConversationDistance) then
|
||||
wanderDialog()
|
||||
end
|
||||
wait(1)
|
||||
end
|
||||
end
|
||||
|
||||
function startDialog(dialog)
|
||||
if dialog.Parent and dialog.Parent:IsA("BasePart") then
|
||||
if player:DistanceFromCharacter(dialog.Parent.Position) >= dialog.ConversationDistance then
|
||||
showMessage(tooFarAwayMessage, tooFarAwaySize)
|
||||
return
|
||||
end
|
||||
|
||||
for dialog, gui in pairs(dialogMap) do
|
||||
if dialog and gui then
|
||||
gui.Enabled = false
|
||||
end
|
||||
end
|
||||
|
||||
contextActionService:BindCoreAction("Nothing", function() end, false, Enum.UserInputType.Gamepad1, Enum.UserInputType.Gamepad2, Enum.UserInputType.Gamepad3, Enum.UserInputType.Gamepad4)
|
||||
|
||||
renewKillswitch(dialog)
|
||||
|
||||
delay(1, checkForLeaveArea)
|
||||
doDialog(dialog)
|
||||
end
|
||||
end
|
||||
|
||||
function removeDialog(dialog)
|
||||
if dialogMap[dialog] then
|
||||
dialogMap[dialog]:Destroy()
|
||||
dialogMap[dialog] = nil
|
||||
end
|
||||
if dialogConnections[dialog] then
|
||||
dialogConnections[dialog]:disconnect()
|
||||
dialogConnections[dialog] = nil
|
||||
end
|
||||
end
|
||||
|
||||
function addDialog(dialog)
|
||||
if dialog.Parent then
|
||||
if dialog.Parent:IsA("BasePart") then
|
||||
local chatGui = chatNotificationGui:clone()
|
||||
chatGui.Enabled = not dialog.InUse
|
||||
chatGui.Adornee = dialog.Parent
|
||||
chatGui.RobloxLocked = true
|
||||
|
||||
chatGui.Parent = game:GetService("CoreGui")
|
||||
|
||||
chatGui.Background.MouseButton1Click:connect(function() startDialog(dialog) end)
|
||||
setChatNotificationTone(chatGui, dialog.Purpose, dialog.Tone)
|
||||
|
||||
dialogMap[dialog] = chatGui
|
||||
|
||||
dialogConnections[dialog] = dialog.Changed:connect(function(prop)
|
||||
if prop == "Parent" and dialog.Parent then
|
||||
--This handles the reparenting case, seperate from removal case
|
||||
removeDialog(dialog)
|
||||
addDialog(dialog)
|
||||
elseif prop == "InUse" then
|
||||
chatGui.Enabled = not currentConversationDialog and not dialog.InUse
|
||||
if dialog == currentConversationDialog then
|
||||
timeoutDialog()
|
||||
end
|
||||
elseif prop == "Tone" or prop == "Purpose" then
|
||||
setChatNotificationTone(chatGui, dialog.Purpose, dialog.Tone)
|
||||
end
|
||||
end)
|
||||
else -- still need to listen to parent changes even if current parent is not a BasePart
|
||||
dialogConnections[dialog] = dialog.Changed:connect(function(prop)
|
||||
if prop == "Parent" and dialog.Parent then
|
||||
--This handles the reparenting case, seperate from removal case
|
||||
removeDialog(dialog)
|
||||
addDialog(dialog)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function fetchScripts()
|
||||
local model = game:GetService("InsertService"):LoadAsset(39226062)
|
||||
if type(model) == "string" then -- load failed, lets try again
|
||||
wait(0.1)
|
||||
model = game:GetService("InsertService"):LoadAsset(39226062)
|
||||
end
|
||||
if type(model) == "string" then -- not going to work, lets bail
|
||||
return
|
||||
end
|
||||
|
||||
waitForChild(model,"TimeoutScript")
|
||||
timeoutScript = model.TimeoutScript
|
||||
waitForChild(model,"ReenableDialogScript")
|
||||
reenableDialogScript = model.ReenableDialogScript
|
||||
end
|
||||
|
||||
function onLoad()
|
||||
waitForProperty(game:GetService("Players"), "LocalPlayer")
|
||||
player = game:GetService("Players").LocalPlayer
|
||||
waitForProperty(player, "Character")
|
||||
|
||||
--print("Creating Guis")
|
||||
createChatNotificationGui()
|
||||
|
||||
--print("Creating MessageDialog")
|
||||
createMessageDialog()
|
||||
messageDialog.RobloxLocked = true
|
||||
messageDialog.Parent = gui
|
||||
|
||||
if not filterEnabledFixActive then
|
||||
fetchScripts()
|
||||
end
|
||||
|
||||
--print("Waiting for BottomLeftControl")
|
||||
waitForChild(gui, "BottomLeftControl")
|
||||
|
||||
--print("Initializing Frame")
|
||||
local frame = Instance.new("Frame")
|
||||
frame.Name = "DialogFrame"
|
||||
frame.Position = UDim2.new(0,0,0,0)
|
||||
frame.Size = UDim2.new(0,0,0,0)
|
||||
frame.BackgroundTransparency = 1
|
||||
frame.RobloxLocked = true
|
||||
game:GetService("GuiService"):AddSelectionParent("RBXDialogGroup", frame)
|
||||
|
||||
if (touchEnabled and not isSmallTouchScreen) then
|
||||
frame.Position = UDim2.new(0,20,0.5,0)
|
||||
frame.Size = UDim2.new(0.25,0,0.1,0)
|
||||
frame.Parent = gui
|
||||
elseif isSmallTouchScreen then
|
||||
frame.Position = UDim2.new(0,0,.9,-10)
|
||||
frame.Size = UDim2.new(0.25,0,0.1,0)
|
||||
frame.Parent = gui
|
||||
else
|
||||
frame.Parent = gui.BottomLeftControl
|
||||
end
|
||||
initialize(frame)
|
||||
|
||||
--print("Adding Dialogs")
|
||||
game:GetService("CollectionService").ItemAdded:connect(function(obj) if obj:IsA("Dialog") then addDialog(obj) end end)
|
||||
game:GetService("CollectionService").ItemRemoved:connect(function(obj) if obj:IsA("Dialog") then removeDialog(obj) end end)
|
||||
for i, obj in pairs(game:GetService("CollectionService"):GetCollection("Dialog")) do
|
||||
if obj:IsA("Dialog") then
|
||||
addDialog(obj)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local lastClosestDialog = nil
|
||||
local getClosestDialogToPosition = guiService.GetClosestDialogToPosition
|
||||
|
||||
game:GetService("RunService").Heartbeat:connect(function()
|
||||
local closestDistance = math.huge
|
||||
local closestDialog = nil
|
||||
if usingGamepad == true then
|
||||
if game.Players.LocalPlayer and game.Players.LocalPlayer.Character and game.Players.LocalPlayer.Character:FindFirstChild("HumanoidRootPart") then
|
||||
local characterPosition = game.Players.LocalPlayer.Character:FindFirstChild("HumanoidRootPart").Position
|
||||
closestDialog = getClosestDialogToPosition(guiService, characterPosition)
|
||||
end
|
||||
end
|
||||
|
||||
if closestDialog ~= lastClosestDialog then
|
||||
if dialogMap[lastClosestDialog] then
|
||||
dialogMap[lastClosestDialog].Background.ActivationButton.Visible = false
|
||||
end
|
||||
lastClosestDialog = closestDialog
|
||||
contextActionService:UnbindCoreAction("StartDialogAction")
|
||||
if closestDialog ~= nil then
|
||||
contextActionService:BindCoreAction("StartDialogAction",
|
||||
function(actionName, userInputState, inputObject)
|
||||
if userInputState == Enum.UserInputState.Begin then
|
||||
if closestDialog and closestDialog.Parent then
|
||||
startDialog(closestDialog)
|
||||
end
|
||||
end
|
||||
end,
|
||||
false,
|
||||
Enum.KeyCode.ButtonX)
|
||||
if dialogMap[closestDialog] then
|
||||
dialogMap[closestDialog].Background.ActivationButton.Visible = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local lastSelectedChoice = nil
|
||||
|
||||
guiService.Changed:connect(function(property)
|
||||
if property == "SelectedCoreObject" then
|
||||
if lastSelectedChoice and lastSelectedChoice:FindFirstChild("RBXchatDialogSelectionButton") then
|
||||
lastSelectedChoice:FindFirstChild("RBXchatDialogSelectionButton").Visible = false
|
||||
lastSelectedChoice.BackgroundTransparency = 1
|
||||
end
|
||||
lastSelectedChoice = guiService.SelectedCoreObject
|
||||
if lastSelectedChoice and lastSelectedChoice:FindFirstChild("RBXchatDialogSelectionButton") then
|
||||
lastSelectedChoice:FindFirstChild("RBXchatDialogSelectionButton").Visible = true
|
||||
lastSelectedChoice.BackgroundTransparency = 0
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
onLoad()
|
||||
@@ -0,0 +1,629 @@
|
||||
--[[
|
||||
Filename: NotificationScript2.lua
|
||||
Version 1.1
|
||||
Written by: jmargh
|
||||
Description: Handles notification gui for the following in game ROBLOX events
|
||||
Badge Awarded
|
||||
Player Points Awarded
|
||||
Friend Request Recieved/New Friend
|
||||
Graphics Quality Changed
|
||||
Teleports
|
||||
CreatePlaceInPlayerInventoryAsync
|
||||
--]]
|
||||
|
||||
--[[ Services ]]--
|
||||
local BadgeService = game:GetService('BadgeService')
|
||||
local GuiService = game:GetService('GuiService')
|
||||
local Players = game:GetService('Players')
|
||||
local PointsService = game:GetService('PointsService')
|
||||
local MarketplaceService = game:GetService('MarketplaceService')
|
||||
local TeleportService = game:GetService('TeleportService')
|
||||
local HttpService = game:GetService("HttpService")
|
||||
local ContextActionService = game:GetService("ContextActionService")
|
||||
local CoreGui = game:GetService("CoreGui")
|
||||
local RobloxGui = CoreGui:WaitForChild("RobloxGui")
|
||||
local Settings = UserSettings()
|
||||
local GameSettings = Settings.GameSettings
|
||||
|
||||
--[[ Fast Flags ]]--
|
||||
local getNotificationDisableSuccess, notificationsDisableActiveValue = pcall(function() return settings():GetFFlag("SetCoreDisableNotifications") end)
|
||||
local allowDisableNotifications = getNotificationDisableSuccess and notificationsDisableActiveValue
|
||||
|
||||
local getSendNotificationSuccess, sendNotificationActiveValue = pcall(function() return settings():GetFFlag("SetCoreSendNotifications") end)
|
||||
local allowSendNotifications = getSendNotificationSuccess and sendNotificationActiveValue
|
||||
|
||||
--[[ Script Variables ]]--
|
||||
local LocalPlayer = nil
|
||||
while not Players.LocalPlayer do
|
||||
wait()
|
||||
end
|
||||
LocalPlayer = Players.LocalPlayer
|
||||
local RbxGui = script.Parent
|
||||
local NotificationQueue = {}
|
||||
local OverflowQueue = {}
|
||||
local FriendRequestBlacklist = {}
|
||||
local CurrentGraphicsQualityLevel = GameSettings.SavedQualityLevel.Value
|
||||
local BindableEvent_SendNotification = Instance.new('BindableFunction')
|
||||
BindableEvent_SendNotification.Name = "SendNotification"
|
||||
BindableEvent_SendNotification.Parent = RbxGui
|
||||
local isPaused = false
|
||||
RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface")
|
||||
local isTenFootInterface = require(RobloxGui.Modules.TenFootInterface):IsEnabled()
|
||||
|
||||
local pointsNotificationsActive = true
|
||||
local badgesNotificationsActive = true
|
||||
|
||||
--[[ Constants ]]--
|
||||
local BG_TRANSPARENCY = 0.7
|
||||
local MAX_NOTIFICATIONS = 3
|
||||
local NOTIFICATION_Y_OFFSET = 64
|
||||
local IMAGE_SIZE = 48
|
||||
local EASE_DIR = Enum.EasingDirection.InOut
|
||||
local EASE_STYLE = Enum.EasingStyle.Sine
|
||||
local TWEEN_TIME = 0.35
|
||||
local DEFAULT_NOTIFICATION_DURATION = 5
|
||||
|
||||
--[[ Images ]]--
|
||||
local PLAYER_POINTS_IMG = 'http://www.watrbx.wtf/asset?id=206410433'
|
||||
local BADGE_IMG = 'http://www.watrbx.wtf/asset?id=206410289'
|
||||
local FRIEND_IMAGE = 'http://www.watrbx.wtf/thumbs/avatar.ashx?userId='
|
||||
|
||||
--[[ Gui Creation ]]--
|
||||
local function createFrame(name, size, position, bgt)
|
||||
local frame = Instance.new('Frame')
|
||||
frame.Name = name
|
||||
frame.Size = size
|
||||
frame.Position = position
|
||||
frame.BackgroundTransparency = bgt
|
||||
|
||||
return frame
|
||||
end
|
||||
|
||||
local function createTextButton(name, text, position)
|
||||
local button = Instance.new('TextButton')
|
||||
button.Name = name
|
||||
button.Size = UDim2.new(0.5, -2, 0.5, 0)
|
||||
button.Position = position
|
||||
button.BackgroundTransparency = BG_TRANSPARENCY
|
||||
button.BackgroundColor3 = Color3.new(0, 0, 0)
|
||||
button.Font = Enum.Font.SourceSansBold
|
||||
button.FontSize = Enum.FontSize.Size18
|
||||
button.TextColor3 = Color3.new(1, 1, 1)
|
||||
button.Text = text
|
||||
|
||||
return button
|
||||
end
|
||||
|
||||
local NotificationFrame = createFrame("NotificationFrame", UDim2.new(0, 200, 0.42, 0), UDim2.new(1, -204, 0.50, 0), 1)
|
||||
NotificationFrame.Parent = RbxGui
|
||||
|
||||
local DefaultNotifcation = createFrame("Notifcation", UDim2.new(1, 0, 0, NOTIFICATION_Y_OFFSET), UDim2.new(0, 0, 0, 0), BG_TRANSPARENCY)
|
||||
DefaultNotifcation.BackgroundColor3 = Color3.new(0, 0, 0)
|
||||
DefaultNotifcation.BorderSizePixel = 0
|
||||
|
||||
local NotificationTitle = Instance.new('TextLabel')
|
||||
NotificationTitle.Name = "NotificationTitle"
|
||||
NotificationTitle.Size = UDim2.new(0, 0, 0, 0)
|
||||
NotificationTitle.Position = UDim2.new(0.5, 0, 0.5, -12)
|
||||
NotificationTitle.BackgroundTransparency = 1
|
||||
NotificationTitle.Font = Enum.Font.SourceSansBold
|
||||
NotificationTitle.FontSize = Enum.FontSize.Size18
|
||||
NotificationTitle.TextColor3 = Color3.new(0.97, 0.97, 0.97)
|
||||
|
||||
local NotificationText = Instance.new('TextLabel')
|
||||
NotificationText.Name = "NotificationText"
|
||||
NotificationText.Size = UDim2.new(1, -20, 0, 28)
|
||||
NotificationText.Position = UDim2.new(0, 10, 0.5, 1)
|
||||
NotificationText.BackgroundTransparency = 1
|
||||
NotificationText.Font = Enum.Font.SourceSans
|
||||
NotificationText.FontSize = Enum.FontSize.Size14
|
||||
NotificationText.TextColor3 = Color3.new(0.92, 0.92, 0.92)
|
||||
NotificationText.TextWrap = true
|
||||
NotificationText.TextYAlignment = Enum.TextYAlignment.Top
|
||||
|
||||
local NotificationImage = Instance.new('ImageLabel')
|
||||
NotificationImage.Name = "NotificationImage"
|
||||
NotificationImage.Size = UDim2.new(0, IMAGE_SIZE, 0, IMAGE_SIZE)
|
||||
NotificationImage.Position = UDim2.new(0, 8, 0.5, -24)
|
||||
NotificationImage.BackgroundTransparency = 1
|
||||
NotificationImage.Image = ""
|
||||
|
||||
-- Would really like to get rid of this but some events still require this
|
||||
local PopupFrame = createFrame("PopupFrame", UDim2.new(0, 360, 0, 160), UDim2.new(0.5, -180, 0.5, -50), 0)
|
||||
PopupFrame.Style = Enum.FrameStyle.DropShadow
|
||||
PopupFrame.ZIndex = 4
|
||||
PopupFrame.Visible = false
|
||||
PopupFrame.Parent = RbxGui
|
||||
|
||||
local PopupAcceptButton = Instance.new('TextButton')
|
||||
PopupAcceptButton.Name = "PopupAcceptButton"
|
||||
PopupAcceptButton.Size = UDim2.new(0, 100, 0, 50)
|
||||
PopupAcceptButton.Position = UDim2.new(0.5, -102, 1, -58)
|
||||
PopupAcceptButton.Style = Enum.ButtonStyle.RobloxRoundButton
|
||||
PopupAcceptButton.Font = Enum.Font.SourceSansBold
|
||||
PopupAcceptButton.FontSize = Enum.FontSize.Size24
|
||||
PopupAcceptButton.TextColor3 = Color3.new(1, 1, 1)
|
||||
PopupAcceptButton.Text = "Accept"
|
||||
PopupAcceptButton.ZIndex = 5
|
||||
PopupAcceptButton.Parent = PopupFrame
|
||||
|
||||
local PopupDeclineButton = PopupAcceptButton:Clone()
|
||||
PopupDeclineButton.Name = "PopupDeclineButton"
|
||||
PopupDeclineButton.Position = UDim2.new(0.5, 2, 1, -58)
|
||||
PopupDeclineButton.Text = "Decline"
|
||||
PopupDeclineButton.Parent = PopupFrame
|
||||
|
||||
local PopupOKButton = PopupAcceptButton:Clone()
|
||||
PopupOKButton.Name = "PopupOKButton"
|
||||
PopupOKButton.Position = UDim2.new(0.5, -50, 1, -58)
|
||||
PopupOKButton.Text = "OK"
|
||||
PopupOKButton.Visible = false
|
||||
PopupOKButton.Parent = PopupFrame
|
||||
|
||||
local PopupText = Instance.new('TextLabel')
|
||||
PopupText.Name = "PopupText"
|
||||
PopupText.Size = UDim2.new(1, -16, 0.8, 0)
|
||||
PopupText.Position = UDim2.new(0, 8, 0, 8)
|
||||
PopupText.BackgroundTransparency = 1
|
||||
PopupText.Font = Enum.Font.SourceSansBold
|
||||
PopupText.FontSize = Enum.FontSize.Size36
|
||||
PopupText.TextColor3 = Color3.new(0.97, 0.97, 0.97)
|
||||
PopupText.TextWrap = true
|
||||
PopupText.ZIndex = 5
|
||||
PopupText.TextYAlignment = Enum.TextYAlignment.Top
|
||||
PopupText.Text = "This is a popup"
|
||||
PopupText.Parent = PopupFrame
|
||||
|
||||
--[[ Helper Functions ]]--
|
||||
local insertNotifcation = nil
|
||||
local removeNotification = nil
|
||||
--
|
||||
local function createNotification(title, text, image)
|
||||
local notificationFrame = DefaultNotifcation:Clone()
|
||||
notificationFrame.Position = UDim2.new(1, 4, 1, -NOTIFICATION_Y_OFFSET - 4)
|
||||
--
|
||||
local notificationTitle = NotificationTitle:Clone()
|
||||
notificationTitle.Text = title
|
||||
notificationTitle.Parent = notificationFrame
|
||||
|
||||
local notificationText = NotificationText:Clone()
|
||||
notificationText.Text = text
|
||||
notificationText.Parent = notificationFrame
|
||||
|
||||
if image and image ~= "" then
|
||||
local notificationImage = NotificationImage:Clone()
|
||||
notificationImage.Image = image
|
||||
notificationImage.Parent = notificationFrame
|
||||
--
|
||||
notificationTitle.Position = UDim2.new(0, NotificationImage.Size.X.Offset + 16, 0.5, -12)
|
||||
notificationTitle.TextXAlignment = Enum.TextXAlignment.Left
|
||||
--
|
||||
notificationText.Size = UDim2.new(1, -IMAGE_SIZE - 16, 0, 28)
|
||||
notificationText.Position = UDim2.new(0, IMAGE_SIZE + 16, 0.5, 1)
|
||||
notificationText.TextXAlignment = Enum.TextXAlignment.Left
|
||||
end
|
||||
|
||||
GuiService:AddSelectionParent(HttpService:GenerateGUID(false), notificationFrame)
|
||||
|
||||
return notificationFrame
|
||||
end
|
||||
|
||||
local function findNotification(notification)
|
||||
local index = nil
|
||||
for i = 1, #NotificationQueue do
|
||||
if NotificationQueue[i] == notification then
|
||||
return i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function updateNotifications()
|
||||
local pos = 1
|
||||
local yOffset = 0
|
||||
for i = #NotificationQueue, 1, -1 do
|
||||
local currentNotification = NotificationQueue[i]
|
||||
if currentNotification then
|
||||
local frame = currentNotification.Frame
|
||||
if frame and frame.Parent then
|
||||
local thisOffset = currentNotification.IsFriend and (NOTIFICATION_Y_OFFSET + 2) * 1.5 or NOTIFICATION_Y_OFFSET
|
||||
yOffset = yOffset + thisOffset
|
||||
frame:TweenPosition(UDim2.new(0, 0, 1, -yOffset - (pos * 4)), EASE_DIR, EASE_STYLE, TWEEN_TIME, true)
|
||||
pos = pos + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local lastTimeInserted = 0
|
||||
insertNotifcation = function(notification)
|
||||
spawn(function()
|
||||
while isPaused do wait() end
|
||||
notification.IsActive = true
|
||||
local size = #NotificationQueue
|
||||
if size == MAX_NOTIFICATIONS then
|
||||
OverflowQueue[#OverflowQueue + 1] = notification
|
||||
return
|
||||
end
|
||||
--
|
||||
NotificationQueue[size + 1] = notification
|
||||
notification.Frame.Parent = NotificationFrame
|
||||
delay(notification.Duration, function()
|
||||
removeNotification(notification)
|
||||
end)
|
||||
while tick() - lastTimeInserted < TWEEN_TIME do
|
||||
wait()
|
||||
end
|
||||
lastTimeInserted = tick()
|
||||
--
|
||||
updateNotifications()
|
||||
end)
|
||||
end
|
||||
|
||||
removeNotification = function(notification)
|
||||
if not notification then return end
|
||||
--
|
||||
local index = findNotification(notification)
|
||||
table.remove(NotificationQueue, index)
|
||||
local frame = notification.Frame
|
||||
if frame and frame.Parent then
|
||||
notification.IsActive = false
|
||||
spawn(function()
|
||||
while isPaused do wait() end
|
||||
|
||||
frame:TweenPosition(UDim2.new(1, 0, 1, frame.Position.Y.Offset), EASE_DIR, EASE_STYLE, TWEEN_TIME, true,
|
||||
function()
|
||||
frame:Destroy()
|
||||
notification = nil
|
||||
end)
|
||||
end)
|
||||
end
|
||||
if #OverflowQueue > 0 then
|
||||
local nextNofication = OverflowQueue[1]
|
||||
table.remove(OverflowQueue, 1)
|
||||
insertNotifcation(nextNofication)
|
||||
else
|
||||
updateNotifications()
|
||||
end
|
||||
end
|
||||
|
||||
local function sendNotifcation(title, text, image, duration, callback, button1Text, button2Text)
|
||||
local notification = {}
|
||||
local notificationFrame = createNotification(title, text, image)
|
||||
--
|
||||
|
||||
local button1 = nil
|
||||
if button1Text and button1Text ~= "" then
|
||||
notification.IsFriend = true -- Prevents other notifications overlapping the buttons
|
||||
button1 = createTextButton("Button1", button1Text, UDim2.new(0, 0, 1, 2))
|
||||
button1.Parent = notificationFrame
|
||||
local button1ClickedConnection = nil
|
||||
button1ClickedConnection = button1.MouseButton1Click:connect(function()
|
||||
if button1ClickedConnection then
|
||||
button1ClickedConnection:disconnect()
|
||||
button1ClickedConnection = nil
|
||||
removeNotification(notification)
|
||||
if callback and type(callback) ~= "function" then -- callback should be a bindable
|
||||
pcall(function() callback:Invoke(button1Text) end)
|
||||
elseif type(callback) == "function" then
|
||||
callback(button1Text)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
if button2Text and button2Text ~= "" then
|
||||
notification.IsFriend = true
|
||||
local button2 = createTextButton("Button1", button2Text, UDim2.new(0.5, 2, 1, 2))
|
||||
button2.Parent = notificationFrame
|
||||
local button2ClickedConnection = nil
|
||||
button2ClickedConnection = button2.MouseButton1Click:connect(function()
|
||||
if button2ClickedConnection then
|
||||
button2ClickedConnection:disconnect()
|
||||
button2ClickedConnection = nil
|
||||
removeNotification(notification)
|
||||
if callback and type(callback) ~= "function" then -- callback should be a bindable
|
||||
pcall(function() callback:Invoke(button2Text) end)
|
||||
elseif type(callback) == "function" then
|
||||
callback(button2Text)
|
||||
end
|
||||
end
|
||||
end)
|
||||
else
|
||||
-- Resize button1 to take up all the space under the notification if button2 doesn't exist
|
||||
if button1 then
|
||||
button1.Size = UDim2.new(1, -2, .5, 0)
|
||||
end
|
||||
end
|
||||
|
||||
notification.Frame = notificationFrame
|
||||
notification.Duration = duration
|
||||
insertNotifcation(notification)
|
||||
end
|
||||
BindableEvent_SendNotification.OnInvoke = function(title, text, image, duration, callback)
|
||||
sendNotifcation(title, text, image, duration, callback)
|
||||
end
|
||||
|
||||
-- New follower notification
|
||||
spawn(function()
|
||||
local RobloxReplicatedStorage = game:GetService('RobloxReplicatedStorage')
|
||||
local RemoteEvent_NewFollower = RobloxReplicatedStorage:WaitForChild('NewFollower')
|
||||
--
|
||||
RemoteEvent_NewFollower.OnClientEvent:connect(function(followerRbxPlayer)
|
||||
sendNotifcation("New Follower", followerRbxPlayer.Name.." is now following you!",
|
||||
FRIEND_IMAGE..followerRbxPlayer.userId.."&x=48&y=48", 5, function() end)
|
||||
end)
|
||||
end)
|
||||
|
||||
local function sendFriendNotification(fromPlayer)
|
||||
local notification = {}
|
||||
local notificationFrame = createNotification(fromPlayer.Name, "Sent you a friend request!",
|
||||
FRIEND_IMAGE..tostring(fromPlayer.userId).."&x=48&y=48")
|
||||
notificationFrame.Position = UDim2.new(1, 4, 1, -(NOTIFICATION_Y_OFFSET + 2) * 1.5 - 4)
|
||||
--
|
||||
local acceptButton = createTextButton("AcceptButton", "Accept", UDim2.new(0, 0, 1, 2))
|
||||
acceptButton.Parent = notificationFrame
|
||||
|
||||
local declineButton = createTextButton("DeclineButton", "Decline", UDim2.new(0.5, 2, 1, 2))
|
||||
declineButton.Parent = notificationFrame
|
||||
|
||||
acceptButton.MouseButton1Click:connect(function()
|
||||
if not notification.IsActive then return end
|
||||
if notification then
|
||||
removeNotification(notification)
|
||||
end
|
||||
LocalPlayer:RequestFriendship(fromPlayer)
|
||||
end)
|
||||
|
||||
declineButton.MouseButton1Click:connect(function()
|
||||
if not notification.IsActive then return end
|
||||
if notification then
|
||||
removeNotification(notification)
|
||||
end
|
||||
LocalPlayer:RevokeFriendship(fromPlayer)
|
||||
FriendRequestBlacklist[fromPlayer] = true
|
||||
end)
|
||||
|
||||
notification.Frame = notificationFrame
|
||||
notification.Duration = 8
|
||||
notification.IsFriend = true
|
||||
insertNotifcation(notification)
|
||||
end
|
||||
|
||||
--[[ Friend Notifications ]]--
|
||||
local function onFriendRequestEvent(fromPlayer, toPlayer, event)
|
||||
if fromPlayer ~= LocalPlayer and toPlayer ~= LocalPlayer then return end
|
||||
--
|
||||
if fromPlayer == LocalPlayer then
|
||||
if event == Enum.FriendRequestEvent.Accept then
|
||||
sendNotifcation("New Friend", "You are now friends with "..toPlayer.Name.."!",
|
||||
FRIEND_IMAGE..tostring(toPlayer.userId).."&x=48&y=48", DEFAULT_NOTIFICATION_DURATION, nil)
|
||||
end
|
||||
elseif toPlayer == LocalPlayer then
|
||||
if event == Enum.FriendRequestEvent.Issue then
|
||||
if FriendRequestBlacklist[fromPlayer] then return end
|
||||
sendFriendNotification(fromPlayer)
|
||||
elseif event == Enum.FriendRequestEvent.Accept then
|
||||
sendNotifcation("New Friend", "You are now friends with "..fromPlayer.Name.."!",
|
||||
FRIEND_IMAGE..tostring(fromPlayer.userId).."&x=48&y=48", DEFAULT_NOTIFICATION_DURATION, nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Player Points Notifications ]]--
|
||||
local function onPointsAwarded(userId, pointsAwarded, userBalanceInGame, userTotalBalance)
|
||||
if pointsNotificationsActive and userId == LocalPlayer.userId then
|
||||
if pointsAwarded == 1 then
|
||||
sendNotifcation("Point Awarded", "You received "..tostring(pointsAwarded).." point!", PLAYER_POINTS_IMG, DEFAULT_NOTIFICATION_DURATION, nil)
|
||||
elseif pointsAwarded > 0 then
|
||||
sendNotifcation("Points Awarded", "You received "..tostring(pointsAwarded).." points!", PLAYER_POINTS_IMG, DEFAULT_NOTIFICATION_DURATION, nil)
|
||||
elseif pointsAwarded < 0 then
|
||||
sendNotifcation("Points Lost", "You lost "..tostring(-pointsAwarded).." points!", PLAYER_POINTS_IMG, DEFAULT_NOTIFICATION_DURATION, nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Badge Notification ]]--
|
||||
local function onBadgeAwarded(message, userId, badgeId)
|
||||
if badgesNotificationsActive and userId == LocalPlayer.userId then
|
||||
sendNotifcation("Badge Awarded", message, BADGE_IMG, DEFAULT_NOTIFICATION_DURATION, nil)
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Graphics Changes Notification ]]--
|
||||
function onGameSettingsChanged(property, amount)
|
||||
if property == "SavedQualityLevel" then
|
||||
local level = GameSettings.SavedQualityLevel.Value + amount
|
||||
if level > 10 then
|
||||
level = 10
|
||||
elseif level < 1 then
|
||||
level = 1
|
||||
end
|
||||
-- value of 0 is automatic, we do not want to send a notification in that case
|
||||
if level > 0 and level ~= CurrentGraphicsQualityLevel then
|
||||
if level > CurrentGraphicsQualityLevel then
|
||||
sendNotifcation("Graphics Quality", "Increased to ("..tostring(level)..")", "", 2, nil)
|
||||
else
|
||||
sendNotifcation("Graphics Quality", "Decreased to ("..tostring(level)..")", "", 2, nil)
|
||||
end
|
||||
CurrentGraphicsQualityLevel = level
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Connections ]]--
|
||||
if not isTenFootInterface then
|
||||
Players.FriendRequestEvent:connect(onFriendRequestEvent)
|
||||
PointsService.PointsAwarded:connect(onPointsAwarded)
|
||||
BadgeService.BadgeAwarded:connect(onBadgeAwarded)
|
||||
--GameSettings.Changed:connect(onGameSettingsChanged)
|
||||
game.GraphicsQualityChangeRequest:connect(function(graphicsIncrease) --graphicsIncrease is a boolean
|
||||
onGameSettingsChanged("SavedQualityLevel", graphicsIncrease == true and 1 or -1)
|
||||
end)
|
||||
end
|
||||
|
||||
GuiService.SendCoreUiNotification = function(title, text)
|
||||
local notification = createNotification(title, text, "")
|
||||
notification.BackgroundTransparency = .5
|
||||
notification.Size = UDim2.new(.5, 0, .1, 0)
|
||||
notification.Position = UDim2.new(.25, 0, -0.1, 0)
|
||||
notification.NotificationTitle.FontSize = Enum.FontSize.Size36
|
||||
notification.NotificationText.FontSize = Enum.FontSize.Size24
|
||||
notification.Parent = RbxGui
|
||||
notification:TweenPosition(UDim2.new(.25, 0, 0, 0), EASE_DIR, EASE_STYLE, TWEEN_TIME, true)
|
||||
wait(5)
|
||||
if notification then
|
||||
notification:Destroy()
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Market Place Events ]]--
|
||||
-- This is used for when a player calls CreatePlaceInPlayerInventoryAsync
|
||||
local function onClientLuaDialogRequested(msg, accept, decline)
|
||||
PopupText.Text = msg
|
||||
--
|
||||
local acceptCn, declineCn = nil, nil
|
||||
local function disconnectCns()
|
||||
if acceptCn then acceptCn:disconnect() end
|
||||
if declineCn then declineCn:disconnect() end
|
||||
--
|
||||
GuiService:RemoveCenterDialog(PopupFrame)
|
||||
PopupFrame.Visible = false
|
||||
end
|
||||
|
||||
acceptCn = PopupAcceptButton.MouseButton1Click:connect(function()
|
||||
disconnectCns()
|
||||
MarketplaceService:SignalServerLuaDialogClosed(true)
|
||||
end)
|
||||
declineCn = PopupDeclineButton.MouseButton1Click:connect(function()
|
||||
disconnectCns()
|
||||
MarketplaceService:SignalServerLuaDialogClosed(false)
|
||||
end)
|
||||
|
||||
local centerDialogSuccess = pcall(
|
||||
function()
|
||||
GuiService:AddCenterDialog(PopupFrame, Enum.CenterDialogType.QuitDialog,
|
||||
function()
|
||||
PopupOKButton.Visible = false
|
||||
PopupAcceptButton.Visible = true
|
||||
PopupDeclineButton.Visible = true
|
||||
PopupAcceptButton.Text = accept
|
||||
PopupDeclineButton.Text = decline
|
||||
PopupFrame.Visible = true
|
||||
end,
|
||||
function()
|
||||
PopupFrame.Visible = false
|
||||
end)
|
||||
end)
|
||||
|
||||
if not centerDialogSuccess then
|
||||
PopupFrame.Visible = true
|
||||
PopupAcceptButton.Text = accept
|
||||
PopupDeclineButton.Text = decline
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
MarketplaceService.ClientLuaDialogRequested:connect(onClientLuaDialogRequested)
|
||||
|
||||
--[[ Developer customization API ]]--
|
||||
local function createDeveloperNotification(notificationTable)
|
||||
if type(notificationTable) == "table" then
|
||||
if type(notificationTable.Title) == "string" and type(notificationTable.Text) == "string" then
|
||||
local iconImage = (type(notificationTable.Icon) == "string" and notificationTable.Icon or "")
|
||||
local duration = (type(notificationTable.Duration) == "number" and notificationTable.Duration or DEFAULT_NOTIFICATION_DURATION)
|
||||
local success, bindable = pcall(function() return (notificationTable.Callback:IsA("BindableFunction") and notificationTable.Callback or nil) end)
|
||||
local button1Text = (type(notificationTable.Button1) == "string" and notificationTable.Button1 or "")
|
||||
local button2Text = (type(notificationTable.Button2) == "string" and notificationTable.Button2 or "")
|
||||
sendNotifcation(notificationTable.Title, notificationTable.Text, iconImage, duration, bindable, button1Text, button2Text)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if allowDisableNotifications then
|
||||
game:WaitForChild("StarterGui"):RegisterSetCore("PointsNotificationsActive", function(value) if type(value) == "boolean" then pointsNotificationsActive = value end end)
|
||||
game:WaitForChild("StarterGui"):RegisterSetCore("BadgesNotificationsActive", function(value) if type(value) == "boolean" then badgesNotificationsActive = value end end)
|
||||
else
|
||||
game:WaitForChild("StarterGui"):RegisterSetCore("PointsNotificationsActive", function() end)
|
||||
game:WaitForChild("StarterGui"):RegisterSetCore("BadgesNotificationsActive", function() end)
|
||||
end
|
||||
|
||||
game:WaitForChild("StarterGui"):RegisterGetCore("PointsNotificationsActive", function() return pointsNotificationsActive end)
|
||||
game:WaitForChild("StarterGui"):RegisterGetCore("BadgesNotificationsActive", function() return badgesNotificationsActive end)
|
||||
|
||||
if allowSendNotifications then
|
||||
game:WaitForChild("StarterGui"):RegisterSetCore("SendNotification", createDeveloperNotification)
|
||||
else
|
||||
game:WaitForChild("StarterGui"):RegisterSetCore("SendNotification", function() end)
|
||||
end
|
||||
|
||||
if not isTenFootInterface then
|
||||
local gamepadMenu = RobloxGui:WaitForChild("CoreScripts/GamepadMenu")
|
||||
local gamepadNotifications = gamepadMenu:FindFirstChild("GamepadNotifications")
|
||||
while not gamepadNotifications do
|
||||
wait()
|
||||
gamepadNotifications = gamepadMenu:FindFirstChild("GamepadNotifications")
|
||||
end
|
||||
|
||||
local leaveNotificationFunc = function(name, state, inputObject)
|
||||
if state ~= Enum.UserInputState.Begin then return end
|
||||
|
||||
if GuiService.SelectedCoreObject:IsDescendantOf(NotificationFrame) then
|
||||
GuiService.SelectedCoreObject = nil
|
||||
end
|
||||
|
||||
ContextActionService:UnbindCoreAction("LeaveNotificationSelection")
|
||||
end
|
||||
|
||||
gamepadNotifications.Event:connect(function(isSelected)
|
||||
if not isSelected then return end
|
||||
|
||||
isPaused = true
|
||||
local notifications = NotificationFrame:GetChildren()
|
||||
for i = 1, #notifications do
|
||||
local noteComponents = notifications[i]:GetChildren()
|
||||
for j = 1, #noteComponents do
|
||||
if noteComponents[j]:IsA("GuiButton") and noteComponents[j].Visible then
|
||||
GuiService.SelectedCoreObject = noteComponents[j]
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if GuiService.SelectedCoreObject then
|
||||
ContextActionService:BindCoreAction("LeaveNotificationSelection", leaveNotificationFunc, false, Enum.KeyCode.ButtonB)
|
||||
else
|
||||
isPaused = false
|
||||
local utility = require(RobloxGui.Modules.Settings.Utility)
|
||||
local okPressedFunc = function() end
|
||||
utility:ShowAlert("You have no notifications", "Ok", settingsHub, okPressedFunc, true)
|
||||
end
|
||||
end)
|
||||
|
||||
GuiService.Changed:connect(function(prop)
|
||||
if prop == "SelectedCoreObject" then
|
||||
if not GuiService.SelectedCoreObject or not GuiService.SelectedCoreObject:IsDescendantOf(NotificationFrame) then
|
||||
isPaused = false
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local UserInputService = game:GetService('UserInputService')
|
||||
local Platform = UserInputService:GetPlatform()
|
||||
local Modules = RobloxGui:FindFirstChild('Modules')
|
||||
if Platform == Enum.Platform.XBoxOne then
|
||||
-- Platform hook for controller connection events
|
||||
-- Displays overlay to user on controller connection lost
|
||||
local PlatformService = nil
|
||||
pcall(function() PlatformService = game:GetService('PlatformService') end)
|
||||
if PlatformService and Modules then
|
||||
local controllerStateManager = require(Modules:FindFirstChild('ControllerStateManager'))
|
||||
if controllerStateManager then
|
||||
controllerStateManager:Initialize()
|
||||
|
||||
-- retro check in case of controller disconnect while loading
|
||||
-- for now, gamepad1 is always mapped to the active user
|
||||
controllerStateManager:CheckUserConnected()
|
||||
end
|
||||
end
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,160 @@
|
||||
--[[
|
||||
// Filename: VehicleHud.lua
|
||||
// Version 1.0
|
||||
// Written by: jmargh
|
||||
// Description: Implementation of the VehicleSeat HUD
|
||||
|
||||
// TODO:
|
||||
Once this is live and stable, move to PlayerScripts as module
|
||||
]]
|
||||
local RunService = game:GetService('RunService')
|
||||
local Players = game:GetService('Players')
|
||||
while not Players.LocalPlayer do
|
||||
wait()
|
||||
end
|
||||
local LocalPlayer = Players.LocalPlayer
|
||||
local RobloxGui = script.Parent
|
||||
local CurrentVehicleSeat = nil
|
||||
local VehicleSeatRenderCn = nil
|
||||
local VehicleSeatHUDChangedCn = nil
|
||||
|
||||
local RobloxGui = game:GetService("CoreGui"):WaitForChild("RobloxGui")
|
||||
RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface")
|
||||
local isTenFootInterface = require(RobloxGui.Modules.TenFootInterface):IsEnabled()
|
||||
|
||||
|
||||
--[[ Images ]]--
|
||||
local VEHICLE_HUD_BG = 'rbxasset://textures/ui/Vehicle/SpeedBarBKG.png'
|
||||
local SPEED_BAR_EMPTY = 'rbxasset://textures/ui/Vehicle/SpeedBarEmpty.png'
|
||||
local SPEED_BAR = 'rbxasset://textures/ui/Vehicle/SpeedBar.png'
|
||||
|
||||
--[[ Constants ]]--
|
||||
local BOTTOM_OFFSET = (isTenFootInterface and 100 or 70)
|
||||
|
||||
--[[ Gui Creation ]]--
|
||||
local function createImageLabel(name, size, position, image, parent)
|
||||
local imageLabel = Instance.new('ImageLabel')
|
||||
imageLabel.Name = name
|
||||
imageLabel.Size = size
|
||||
imageLabel.Position = position
|
||||
imageLabel.BackgroundTransparency = 1
|
||||
imageLabel.Image = image
|
||||
imageLabel.Parent = parent
|
||||
|
||||
return imageLabel
|
||||
end
|
||||
|
||||
local function createTextLabel(name, alignment, text, parent)
|
||||
local textLabel = Instance.new('TextLabel')
|
||||
textLabel.Name = name
|
||||
textLabel.Size = UDim2.new(1, -4, 0, (isTenFootInterface and 50 or 20))
|
||||
textLabel.Position = UDim2.new(0, 2, 0, (isTenFootInterface and -50 or -20))
|
||||
textLabel.BackgroundTransparency = 1
|
||||
textLabel.TextXAlignment = alignment
|
||||
textLabel.Font = Enum.Font.SourceSans
|
||||
textLabel.FontSize = (isTenFootInterface and Enum.FontSize.Size48 or Enum.FontSize.Size18)
|
||||
textLabel.TextColor3 = Color3.new(1, 1, 1)
|
||||
textLabel.TextStrokeTransparency = 0.5
|
||||
textLabel.TextStrokeColor3 = Color3.new(49/255, 49/255, 49/255)
|
||||
textLabel.Text = text
|
||||
textLabel.Parent = parent
|
||||
|
||||
return textLabel
|
||||
end
|
||||
|
||||
local VehicleHudFrame = Instance.new('Frame')
|
||||
VehicleHudFrame.Name = "VehicleHudFrame"
|
||||
VehicleHudFrame.Size = UDim2.new(0, (isTenFootInterface and 316 or 158), 0, (isTenFootInterface and 50 or 14))
|
||||
VehicleHudFrame.Position = UDim2.new(0.5, -(VehicleHudFrame.Size.X.Offset/2), 1, -BOTTOM_OFFSET - VehicleHudFrame.Size.Y.Offset)
|
||||
VehicleHudFrame.BackgroundTransparency = 1
|
||||
VehicleHudFrame.Visible = false
|
||||
VehicleHudFrame.Parent = RobloxGui
|
||||
|
||||
local speedBarClippingFrame = Instance.new("Frame")
|
||||
speedBarClippingFrame.Name = "SpeedBarClippingFrame"
|
||||
speedBarClippingFrame.Size = UDim2.new(0, 0, 0, (isTenFootInterface and 24 or 4))
|
||||
speedBarClippingFrame.Position = UDim2.new(0.5, (isTenFootInterface and -142 or -71), 0.5, (isTenFootInterface and -13 or -2))
|
||||
speedBarClippingFrame.BackgroundTransparency = 1
|
||||
speedBarClippingFrame.ClipsDescendants = true
|
||||
speedBarClippingFrame.Parent = VehicleHudFrame
|
||||
|
||||
local HudBG = createImageLabel("HudBG", UDim2.new(1, 0, 1, 0), UDim2.new(0, 0, 0, 1), VEHICLE_HUD_BG, VehicleHudFrame)
|
||||
local SpeedBG = createImageLabel("SpeedBG", UDim2.new(0, (isTenFootInterface and 284 or 142), 0, (isTenFootInterface and 24 or 4)), UDim2.new(0.5, (isTenFootInterface and -142 or -71), 0.5, (isTenFootInterface and -13 or -2)), SPEED_BAR_EMPTY, VehicleHudFrame)
|
||||
local SpeedBarImage = createImageLabel("SpeedBarImage", UDim2.new(0, (isTenFootInterface and 284 or 142), 1, 0), UDim2.new(0, 0, 0, 0), SPEED_BAR, speedBarClippingFrame)
|
||||
SpeedBarImage.ZIndex = 2
|
||||
|
||||
local SpeedLabel = createTextLabel("SpeedLabel", Enum.TextXAlignment.Left, "Speed", VehicleHudFrame)
|
||||
local SpeedText = createTextLabel("SpeedText", Enum.TextXAlignment.Right, "0", VehicleHudFrame)
|
||||
|
||||
--[[ Local Functions ]]--
|
||||
local function getHumanoid()
|
||||
local character = LocalPlayer and LocalPlayer.Character
|
||||
if character then
|
||||
for _,child in pairs(character:GetChildren()) do
|
||||
if child:IsA('Humanoid') then
|
||||
return child
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function onRenderStepped()
|
||||
if CurrentVehicleSeat then
|
||||
local speed = CurrentVehicleSeat.Velocity.magnitude
|
||||
SpeedText.Text = tostring(math.min(math.floor(speed), 9999))
|
||||
local drawSize = math.floor((speed / CurrentVehicleSeat.MaxSpeed) * SpeedBG.Size.X.Offset)
|
||||
drawSize = math.min(drawSize, SpeedBG.Size.X.Offset)
|
||||
speedBarClippingFrame.Size = UDim2.new(0, drawSize, 0, (isTenFootInterface and 24 or 4))
|
||||
end
|
||||
end
|
||||
|
||||
local function onVehicleSeatChanged(property)
|
||||
if property == "HeadsUpDisplay" then
|
||||
VehicleHudFrame.Visible = not VehicleHudFrame.Visible
|
||||
end
|
||||
end
|
||||
|
||||
local function onSeated(active, currentSeatPart)
|
||||
if active then
|
||||
-- TODO: Clean up when new API is live for a while
|
||||
if currentSeatPart and currentSeatPart:IsA('VehicleSeat') then
|
||||
CurrentVehicleSeat = currentSeatPart
|
||||
else
|
||||
local camSubject = workspace.CurrentCamera.CameraSubject
|
||||
if camSubject and camSubject:IsA('VehicleSeat') then
|
||||
CurrentVehicleSeat = camSubject
|
||||
end
|
||||
end
|
||||
if CurrentVehicleSeat then
|
||||
VehicleHudFrame.Visible = CurrentVehicleSeat.HeadsUpDisplay
|
||||
VehicleSeatRenderCn = RunService.RenderStepped:connect(onRenderStepped)
|
||||
VehicleSeatHUDChangedCn = CurrentVehicleSeat.Changed:connect(onVehicleSeatChanged)
|
||||
end
|
||||
else
|
||||
if CurrentVehicleSeat then
|
||||
VehicleHudFrame.Visible = false
|
||||
CurrentVehicleSeat = nil
|
||||
if VehicleSeatRenderCn then
|
||||
VehicleSeatRenderCn:disconnect()
|
||||
VehicleSeatRenderCn = nil
|
||||
end
|
||||
if VehicleSeatHUDChangedCn then
|
||||
VehicleSeatHUDChangedCn:disconnect()
|
||||
VehicleSeatHUDChangedCn = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function connectSeated()
|
||||
local humanoid = getHumanoid()
|
||||
while not humanoid do
|
||||
wait()
|
||||
humanoid = getHumanoid()
|
||||
end
|
||||
humanoid.Seated:connect(onSeated)
|
||||
end
|
||||
connectSeated()
|
||||
LocalPlayer.CharacterAdded:connect(function(character)
|
||||
connectSeated()
|
||||
end)
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,775 @@
|
||||
-- Creates the generic "ROBLOX" loading screen on startup
|
||||
-- Written by ArceusInator & Ben Tkacheff, 2014
|
||||
--
|
||||
|
||||
-- Constants
|
||||
local PLACEID = game.PlaceId
|
||||
|
||||
local MPS = game:GetService('MarketplaceService')
|
||||
local UIS = game:GetService('UserInputService')
|
||||
local CP = game:GetService('ContentProvider')
|
||||
local guiService = game:GetService("GuiService")
|
||||
local ContextActionService = game:GetService('ContextActionService')
|
||||
|
||||
local startTime = tick()
|
||||
|
||||
local COLORS = {
|
||||
BLACK = Color3.new(0, 0, 0),
|
||||
BACKGROUND_COLOR = Color3.new(45/255, 45/255, 45/255),
|
||||
WHITE = Color3.new(1, 1, 1),
|
||||
ERROR = Color3.new(253/255,68/255,72/255)
|
||||
}
|
||||
|
||||
local function getViewportSize()
|
||||
while not game.Workspace.CurrentCamera do
|
||||
game.Workspace.Changed:wait()
|
||||
end
|
||||
|
||||
while game.Workspace.CurrentCamera.ViewportSize == Vector2.new(0,0) do
|
||||
game.Workspace.CurrentCamera.Changed:wait()
|
||||
end
|
||||
|
||||
return game.Workspace.CurrentCamera.ViewportSize
|
||||
end
|
||||
|
||||
--
|
||||
-- Variables
|
||||
local GameAssetInfo -- loaded by InfoProvider:LoadAssets()
|
||||
local currScreenGui = nil
|
||||
local renderSteppedConnection = nil
|
||||
local fadingBackground = false
|
||||
local destroyingBackground = false
|
||||
local destroyedLoadingGui = false
|
||||
local hasReplicatedFirstElements = false
|
||||
local backgroundImageTransparency = 0
|
||||
local isMobile = (UIS.TouchEnabled == true and UIS.MouseEnabled == false and getViewportSize().Y <= 500)
|
||||
local isTenFootInterface = false
|
||||
pcall(function() isTenFootInterface = guiService:IsTenFootInterface() end)
|
||||
local platform = UIS:GetPlatform()
|
||||
|
||||
local useGameLoadedSuccess, useGameLoadedFlagValue = pcall(function() return settings():GetFFlag("UseGameLoadedInLoadingScript") end)
|
||||
local useGameLoadedToWait = (useGameLoadedSuccess and useGameLoadedFlagValue == true)
|
||||
|
||||
local function IsConvertMyPlaceNameInXboxAppEnabled()
|
||||
if UIS:GetPlatform() == Enum.Platform.XBoxOne then
|
||||
local success, flagValue = pcall(function() return settings():GetFFlag("ConvertMyPlaceNameInXboxApp") end)
|
||||
return (success and flagValue == true)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--
|
||||
-- Utility functions
|
||||
local create = function(className, defaultParent)
|
||||
return function(propertyList)
|
||||
local object = Instance.new(className)
|
||||
|
||||
for index, value in next, propertyList do
|
||||
if type(index) == 'string' then
|
||||
object[index] = value
|
||||
else
|
||||
if type(value) == 'function' then
|
||||
value(object)
|
||||
elseif type(value) == 'userdata' then
|
||||
value.Parent = object
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if object.Parent == nil then
|
||||
object.Parent = defaultParent
|
||||
end
|
||||
|
||||
return object
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Create objects
|
||||
|
||||
local MainGui = {}
|
||||
local InfoProvider = {}
|
||||
|
||||
|
||||
function ExtractGeneratedUsername(gameName)
|
||||
local tempUsername = string.match(gameName, "^([0-9a-fA-F]+)'s Place$")
|
||||
if tempUsername and #tempUsername == 32 then
|
||||
return tempUsername
|
||||
end
|
||||
end
|
||||
|
||||
-- Fix places that have been made with incorrect temporary usernames
|
||||
function GetFilteredGameName(gameName, creatorName)
|
||||
if gameName and type(gameName) == 'string' then
|
||||
local tempUsername = ExtractGeneratedUsername(gameName)
|
||||
if tempUsername then
|
||||
local newGameName = string.gsub(gameName, tempUsername, creatorName, 1)
|
||||
if newGameName then
|
||||
return newGameName
|
||||
end
|
||||
end
|
||||
end
|
||||
return gameName
|
||||
end
|
||||
|
||||
|
||||
function InfoProvider:GetGameName()
|
||||
if GameAssetInfo ~= nil then
|
||||
if IsConvertMyPlaceNameInXboxAppEnabled() then
|
||||
return GetFilteredGameName(GameAssetInfo.Name, self:GetCreatorName())
|
||||
else
|
||||
return GameAssetInfo.Name
|
||||
end
|
||||
else
|
||||
return ''
|
||||
end
|
||||
end
|
||||
|
||||
function InfoProvider:GetCreatorName()
|
||||
if GameAssetInfo ~= nil then
|
||||
return GameAssetInfo.Creator.Name
|
||||
else
|
||||
return ''
|
||||
end
|
||||
end
|
||||
|
||||
function InfoProvider:LoadAssets()
|
||||
spawn(function()
|
||||
if PLACEID <= 0 then
|
||||
while game.PlaceId <= 0 do
|
||||
wait()
|
||||
end
|
||||
PLACEID = game.PlaceId
|
||||
end
|
||||
|
||||
-- load game asset info
|
||||
coroutine.resume(coroutine.create(function()
|
||||
local success, result = pcall(function()
|
||||
GameAssetInfo = MPS:GetProductInfo(PLACEID)
|
||||
end)
|
||||
if not success then
|
||||
print("LoadingScript->InfoProvider:LoadAssets:", result)
|
||||
end
|
||||
end))
|
||||
end)
|
||||
end
|
||||
|
||||
function MainGui:tileBackgroundTexture(frameToFill)
|
||||
if not frameToFill then return end
|
||||
frameToFill:ClearAllChildren()
|
||||
if backgroundImageTransparency < 1 then
|
||||
local backgroundTextureSize = Vector2.new(512, 512)
|
||||
for i = 0, math.ceil(frameToFill.AbsoluteSize.X/backgroundTextureSize.X) do
|
||||
for j = 0, math.ceil(frameToFill.AbsoluteSize.Y/backgroundTextureSize.Y) do
|
||||
create 'ImageLabel' {
|
||||
Name = 'BackgroundTextureImage',
|
||||
BackgroundTransparency = 1,
|
||||
ImageTransparency = backgroundImageTransparency,
|
||||
Image = 'rbxasset://textures/loading/darkLoadingTexture.png',
|
||||
Position = UDim2.new(0, i*backgroundTextureSize.X, 0, j*backgroundTextureSize.Y),
|
||||
Size = UDim2.new(0, backgroundTextureSize.X, 0, backgroundTextureSize.Y),
|
||||
ZIndex = 1,
|
||||
Parent = frameToFill
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- create a cancel binding for console to be able to cancel anytime while loading
|
||||
local function createTenfootCancelGui()
|
||||
local cancelLabel = create'ImageLabel'
|
||||
{
|
||||
Name = "CancelLabel";
|
||||
Size = UDim2.new(0, 83, 0, 83);
|
||||
Position = UDim2.new(1, -32 - 83, 0, 32);
|
||||
BackgroundTransparency = 1;
|
||||
Image = 'rbxasset://textures/ui/Shell/ButtonIcons/BButton.png';
|
||||
}
|
||||
local cancelText = create'TextLabel'
|
||||
{
|
||||
Name = "CancelText";
|
||||
Size = UDim2.new(0, 0, 0, 0);
|
||||
Position = UDim2.new(1, -131, 0, 64);
|
||||
BackgroundTransparency = 1;
|
||||
FontSize = Enum.FontSize.Size36;
|
||||
TextXAlignment = Enum.TextXAlignment.Right;
|
||||
TextColor3 = COLORS.WHITE;
|
||||
Text = "Cancel";
|
||||
}
|
||||
|
||||
-- bind cancel action
|
||||
local platformService = nil
|
||||
pcall(function()
|
||||
platformService = game:GetService('PlatformService')
|
||||
end)
|
||||
|
||||
if platformService then
|
||||
if not game:GetService("ReplicatedFirst"):IsFinishedReplicating() then
|
||||
local seenBButtonBegin = false
|
||||
ContextActionService:BindCoreAction("CancelGameLoad",
|
||||
function(actionName, inputState, inputObject)
|
||||
if inputState == Enum.UserInputState.Begin then
|
||||
seenBButtonBegin = true
|
||||
elseif inputState == Enum.UserInputState.End and seenBButtonBegin then
|
||||
cancelLabel:Destroy()
|
||||
cancelText.Text = "Canceling..."
|
||||
cancelText.Position = UDim2.new(1, -32, 0, 64)
|
||||
ContextActionService:UnbindCoreAction('CancelGameLoad')
|
||||
platformService:RequestGameShutdown()
|
||||
end
|
||||
end,
|
||||
false,
|
||||
Enum.KeyCode.ButtonB)
|
||||
end
|
||||
end
|
||||
|
||||
while cancelLabel.Parent == nil do
|
||||
if currScreenGui then
|
||||
local blackFrame = currScreenGui:FindFirstChild('BlackFrame')
|
||||
if blackFrame then
|
||||
cancelLabel.Parent = blackFrame
|
||||
cancelText.Parent = blackFrame
|
||||
break
|
||||
end
|
||||
end
|
||||
wait()
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Declare member functions
|
||||
function MainGui:GenerateMain()
|
||||
local screenGui = create 'ScreenGui' {
|
||||
Name = 'RobloxLoadingGui'
|
||||
}
|
||||
|
||||
--
|
||||
-- create descendant frames
|
||||
local mainBackgroundContainer = create 'Frame' {
|
||||
Name = 'BlackFrame',
|
||||
BackgroundColor3 = COLORS.BACKGROUND_COLOR,
|
||||
BackgroundTransparency = 0,
|
||||
Size = UDim2.new(1, 0, 1, 0),
|
||||
Position = UDim2.new(0, 0, 0, 0),
|
||||
Active = true,
|
||||
Parent = screenGui,
|
||||
}
|
||||
|
||||
local closeButton = create 'ImageButton' {
|
||||
Name = 'CloseButton',
|
||||
Image = 'rbxasset://textures/loading/cancelButton.png',
|
||||
ImageTransparency = 1,
|
||||
BackgroundTransparency = 1,
|
||||
Position = UDim2.new(1, -37, 0, 5),
|
||||
Size = UDim2.new(0, 32, 0, 32),
|
||||
Active = false,
|
||||
ZIndex = 10,
|
||||
Parent = mainBackgroundContainer,
|
||||
}
|
||||
|
||||
local graphicsFrame = create 'Frame' {
|
||||
Name = 'GraphicsFrame',
|
||||
BorderSizePixel = 0,
|
||||
BackgroundTransparency = 1,
|
||||
Position = UDim2.new(1, (isMobile == true and -75 or (isTenFootInterface and -245 or -225)), 1, (isMobile == true and -75 or (isTenFootInterface and -185 or -165))),
|
||||
Size = UDim2.new(0, (isMobile == true and 70 or (isTenFootInterface and 140 or 120)), 0, (isMobile == true and 70 or (isTenFootInterface and 140 or 120))),
|
||||
ZIndex = 2,
|
||||
Parent = mainBackgroundContainer,
|
||||
}
|
||||
|
||||
local loadingImage = create 'ImageLabel' {
|
||||
Name = 'LoadingImage',
|
||||
BackgroundTransparency = 1,
|
||||
Image = 'rbxasset://textures/loading/loadingCircle.png',
|
||||
Position = UDim2.new(0, 0, 0, 0),
|
||||
Size = UDim2.new(1, 0, 1, 0),
|
||||
ZIndex = 2,
|
||||
Parent = graphicsFrame,
|
||||
}
|
||||
|
||||
local loadingText = create 'TextLabel' {
|
||||
Name = 'LoadingText',
|
||||
BackgroundTransparency = 1,
|
||||
Size = UDim2.new(1, (isMobile == true and -14 or -56), 1, 0),
|
||||
Position = UDim2.new(0, (isMobile == true and 12 or 28), 0, 0),
|
||||
Font = Enum.Font.SourceSans,
|
||||
FontSize = (isMobile == true and Enum.FontSize.Size12 or Enum.FontSize.Size18),
|
||||
TextWrapped = true,
|
||||
TextColor3 = COLORS.WHITE,
|
||||
TextXAlignment = Enum.TextXAlignment.Left,
|
||||
Visible = not isTenFootInterface,
|
||||
Text = "Loading...",
|
||||
ZIndex = 2,
|
||||
Parent = graphicsFrame,
|
||||
}
|
||||
|
||||
local uiMessageFrame = create 'Frame' {
|
||||
Name = 'UiMessageFrame',
|
||||
BackgroundTransparency = 1,
|
||||
Position = UDim2.new(0.25, 0, 1, -120),
|
||||
Size = UDim2.new(0.5, 0, 0, 80),
|
||||
ZIndex = 2,
|
||||
Parent = mainBackgroundContainer,
|
||||
}
|
||||
|
||||
local uiMessage = create 'TextLabel' {
|
||||
Name = 'UiMessage',
|
||||
BackgroundTransparency = 1,
|
||||
Size = UDim2.new(1, 0, 1, 0),
|
||||
Font = Enum.Font.SourceSansBold,
|
||||
FontSize = Enum.FontSize.Size18,
|
||||
TextWrapped = true,
|
||||
TextColor3 = COLORS.WHITE,
|
||||
Text = "",
|
||||
ZIndex = 2,
|
||||
Parent = uiMessageFrame,
|
||||
}
|
||||
|
||||
local infoFrame = create 'Frame' {
|
||||
Name = 'InfoFrame',
|
||||
BackgroundTransparency = 1,
|
||||
Position = UDim2.new(0, (isMobile == true and 20 or 100), 1, (isMobile == true and -120 or -150)),
|
||||
Size = UDim2.new(0.4, 0, 0, 110),
|
||||
ZIndex = 2,
|
||||
Parent = mainBackgroundContainer,
|
||||
}
|
||||
|
||||
local placeLabel = create 'TextLabel' {
|
||||
Name = 'PlaceLabel',
|
||||
BackgroundTransparency = 1,
|
||||
Size = UDim2.new(1, 0, 0, 80),
|
||||
Position = UDim2.new(0, 0, 0, 0),
|
||||
Font = Enum.Font.SourceSans,
|
||||
FontSize = (isTenFootInterface and Enum.FontSize.Size48 or Enum.FontSize.Size24),
|
||||
TextWrapped = true,
|
||||
TextScaled = true,
|
||||
TextColor3 = COLORS.WHITE,
|
||||
TextStrokeTransparency = 0,
|
||||
Text = "",
|
||||
TextXAlignment = Enum.TextXAlignment.Left,
|
||||
TextYAlignment = Enum.TextYAlignment.Bottom,
|
||||
ZIndex = 2,
|
||||
Parent = infoFrame,
|
||||
}
|
||||
|
||||
if isTenFootInterface then
|
||||
local byLabel = create'TextLabel' {
|
||||
Name = "ByLabel",
|
||||
BackgroundTransparency = 1,
|
||||
Size = UDim2.new(0, 36, 0, 30),
|
||||
Position = UDim2.new(0, 0, 0, 80),
|
||||
Font = Enum.Font.SourceSans,
|
||||
FontSize = Enum.FontSize.Size36,
|
||||
TextScaled = true,
|
||||
TextColor3 = COLORS.WHITE,
|
||||
TextStrokeTransparency = 0,
|
||||
Text = "By",
|
||||
TextXAlignment = Enum.TextXAlignment.Left,
|
||||
TextYAlignment = Enum.TextYAlignment.Top,
|
||||
ZIndex = 2,
|
||||
Visible = false,
|
||||
Parent = infoFrame,
|
||||
}
|
||||
local creatorIcon = create'ImageLabel' {
|
||||
Name = "CreatorIcon",
|
||||
BackgroundTransparency = 1,
|
||||
Size = UDim2.new(0, 30, 0, 30),
|
||||
Position = UDim2.new(0, 38, 0, 80),
|
||||
ImageTransparency = 0,
|
||||
Image = 'rbxasset://textures/ui/Shell/Icons/RobloxIcon32.png',
|
||||
ZIndex = 2,
|
||||
Visible = false,
|
||||
Parent = infoFrame,
|
||||
}
|
||||
end
|
||||
|
||||
local creatorLabel = create 'TextLabel' {
|
||||
Name = 'CreatorLabel',
|
||||
BackgroundTransparency = 1,
|
||||
Size = UDim2.new(1, 0, 0, 30),
|
||||
Position = UDim2.new(0, isTenFootInterface and 72 or 0, 0, 80),
|
||||
Font = Enum.Font.SourceSans,
|
||||
FontSize = (isTenFootInterface and Enum.FontSize.Size36 or Enum.FontSize.Size18),
|
||||
TextWrapped = true,
|
||||
TextScaled = true,
|
||||
TextColor3 = COLORS.WHITE,
|
||||
TextStrokeTransparency = 0,
|
||||
Text = "",
|
||||
TextXAlignment = Enum.TextXAlignment.Left,
|
||||
TextYAlignment = Enum.TextYAlignment.Top,
|
||||
ZIndex = 2,
|
||||
Parent = infoFrame,
|
||||
}
|
||||
|
||||
local backgroundTextureFrame = create 'Frame' {
|
||||
Name = 'BackgroundTextureFrame',
|
||||
BorderSizePixel = 0,
|
||||
Size = UDim2.new(1, 0, 1, 0),
|
||||
Position = UDim2.new(0, 0, 0, 0),
|
||||
ClipsDescendants = true,
|
||||
ZIndex = 1,
|
||||
BackgroundTransparency = 1,
|
||||
Parent = mainBackgroundContainer,
|
||||
}
|
||||
|
||||
local errorFrame = create 'Frame' {
|
||||
Name = 'ErrorFrame',
|
||||
BackgroundColor3 = COLORS.ERROR,
|
||||
BorderSizePixel = 0,
|
||||
Position = UDim2.new(0.25,0,0,0),
|
||||
Size = UDim2.new(0.5, 0, 0, 80),
|
||||
ZIndex = 8,
|
||||
Visible = false,
|
||||
Parent = screenGui,
|
||||
}
|
||||
|
||||
local errorText = create 'TextLabel' {
|
||||
Name = "ErrorText",
|
||||
BackgroundTransparency = 1,
|
||||
Size = UDim2.new(1, 0, 1, 0),
|
||||
Font = Enum.Font.SourceSansBold,
|
||||
FontSize = Enum.FontSize.Size14,
|
||||
TextWrapped = true,
|
||||
TextColor3 = COLORS.WHITE,
|
||||
Text = "",
|
||||
ZIndex = 8,
|
||||
Parent = errorFrame,
|
||||
}
|
||||
|
||||
while not game:GetService("CoreGui") do
|
||||
wait()
|
||||
end
|
||||
screenGui.Parent = game:GetService("CoreGui")
|
||||
currScreenGui = screenGui
|
||||
end
|
||||
|
||||
function round(num, idp)
|
||||
local mult = 10^(idp or 0)
|
||||
return math.floor(num * mult + 0.5) / mult
|
||||
end
|
||||
|
||||
---------------------------------------------------------
|
||||
-- Main Script (show something now + setup connections)
|
||||
|
||||
-- start loading assets asap
|
||||
InfoProvider:LoadAssets()
|
||||
MainGui:GenerateMain()
|
||||
if isTenFootInterface then
|
||||
createTenfootCancelGui()
|
||||
end
|
||||
|
||||
local removedLoadingScreen = false
|
||||
local setVerb = true
|
||||
local lastRenderTime = nil
|
||||
local fadeCycleTime = 1.7
|
||||
local turnCycleTime = 2
|
||||
local lastAbsoluteSize = Vector2.new(0, 0)
|
||||
local loadingDots = "..."
|
||||
local lastDotUpdateTime = nil
|
||||
local dotChangeTime = .2
|
||||
local brickCountChange = nil
|
||||
local lastBrickCount = 0
|
||||
|
||||
renderSteppedConnection = game:GetService("RunService").RenderStepped:connect(function()
|
||||
if not currScreenGui then return end
|
||||
if not currScreenGui:FindFirstChild("BlackFrame") then return end
|
||||
|
||||
if setVerb then
|
||||
currScreenGui.BlackFrame.CloseButton:SetVerb("Exit")
|
||||
setVerb = false
|
||||
end
|
||||
|
||||
if currScreenGui.BlackFrame:FindFirstChild("BackgroundTextureFrame") and currScreenGui.BlackFrame.BackgroundTextureFrame.AbsoluteSize ~= lastAbsoluteSize then
|
||||
lastAbsoluteSize = currScreenGui.BlackFrame.BackgroundTextureFrame.AbsoluteSize
|
||||
MainGui:tileBackgroundTexture(currScreenGui.BlackFrame.BackgroundTextureFrame)
|
||||
end
|
||||
|
||||
local infoFrame = currScreenGui.BlackFrame:FindFirstChild('InfoFrame')
|
||||
if infoFrame then
|
||||
-- set place name
|
||||
local placeLabel = infoFrame:FindFirstChild('PlaceLabel')
|
||||
if placeLabel and placeLabel.Text == "" then
|
||||
placeLabel.Text = InfoProvider:GetGameName()
|
||||
end
|
||||
|
||||
-- set creator name
|
||||
local creatorLabel = infoFrame:FindFirstChild('CreatorLabel')
|
||||
if creatorLabel and creatorLabel.Text == "" then
|
||||
local creatorName = InfoProvider:GetCreatorName()
|
||||
if creatorName ~= "" then
|
||||
if isTenFootInterface then
|
||||
local showDevName = true
|
||||
if platform == Enum.Platform.XBoxOne then
|
||||
local success, result = pcall(function()
|
||||
return settings():GetFFlag("ShowDevNameInXboxApp")
|
||||
end)
|
||||
if success then
|
||||
showDevName = result
|
||||
end
|
||||
end
|
||||
creatorLabel.Text = showDevName and creatorName or ""
|
||||
local creatorIcon = infoFrame:FindFirstChild('CreatorIcon')
|
||||
local byLabel = infoFrame:FindFirstChild('ByLabel')
|
||||
if creatorIcon then creatorIcon.Visible = showDevName end
|
||||
if byLabel then byLabel.Visible = showDevName end
|
||||
else
|
||||
creatorLabel.Text = "By "..creatorName
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not lastRenderTime then
|
||||
lastRenderTime = tick()
|
||||
lastDotUpdateTime = lastRenderTime
|
||||
return
|
||||
end
|
||||
|
||||
local currentTime = tick()
|
||||
local fadeAmount = (currentTime - lastRenderTime) * fadeCycleTime
|
||||
local turnAmount = (currentTime - lastRenderTime) * (360/turnCycleTime)
|
||||
lastRenderTime = currentTime
|
||||
|
||||
currScreenGui.BlackFrame.GraphicsFrame.LoadingImage.Rotation = currScreenGui.BlackFrame.GraphicsFrame.LoadingImage.Rotation + turnAmount
|
||||
|
||||
local updateLoadingDots = function()
|
||||
loadingDots = loadingDots.. "."
|
||||
if loadingDots == "..........." then
|
||||
loadingDots = ""
|
||||
end
|
||||
currScreenGui.BlackFrame.GraphicsFrame.LoadingText.Text = "Loading" ..loadingDots
|
||||
end
|
||||
|
||||
if currentTime - lastDotUpdateTime >= dotChangeTime and InfoProvider:GetCreatorName() == "" then
|
||||
lastDotUpdateTime = currentTime
|
||||
updateLoadingDots()
|
||||
else
|
||||
if guiService:GetBrickCount() > 0 then
|
||||
if brickCountChange == nil then
|
||||
brickCountChange = guiService:GetBrickCount()
|
||||
end
|
||||
if guiService:GetBrickCount() - lastBrickCount >= brickCountChange then
|
||||
lastBrickCount = guiService:GetBrickCount()
|
||||
updateLoadingDots()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not isTenFootInterface then
|
||||
if currentTime - startTime > 5 and currScreenGui.BlackFrame.CloseButton.ImageTransparency > 0 then
|
||||
currScreenGui.BlackFrame.CloseButton.ImageTransparency = currScreenGui.BlackFrame.CloseButton.ImageTransparency - fadeAmount
|
||||
|
||||
if currScreenGui.BlackFrame.CloseButton.ImageTransparency <= 0 then
|
||||
currScreenGui.BlackFrame.CloseButton.Active = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
spawn(function()
|
||||
local RobloxGui = game:GetService("CoreGui"):WaitForChild("RobloxGui")
|
||||
local guiInsetChangedEvent = Instance.new("BindableEvent")
|
||||
guiInsetChangedEvent.Name = "GuiInsetChanged"
|
||||
guiInsetChangedEvent.Parent = RobloxGui
|
||||
guiInsetChangedEvent.Event:connect(function(x1, y1, x2, y2)
|
||||
if currScreenGui and currScreenGui:FindFirstChild("BlackFrame") then
|
||||
currScreenGui.BlackFrame.Position = UDim2.new(0, -x1, 0, -y1)
|
||||
currScreenGui.BlackFrame.Size = UDim2.new(1, x1 + x2, 1, y1 + y2)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
local leaveGameButton, leaveGameTextLabel, errorImage = nil
|
||||
|
||||
guiService.ErrorMessageChanged:connect(function()
|
||||
if guiService:GetErrorMessage() ~= '' then
|
||||
if isTenFootInterface then
|
||||
currScreenGui.ErrorFrame.Size = UDim2.new(1, 0, 0, 144)
|
||||
currScreenGui.ErrorFrame.Position = UDim2.new(0, 0, 0, 0)
|
||||
currScreenGui.ErrorFrame.BackgroundColor3 = COLORS.BLACK
|
||||
currScreenGui.ErrorFrame.BackgroundTransparency = 0.5
|
||||
currScreenGui.ErrorFrame.ErrorText.FontSize = Enum.FontSize.Size36
|
||||
currScreenGui.ErrorFrame.ErrorText.Position = UDim2.new(.3, 0, 0, 0)
|
||||
currScreenGui.ErrorFrame.ErrorText.Size = UDim2.new(.4, 0, 0, 144)
|
||||
if errorImage == nil then
|
||||
errorImage = Instance.new("ImageLabel")
|
||||
errorImage.Image = "rbxasset://textures/ui/ErrorIconSmall.png"
|
||||
errorImage.Size = UDim2.new(0, 96, 0, 79)
|
||||
errorImage.Position = UDim2.new(0.228125, 0, 0, 32)
|
||||
errorImage.ZIndex = 9
|
||||
errorImage.BackgroundTransparency = 1
|
||||
errorImage.Parent = currScreenGui.ErrorFrame
|
||||
end
|
||||
-- we show a B button to kill game data model on console
|
||||
if not isTenFootInterface then
|
||||
if leaveGameButton == nil then
|
||||
local RobloxGui = game:GetService("CoreGui"):WaitForChild("RobloxGui")
|
||||
local utility = require(RobloxGui.Modules.Settings.Utility)
|
||||
local textLabel = nil
|
||||
leaveGameButton, leaveGameTextLabel = utility:MakeStyledButton("LeaveGame", "Leave", UDim2.new(0, 288, 0, 78))
|
||||
leaveGameButton:SetVerb("Exit")
|
||||
leaveGameButton.NextSelectionDown = leaveGameButton
|
||||
leaveGameButton.NextSelectionLeft = leaveGameButton
|
||||
leaveGameButton.NextSelectionRight = leaveGameButton
|
||||
leaveGameButton.NextSelectionUp = leaveGameButton
|
||||
leaveGameButton.ZIndex = 9
|
||||
leaveGameButton.Position = UDim2.new(0.771875, 0, 0, 37)
|
||||
leaveGameButton.Parent = currScreenGui.ErrorFrame
|
||||
leaveGameTextLabel.FontSize = Enum.FontSize.Size36
|
||||
leaveGameTextLabel.ZIndex = 10
|
||||
game:GetService("GuiService").SelectedCoreObject = leaveGameButton
|
||||
else
|
||||
game:GetService("GuiService").SelectedCoreObject = leaveGameButton
|
||||
end
|
||||
end
|
||||
end
|
||||
currScreenGui.ErrorFrame.ErrorText.Text = guiService:GetErrorMessage()
|
||||
currScreenGui.ErrorFrame.Visible = true
|
||||
local blackFrame = currScreenGui:FindFirstChild('BlackFrame')
|
||||
if blackFrame then
|
||||
blackFrame.CloseButton.ImageTransparency = 0
|
||||
blackFrame.CloseButton.Active = true
|
||||
end
|
||||
else
|
||||
currScreenGui.ErrorFrame.Visible = false
|
||||
end
|
||||
end)
|
||||
|
||||
guiService.UiMessageChanged:connect(function(type, newMessage)
|
||||
if type == Enum.UiMessageType.UiMessageInfo then
|
||||
local blackFrame = currScreenGui and currScreenGui:FindFirstChild('BlackFrame')
|
||||
if blackFrame then
|
||||
blackFrame.UiMessageFrame.UiMessage.Text = newMessage
|
||||
if newMessage ~= '' then
|
||||
blackFrame.UiMessageFrame.Visible = true
|
||||
else
|
||||
blackFrame.UiMessageFrame.Visible = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
if guiService:GetErrorMessage() ~= '' then
|
||||
currScreenGui.ErrorFrame.ErrorText.Text = guiService:GetErrorMessage()
|
||||
currScreenGui.ErrorFrame.Visible = true
|
||||
end
|
||||
|
||||
|
||||
function stopListeningToRenderingStep()
|
||||
if renderSteppedConnection then
|
||||
renderSteppedConnection:disconnect()
|
||||
renderSteppedConnection = nil
|
||||
end
|
||||
end
|
||||
|
||||
function fadeAndDestroyBlackFrame(blackFrame)
|
||||
if destroyingBackground then return end
|
||||
destroyingBackground = true
|
||||
spawn(function()
|
||||
local infoFrame = blackFrame:FindFirstChild("InfoFrame")
|
||||
local graphicsFrame = blackFrame:FindFirstChild("GraphicsFrame")
|
||||
|
||||
local infoFrameChildren = infoFrame:GetChildren()
|
||||
local transparency = 0
|
||||
local rateChange = 1.8
|
||||
local lastUpdateTime = nil
|
||||
|
||||
while transparency < 1 do
|
||||
if not lastUpdateTime then
|
||||
lastUpdateTime = tick()
|
||||
else
|
||||
local newTime = tick()
|
||||
transparency = transparency + rateChange * (newTime - lastUpdateTime)
|
||||
for i = 1, #infoFrameChildren do
|
||||
local child = infoFrameChildren[i]
|
||||
if child:IsA('TextLabel') then
|
||||
child.TextTransparency = transparency
|
||||
child.TextStrokeTransparency = transparency
|
||||
elseif child:IsA('ImageLabel') then
|
||||
child.ImageTransparency = transparency
|
||||
end
|
||||
end
|
||||
graphicsFrame.LoadingImage.ImageTransparency = transparency
|
||||
blackFrame.BackgroundTransparency = transparency
|
||||
|
||||
if backgroundImageTransparency < 1 then
|
||||
backgroundImageTransparency = transparency
|
||||
local backgroundImages = blackFrame.BackgroundTextureFrame:GetChildren()
|
||||
for i = 1, #backgroundImages do
|
||||
backgroundImages[i].ImageTransparency = backgroundImageTransparency
|
||||
end
|
||||
end
|
||||
|
||||
lastUpdateTime = newTime
|
||||
end
|
||||
wait()
|
||||
end
|
||||
if blackFrame ~= nil then
|
||||
stopListeningToRenderingStep()
|
||||
blackFrame:Destroy()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function destroyLoadingElements()
|
||||
if not currScreenGui then return end
|
||||
if destroyedLoadingGui then return end
|
||||
destroyedLoadingGui = true
|
||||
|
||||
local guiChildren = currScreenGui:GetChildren()
|
||||
for i=1, #guiChildren do
|
||||
-- need to keep this around in case we get a connection error later
|
||||
if guiChildren[i].Name ~= "ErrorFrame" then
|
||||
if guiChildren[i].Name == "BlackFrame" then
|
||||
fadeAndDestroyBlackFrame(guiChildren[i])
|
||||
else
|
||||
guiChildren[i]:Destroy()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function handleFinishedReplicating()
|
||||
hasReplicatedFirstElements = (#game:GetService("ReplicatedFirst"):GetChildren() > 0)
|
||||
|
||||
if not hasReplicatedFirstElements then
|
||||
if useGameLoadedToWait then
|
||||
if game:IsLoaded() then
|
||||
handleRemoveDefaultLoadingGui()
|
||||
else
|
||||
local gameLoadedCon = nil
|
||||
gameLoadedCon = game.Loaded:connect(function()
|
||||
gameLoadedCon:disconnect()
|
||||
gameLoadedCon = nil
|
||||
handleRemoveDefaultLoadingGui()
|
||||
end)
|
||||
end
|
||||
else
|
||||
while game:GetService("ContentProvider").RequestQueueSize > 0 do
|
||||
wait()
|
||||
end
|
||||
handleRemoveDefaultLoadingGui()
|
||||
end
|
||||
else
|
||||
wait(5) -- make sure after 5 seconds we remove the default gui, even if the user doesn't
|
||||
handleRemoveDefaultLoadingGui()
|
||||
end
|
||||
end
|
||||
|
||||
function handleRemoveDefaultLoadingGui()
|
||||
if isTenFootInterface then
|
||||
ContextActionService:UnbindCoreAction('CancelGameLoad')
|
||||
end
|
||||
destroyLoadingElements()
|
||||
end
|
||||
|
||||
game:GetService("ReplicatedFirst").FinishedReplicating:connect(handleFinishedReplicating)
|
||||
if game:GetService("ReplicatedFirst"):IsFinishedReplicating() then
|
||||
handleFinishedReplicating()
|
||||
end
|
||||
|
||||
game:GetService("ReplicatedFirst").RemoveDefaultLoadingGuiSignal:connect(handleRemoveDefaultLoadingGui)
|
||||
if game:GetService("ReplicatedFirst"):IsDefaultLoadingGuiRemoved() then
|
||||
handleRemoveDefaultLoadingGui()
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,632 @@
|
||||
--[[
|
||||
// FileName: PlayerDropDown.lua
|
||||
// Written by: TheGamer101
|
||||
// Description: Code for the player drop down in the PlayerList and Chat
|
||||
]]
|
||||
local moduleApiTable = {}
|
||||
|
||||
--[[ Services ]]--
|
||||
local CoreGui = game:GetService('CoreGui')
|
||||
local HttpService = game:GetService('HttpService')
|
||||
local HttpRbxApiService = game:GetService('HttpRbxApiService')
|
||||
local PlayersService = game:GetService('Players')
|
||||
|
||||
--[[ Script Variables ]]--
|
||||
local LocalPlayer = PlayersService.LocalPlayer
|
||||
|
||||
--[[ Constants ]]--
|
||||
local POPUP_ENTRY_SIZE_Y = 24
|
||||
local ENTRY_PAD = 2
|
||||
local BG_TRANSPARENCY = 0.5
|
||||
local BG_COLOR = Color3.new(31/255, 31/255, 31/255)
|
||||
local TEXT_STROKE_TRANSPARENCY = 0.75
|
||||
local TEXT_COLOR = Color3.new(1, 1, 243/255)
|
||||
local TEXT_STROKE_COLOR = Color3.new(34/255, 34/255, 34/255)
|
||||
local MAX_FRIEND_COUNT = 200
|
||||
local FRIEND_IMAGE = 'http://www.watrbx.wtf/thumbs/avatar.ashx?userId='
|
||||
|
||||
--[[ Fast Flags ]]--
|
||||
local followerSuccess, isFollowersEnabled = pcall(function() return settings():GetFFlag("EnableLuaFollowers") end)
|
||||
local IsFollowersEnabled = followerSuccess and isFollowersEnabled
|
||||
|
||||
local serverFollowersSuccess, serverFollowersEnabled = pcall(function() return settings():GetFFlag("UserServerFollowers") end)
|
||||
local IsServerFollowers = serverFollowersSuccess and serverFollowersEnabled
|
||||
|
||||
--[[ Modules ]]--
|
||||
local RobloxGui = CoreGui:WaitForChild('RobloxGui')
|
||||
local settingsHub = nil
|
||||
|
||||
spawn(function()
|
||||
settingsHub = require(RobloxGui:WaitForChild("Modules"):WaitForChild("Settings"):WaitForChild("SettingsHub"))
|
||||
end)
|
||||
|
||||
--[[ Bindables ]]--
|
||||
local BinbableFunction_SendNotification = nil
|
||||
spawn(function()
|
||||
BinbableFunction_SendNotification = RobloxGui:WaitForChild("SendNotification")
|
||||
end)
|
||||
|
||||
--[[ Remotes ]]--
|
||||
local RemoteEvent_NewFollower = nil
|
||||
|
||||
spawn(function()
|
||||
local RobloxReplicatedStorage = game:GetService('RobloxReplicatedStorage')
|
||||
RemoteEvent_NewFollower = RobloxReplicatedStorage:WaitForChild('NewFollower')
|
||||
end)
|
||||
|
||||
--[[ Utility Functions ]]--
|
||||
local function createSignal()
|
||||
local sig = {}
|
||||
|
||||
local mSignaler = Instance.new('BindableEvent')
|
||||
|
||||
local mArgData = nil
|
||||
local mArgDataCount = nil
|
||||
|
||||
function sig:fire(...)
|
||||
mArgData = {...}
|
||||
mArgDataCount = select('#', ...)
|
||||
mSignaler:Fire()
|
||||
end
|
||||
|
||||
function sig:connect(f)
|
||||
if not f then error("connect(nil)", 2) end
|
||||
return mSignaler.Event:connect(function()
|
||||
f(unpack(mArgData, 1, mArgDataCount))
|
||||
end)
|
||||
end
|
||||
|
||||
function sig:wait()
|
||||
mSignaler.Event:wait()
|
||||
assert(mArgData, "Missing arg data, likely due to :TweenSize/Position corrupting threadrefs.")
|
||||
return unpack(mArgData, 1, mArgDataCount)
|
||||
end
|
||||
|
||||
return sig
|
||||
end
|
||||
|
||||
--[[ Events ]]--
|
||||
local BlockStatusChanged = createSignal()
|
||||
|
||||
--[[ Personal Server Stuff ]]--
|
||||
local IsPersonalServer = false
|
||||
local PersonalServerService = nil
|
||||
if game.Workspace:FindFirstChild('PSVariable') then
|
||||
IsPersonalServer = true
|
||||
PersonalServerService = game:GetService('PersonalServerService')
|
||||
end
|
||||
game.Workspace.ChildAdded:connect(function(child)
|
||||
if child.Name == 'PSVariable' and child:IsA('BoolValue') then
|
||||
IsPersonalServer = true
|
||||
PersonalServerService = game:GetService('PersonalServerService')
|
||||
end
|
||||
end)
|
||||
|
||||
local PRIVILEGE_LEVEL = {
|
||||
OWNER = 255,
|
||||
ADMIN = 240,
|
||||
MEMBER = 128,
|
||||
VISITOR = 10,
|
||||
BANNED = 0,
|
||||
}
|
||||
|
||||
local function onPrivilegeLevelSelect(player, rank)
|
||||
while player.PersonalServerRank < rank do
|
||||
PersonalServerService:Promote(player)
|
||||
end
|
||||
while player.PersonalServerRank > rank do
|
||||
PersonalServerService:Demote(player)
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Follower Notifications ]]--
|
||||
local function sendNotification(title, text, image, duration, callback)
|
||||
if BinbableFunction_SendNotification then
|
||||
BinbableFunction_SendNotification:Invoke(title, text, image, duration, callback)
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Friend Functions ]]--
|
||||
local function getFriendStatus(selectedPlayer)
|
||||
if selectedPlayer == LocalPlayer then
|
||||
return Enum.FriendStatus.NotFriend
|
||||
else
|
||||
local success, result = pcall(function()
|
||||
-- NOTE: Core script only
|
||||
return LocalPlayer:GetFriendStatus(selectedPlayer)
|
||||
end)
|
||||
if success then
|
||||
return result
|
||||
else
|
||||
return Enum.FriendStatus.NotFriend
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- if userId = nil, then it will get count for local player
|
||||
local function getFriendCountAsync(userId)
|
||||
local friendCount = nil
|
||||
local wasSuccess, result = pcall(function()
|
||||
local str = 'user/get-friendship-count'
|
||||
if userId then
|
||||
str = str..'?userId='..tostring(userId)
|
||||
end
|
||||
return HttpRbxApiService:GetAsync(str, true)
|
||||
end)
|
||||
if not wasSuccess then
|
||||
print("getFriendCountAsync() failed because", result)
|
||||
return nil
|
||||
end
|
||||
result = HttpService:JSONDecode(result)
|
||||
|
||||
if result["success"] and result["count"] then
|
||||
friendCount = result["count"]
|
||||
end
|
||||
|
||||
return friendCount
|
||||
end
|
||||
|
||||
-- checks if we can send a friend request. Right now the only way we
|
||||
-- can't is if one of the players is at the max friend limit
|
||||
local function canSendFriendRequestAsync(otherPlayer)
|
||||
local theirFriendCount = getFriendCountAsync(otherPlayer.userId)
|
||||
local myFriendCount = getFriendCountAsync()
|
||||
|
||||
-- assume max friends if web call fails
|
||||
if not myFriendCount or not theirFriendCount then
|
||||
return false
|
||||
end
|
||||
if myFriendCount < MAX_FRIEND_COUNT and theirFriendCount < MAX_FRIEND_COUNT then
|
||||
return true
|
||||
elseif myFriendCount >= MAX_FRIEND_COUNT then
|
||||
sendNotification("Cannot send friend request", "You are at the max friends limit.", "", 5, function() end)
|
||||
return false
|
||||
elseif theirFriendCount >= MAX_FRIEND_COUNT then
|
||||
sendNotification("Cannot send friend request", otherPlayer.Name.." is at the max friends limit.", "", 5, function() end)
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Follower Functions ]]--
|
||||
|
||||
-- Returns whether followerUserId is following userId
|
||||
local function isFollowing(userId, followerUserId)
|
||||
local apiPath = "user/following-exists?userId="
|
||||
local params = userId.."&followerUserId="..followerUserId
|
||||
local success, result = pcall(function()
|
||||
return HttpRbxApiService:GetAsync(apiPath..params, true)
|
||||
end)
|
||||
if not success then
|
||||
print("isFollowing() failed because", result)
|
||||
return false
|
||||
end
|
||||
|
||||
-- can now parse web response
|
||||
result = HttpService:JSONDecode(result)
|
||||
return result["success"] and result["isFollowing"]
|
||||
end
|
||||
|
||||
--[[ Functions for Blocking users ]]--
|
||||
local BlockedList = {}
|
||||
local MutedList = {}
|
||||
|
||||
local function GetBlockedPlayersAsync()
|
||||
local userId = LocalPlayer.userId
|
||||
local apiPath = "userblock/getblockedusers" .. "?" .. "userId=" .. tostring(userId) .. "&" .. "page=" .. "1"
|
||||
if userId > 0 then
|
||||
local blockList = nil
|
||||
local success, msg = pcall(function()
|
||||
local request = HttpRbxApiService:GetAsync(apiPath)
|
||||
blockList = request and game:GetService('HttpService'):JSONDecode(request)
|
||||
end)
|
||||
if blockList and blockList['success'] == true and blockList['userList'] then
|
||||
return blockList['userList']
|
||||
end
|
||||
end
|
||||
return {}
|
||||
end
|
||||
|
||||
spawn(function()
|
||||
BlockedList = GetBlockedPlayersAsync()
|
||||
end)
|
||||
|
||||
local function isBlocked(userId)
|
||||
if (BlockedList[userId] ~= nil and BlockedList[userId] == true) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function isMuted(userId)
|
||||
if (MutedList[userId] ~= nil and MutedList[userId] == true) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function BlockPlayerAsync(playerToBlock)
|
||||
if playerToBlock and LocalPlayer ~= playerToBlock then
|
||||
local blockUserId = playerToBlock.UserId
|
||||
if blockUserId > 0 then
|
||||
if not isBlocked(blockUserId) then
|
||||
BlockedList[blockUserId] = true
|
||||
BlockStatusChanged:fire(blockUserId, true)
|
||||
pcall(function()
|
||||
local success = PlayersService:BlockUser(LocalPlayer.userId, blockUserId)
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function UnblockPlayerAsync(playerToUnblock)
|
||||
if playerToUnblock then
|
||||
local unblockUserId = playerToUnblock.userId
|
||||
|
||||
if isBlocked(unblockUserId) then
|
||||
BlockedList[unblockUserId] = nil
|
||||
BlockStatusChanged:fire(unblockUserId, false)
|
||||
pcall(function()
|
||||
local success = PlayersService:UnblockUser(LocalPlayer.userId, unblockUserId)
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function MutePlayer(playerToMute)
|
||||
if playerToMute and LocalPlayer ~= playerToMute then
|
||||
local muteUserId = playerToMute.UserId
|
||||
if muteUserId > 0 then
|
||||
if not isMuted(muteUserId) then
|
||||
MutedList[muteUserId] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function UnmutePlayer(playerToUnmute)
|
||||
if playerToUnmute then
|
||||
local unmuteUserId = playerToUnmute.UserId
|
||||
MutedList[unmuteUserId] = nil
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Function to create DropDown class ]]--
|
||||
function createPlayerDropDown()
|
||||
local playerDropDown = {}
|
||||
playerDropDown.Player = nil
|
||||
playerDropDown.PopupFrame = nil
|
||||
playerDropDown.HidePopupImmediately = false
|
||||
playerDropDown.PopupFrameOffScreenPosition = nil -- if this is set the popup frame tweens to a different offscreen position than the default
|
||||
|
||||
playerDropDown.HiddenSignal = createSignal()
|
||||
|
||||
--[[ Functions for when options in the dropdown are pressed ]]--
|
||||
local function onFriendButtonPressed()
|
||||
if playerDropDown.Player then
|
||||
local status = getFriendStatus(playerDropDown.Player)
|
||||
if status == Enum.FriendStatus.Friend then
|
||||
LocalPlayer:RevokeFriendship(playerDropDown.Player)
|
||||
elseif status == Enum.FriendStatus.Unknown or status == Enum.FriendStatus.NotFriend then
|
||||
-- cache and spawn
|
||||
local cachedLastSelectedPlayer = playerDropDown.Player
|
||||
spawn(function()
|
||||
-- check for max friends before letting them send the request
|
||||
if canSendFriendRequestAsync(cachedLastSelectedPlayer) then -- Yields
|
||||
if cachedLastSelectedPlayer and cachedLastSelectedPlayer.Parent == PlayersService then
|
||||
LocalPlayer:RequestFriendship(cachedLastSelectedPlayer)
|
||||
end
|
||||
end
|
||||
end)
|
||||
elseif status == Enum.FriendStatus.FriendRequestSent then
|
||||
LocalPlayer:RevokeFriendship(playerDropDown.Player)
|
||||
elseif status == Enum.FriendStatus.FriendRequestReceived then
|
||||
LocalPlayer:RequestFriendship(playerDropDown.Player)
|
||||
end
|
||||
|
||||
playerDropDown:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
local function onDeclineFriendButonPressed()
|
||||
if playerDropDown.Player then
|
||||
LocalPlayer:RevokeFriendship(playerDropDown.Player)
|
||||
playerDropDown:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
-- Client unfollows followedUserId
|
||||
local function onUnfollowButtonPressed()
|
||||
if not playerDropDown.Player then return end
|
||||
--
|
||||
local apiPath = "user/unfollow"
|
||||
local params = "followedUserId="..tostring(playerDropDown.Player.userId)
|
||||
local success, result = pcall(function()
|
||||
return HttpRbxApiService:PostAsync(apiPath, params, true, Enum.ThrottlingPriority.Default, Enum.HttpContentType.ApplicationUrlEncoded)
|
||||
end)
|
||||
if not success then
|
||||
print("unfollowPlayer() failed because", result)
|
||||
playerDropDown:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
result = HttpService:JSONDecode(result)
|
||||
if result["success"] then
|
||||
if RemoteEvent_NewFollower then
|
||||
RemoteEvent_NewFollower:FireServer(playerDropDown.Player, false)
|
||||
end
|
||||
moduleApiTable.FollowerStatusChanged:fire()
|
||||
end
|
||||
|
||||
playerDropDown:Hide()
|
||||
-- no need to send notification when someone unfollows
|
||||
end
|
||||
|
||||
local function onBlockButtonPressed()
|
||||
if playerDropDown.Player then
|
||||
local cachedPlayer = playerDropDown.Player
|
||||
spawn(function()
|
||||
BlockPlayerAsync(cachedPlayer)
|
||||
end)
|
||||
playerDropDown:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
local function onUnblockButtonPressed()
|
||||
if playerDropDown.Player then
|
||||
local cachedPlayer = playerDropDown.Player
|
||||
spawn(function()
|
||||
UnblockPlayerAsync(cachedPlayer)
|
||||
end)
|
||||
playerDropDown:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
local function onReportButtonPressed()
|
||||
if playerDropDown.Player then
|
||||
settingsHub:ReportPlayer(playerDropDown.Player)
|
||||
playerDropDown:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
-- Client follows followedUserId
|
||||
local function onFollowButtonPressed()
|
||||
if not playerDropDown.Player then return end
|
||||
--
|
||||
local followedUserId = tostring(playerDropDown.Player.userId)
|
||||
local apiPath = "user/follow"
|
||||
local params = "followedUserId="..followedUserId
|
||||
local success, result = pcall(function()
|
||||
return HttpRbxApiService:PostAsync(apiPath, params, true, Enum.ThrottlingPriority.Default, Enum.HttpContentType.ApplicationUrlEncoded)
|
||||
end)
|
||||
if not success then
|
||||
print("followPlayer() failed because", result)
|
||||
playerDropDown:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
result = HttpService:JSONDecode(result)
|
||||
if result["success"] then
|
||||
sendNotification("You are", "now following "..playerDropDown.Player.Name, FRIEND_IMAGE..followedUserId.."&x=48&y=48", 5, function() end)
|
||||
if RemoteEvent_NewFollower then
|
||||
RemoteEvent_NewFollower:FireServer(playerDropDown.Player, true)
|
||||
end
|
||||
moduleApiTable.FollowerStatusChanged:fire()
|
||||
end
|
||||
|
||||
playerDropDown:Hide()
|
||||
end
|
||||
|
||||
--[[ GUI Creation Functions ]]--
|
||||
local function createPersonalServerDialog(buttons, selectedPlayer)
|
||||
local showPersonalServerRanks = IsPersonalServer and LocalPlayer.PersonalServerRank >= PRIVILEGE_LEVEL.ADMIN and LocalPlayer.PersonalServerRank > selectedPlayer.PersonalServerRank
|
||||
if showPersonalServerRanks then
|
||||
table.insert(buttons, {
|
||||
Name = "BanButton",
|
||||
Text = "Ban",
|
||||
OnPress = function()
|
||||
playerDropDown:Hide()
|
||||
onPrivilegeLevelSelect(selectedPlayer, PRIVILEGE_LEVEL.BANNED)
|
||||
end,
|
||||
})
|
||||
table.insert(buttons, {
|
||||
Name = "VistorButton",
|
||||
Text = "Visitor",
|
||||
OnPress = function()
|
||||
onPrivilegeLevelSelect(selectedPlayer, PRIVILEGE_LEVEL.VISITOR)
|
||||
end,
|
||||
})
|
||||
table.insert(buttons, {
|
||||
Name = "MemberButton",
|
||||
Text = "Member",
|
||||
OnPress = function()
|
||||
onPrivilegeLevelSelect(selectedPlayer, PRIVILEGE_LEVEL.MEMBER)
|
||||
end,
|
||||
})
|
||||
table.insert(buttons, {
|
||||
Name = "AdminButton",
|
||||
Text = "Admin",
|
||||
OnPress = function()
|
||||
onPrivilegeLevelSelect(selectedPlayer, PRIVILEGE_LEVEL.ADMIN)
|
||||
end,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
local function createPopupFrame(buttons)
|
||||
local frame = Instance.new('Frame')
|
||||
frame.Name = "PopupFrame"
|
||||
frame.Size = UDim2.new(1, 0, 0, (POPUP_ENTRY_SIZE_Y * #buttons) + (#buttons - ENTRY_PAD))
|
||||
frame.Position = UDim2.new(1, 1, 0, 0)
|
||||
frame.BackgroundTransparency = 1
|
||||
|
||||
for i,button in ipairs(buttons) do
|
||||
local btn = Instance.new('TextButton')
|
||||
btn.Name = button.Name
|
||||
btn.Size = UDim2.new(1, 0, 0, POPUP_ENTRY_SIZE_Y)
|
||||
btn.Position = UDim2.new(0, 0, 0, POPUP_ENTRY_SIZE_Y * (i - 1) + ((i - 1) * ENTRY_PAD))
|
||||
btn.BackgroundTransparency = BG_TRANSPARENCY
|
||||
btn.BackgroundColor3 = BG_COLOR
|
||||
btn.BorderSizePixel = 0
|
||||
btn.Text = button.Text
|
||||
btn.Font = Enum.Font.SourceSans
|
||||
btn.FontSize = Enum.FontSize.Size14
|
||||
btn.TextColor3 = TEXT_COLOR
|
||||
btn.TextStrokeTransparency = TEXT_STROKE_TRANSPARENCY
|
||||
btn.TextStrokeColor3 = TEXT_STROKE_COLOR
|
||||
btn.AutoButtonColor = true
|
||||
btn.Parent = frame
|
||||
|
||||
btn.MouseButton1Click:connect(button.OnPress)
|
||||
end
|
||||
|
||||
return frame
|
||||
end
|
||||
|
||||
--[[ PlayerDropDown Functions ]]--
|
||||
function playerDropDown:Hide()
|
||||
if playerDropDown.PopupFrame then
|
||||
local offscreenPosition = (playerDropDown.PopupFrameOffScreenPosition ~= nil and playerDropDown.PopupFrameOffScreenPosition or UDim2.new(1, 1, 0, playerDropDown.PopupFrame.Position.Y.Offset))
|
||||
if not playerDropDown.HidePopupImmediately then
|
||||
playerDropDown.PopupFrame:TweenPosition(offscreenPosition, Enum.EasingDirection.InOut,
|
||||
Enum.EasingStyle.Quad, TWEEN_TIME, true, function()
|
||||
if playerDropDown.PopupFrame then
|
||||
playerDropDown.PopupFrame:Destroy()
|
||||
playerDropDown.PopupFrame = nil
|
||||
end
|
||||
end)
|
||||
else
|
||||
playerDropDown.PopupFrame:Destroy()
|
||||
playerDropDown.PopupFrame = nil
|
||||
end
|
||||
end
|
||||
if playerDropDown.Player then
|
||||
playerDropDown.Player = nil
|
||||
end
|
||||
playerDropDown.HiddenSignal:fire()
|
||||
end
|
||||
|
||||
function playerDropDown:CreatePopup(Player)
|
||||
playerDropDown.Player = Player
|
||||
|
||||
local buttons = {}
|
||||
|
||||
local status = getFriendStatus(playerDropDown.Player)
|
||||
local friendText = ""
|
||||
local canDeclineFriend = false
|
||||
if status == Enum.FriendStatus.Friend then
|
||||
friendText = "Unfriend Player"
|
||||
elseif status == Enum.FriendStatus.Unknown or status == Enum.FriendStatus.NotFriend then
|
||||
friendText = "Send Friend Request"
|
||||
elseif status == Enum.FriendStatus.FriendRequestSent then
|
||||
friendText = "Revoke Friend Request"
|
||||
elseif status == Enum.FriendStatus.FriendRequestReceived then
|
||||
friendText = "Accept Friend Request"
|
||||
canDeclineFriend = true
|
||||
end
|
||||
|
||||
local blocked = isBlocked(playerDropDown.Player.userId)
|
||||
|
||||
if not blocked then
|
||||
table.insert(buttons, {
|
||||
Name = "FriendButton",
|
||||
Text = friendText,
|
||||
OnPress = onFriendButtonPressed,
|
||||
})
|
||||
end
|
||||
|
||||
if canDeclineFriend and not blocked then
|
||||
table.insert(buttons, {
|
||||
Name = "DeclineFriend",
|
||||
Text = "Decline Friend Request",
|
||||
OnPress = onDeclineFriendButonPressed,
|
||||
})
|
||||
end
|
||||
-- following status
|
||||
if IsServerFollowers or IsFollowersEnabled then
|
||||
local following = isFollowing(playerDropDown.Player.userId, LocalPlayer.userId)
|
||||
local followerText = following and "Unfollow Player" or "Follow Player"
|
||||
|
||||
if not blocked then
|
||||
table.insert(buttons, {
|
||||
Name = "FollowerButton",
|
||||
Text = followerText,
|
||||
OnPress = following and onUnfollowButtonPressed or onFollowButtonPressed,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
local blockedText = blocked and "Unblock Player" or "Block Player"
|
||||
table.insert(buttons, {
|
||||
Name = "BlockButton",
|
||||
Text = blockedText,
|
||||
OnPress = blocked and onUnblockButtonPressed or onBlockButtonPressed,
|
||||
})
|
||||
table.insert(buttons, {
|
||||
Name = "ReportButton",
|
||||
Text = "Report Abuse",
|
||||
OnPress = onReportButtonPressed,
|
||||
})
|
||||
|
||||
createPersonalServerDialog(buttons, playerDropDown.Player)
|
||||
if playerDropDown.PopupFrame then
|
||||
playerDropDown.PopupFrame:Destroy()
|
||||
end
|
||||
playerDropDown.PopupFrame = createPopupFrame(buttons)
|
||||
return playerDropDown.PopupFrame
|
||||
end
|
||||
|
||||
--[[ PlayerRemoving Connection ]]--
|
||||
PlayersService.PlayerRemoving:connect(function(leavingPlayer)
|
||||
if playerDropDown.Player == leavingPlayer then
|
||||
playerDropDown:Hide()
|
||||
end
|
||||
end)
|
||||
|
||||
return playerDropDown
|
||||
end
|
||||
|
||||
|
||||
do
|
||||
moduleApiTable.FollowerStatusChanged = createSignal()
|
||||
|
||||
function moduleApiTable:CreatePlayerDropDown()
|
||||
return createPlayerDropDown()
|
||||
end
|
||||
|
||||
function moduleApiTable:CreateBlockingUtility()
|
||||
local blockingUtility = {}
|
||||
|
||||
function blockingUtility:BlockPlayerAsync(player)
|
||||
return BlockPlayerAsync(player)
|
||||
end
|
||||
|
||||
function blockingUtility:UnblockPlayerAsync(player)
|
||||
return UnblockPlayerAsync(player)
|
||||
end
|
||||
|
||||
function blockingUtility:MutePlayer(player)
|
||||
return MutePlayer(player)
|
||||
end
|
||||
|
||||
function blockingUtility:UnmutePlayer(player)
|
||||
return UnmutePlayer(player)
|
||||
end
|
||||
|
||||
function blockingUtility:IsPlayerBlockedByUserId(userId)
|
||||
return isBlocked(userId)
|
||||
end
|
||||
|
||||
function blockingUtility:GetBlockedStatusChangedEvent()
|
||||
return BlockStatusChanged
|
||||
end
|
||||
|
||||
function blockingUtility:IsPlayerMutedByUserId(userId)
|
||||
return isMuted(userId)
|
||||
end
|
||||
|
||||
return blockingUtility
|
||||
end
|
||||
end
|
||||
|
||||
return moduleApiTable
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,599 @@
|
||||
--[[
|
||||
Filename: GameSettings.lua
|
||||
Written by: jeditkacheff
|
||||
Version 1.0
|
||||
Description: Takes care of the Game Settings Tab in Settings Menu
|
||||
--]]
|
||||
|
||||
-------------- SERVICES --------------
|
||||
local CoreGui = game:GetService("CoreGui")
|
||||
local RobloxGui = CoreGui:WaitForChild("RobloxGui")
|
||||
local GuiService = game:GetService("GuiService")
|
||||
local UserInputService = game:GetService("UserInputService")
|
||||
local PlatformService = nil
|
||||
pcall(function() PlatformService = game:GetService("PlatformService") end)
|
||||
local ContextActionService = game:GetService("ContextActionService")
|
||||
local Settings = UserSettings()
|
||||
local GameSettings = Settings.GameSettings
|
||||
|
||||
-------------- CONSTANTS --------------
|
||||
local GRAPHICS_QUALITY_LEVELS = 10
|
||||
local GRAPHICS_QUALITY_TO_INT = {
|
||||
["Enum.SavedQualitySetting.Automatic"] = 0,
|
||||
["Enum.SavedQualitySetting.QualityLevel1"] = 1,
|
||||
["Enum.SavedQualitySetting.QualityLevel2"] = 2,
|
||||
["Enum.SavedQualitySetting.QualityLevel3"] = 3,
|
||||
["Enum.SavedQualitySetting.QualityLevel4"] = 4,
|
||||
["Enum.SavedQualitySetting.QualityLevel5"] = 5,
|
||||
["Enum.SavedQualitySetting.QualityLevel6"] = 6,
|
||||
["Enum.SavedQualitySetting.QualityLevel7"] = 7,
|
||||
["Enum.SavedQualitySetting.QualityLevel8"] = 8,
|
||||
["Enum.SavedQualitySetting.QualityLevel9"] = 9,
|
||||
["Enum.SavedQualitySetting.QualityLevel10"] = 10,
|
||||
}
|
||||
local PC_CHANGED_PROPS = {
|
||||
DevComputerMovementMode = true,
|
||||
DevComputerCameraMode = true,
|
||||
DevEnableMouseLock = true,
|
||||
}
|
||||
local TOUCH_CHANGED_PROPS = {
|
||||
DevTouchMovementMode = true,
|
||||
DevTouchCameraMode = true,
|
||||
}
|
||||
local CAMERA_MODE_DEFAULT_STRING = UserInputService.TouchEnabled and "Default (Follow)" or "Default (Classic)"
|
||||
|
||||
local MOVEMENT_MODE_DEFAULT_STRING = UserInputService.TouchEnabled and "Default (Thumbstick)" or "Default (Keyboard)"
|
||||
local MOVEMENT_MODE_KEYBOARDMOUSE_STRING = "Keyboard + Mouse"
|
||||
local MOVEMENT_MODE_CLICKTOMOVE_STRING = UserInputService.TouchEnabled and "Tap to Move" or "Click to Move"
|
||||
|
||||
----------- UTILITIES --------------
|
||||
local utility = require(RobloxGui.Modules.Settings.Utility)
|
||||
|
||||
------------ Variables -------------------
|
||||
RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface")
|
||||
RobloxGui:WaitForChild("Modules"):WaitForChild("Settings"):WaitForChild("SettingsHub")
|
||||
local isTenFootInterface = require(RobloxGui.Modules.TenFootInterface):IsEnabled()
|
||||
local PageInstance = nil
|
||||
local LocalPlayer = game.Players.LocalPlayer
|
||||
local platform = UserInputService:GetPlatform()
|
||||
local overscanScreen = nil
|
||||
|
||||
----------- CLASS DECLARATION --------------
|
||||
|
||||
local function Initialize()
|
||||
local settingsPageFactory = require(RobloxGui.Modules.Settings.SettingsPageFactory)
|
||||
local this = settingsPageFactory:CreateNewPage()
|
||||
|
||||
----------- FUNCTIONS ---------------
|
||||
local function createGraphicsOptions()
|
||||
|
||||
------------------ Fullscreen Selection GUI Setup ------------------
|
||||
local fullScreenInit = 1
|
||||
if not GameSettings:InFullScreen() then
|
||||
fullScreenInit = 2
|
||||
end
|
||||
|
||||
this.FullscreenFrame,
|
||||
this.FullscreenLabel,
|
||||
this.FullscreenEnabler = utility:AddNewRow(this, "Fullscreen", "Selector", {"On", "Off"}, fullScreenInit)
|
||||
|
||||
local fullScreenSelectionFrame = this.FullscreenEnabler.SliderFrame and this.FullscreenEnabler.SliderFrame or this.FullscreenEnabler.SelectorFrame
|
||||
|
||||
this.FullscreenEnabler.IndexChanged:connect(function(newIndex)
|
||||
GuiService:ToggleFullscreen()
|
||||
end)
|
||||
|
||||
------------------ Gfx Enabler Selection GUI Setup ------------------
|
||||
this.GraphicsEnablerFrame,
|
||||
this.GraphicsEnablerLabel,
|
||||
this.GraphicsQualityEnabler = utility:AddNewRow(this, "Graphics Mode", "Selector", {"Automatic", "Manual"}, 1)
|
||||
|
||||
------------------ Gfx Slider GUI Setup ------------------
|
||||
this.GraphicsQualityFrame,
|
||||
this.GraphicsQualityLabel,
|
||||
this.GraphicsQualitySlider = utility:AddNewRow(this, "Graphics Quality", "Slider", GRAPHICS_QUALITY_LEVELS, 1)
|
||||
this.GraphicsQualitySlider:SetMinStep(1)
|
||||
|
||||
------------------------- Connection Setup ----------------------------
|
||||
settings().Rendering.EnableFRM = true
|
||||
|
||||
function SetGraphicsQuality(newValue, automaticSettingAllowed)
|
||||
local percentage = newValue/GRAPHICS_QUALITY_LEVELS
|
||||
local newQualityLevel = math.floor((settings().Rendering:GetMaxQualityLevel() - 1) * percentage)
|
||||
if newQualityLevel == 20 then
|
||||
newQualityLevel = 21
|
||||
elseif newValue == 1 then
|
||||
newQualityLevel = 1
|
||||
elseif newValue < 1 and not automaticSettingAllowed then
|
||||
newValue = 1
|
||||
newQualityLevel = 1
|
||||
elseif newQualityLevel > settings().Rendering:GetMaxQualityLevel() then
|
||||
newQualityLevel = settings().Rendering:GetMaxQualityLevel() - 1
|
||||
end
|
||||
|
||||
GameSettings.SavedQualityLevel = newValue
|
||||
settings().Rendering.QualityLevel = newQualityLevel
|
||||
end
|
||||
|
||||
local function setGraphicsToAuto()
|
||||
this.GraphicsQualitySlider:SetZIndex(1)
|
||||
this.GraphicsQualityLabel.ZIndex = 1
|
||||
this.GraphicsQualitySlider:SetInteractable(false)
|
||||
|
||||
SetGraphicsQuality(Enum.QualityLevel.Automatic.Value, true)
|
||||
end
|
||||
local function setGraphicsToManual(level)
|
||||
this.GraphicsQualitySlider:SetZIndex(2)
|
||||
this.GraphicsQualityLabel.ZIndex = 2
|
||||
this.GraphicsQualitySlider:SetInteractable(true)
|
||||
|
||||
-- need to force the quality change if slider is already at this position
|
||||
if this.GraphicsQualitySlider:GetValue() == level then
|
||||
SetGraphicsQuality(level)
|
||||
else
|
||||
this.GraphicsQualitySlider:SetValue(level)
|
||||
end
|
||||
end
|
||||
|
||||
game.GraphicsQualityChangeRequest:connect(function(isIncrease)
|
||||
if settings().Rendering.QualityLevel == Enum.QualityLevel.Automatic then return end
|
||||
--
|
||||
local currentGraphicsSliderValue = this.GraphicsQualitySlider:GetValue()
|
||||
if isIncrease then
|
||||
currentGraphicsSliderValue = currentGraphicsSliderValue + 1
|
||||
else
|
||||
currentGraphicsSliderValue = currentGraphicsSliderValue - 1
|
||||
end
|
||||
|
||||
this.GraphicsQualitySlider:SetValue(currentGraphicsSliderValue)
|
||||
end)
|
||||
|
||||
this.GraphicsQualitySlider.ValueChanged:connect(function(newValue)
|
||||
SetGraphicsQuality(newValue)
|
||||
end)
|
||||
|
||||
this.GraphicsQualityEnabler.IndexChanged:connect(function(newIndex)
|
||||
if newIndex == 1 then
|
||||
setGraphicsToAuto()
|
||||
elseif newIndex == 2 then
|
||||
setGraphicsToManual( this.GraphicsQualitySlider:GetValue() )
|
||||
end
|
||||
end)
|
||||
|
||||
-- initialize the slider position
|
||||
if GameSettings.SavedQualityLevel == Enum.SavedQualitySetting.Automatic then
|
||||
this.GraphicsQualitySlider:SetValue(5)
|
||||
this.GraphicsQualityEnabler:SetSelectionIndex(1)
|
||||
else
|
||||
local graphicsLevel = tostring(GameSettings.SavedQualityLevel)
|
||||
if GRAPHICS_QUALITY_TO_INT[graphicsLevel] then
|
||||
graphicsLevel = GRAPHICS_QUALITY_TO_INT[graphicsLevel]
|
||||
else
|
||||
graphicsLevel = GRAPHICS_QUALITY_LEVELS
|
||||
end
|
||||
|
||||
spawn(function()
|
||||
this.GraphicsQualitySlider:SetValue(graphicsLevel)
|
||||
this.GraphicsQualityEnabler:SetSelectionIndex(2)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
local function createCameraModeOptions(movementModeEnabled)
|
||||
------------------------------------------------------
|
||||
------------------
|
||||
------------------ Shift Lock Switch -----------------
|
||||
if UserInputService.MouseEnabled then
|
||||
this.ShiftLockFrame,
|
||||
this.ShiftLockLabel,
|
||||
this.ShiftLockMode,
|
||||
this.ShiftLockOverrideText = nil
|
||||
|
||||
if UserInputService.MouseEnabled and UserInputService.KeyboardEnabled then
|
||||
local startIndex = 2
|
||||
if GameSettings.ControlMode == Enum.ControlMode.MouseLockSwitch then
|
||||
startIndex = 1
|
||||
end
|
||||
|
||||
this.ShiftLockFrame,
|
||||
this.ShiftLockLabel,
|
||||
this.ShiftLockMode = utility:AddNewRow(this, "Shift Lock Switch", "Selector", {"On", "Off"}, startIndex)
|
||||
|
||||
this.ShiftLockOverrideText = utility:Create'TextLabel'
|
||||
{
|
||||
Name = "ShiftLockOverrideLabel",
|
||||
Text = "Set by Developer",
|
||||
TextColor3 = Color3.new(1,1,1),
|
||||
Font = Enum.Font.SourceSans,
|
||||
FontSize = Enum.FontSize.Size24,
|
||||
BackgroundTransparency = 1,
|
||||
Size = UDim2.new(0,200,1,0),
|
||||
Position = UDim2.new(1,-350,0,0),
|
||||
Visible = false,
|
||||
ZIndex = 2,
|
||||
Parent = this.ShiftLockFrame
|
||||
};
|
||||
|
||||
this.ShiftLockMode.IndexChanged:connect(function(newIndex)
|
||||
if newIndex == 1 then
|
||||
GameSettings.ControlMode = Enum.ControlMode.MouseLockSwitch
|
||||
else
|
||||
GameSettings.ControlMode = Enum.ControlMode.Classic
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------------
|
||||
------------------
|
||||
------------------ Camera Mode -----------------------
|
||||
do
|
||||
local enumItems = nil
|
||||
local startingCameraEnumItem = 1
|
||||
if UserInputService.TouchEnabled then
|
||||
enumItems = Enum.TouchCameraMovementMode:GetEnumItems()
|
||||
else
|
||||
enumItems = Enum.ComputerCameraMovementMode:GetEnumItems()
|
||||
end
|
||||
|
||||
local cameraEnumNames = {}
|
||||
local cameraEnumNameToItem = {}
|
||||
for i = 1, #enumItems do
|
||||
local displayName = enumItems[i].Name
|
||||
if displayName == 'Default' then
|
||||
displayName = CAMERA_MODE_DEFAULT_STRING
|
||||
end
|
||||
|
||||
if UserInputService.TouchEnabled then
|
||||
if GameSettings.TouchCameraMovementMode == enumItems[i] then
|
||||
startingCameraEnumItem = i
|
||||
end
|
||||
else
|
||||
if GameSettings.ComputerCameraMovementMode == enumItems[i] then
|
||||
startingCameraEnumItem = i
|
||||
end
|
||||
end
|
||||
|
||||
cameraEnumNames[i] = displayName
|
||||
cameraEnumNameToItem[displayName] = enumItems[i].Value
|
||||
end
|
||||
|
||||
this.CameraModeFrame,
|
||||
this.CameraModeLabel,
|
||||
this.CameraMode = utility:AddNewRow(this, "Camera Mode", "Selector", cameraEnumNames, startingCameraEnumItem)
|
||||
|
||||
this.CameraModeOverrideText = utility:Create'TextLabel'
|
||||
{
|
||||
Name = "CameraDevOverrideLabel",
|
||||
Text = "Set by Developer",
|
||||
TextColor3 = Color3.new(1,1,1),
|
||||
Font = Enum.Font.SourceSans,
|
||||
FontSize = Enum.FontSize.Size24,
|
||||
BackgroundTransparency = 1,
|
||||
Size = UDim2.new(0,200,1,0),
|
||||
Position = UDim2.new(1,-350,0,0),
|
||||
Visible = false,
|
||||
ZIndex = 2,
|
||||
Parent = this.CameraModeFrame
|
||||
};
|
||||
|
||||
this.CameraMode.IndexChanged:connect(function(newIndex)
|
||||
local newEnumSetting = cameraEnumNameToItem[cameraEnumNames[newIndex]]
|
||||
|
||||
if UserInputService.TouchEnabled then
|
||||
GameSettings.TouchCameraMovementMode = newEnumSetting
|
||||
else
|
||||
GameSettings.ComputerCameraMovementMode = newEnumSetting
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
------------------------------------------------------
|
||||
------------------
|
||||
------------------ Movement Mode ---------------------
|
||||
if movementModeEnabled then
|
||||
local movementEnumItems = nil
|
||||
local startingMovementEnumItem = 1
|
||||
if UserInputService.TouchEnabled then
|
||||
movementEnumItems = Enum.TouchMovementMode:GetEnumItems()
|
||||
else
|
||||
movementEnumItems = Enum.ComputerMovementMode:GetEnumItems()
|
||||
end
|
||||
|
||||
local movementEnumNames = {}
|
||||
local movementEnumNameToItem = {}
|
||||
for i = 1, #movementEnumItems do
|
||||
local displayName = movementEnumItems[i].Name
|
||||
if displayName == "Default" then
|
||||
displayName = MOVEMENT_MODE_DEFAULT_STRING
|
||||
elseif displayName == "KeyboardMouse" then
|
||||
displayName = MOVEMENT_MODE_KEYBOARDMOUSE_STRING
|
||||
elseif displayName == "ClickToMove" then
|
||||
displayName = MOVEMENT_MODE_CLICKTOMOVE_STRING
|
||||
end
|
||||
|
||||
if UserInputService.TouchEnabled then
|
||||
if GameSettings.TouchMovementMode == movementEnumItems[i] then
|
||||
startingMovementEnumItem = i
|
||||
end
|
||||
else
|
||||
if GameSettings.ComputerMovementMode == movementEnumItems[i] then
|
||||
startingMovementEnumItem = i
|
||||
end
|
||||
end
|
||||
|
||||
movementEnumNames[i] = displayName
|
||||
movementEnumNameToItem[displayName] = movementEnumItems[i]
|
||||
end
|
||||
|
||||
this.MovementModeFrame,
|
||||
this.MovementModeLabel,
|
||||
this.MovementMode = utility:AddNewRow(this, "Movement Mode", "Selector", movementEnumNames, startingMovementEnumItem)
|
||||
|
||||
this.MovementModeOverrideText = utility:Create'TextLabel'
|
||||
{
|
||||
Name = "MovementDevOverrideLabel",
|
||||
Text = "Set by Developer",
|
||||
TextColor3 = Color3.new(1,1,1),
|
||||
Font = Enum.Font.SourceSans,
|
||||
FontSize = Enum.FontSize.Size24,
|
||||
BackgroundTransparency = 1,
|
||||
Size = UDim2.new(0,200,1,0),
|
||||
Position = UDim2.new(1,-350,0,0),
|
||||
Visible = false,
|
||||
ZIndex = 2,
|
||||
Parent = this.MovementModeFrame
|
||||
};
|
||||
|
||||
this.MovementMode.IndexChanged:connect(function(newIndex)
|
||||
local newEnumSetting = movementEnumNameToItem[movementEnumNames[newIndex]]
|
||||
|
||||
if UserInputService.TouchEnabled then
|
||||
GameSettings.TouchMovementMode = newEnumSetting
|
||||
else
|
||||
GameSettings.ComputerMovementMode = newEnumSetting
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------------
|
||||
------------------
|
||||
------------------------- Connection Setup -----------
|
||||
function setCameraModeVisible(visible)
|
||||
if this.CameraMode then
|
||||
this.CameraMode.SelectorFrame.Visible = visible
|
||||
this.CameraMode:SetInteractable(visible)
|
||||
end
|
||||
end
|
||||
|
||||
function setMovementModeVisible(visible)
|
||||
if this.MovementMode then
|
||||
this.MovementMode.SelectorFrame.Visible = visible
|
||||
this.MovementMode:SetInteractable(visible)
|
||||
end
|
||||
end
|
||||
|
||||
function setShiftLockVisible(visible)
|
||||
if this.ShiftLockMode then
|
||||
this.ShiftLockMode.SelectorFrame.Visible = visible
|
||||
this.ShiftLockMode:SetInteractable(visible)
|
||||
end
|
||||
end
|
||||
|
||||
do -- initial set of dev vs user choice for guis
|
||||
local isUserChoiceCamera = false
|
||||
if UserInputService.TouchEnabled then
|
||||
isUserChoiceCamera = LocalPlayer.DevTouchCameraMode == Enum.DevTouchCameraMovementMode.UserChoice
|
||||
else
|
||||
isUserChoiceCamera = LocalPlayer.DevComputerCameraMode == Enum.DevComputerCameraMovementMode.UserChoice
|
||||
end
|
||||
|
||||
if not isUserChoiceCamera then
|
||||
this.CameraModeOverrideText.Visible = true
|
||||
setCameraModeVisible(false)
|
||||
else
|
||||
this.CameraModeOverrideText.Visible = false
|
||||
setCameraModeVisible(true)
|
||||
end
|
||||
|
||||
|
||||
local isUserChoiceMovement = false
|
||||
if UserInputService.TouchEnabled then
|
||||
isUserChoiceMovement = LocalPlayer.DevTouchMovementMode == Enum.DevTouchMovementMode.UserChoice
|
||||
else
|
||||
isUserChoiceMovement = LocalPlayer.DevComputerMovementMode == Enum.DevComputerMovementMode.UserChoice
|
||||
end
|
||||
|
||||
if this.MovementModeOverrideText then
|
||||
if not isUserChoiceMovement then
|
||||
this.MovementModeOverrideText.Visible = true
|
||||
setMovementModeVisible(false)
|
||||
else
|
||||
this.MovementModeOverrideText.Visible = false
|
||||
setMovementModeVisible(true)
|
||||
end
|
||||
end
|
||||
|
||||
if this.ShiftLockOverrideText then
|
||||
this.ShiftLockOverrideText.Visible = not LocalPlayer.DevEnableMouseLock
|
||||
setShiftLockVisible(LocalPlayer.DevEnableMouseLock)
|
||||
end
|
||||
end
|
||||
|
||||
local function updateUserSettingsMenu(property)
|
||||
if this.ShiftLockOverrideText and property == "DevEnableMouseLock" then
|
||||
this.ShiftLockOverrideText.Visible = not LocalPlayer.DevEnableMouseLock
|
||||
setShiftLockVisible(LocalPlayer.DevEnableMouseLock)
|
||||
elseif property == "DevComputerCameraMode" then
|
||||
local isUserChoice = LocalPlayer.DevComputerCameraMode == Enum.DevComputerCameraMovementMode.UserChoice
|
||||
setCameraModeVisible(isUserChoice)
|
||||
this.CameraModeOverrideText.Visible = not isUserChoice
|
||||
elseif property == "DevComputerMovementMode" then
|
||||
local isUserChoice = LocalPlayer.DevComputerMovementMode == Enum.DevComputerMovementMode.UserChoice
|
||||
setMovementModeVisible(isUserChoice)
|
||||
if this.MovementModeOverrideText then
|
||||
this.MovementModeOverrideText.Visible = not isUserChoice
|
||||
end
|
||||
-- TOUCH
|
||||
elseif property == "DevTouchMovementMode" then
|
||||
local isUserChoice = LocalPlayer.DevTouchMovementMode == Enum.DevTouchMovementMode.UserChoice
|
||||
setMovementModeVisible(isUserChoice)
|
||||
if this.MovementModeOverrideText then
|
||||
this.MovementModeOverrideText.Visible = not isUserChoice
|
||||
end
|
||||
elseif property == "DevTouchCameraMode" then
|
||||
local isUserChoice = LocalPlayer.DevTouchCameraMode == Enum.DevTouchCameraMovementMode.UserChoice
|
||||
setCameraModeVisible(isUserChoice)
|
||||
this.CameraModeOverrideText.Visible = not isUserChoice
|
||||
end
|
||||
end
|
||||
|
||||
LocalPlayer.Changed:connect(function(property)
|
||||
if IsTouchClient then
|
||||
if TOUCH_CHANGED_PROPS[property] then
|
||||
updateUserSettingsMenu(property)
|
||||
end
|
||||
else
|
||||
if PC_CHANGED_PROPS[property] then
|
||||
updateUserSettingsMenu(property)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local function createVolumeOptions()
|
||||
local startVolumeLevel = math.floor(GameSettings.MasterVolume * 10)
|
||||
this.VolumeFrame,
|
||||
this.VolumeLabel,
|
||||
this.VolumeSlider = utility:AddNewRow(this, "Volume", "Slider", 10, startVolumeLevel)
|
||||
|
||||
local volumeSound = Instance.new("Sound", game.CoreGui.RobloxGui.Sounds)
|
||||
volumeSound.Name = "VolumeChangeSound"
|
||||
volumeSound.SoundId = "rbxasset://sounds/uuhhh.mp3"
|
||||
|
||||
this.VolumeSlider.ValueChanged:connect(function(newValue)
|
||||
local soundPercent = newValue/10
|
||||
volumeSound.Volume = soundPercent
|
||||
volumeSound:Play()
|
||||
GameSettings.MasterVolume = soundPercent
|
||||
end)
|
||||
end
|
||||
|
||||
local function createMouseOptions()
|
||||
local MouseSteps = 10
|
||||
local MinMouseSensitivity = 0.2
|
||||
|
||||
-- equations below map a function to include points (0, 0.2) (5, 1) (10, 4)
|
||||
-- where x is the slider position, y is the mouse sensitivity
|
||||
local function translateEngineMouseSensitivityToGui(engineSensitivity)
|
||||
return math.floor((2.0/3.0) * (math.sqrt(75.0 * engineSensitivity - 11.0) - 2))
|
||||
end
|
||||
|
||||
local function translateGuiMouseSensitivityToEngine(guiSensitivity)
|
||||
return 0.03 * math.pow(guiSensitivity,2) + (0.08 * guiSensitivity) + MinMouseSensitivity
|
||||
end
|
||||
|
||||
local startMouseLevel = translateEngineMouseSensitivityToGui(GameSettings.MouseSensitivity)
|
||||
|
||||
this.MouseSensitivityFrame,
|
||||
this.MouseSensitivityLabel,
|
||||
this.MouseSensitivitySlider = utility:AddNewRow(this, "Mouse Sensitivity", "Slider", MouseSteps, startMouseLevel)
|
||||
this.MouseSensitivitySlider:SetMinStep(1)
|
||||
|
||||
this.MouseSensitivitySlider.ValueChanged:connect(function(newValue)
|
||||
GameSettings.MouseSensitivity = translateGuiMouseSensitivityToEngine(newValue)
|
||||
end)
|
||||
end
|
||||
|
||||
local function createOverscanOption()
|
||||
local showOverscanScreen = function()
|
||||
|
||||
if not overscanScreen then
|
||||
local createOverscanFunc = require(RobloxGui.Modules.OverscanScreen)
|
||||
overscanScreen = createOverscanFunc(RobloxGui)
|
||||
overscanScreen:SetStyleForInGame()
|
||||
end
|
||||
|
||||
local MenuModule = require(RobloxGui.Modules.Settings.SettingsHub)
|
||||
MenuModule:SetVisibility(false, true)
|
||||
|
||||
local closedCon = nil
|
||||
closedCon = overscanScreen.Closed:connect(function()
|
||||
closedCon:disconnect()
|
||||
pcall(function() PlatformService.BlurIntensity = 0 end)
|
||||
ContextActionService:UnbindCoreAction("RbxStopOverscanMovement")
|
||||
MenuModule:SetVisibility(true, true)
|
||||
end)
|
||||
|
||||
pcall(function() PlatformService.BlurIntensity = 10 end)
|
||||
|
||||
local noOpFunc = function() end
|
||||
ContextActionService:BindCoreAction("RbxStopOverscanMovement", noOpFunc, false,
|
||||
Enum.UserInputType.Gamepad1, Enum.UserInputType.Gamepad2,
|
||||
Enum.UserInputType.Gamepad3, Enum.UserInputType.Gamepad4)
|
||||
|
||||
local ScreenManager = require(RobloxGui.Modules.ScreenManager)
|
||||
ScreenManager:OpenScreen(overscanScreen)
|
||||
|
||||
end
|
||||
|
||||
local adjustButton, adjustText, setButtonRowRef = utility:MakeStyledButton("AdjustButton", "Adjust", UDim2.new(0,300,1,-20), showOverscanScreen, this)
|
||||
adjustText.Font = Enum.Font.SourceSans
|
||||
adjustButton.Position = UDim2.new(1,-400,0,12)
|
||||
|
||||
local row = utility:AddNewRowObject(this, "Safe Zone", adjustButton)
|
||||
setButtonRowRef(row)
|
||||
end
|
||||
|
||||
createCameraModeOptions(not isTenFootInterface and
|
||||
(UserInputService.TouchEnabled or UserInputService.MouseEnabled or UserInputService.KeyboardEnabled))
|
||||
|
||||
if UserInputService.MouseEnabled then
|
||||
createMouseOptions()
|
||||
end
|
||||
|
||||
createVolumeOptions()
|
||||
|
||||
if platform == Enum.Platform.Windows or platform == Enum.Platform.OSX then
|
||||
createGraphicsOptions()
|
||||
end
|
||||
|
||||
if isTenFootInterface then
|
||||
createOverscanOption()
|
||||
end
|
||||
|
||||
------ TAB CUSTOMIZATION -------
|
||||
this.TabHeader.Name = "GameSettingsTab"
|
||||
|
||||
this.TabHeader.Icon.Image = "rbxasset://textures/ui/Settings/MenuBarIcons/GameSettingsTab.png"
|
||||
if utility:IsSmallTouchScreen() then
|
||||
this.TabHeader.Icon.Size = UDim2.new(0,34,0,34)
|
||||
this.TabHeader.Icon.Position = UDim2.new(this.TabHeader.Icon.Position.X.Scale,this.TabHeader.Icon.Position.X.Offset,0.5,-17)
|
||||
this.TabHeader.Size = UDim2.new(0,125,1,0)
|
||||
elseif isTenFootInterface then
|
||||
this.TabHeader.Icon.Image = "rbxasset://textures/ui/Settings/MenuBarIcons/GameSettingsTab@2x.png"
|
||||
this.TabHeader.Icon.Size = UDim2.new(0,90,0,90)
|
||||
this.TabHeader.Icon.Position = UDim2.new(0,0,0.5,-43)
|
||||
this.TabHeader.Size = UDim2.new(0,280,1,0)
|
||||
else
|
||||
this.TabHeader.Icon.Size = UDim2.new(0,45,0,45)
|
||||
this.TabHeader.Icon.Position = UDim2.new(0,15,0.5,-22)
|
||||
end
|
||||
|
||||
|
||||
this.TabHeader.Icon.Title.Text = "Settings"
|
||||
|
||||
------ PAGE CUSTOMIZATION -------
|
||||
this.Page.ZIndex = 5
|
||||
|
||||
return this
|
||||
end
|
||||
|
||||
|
||||
----------- Page Instantiation --------------
|
||||
|
||||
PageInstance = Initialize()
|
||||
|
||||
return PageInstance
|
||||
@@ -0,0 +1,489 @@
|
||||
--[[
|
||||
Filename: Help.lua
|
||||
Written by: jeditkacheff
|
||||
Version 1.0
|
||||
Description: Takes care of the help page in Settings Menu
|
||||
--]]
|
||||
-------------- CONSTANTS --------------
|
||||
local KEYBOARD_MOUSE_TAG = "KeyboardMouse"
|
||||
local TOUCH_TAG = "Touch"
|
||||
local GAMEPAD_TAG = "Gamepad"
|
||||
local PC_TABLE_SPACING = 4
|
||||
|
||||
-------------- SERVICES --------------
|
||||
local CoreGui = game:GetService("CoreGui")
|
||||
local RobloxGui = CoreGui:WaitForChild("RobloxGui")
|
||||
local UserInputService = game:GetService("UserInputService")
|
||||
local GuiService = game:GetService("GuiService")
|
||||
|
||||
----------- UTILITIES --------------
|
||||
local utility = require(RobloxGui.Modules.Settings.Utility)
|
||||
|
||||
------------ Variables -------------------
|
||||
local PageInstance = nil
|
||||
RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface")
|
||||
local isTenFootInterface = require(RobloxGui.Modules.TenFootInterface):IsEnabled()
|
||||
|
||||
----------- CLASS DECLARATION --------------
|
||||
|
||||
local function Initialize()
|
||||
local settingsPageFactory = require(RobloxGui.Modules.Settings.SettingsPageFactory)
|
||||
local this = settingsPageFactory:CreateNewPage()
|
||||
this.HelpPages = {}
|
||||
|
||||
-- TODO: Change dev console script to parent this to somewhere other than an engine created gui
|
||||
local ControlFrame = RobloxGui:WaitForChild('ControlFrame')
|
||||
local ToggleDevConsoleBindableFunc = ControlFrame:WaitForChild('ToggleDevConsole')
|
||||
local lastInputType = nil
|
||||
|
||||
function this:GetCurrentInputType()
|
||||
if lastInputType == nil then -- we don't know what controls the user has, just use reasonable defaults
|
||||
local platform = UserInputService:GetPlatform()
|
||||
if platform == Enum.Platform.XBoxOne or platform == Enum.Platform.WiiU then
|
||||
|
||||
return GAMEPAD_TAG
|
||||
elseif platform == Enum.Platform.Windows or platform == Enum.Platform.OSX then
|
||||
return KEYBOARD_MOUSE_TAG
|
||||
else
|
||||
return TOUCH_TAG
|
||||
end
|
||||
end
|
||||
|
||||
if lastInputType == Enum.UserInputType.Keyboard or lastInputType == Enum.UserInputType.MouseMovement or
|
||||
lastInputType == Enum.UserInputType.MouseButton1 or lastInputType == Enum.UserInputType.MouseButton2 or
|
||||
lastInputType == Enum.UserInputType.MouseButton3 or lastInputType == Enum.UserInputType.MouseWheel then
|
||||
return KEYBOARD_MOUSE_TAG
|
||||
elseif lastInputType == Enum.UserInputType.Touch then
|
||||
return TOUCH_TAG
|
||||
elseif lastInputType == Enum.UserInputType.Gamepad1 or lastInputType == Enum.UserInputType.Gamepad2 or
|
||||
inputType == Enum.UserInputType.Gamepad3 or lastInputType == Enum.UserInputType.Gamepad4 then
|
||||
return GAMEPAD_TAG
|
||||
end
|
||||
|
||||
return KEYBOARD_MOUSE_TAG
|
||||
end
|
||||
|
||||
|
||||
local function createPCHelp(parentFrame)
|
||||
local function createPCGroup(title, actionInputBindings)
|
||||
local textIndent = 9
|
||||
|
||||
local pcGroupFrame = utility:Create'Frame'
|
||||
{
|
||||
Size = UDim2.new(1/3,-PC_TABLE_SPACING,1,0),
|
||||
BackgroundTransparency = 1,
|
||||
Name = "PCGroupFrame" .. tostring(title)
|
||||
};
|
||||
local pcGroupTitle = utility:Create'TextLabel'
|
||||
{
|
||||
Position = UDim2.new(0,textIndent,0,0),
|
||||
Size = UDim2.new(1,-textIndent,0,30),
|
||||
BackgroundTransparency = 1,
|
||||
Text = title,
|
||||
Font = Enum.Font.SourceSansBold,
|
||||
FontSize = Enum.FontSize.Size18,
|
||||
TextColor3 = Color3.new(1,1,1),
|
||||
TextXAlignment = Enum.TextXAlignment.Left,
|
||||
Name = "PCGroupTitle" .. tostring(title),
|
||||
ZIndex = 2,
|
||||
Parent = pcGroupFrame
|
||||
};
|
||||
|
||||
local count = 0
|
||||
local frameHeight = 42
|
||||
local spacing = 2
|
||||
local offset = pcGroupTitle.Size.Y.Offset
|
||||
for i = 1, #actionInputBindings do
|
||||
for actionName, inputName in pairs(actionInputBindings[i]) do
|
||||
local actionInputFrame = utility:Create'Frame'
|
||||
{
|
||||
Size = UDim2.new(1,0,0,frameHeight),
|
||||
Position = UDim2.new(0,0,0, offset + ((frameHeight + spacing) * count)),
|
||||
BackgroundTransparency = 0.65,
|
||||
BorderSizePixel = 0,
|
||||
ZIndex = 2,
|
||||
Name = "ActionInputBinding" .. tostring(actionName),
|
||||
Parent = pcGroupFrame
|
||||
};
|
||||
|
||||
local nameLabel = utility:Create'TextLabel'
|
||||
{
|
||||
Size = UDim2.new(0.4,-textIndent,0,frameHeight),
|
||||
Position = UDim2.new(0,textIndent,0,0),
|
||||
BackgroundTransparency = 1,
|
||||
Text = actionName,
|
||||
Font = Enum.Font.SourceSansBold,
|
||||
FontSize = Enum.FontSize.Size18,
|
||||
TextColor3 = Color3.new(1,1,1),
|
||||
TextXAlignment = Enum.TextXAlignment.Left,
|
||||
Name = actionName .. "Label",
|
||||
ZIndex = 2,
|
||||
Parent = actionInputFrame
|
||||
};
|
||||
|
||||
local inputLabel = utility:Create'TextLabel'
|
||||
{
|
||||
Size = UDim2.new(0.6,0,0,frameHeight),
|
||||
Position = UDim2.new(0.5,-4,0,0),
|
||||
BackgroundTransparency = 1,
|
||||
Text = inputName,
|
||||
Font = Enum.Font.SourceSans,
|
||||
FontSize = Enum.FontSize.Size18,
|
||||
TextColor3 = Color3.new(1,1,1),
|
||||
TextXAlignment = Enum.TextXAlignment.Left,
|
||||
Name = inputName .. "Label",
|
||||
ZIndex = 2,
|
||||
Parent = actionInputFrame
|
||||
};
|
||||
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
|
||||
pcGroupFrame.Size = UDim2.new(pcGroupFrame.Size.X.Scale,pcGroupFrame.Size.X.Offset,
|
||||
0, offset + ((frameHeight + spacing) * count))
|
||||
|
||||
return pcGroupFrame
|
||||
end
|
||||
|
||||
local rowOffset = 50
|
||||
local isOSX = UserInputService:GetPlatform() == Enum.Platform.OSX
|
||||
|
||||
local charMoveFrame = createPCGroup( "Character Movement", {[1] = {["Move Forward"] = "W/Up Arrow"},
|
||||
[2] = {["Move Backward"] = "S/Down Arrow"},
|
||||
[3] = {["Move Left"] = "A/Left Arrow"},
|
||||
[4] = {["Move Right"] = "D/Right Arrow"},
|
||||
[5] = {["Jump"] = "Space"}} )
|
||||
charMoveFrame.Parent = parentFrame
|
||||
|
||||
local accessoriesFrame = createPCGroup("Accessories", { [1] = {["Equip Tools"] = "1,2,3..."},
|
||||
[2] = {["Unequip Tools"] = "1,2,3..."},
|
||||
[3] = {["Drop Tool"] = "Backspace"},
|
||||
[4] = {["Use Tool"] = "Left Mouse Button"},
|
||||
[5] = {["Drop Hats"] = "+"} })
|
||||
accessoriesFrame.Position = UDim2.new(1/3,PC_TABLE_SPACING,0,0)
|
||||
accessoriesFrame.Parent = parentFrame
|
||||
|
||||
local miscFrame = nil
|
||||
local hideHudSuccess, hideHudFlagValue = pcall(function() return settings():GetFFlag("AllowHideHudShortcut") end)
|
||||
if (hideHudSuccess and hideHudFlagValue) then
|
||||
miscFrame = createPCGroup("Misc", { [1] = {["Screenshot"] = "Print Screen"},
|
||||
[2] = {["Record Video"] = isOSX and "F12/fn + F12" or "F12"},
|
||||
[3] = {["Hide HUD"] = isOSX and "F7/fn + F7" or "F7"},
|
||||
[4] = {["Dev Console"] = isOSX and "F9/fn + F9" or "F9"},
|
||||
[5] = {["Mouselock"] = "Shift"},
|
||||
[6] = {["Graphics Level"] = isOSX and "F10/fn + F10" or "F10"},
|
||||
[7] = {["Fullscreen"] = isOSX and "F11/fn + F11" or "F11"} })
|
||||
else
|
||||
miscFrame = createPCGroup("Misc", { [1] = {["Screenshot"] = "Print Screen"},
|
||||
[2] = {["Record Video"] = isOSX and "F12/fn + F12" or "F12"},
|
||||
[3] = {["Dev Console"] = isOSX and "F9/fn + F9" or "F9"},
|
||||
[4] = {["Mouselock"] = "Shift"},
|
||||
[5] = {["Graphics Level"] = isOSX and "F10/fn + F10" or "F10"},
|
||||
[6] = {["Fullscreen"] = isOSX and "F11/fn + F11" or "F11"} })
|
||||
end
|
||||
miscFrame.Position = UDim2.new(2/3,PC_TABLE_SPACING * 2,0,0)
|
||||
miscFrame.Parent = parentFrame
|
||||
|
||||
local camFrame = createPCGroup("Camera Movement", { [1] = {["Rotate"] = "Right Mouse Button"},
|
||||
[2] = {["Zoom In/Out"] = "Mouse Wheel"},
|
||||
[3] = {["Zoom In"] = "I"},
|
||||
[4] = {["Zoom Out"] = "O"} })
|
||||
camFrame.Position = UDim2.new(0,0,charMoveFrame.Size.Y.Scale,charMoveFrame.Size.Y.Offset + rowOffset)
|
||||
camFrame.Parent = parentFrame
|
||||
|
||||
local menuFrame = createPCGroup("Menu Items", { [1] = {["ROBLOX Menu"] = "ESC"},
|
||||
[2] = {["Backpack"] = "~"},
|
||||
[3] = {["Playerlist"] = "TAB"},
|
||||
[4] = {["Chat"] = "/"} })
|
||||
menuFrame.Position = UDim2.new(1/3,PC_TABLE_SPACING,charMoveFrame.Size.Y.Scale,charMoveFrame.Size.Y.Offset + rowOffset)
|
||||
menuFrame.Parent = parentFrame
|
||||
|
||||
parentFrame.Size = UDim2.new(parentFrame.Size.X.Scale, parentFrame.Size.X.Offset, 0,
|
||||
menuFrame.Size.Y.Offset + menuFrame.Position.Y.Offset)
|
||||
end
|
||||
|
||||
local function createGamepadHelp(parentFrame)
|
||||
local gamepadImage = "rbxasset://textures/ui/Settings/Help/GenericController.png"
|
||||
local imageSize = UDim2.new(0,650,0,239)
|
||||
local imagePosition = UDim2.new(0.5,-imageSize.X.Offset/2,0.5,-imageSize.Y.Offset/2)
|
||||
if UserInputService:GetPlatform() == Enum.Platform.XBoxOne or UserInputService:GetPlatform() == Enum.Platform.XBox360 then
|
||||
gamepadImage = "rbxasset://textures/ui/Settings/Help/XboxController.png"
|
||||
imageSize = UDim2.new(0,1334,0,570)
|
||||
imagePosition = UDim2.new(0.5, (-imageSize.X.Offset/2) - 50, 0.5, -imageSize.Y.Offset/2)
|
||||
elseif UserInputService:GetPlatform() == Enum.Platform.PS4 or UserInputService:GetPlatform() == Enum.Platform.PS3 then
|
||||
gamepadImage = "rbxasset://textures/ui/Settings/Help/PSController.png"
|
||||
end
|
||||
|
||||
local gamepadImageLabel = utility:Create'ImageLabel'
|
||||
{
|
||||
Name = "GamepadImage",
|
||||
Size = imageSize,
|
||||
Position = imagePosition,
|
||||
Image = gamepadImage,
|
||||
BackgroundTransparency = 1,
|
||||
ZIndex = 2,
|
||||
Parent = parentFrame
|
||||
};
|
||||
parentFrame.Size = UDim2.new(parentFrame.Size.X.Scale, parentFrame.Size.X.Offset, 0, gamepadImageLabel.Size.Y.Offset + 100)
|
||||
|
||||
local gamepadFontSize = isTenFootInterface and Enum.FontSize.Size36 or Enum.FontSize.Size24
|
||||
local function createGamepadLabel(text, position, size)
|
||||
local nameLabel = utility:Create'TextLabel'
|
||||
{
|
||||
Position = position,
|
||||
Size = size,
|
||||
BackgroundTransparency = 1,
|
||||
Text = text,
|
||||
TextXAlignment = Enum.TextXAlignment.Left,
|
||||
Font = Enum.Font.SourceSansBold,
|
||||
FontSize = gamepadFontSize,
|
||||
TextColor3 = Color3.new(1,1,1),
|
||||
Name = text .. "Label",
|
||||
ZIndex = 2,
|
||||
Parent = gamepadImageLabel
|
||||
};
|
||||
end
|
||||
|
||||
local textVerticalSize = (gamepadFontSize == Enum.FontSize.Size36) and 36 or 24
|
||||
|
||||
if gamepadImage == "rbxasset://textures/ui/Settings/Help/XboxController.png" then
|
||||
createGamepadLabel("Switch Tool", UDim2.new(0,50,0,-textVerticalSize/2), UDim2.new(0,100,0,textVerticalSize))
|
||||
createGamepadLabel("Game Menu Toggle", UDim2.new(0,-38,0.15,-textVerticalSize/2), UDim2.new(0,164,0,textVerticalSize))
|
||||
createGamepadLabel("Move", UDim2.new(0,-80,0.31,-textVerticalSize/2), UDim2.new(0,46,0,textVerticalSize))
|
||||
createGamepadLabel("Menu Navigation", UDim2.new(0,-50,0.46,-textVerticalSize/2), UDim2.new(0,164,0,textVerticalSize))
|
||||
createGamepadLabel("Use Tool", UDim2.new(0.96,0,0,-textVerticalSize/2), UDim2.new(0,73,0,textVerticalSize))
|
||||
createGamepadLabel("ROBLOX Menu", UDim2.new(0.96,0,0.15,-textVerticalSize/2), UDim2.new(0,122,0,textVerticalSize))
|
||||
createGamepadLabel("Back", UDim2.new(0.96,0,0.31,-textVerticalSize/2), UDim2.new(0,43,0,textVerticalSize))
|
||||
createGamepadLabel("Jump", UDim2.new(0.96,0,0.46,-textVerticalSize/2), UDim2.new(0,49,0,textVerticalSize))
|
||||
createGamepadLabel("Rotate Camera", UDim2.new(1,0,0.62,-textVerticalSize/2), UDim2.new(0,132,0,textVerticalSize))
|
||||
createGamepadLabel("Camera Zoom", UDim2.new(1,0,0.77,-textVerticalSize/2), UDim2.new(0,122,0,textVerticalSize))
|
||||
else
|
||||
createGamepadLabel("Switch Tool", UDim2.new(-0.01,0,0,-textVerticalSize/2), UDim2.new(0,100,0,textVerticalSize))
|
||||
createGamepadLabel("Game Menu Toggle", UDim2.new(-0.11,0,0.15,-textVerticalSize/2), UDim2.new(0,164,0,textVerticalSize))
|
||||
createGamepadLabel("Move", UDim2.new(-0.08,0,0.31,-textVerticalSize/2), UDim2.new(0,46,0,textVerticalSize))
|
||||
createGamepadLabel("Menu Navigation", UDim2.new(-0.125,0,0.46,-textVerticalSize/2), UDim2.new(0,164,0,textVerticalSize))
|
||||
createGamepadLabel("Use Tool", UDim2.new(0.96,0,0,-textVerticalSize/2), UDim2.new(0,73,0,textVerticalSize))
|
||||
createGamepadLabel("ROBLOX Menu", UDim2.new(0.9,0,0.15,-textVerticalSize/2), UDim2.new(0,122,0,textVerticalSize))
|
||||
createGamepadLabel("Back", UDim2.new(1.01,0,0.31,-textVerticalSize/2), UDim2.new(0,43,0,textVerticalSize))
|
||||
createGamepadLabel("Jump", UDim2.new(0.91,0,0.46,-textVerticalSize/2), UDim2.new(0,49,0,textVerticalSize))
|
||||
createGamepadLabel("Rotate Camera", UDim2.new(0.91,0,0.62,-textVerticalSize/2), UDim2.new(0,132,0,textVerticalSize))
|
||||
createGamepadLabel("Camera Zoom", UDim2.new(0.91,0,0.77,-textVerticalSize/2), UDim2.new(0,122,0,textVerticalSize))
|
||||
end
|
||||
|
||||
|
||||
-- todo: turn on dev console button when dev console is ready
|
||||
--[[local openDevConsoleFunc = function()
|
||||
this.HubRef:SetVisibility(false)
|
||||
ToggleDevConsoleBindableFunc:Invoke()
|
||||
end
|
||||
local devConsoleButton = utility:MakeStyledButton("ConsoleButton", " Toggle Dev Console", UDim2.new(0,300,0,44), openDevConsoleFunc)
|
||||
devConsoleButton.Size = UDim2.new(devConsoleButton.Size.X.Scale, devConsoleButton.Size.X.Offset, 0, 60)
|
||||
devConsoleButton.Position = UDim2.new(1,-300,1,30)
|
||||
if UserInputService.GamepadEnabled and not UserInputService.TouchEnabled and not UserInputService.MouseEnabled and not UserInputService.KeyboardEnabled then
|
||||
devConsoleButton.ImageTransparency = 1
|
||||
end
|
||||
devConsoleButton.Parent = gamepadImageLabel
|
||||
local aButtonImage = utility:Create'ImageLabel'
|
||||
{
|
||||
Name = "AButtonImage",
|
||||
Size = UDim2.new(0,55,0,55),
|
||||
Position = UDim2.new(0,5,0.5,-28),
|
||||
Image = "rbxasset://textures/ui/Settings/Help/AButtonDark.png",
|
||||
BackgroundTransparency = 1,
|
||||
ZIndex = 2,
|
||||
Parent = devConsoleButton
|
||||
};
|
||||
|
||||
this:AddRow(nil, nil, devConsoleButton, 340)]]
|
||||
end
|
||||
|
||||
local function createTouchHelp(parentFrame)
|
||||
local smallScreen = utility:IsSmallTouchScreen()
|
||||
local ySize = GuiService:GetScreenResolution().y - 350
|
||||
if smallScreen then
|
||||
ySize = GuiService:GetScreenResolution().y - 100
|
||||
end
|
||||
parentFrame.Size = UDim2.new(1,0,0,ySize)
|
||||
|
||||
local function createTouchLabel(text, position, size, parent)
|
||||
local nameLabel = utility:Create'TextLabel'
|
||||
{
|
||||
Position = position,
|
||||
Size = size,
|
||||
BackgroundTransparency = 1,
|
||||
Text = text,
|
||||
Font = Enum.Font.SourceSansBold,
|
||||
FontSize = Enum.FontSize.Size14,
|
||||
TextColor3 = Color3.new(1,1,1),
|
||||
Name = text .. "Label",
|
||||
ZIndex = 2,
|
||||
Parent = parent
|
||||
};
|
||||
if not smallScreen then
|
||||
nameLabel.FontSize = Enum.FontSize.Size18
|
||||
nameLabel.Size = UDim2.new(nameLabel.Size.X.Scale, nameLabel.Size.X.Offset, nameLabel.Size.Y.Scale, nameLabel.Size.Y.Offset + 4)
|
||||
end
|
||||
local nameBackgroundImage = utility:Create'ImageLabel'
|
||||
{
|
||||
Name = text .. "BackgroundImage",
|
||||
Size = UDim2.new(1,0,1,0),
|
||||
Position = UDim2.new(0,0,0,2),
|
||||
BackgroundTransparency = 1,
|
||||
Image = "rbxasset://textures/ui/Settings/Radial/RadialLabel.png",
|
||||
ScaleType = Enum.ScaleType.Slice,
|
||||
SliceCenter = Rect.new(12,2,65,21),
|
||||
ZIndex = 2,
|
||||
Parent = nameLabel
|
||||
};
|
||||
|
||||
return nameLabel
|
||||
end
|
||||
|
||||
local function createTouchGestureImage(name, image, position, size, parent)
|
||||
local gestureImage = utility:Create'ImageLabel'
|
||||
{
|
||||
Name = name,
|
||||
Size = size,
|
||||
Position = position,
|
||||
BackgroundTransparency = 1,
|
||||
Image = image,
|
||||
ZIndex = 2,
|
||||
Parent = parent
|
||||
};
|
||||
|
||||
return gestureImage
|
||||
end
|
||||
|
||||
local xSizeOffset = 30
|
||||
local ySize = 25
|
||||
if smallScreen then xSizeOffset = 0 end
|
||||
|
||||
local moveLabel = createTouchLabel("Move", UDim2.new(0.06,0,0.58,0), UDim2.new(0,77 + xSizeOffset,0,ySize), parentFrame)
|
||||
if not smallScreen then moveLabel.Position = UDim2.new(-0.03,0,0.7,0) end
|
||||
local jumpLabel = createTouchLabel("Jump", UDim2.new(0.8,0,0.58,0), UDim2.new(0,77 + xSizeOffset,0,ySize), parentFrame)
|
||||
if not smallScreen then jumpLabel.Position = UDim2.new(0.85,0,0.7,0) end
|
||||
local equipLabel = createTouchLabel("Equip/Unequip Tools", UDim2.new(0.5,-60,0.64,0), UDim2.new(0,120 + xSizeOffset,0,ySize), parentFrame)
|
||||
if not smallScreen then equipLabel.Position = UDim2.new(0.5,-60,0.95,0) end
|
||||
|
||||
local zoomLabel = createTouchLabel("Zoom In/Out", UDim2.new(0.15,-60,0.02,0), UDim2.new(0,120,0,ySize), parentFrame)
|
||||
createTouchGestureImage("ZoomImage", "rbxasset://textures/ui/Settings/Help/ZoomGesture.png", UDim2.new(0.5,-26,1,3), UDim2.new(0,53,0,59), zoomLabel)
|
||||
local rotateLabel = createTouchLabel("Rotate Camera", UDim2.new(0.5,-60,0.02,0), UDim2.new(0,120,0,ySize), parentFrame)
|
||||
createTouchGestureImage("RotateImage", "rbxasset://textures/ui/Settings/Help/RotateCameraGesture.png", UDim2.new(0.5,-32,1,3), UDim2.new(0,65,0,48), rotateLabel)
|
||||
local useToolLabel = createTouchLabel("Use Tool", UDim2.new(0.85,-60,0.02,0), UDim2.new(0,120,0,ySize), parentFrame)
|
||||
createTouchGestureImage("ToolImage", "rbxasset://textures/ui/Settings/Help/UseToolGesture.png", UDim2.new(0.5,-19,1,3), UDim2.new(0,38,0,52), useToolLabel)
|
||||
|
||||
end
|
||||
|
||||
local function createHelpDisplay(typeOfHelp)
|
||||
local helpFrame = utility:Create'Frame'
|
||||
{
|
||||
Size = UDim2.new(1,0,1,0),
|
||||
BackgroundTransparency = 1,
|
||||
Name = "HelpFrame" .. tostring(typeOfHelp)
|
||||
};
|
||||
|
||||
if typeOfHelp == KEYBOARD_MOUSE_TAG then
|
||||
createPCHelp(helpFrame)
|
||||
elseif typeOfHelp == GAMEPAD_TAG then
|
||||
createGamepadHelp(helpFrame)
|
||||
elseif typeOfHelp == TOUCH_TAG then
|
||||
createTouchHelp(helpFrame)
|
||||
end
|
||||
|
||||
return helpFrame
|
||||
end
|
||||
|
||||
local function displayHelp(currentPage)
|
||||
for i, helpPage in pairs(this.HelpPages) do
|
||||
if helpPage == currentPage then
|
||||
helpPage.Parent = this.Page
|
||||
this.Page.Size = helpPage.Size
|
||||
else
|
||||
helpPage.Parent = nil
|
||||
end
|
||||
end
|
||||
if UserInputService:GetPlatform() == Enum.Platform.XBoxOne then
|
||||
this.HubRef.PageViewClipper.ClipsDescendants = false
|
||||
this.HubRef.PageView.ClipsDescendants = false
|
||||
end
|
||||
end
|
||||
|
||||
local function switchToHelp(typeOfHelp)
|
||||
local helpPage = this.HelpPages[typeOfHelp]
|
||||
if helpPage then
|
||||
displayHelp(helpPage)
|
||||
else
|
||||
this.HelpPages[typeOfHelp] = createHelpDisplay(typeOfHelp)
|
||||
switchToHelp(typeOfHelp)
|
||||
end
|
||||
end
|
||||
|
||||
local function showTypeOfHelp()
|
||||
switchToHelp(this:GetCurrentInputType())
|
||||
end
|
||||
|
||||
------ TAB CUSTOMIZATION -------
|
||||
this.TabHeader.Name = "HelpTab"
|
||||
|
||||
this.TabHeader.Icon.Image = "rbxasset://textures/ui/Settings/MenuBarIcons/HelpTab.png"
|
||||
|
||||
if utility:IsSmallTouchScreen() then
|
||||
this.TabHeader.Icon.Size = UDim2.new(0,33,0,33)
|
||||
this.TabHeader.Icon.Position = UDim2.new(this.TabHeader.Icon.Position.X.Scale,this.TabHeader.Icon.Position.X.Offset,0.5,-16)
|
||||
this.TabHeader.Size = UDim2.new(0,100,1,0)
|
||||
elseif isTenFootInterface then
|
||||
this.TabHeader.Icon.Image = "rbxasset://textures/ui/Settings/MenuBarIcons/HelpTab@2x.png"
|
||||
this.TabHeader.Icon.Size = UDim2.new(0,90,0,90)
|
||||
this.TabHeader.Icon.Position = UDim2.new(0,0,0.5,-43)
|
||||
this.TabHeader.Size = UDim2.new(0,210,1,0)
|
||||
else
|
||||
this.TabHeader.Icon.Size = UDim2.new(0,44,0,44)
|
||||
this.TabHeader.Icon.Position = UDim2.new(this.TabHeader.Icon.Position.X.Scale,this.TabHeader.Icon.Position.X.Offset,0.5,-22)
|
||||
this.TabHeader.Size = UDim2.new(0,130,1,0)
|
||||
end
|
||||
|
||||
this.TabHeader.Icon.Title.Text = "Help"
|
||||
|
||||
|
||||
------ PAGE CUSTOMIZATION -------
|
||||
this.Page.Name = "Help"
|
||||
|
||||
UserInputService.InputBegan:connect(function(inputObject)
|
||||
local inputType = inputObject.UserInputType
|
||||
if inputType ~= Enum.UserInputType.Focus and inputType ~= Enum.UserInputType.None then
|
||||
lastInputType = inputObject.UserInputType
|
||||
showTypeOfHelp()
|
||||
end
|
||||
end)
|
||||
|
||||
return this
|
||||
end
|
||||
|
||||
|
||||
----------- Public Facing API Additions --------------
|
||||
do
|
||||
PageInstance = Initialize()
|
||||
|
||||
PageInstance.Displayed.Event:connect(function()
|
||||
if PageInstance:GetCurrentInputType() == TOUCH_TAG then
|
||||
if PageInstance.HubRef.BottomButtonFrame and not utility:IsSmallTouchScreen() then
|
||||
PageInstance.HubRef.BottomButtonFrame.Visible = false
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
PageInstance.Hidden.Event:connect(function()
|
||||
PageInstance.HubRef.PageViewClipper.ClipsDescendants = true
|
||||
PageInstance.HubRef.PageView.ClipsDescendants = true
|
||||
|
||||
PageInstance.HubRef:ShowShield()
|
||||
|
||||
if PageInstance:GetCurrentInputType() == TOUCH_TAG then
|
||||
PageInstance.HubRef.BottomButtonFrame.Visible = true
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
return PageInstance
|
||||
@@ -0,0 +1,83 @@
|
||||
--[[
|
||||
Filename: Home.lua
|
||||
Written by: jeditkacheff
|
||||
Version 1.0
|
||||
Description: Takes care of the home page in Settings Menu
|
||||
--]]
|
||||
|
||||
local BUTTON_OFFSET = 20
|
||||
local BUTTON_SPACING = 10
|
||||
|
||||
-------------- SERVICES --------------
|
||||
local CoreGui = game:GetService("CoreGui")
|
||||
local RobloxGui = CoreGui:WaitForChild("RobloxGui")
|
||||
local GuiService = game:GetService("GuiService")
|
||||
|
||||
----------- UTILITIES --------------
|
||||
local utility = require(RobloxGui.Modules.Settings.Utility)
|
||||
|
||||
------------ Variables -------------------
|
||||
local PageInstance = nil
|
||||
|
||||
----------- CLASS DECLARATION --------------
|
||||
|
||||
local function Initialize()
|
||||
local settingsPageFactory = require(RobloxGui.Modules.Settings.SettingsPageFactory)
|
||||
local this = settingsPageFactory:CreateNewPage()
|
||||
|
||||
------ TAB CUSTOMIZATION -------
|
||||
this.TabHeader.Name = "HomeTab"
|
||||
|
||||
this.TabHeader.Icon.Image = "rbxasset://textures/ui/Settings/MenuBarIcons/HomeTab.png"
|
||||
this.TabHeader.Icon.Size = UDim2.new(0,32,0,30)
|
||||
this.TabHeader.Icon.Position = UDim2.new(0,5,0.5,-15)
|
||||
|
||||
this.TabHeader.Icon.Title.Text = "Home"
|
||||
|
||||
this.TabHeader.Size = UDim2.new(0,100,1,0)
|
||||
|
||||
------ PAGE CUSTOMIZATION -------
|
||||
this.Page.Name = "Home"
|
||||
local resumeGameFunc = function()
|
||||
this.HubRef:SetVisibility(false)
|
||||
end
|
||||
|
||||
this.ResumeButton = utility:MakeStyledButton("ResumeButton", "Resume Game", UDim2.new(0, 200, 0, 50), resumeGameFunc)
|
||||
this.ResumeButton.Position = UDim2.new(0.5,-100,0,BUTTON_OFFSET)
|
||||
this.ResumeButton.Parent = this.Page
|
||||
|
||||
local resetFunc = function()
|
||||
this.HubRef:SwitchToPage(this.HubRef.ResetCharacterPage, false, 1)
|
||||
end
|
||||
|
||||
local resetButton = utility:MakeStyledButton("ResetButton", "Reset Character", UDim2.new(0, 200, 0, 50), resetFunc)
|
||||
resetButton.Position = UDim2.new(0.5,-100,0,this.ResumeButton.AbsolutePosition.Y + this.ResumeButton.AbsoluteSize.Y + BUTTON_SPACING)
|
||||
resetButton.Parent = this.Page
|
||||
|
||||
local leaveGameFunc = function()
|
||||
this.HubRef:SwitchToPage(this.HubRef.LeaveGamePage, false, 1)
|
||||
end
|
||||
|
||||
local leaveButton = utility:MakeStyledButton("LeaveButton", "Leave Game", UDim2.new(0, 200, 0, 50), leaveGameFunc)
|
||||
leaveButton.Position = UDim2.new(0.5,-100,0,resetButton.AbsolutePosition.Y + resetButton.AbsoluteSize.Y + BUTTON_SPACING)
|
||||
leaveButton.Parent = this.Page
|
||||
|
||||
this.Page.Size = UDim2.new(1,0,0,leaveButton.AbsolutePosition.Y + leaveButton.AbsoluteSize.Y)
|
||||
|
||||
return this
|
||||
end
|
||||
|
||||
|
||||
----------- Public Facing API Additions --------------
|
||||
do
|
||||
PageInstance = Initialize()
|
||||
|
||||
PageInstance.Displayed.Event:connect(function()
|
||||
if not utility:UsesSelectedObject() then return end
|
||||
|
||||
GuiService.SelectedCoreObject = PageInstance.ResumeButton
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
return PageInstance
|
||||
@@ -0,0 +1,124 @@
|
||||
--[[
|
||||
Filename: LeaveGame.lua
|
||||
Written by: jeditkacheff
|
||||
Version 1.0
|
||||
Description: Takes care of the leave game in Settings Menu
|
||||
--]]
|
||||
|
||||
|
||||
-------------- CONSTANTS -------------
|
||||
local LEAVE_GAME_ACTION = "LeaveGameCancelAction"
|
||||
|
||||
-------------- SERVICES --------------
|
||||
local CoreGui = game:GetService("CoreGui")
|
||||
local ContextActionService = game:GetService("ContextActionService")
|
||||
local RobloxGui = CoreGui:WaitForChild("RobloxGui")
|
||||
local GuiService = game:GetService("GuiService")
|
||||
|
||||
----------- UTILITIES --------------
|
||||
local utility = require(RobloxGui.Modules.Settings.Utility)
|
||||
|
||||
------------ Variables -------------------
|
||||
local PageInstance = nil
|
||||
RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface")
|
||||
local isTenFootInterface = require(RobloxGui.Modules.TenFootInterface):IsEnabled()
|
||||
|
||||
|
||||
----------- CLASS DECLARATION --------------
|
||||
|
||||
local function Initialize()
|
||||
local settingsPageFactory = require(RobloxGui.Modules.Settings.SettingsPageFactory)
|
||||
local this = settingsPageFactory:CreateNewPage()
|
||||
|
||||
this.DontLeaveFunc = function(isUsingGamepad)
|
||||
if this.HubRef then
|
||||
this.HubRef:PopMenu(isUsingGamepad, true)
|
||||
end
|
||||
end
|
||||
this.DontLeaveFromHotkey = function(name, state, input)
|
||||
if state == Enum.UserInputState.Begin then
|
||||
local isUsingGamepad = input.UserInputType == Enum.UserInputType.Gamepad1 or input.UserInputType == Enum.UserInputType.Gamepad2
|
||||
or input.UserInputType == Enum.UserInputType.Gamepad3 or input.UserInputType == Enum.UserInputType.Gamepad4
|
||||
|
||||
this.DontLeaveFunc(isUsingGamepad)
|
||||
end
|
||||
end
|
||||
this.DontLeaveFromButton = function(isUsingGamepad)
|
||||
this.DontLeaveFunc(isUsingGamepad)
|
||||
end
|
||||
|
||||
------ TAB CUSTOMIZATION -------
|
||||
this.TabHeader = nil -- no tab for this page
|
||||
|
||||
------ PAGE CUSTOMIZATION -------
|
||||
this.Page.Name = "LeaveGamePage"
|
||||
|
||||
local leaveGameText = utility:Create'TextLabel'
|
||||
{
|
||||
Name = "LeaveGameText",
|
||||
Text = "Are you sure you want to leave the game?",
|
||||
Font = Enum.Font.SourceSansBold,
|
||||
FontSize = Enum.FontSize.Size36,
|
||||
TextColor3 = Color3.new(1,1,1),
|
||||
BackgroundTransparency = 1,
|
||||
Size = UDim2.new(1,0,0,200),
|
||||
TextWrapped = true,
|
||||
ZIndex = 2,
|
||||
Parent = this.Page
|
||||
};
|
||||
if utility:IsSmallTouchScreen() then
|
||||
leaveGameText.FontSize = Enum.FontSize.Size24
|
||||
leaveGameText.Size = UDim2.new(1,0,0,100)
|
||||
elseif isTenFootInterface then
|
||||
leaveGameText.FontSize = Enum.FontSize.Size48
|
||||
end
|
||||
|
||||
local buttonSpacing = 20
|
||||
local buttonSize = UDim2.new(0, 200, 0, 50)
|
||||
if isTenFootInterface then
|
||||
leaveGameText.Position = UDim2.new(0,0,0,100)
|
||||
buttonSize = UDim2.new(0, 300, 0, 80)
|
||||
end
|
||||
|
||||
this.LeaveGameButton = utility:MakeStyledButton("LeaveGame", "Leave", buttonSize)
|
||||
this.LeaveGameButton.NextSelectionRight = nil
|
||||
this.LeaveGameButton:SetVerb("Exit")
|
||||
if utility:IsSmallTouchScreen() then
|
||||
this.LeaveGameButton.Position = UDim2.new(0.5, -buttonSize.X.Offset - buttonSpacing, 1, 0)
|
||||
else
|
||||
this.LeaveGameButton.Position = UDim2.new(0.5, -buttonSize.X.Offset - buttonSpacing, 1, -30)
|
||||
end
|
||||
this.LeaveGameButton.Parent = leaveGameText
|
||||
|
||||
|
||||
------------- Init ----------------------------------
|
||||
|
||||
local dontleaveGameButton = utility:MakeStyledButton("DontLeaveGame", "Don't Leave", buttonSize, this.DontLeaveFromButton)
|
||||
dontleaveGameButton.NextSelectionLeft = nil
|
||||
if utility:IsSmallTouchScreen() then
|
||||
dontleaveGameButton.Position = UDim2.new(0.5, buttonSpacing, 1, 0)
|
||||
else
|
||||
dontleaveGameButton.Position = UDim2.new(0.5, buttonSpacing, 1, -30)
|
||||
end
|
||||
dontleaveGameButton.Parent = leaveGameText
|
||||
|
||||
this.Page.Size = UDim2.new(1,0,0,dontleaveGameButton.AbsolutePosition.Y + dontleaveGameButton.AbsoluteSize.Y)
|
||||
|
||||
return this
|
||||
end
|
||||
|
||||
|
||||
----------- Public Facing API Additions --------------
|
||||
PageInstance = Initialize()
|
||||
|
||||
PageInstance.Displayed.Event:connect(function()
|
||||
GuiService.SelectedCoreObject = PageInstance.LeaveGameButton
|
||||
ContextActionService:BindCoreAction(LEAVE_GAME_ACTION, PageInstance.DontLeaveFromHotkey, false, Enum.KeyCode.ButtonB)
|
||||
end)
|
||||
|
||||
PageInstance.Hidden.Event:connect(function()
|
||||
ContextActionService:UnbindCoreAction(LEAVE_GAME_ACTION)
|
||||
end)
|
||||
|
||||
|
||||
return PageInstance
|
||||
@@ -0,0 +1,307 @@
|
||||
--[[
|
||||
Filename: Players.lua
|
||||
Written by: Stickmasterluke
|
||||
Version 1.0
|
||||
Description: Player list inside escape menu, with friend adding functionality.
|
||||
--]]
|
||||
-------------- SERVICES --------------
|
||||
local CoreGui = game:GetService("CoreGui")
|
||||
local RobloxGui = CoreGui:WaitForChild("RobloxGui")
|
||||
local GuiService = game:GetService("GuiService")
|
||||
local PlayersService = game:GetService('Players')
|
||||
local HttpService = game:GetService('HttpService')
|
||||
local HttpRbxApiService = game:GetService('HttpRbxApiService')
|
||||
local UserInputService = game:GetService('UserInputService')
|
||||
local Settings = UserSettings()
|
||||
local GameSettings = Settings.GameSettings
|
||||
|
||||
----------- UTILITIES --------------
|
||||
RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface")
|
||||
local utility = require(RobloxGui.Modules.Settings.Utility)
|
||||
local isTenFootInterface = require(RobloxGui.Modules.TenFootInterface):IsEnabled()
|
||||
|
||||
------------ Constants -------------------
|
||||
local frameDefaultTransparency = .85
|
||||
local frameSelectedTransparency = .65
|
||||
|
||||
------------ Variables -------------------
|
||||
local PageInstance = nil
|
||||
local localPlayer = PlayersService.LocalPlayer
|
||||
|
||||
----------- CLASS DECLARATION --------------
|
||||
local function Initialize()
|
||||
local settingsPageFactory = require(RobloxGui.Modules.Settings.SettingsPageFactory)
|
||||
local this = settingsPageFactory:CreateNewPage()
|
||||
|
||||
local playerLabelFakeSelection = Instance.new('ImageLabel')
|
||||
playerLabelFakeSelection.BackgroundTransparency = 1
|
||||
--[[playerLabelFakeSelection.Image = 'rbxasset://textures/ui/SelectionBox.png'
|
||||
playerLabelFakeSelection.ScaleType = 'Slice'
|
||||
playerLabelFakeSelection.SliceCenter = Rect.new(31,31,31,31)]]
|
||||
playerLabelFakeSelection.Image = ''
|
||||
playerLabelFakeSelection.Size = UDim2.new(0,0,0,0)
|
||||
|
||||
------ TAB CUSTOMIZATION -------
|
||||
this.TabHeader.Name = "PlayersTab"
|
||||
|
||||
this.TabHeader.Icon.Image = "rbxasset://textures/ui/Settings/MenuBarIcons/PlayersTabIcon.png"
|
||||
if utility:IsSmallTouchScreen() then
|
||||
this.TabHeader.Icon.Size = UDim2.new(0,34,0,28)
|
||||
this.TabHeader.Icon.Position = UDim2.new(this.TabHeader.Icon.Position.X.Scale,this.TabHeader.Icon.Position.X.Offset,0.5,-14)
|
||||
this.TabHeader.Size = UDim2.new(0,115,1,0)
|
||||
elseif isTenFootInterface then
|
||||
this.TabHeader.Icon.Image = "rbxasset://textures/ui/Settings/MenuBarIcons/PlayersTabIcon@2x.png"
|
||||
this.TabHeader.Icon.Size = UDim2.new(0,88,0,74)
|
||||
this.TabHeader.Icon.Position = UDim2.new(0,0,0.5,-43)
|
||||
this.TabHeader.Size = UDim2.new(0,280,1,0)
|
||||
else
|
||||
this.TabHeader.Icon.Size = UDim2.new(0,44,0,37)
|
||||
this.TabHeader.Icon.Position = UDim2.new(0,15,0.5,-18) -- -22
|
||||
this.TabHeader.Size = UDim2.new(0,150,1,0)
|
||||
end
|
||||
|
||||
this.TabHeader.Icon.Title.Text = "Players"
|
||||
|
||||
----- FRIENDSHIP FUNCTIONS ------
|
||||
local function getFriendStatus(selectedPlayer)
|
||||
if selectedPlayer == localPlayer then
|
||||
return Enum.FriendStatus.NotFriend
|
||||
else
|
||||
local success, result = pcall(function()
|
||||
-- NOTE: Core script only
|
||||
return localPlayer:GetFriendStatus(selectedPlayer)
|
||||
end)
|
||||
if success then
|
||||
return result
|
||||
else
|
||||
return Enum.FriendStatus.NotFriend
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
------ PAGE CUSTOMIZATION -------
|
||||
this.Page.Name = "Players"
|
||||
|
||||
local selectionFound = nil
|
||||
local function friendStatusCreate(playerLabel, player)
|
||||
if playerLabel then
|
||||
-- remove any previous friend status labels
|
||||
for _, item in pairs(playerLabel:GetChildren()) do
|
||||
if item and item.Name == 'FriendStatus' then
|
||||
if GuiService.SelectedCoreObject == item then
|
||||
selectionFound = nil
|
||||
GuiService.SelectedCoreObject = nil
|
||||
end
|
||||
item:Destroy()
|
||||
end
|
||||
end
|
||||
|
||||
-- create new friend status label
|
||||
local status = nil
|
||||
if player and player ~= localPlayer and player.userId > 1 and localPlayer.userId > 1 then
|
||||
status = getFriendStatus(player)
|
||||
end
|
||||
|
||||
local friendLabel = nil
|
||||
local friendLabelText = nil
|
||||
if not status then
|
||||
friendLabel = Instance.new('TextButton')
|
||||
friendLabel.Text = ''
|
||||
friendLabel.BackgroundTransparency = 1
|
||||
friendLabel.Position = UDim2.new(1,-198,0,7)
|
||||
elseif status == Enum.FriendStatus.Friend then
|
||||
friendLabel = Instance.new('TextButton')
|
||||
friendLabel.Text = 'Friend'
|
||||
friendLabel.BackgroundTransparency = 1
|
||||
friendLabel.FontSize = 'Size24'
|
||||
friendLabel.Font = 'SourceSans'
|
||||
friendLabel.TextColor3 = Color3.new(1,1,1)
|
||||
friendLabel.Position = UDim2.new(1,-198,0,7)
|
||||
elseif status == Enum.FriendStatus.Unknown or status == Enum.FriendStatus.NotFriend or status == Enum.FriendStatus.FriendRequestReceived then
|
||||
local addFriendFunc = function()
|
||||
if friendLabel and friendLabelText and friendLabelText.Text ~= '' then
|
||||
friendLabel.ImageTransparency = 1
|
||||
friendLabelText.Text = ''
|
||||
if localPlayer and player then
|
||||
localPlayer:RequestFriendship(player)
|
||||
end
|
||||
end
|
||||
end
|
||||
local friendLabel2, friendLabelText2 = utility:MakeStyledButton("FriendStatus", "Add Friend", UDim2.new(0, 182, 0, 46), addFriendFunc)
|
||||
friendLabel = friendLabel2
|
||||
friendLabelText = friendLabelText2
|
||||
friendLabelText.ZIndex = 3
|
||||
friendLabelText.Position = friendLabelText.Position + UDim2.new(0,0,0,1)
|
||||
friendLabel.Position = UDim2.new(1,-198,0,7)
|
||||
elseif status == Enum.FriendStatus.FriendRequestSent then
|
||||
friendLabel = Instance.new('TextButton')
|
||||
friendLabel.Text = 'Request Sent'
|
||||
friendLabel.BackgroundTransparency = 1
|
||||
friendLabel.FontSize = 'Size24'
|
||||
friendLabel.Font = 'SourceSans'
|
||||
friendLabel.TextColor3 = Color3.new(1,1,1)
|
||||
friendLabel.Position = UDim2.new(1,-198,0,7)
|
||||
end
|
||||
|
||||
if friendLabel then
|
||||
friendLabel.Name = 'FriendStatus'
|
||||
friendLabel.Size = UDim2.new(0,182,0,46)
|
||||
friendLabel.ZIndex = 3
|
||||
friendLabel.Parent = playerLabel
|
||||
friendLabel.SelectionImageObject = playerLabelFakeSelection
|
||||
|
||||
local updateHighlight = function()
|
||||
if playerLabel then
|
||||
playerLabel.ImageTransparency = friendLabel and GuiService.SelectedCoreObject == friendLabel and frameSelectedTransparency or frameDefaultTransparency
|
||||
end
|
||||
end
|
||||
friendLabel.SelectionGained:connect(updateHighlight)
|
||||
friendLabel.SelectionLost:connect(updateHighlight)
|
||||
|
||||
if UserInputService.GamepadEnabled and not selectionFound then
|
||||
selectionFound = true
|
||||
local fakeSize = 20
|
||||
playerLabelFakeSelection.Size = UDim2.new(0,playerLabel.AbsoluteSize.X+fakeSize,0,playerLabel.AbsoluteSize.Y+fakeSize)
|
||||
playerLabelFakeSelection.Position = UDim2.new(0, -(playerLabel.AbsoluteSize.X-198)-fakeSize*.5, 0, -8-fakeSize*.5)
|
||||
GuiService.SelectedCoreObject = friendLabel
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
localPlayer.FriendStatusChanged:connect(function(player, friendStatus)
|
||||
if player then
|
||||
local playerLabel = this.Page:FindFirstChild('PlayerLabel'..player.Name)
|
||||
if playerLabel then
|
||||
friendStatusCreate(playerLabel, player)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
if utility:IsSmallTouchScreen() then
|
||||
local spaceFor3Buttons = RobloxGui.AbsoluteSize.x >= 720 -- else there is only space for 2
|
||||
|
||||
local resetFunc = function()
|
||||
this.HubRef:SwitchToPage(this.HubRef.ResetCharacterPage, false, 1)
|
||||
end
|
||||
local resetButton, resetLabel = utility:MakeStyledButton("ResetButton", "Reset Character", UDim2.new(0, 200, 0, 62), resetFunc)
|
||||
resetLabel.Size = UDim2.new(1, 0, 1, -6)
|
||||
resetLabel.FontSize = Enum.FontSize.Size24
|
||||
resetButton.Position = UDim2.new(0.5,spaceFor3Buttons and -340 or -220,0,14)
|
||||
resetButton.Parent = this.Page
|
||||
|
||||
local leaveGameFunc = function()
|
||||
this.HubRef:SwitchToPage(this.HubRef.LeaveGamePage, false, 1)
|
||||
end
|
||||
local leaveButton, leaveLabel = utility:MakeStyledButton("LeaveButton", "Leave Game", UDim2.new(0, 200, 0, 62), leaveGameFunc)
|
||||
leaveLabel.Size = UDim2.new(1, 0, 1, -6)
|
||||
leaveLabel.FontSize = Enum.FontSize.Size24
|
||||
leaveButton.Position = UDim2.new(0.5,spaceFor3Buttons and -100 or 20,0,14)
|
||||
leaveButton.Parent = this.Page
|
||||
|
||||
if spaceFor3Buttons then
|
||||
local resumeGameFunc = function()
|
||||
this.HubRef:SetVisibility(false)
|
||||
end
|
||||
resumeButton, resumeLabel = utility:MakeStyledButton("ResumeButton", "Resume Game", UDim2.new(0, 200, 0, 62), resumeGameFunc)
|
||||
resumeLabel.Size = UDim2.new(1, 0, 1, -6)
|
||||
resumeLabel.FontSize = Enum.FontSize.Size24
|
||||
resumeButton.Position = UDim2.new(0.5,140,0,14)
|
||||
resumeButton.Parent = this.Page
|
||||
end
|
||||
end
|
||||
|
||||
local existingPlayerLabels = {}
|
||||
this.Displayed.Event:connect(function(switchedFromGamepadInput)
|
||||
local sortedPlayers = PlayersService:GetPlayers()
|
||||
table.sort(sortedPlayers,function(item1,item2)
|
||||
return item1.Name < item2.Name
|
||||
end)
|
||||
|
||||
local extraOffset = 20
|
||||
if utility:IsSmallTouchScreen() then
|
||||
extraOffset = 85
|
||||
end
|
||||
|
||||
selectionFound = nil
|
||||
|
||||
|
||||
-- iterate through players to reuse or create labels for players
|
||||
for index=1, #sortedPlayers do
|
||||
local player = sortedPlayers[index]
|
||||
local frame = existingPlayerLabels[index]
|
||||
if player then
|
||||
-- create label (frame) for this player index if one does not exist
|
||||
if not frame or not frame.Parent then
|
||||
frame = Instance.new('ImageLabel')
|
||||
frame.Image = "rbxasset://textures/ui/dialog_white.png"
|
||||
frame.ScaleType = 'Slice'
|
||||
frame.SliceCenter = Rect.new(10,10,10,10)
|
||||
frame.Size = UDim2.new(1,0,0,60)
|
||||
frame.Position = UDim2.new(0,0,0,(index-1)*80 + extraOffset)
|
||||
frame.BackgroundTransparency = 1
|
||||
frame.ZIndex = 2
|
||||
|
||||
local icon = Instance.new('ImageLabel')
|
||||
icon.Name = 'Icon'
|
||||
icon.BackgroundTransparency = 1
|
||||
icon.Size = UDim2.new(0,36,0,36)
|
||||
icon.Position = UDim2.new(0,12,0,12)
|
||||
icon.ZIndex = 3
|
||||
icon.Parent = frame
|
||||
|
||||
local nameLabel = Instance.new('TextLabel')
|
||||
nameLabel.Name = 'NameLabel'
|
||||
nameLabel.TextXAlignment = Enum.TextXAlignment.Left
|
||||
nameLabel.Font = 'SourceSans'
|
||||
nameLabel.FontSize = 'Size24'
|
||||
nameLabel.TextColor3 = Color3.new(1,1,1)
|
||||
nameLabel.BackgroundTransparency = 1
|
||||
nameLabel.Position = UDim2.new(0,60,.5,0)
|
||||
nameLabel.Size = UDim2.new(0,0,0,0)
|
||||
nameLabel.ZIndex = 3
|
||||
nameLabel.Parent = frame
|
||||
|
||||
frame.MouseEnter:connect(function()
|
||||
frame.ImageTransparency = frameSelectedTransparency
|
||||
end)
|
||||
frame.MouseLeave:connect(function()
|
||||
frame.ImageTransparency = frameDefaultTransparency
|
||||
end)
|
||||
|
||||
frame.Parent = this.Page
|
||||
table.insert(existingPlayerLabels, index, frame)
|
||||
end
|
||||
frame.Name = 'PlayerLabel'..player.Name
|
||||
frame.Icon.Image = 'http://www.watrbx.wtf/Thumbs/Avatar.ashx?x=100&y=100&userId='..math.max(1, player.userId)
|
||||
frame.NameLabel.Text = player.Name
|
||||
frame.ImageTransparency = frameDefaultTransparency
|
||||
|
||||
friendStatusCreate(frame, player)
|
||||
end
|
||||
end
|
||||
|
||||
-- iterate through existing labels in reverse to destroy and remove unused labels
|
||||
for index=#existingPlayerLabels, 1, -1 do
|
||||
local player = sortedPlayers[index]
|
||||
local frame = existingPlayerLabels[index]
|
||||
if frame and not player then
|
||||
table.remove(existingPlayerLabels, i)
|
||||
frame:Destroy()
|
||||
end
|
||||
end
|
||||
|
||||
this.Page.Size = UDim2.new(1,0,0, extraOffset + 80 * #sortedPlayers - 5)
|
||||
end)
|
||||
|
||||
return this
|
||||
end
|
||||
|
||||
|
||||
----------- Public Facing API Additions --------------
|
||||
PageInstance = Initialize()
|
||||
|
||||
return PageInstance
|
||||
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
--[[r
|
||||
Filename: Record.lua
|
||||
Written by: jeditkacheff
|
||||
Version 1.0
|
||||
Description: Takes care of the Record Tab in Settings Menu
|
||||
--]]
|
||||
-------------- SERVICES --------------
|
||||
local CoreGui = game:GetService("CoreGui")
|
||||
local RobloxGui = CoreGui:WaitForChild("RobloxGui")
|
||||
local GuiService = game:GetService("GuiService")
|
||||
local Settings = UserSettings()
|
||||
local GameSettings = Settings.GameSettings
|
||||
|
||||
----------- UTILITIES --------------
|
||||
RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface")
|
||||
local utility = require(RobloxGui.Modules.Settings.Utility)
|
||||
local isTenFootInterface = require(RobloxGui.Modules.TenFootInterface):IsEnabled()
|
||||
|
||||
------------ Variables -------------------
|
||||
local PageInstance = nil
|
||||
|
||||
----------- CLASS DECLARATION --------------
|
||||
|
||||
local function Initialize()
|
||||
local settingsPageFactory = require(RobloxGui.Modules.Settings.SettingsPageFactory)
|
||||
local this = settingsPageFactory:CreateNewPage()
|
||||
local isRecordingVideo = false
|
||||
|
||||
local recordingEvent = Instance.new("BindableEvent")
|
||||
recordingEvent.Name = "RecordingEvent"
|
||||
this.RecordingChanged = recordingEvent.Event
|
||||
function this:IsRecording()
|
||||
return isRecordingVideo
|
||||
end
|
||||
|
||||
------ TAB CUSTOMIZATION -------
|
||||
this.TabHeader.Name = "RecordTab"
|
||||
|
||||
this.TabHeader.Icon.Image = "rbxasset://textures/ui/Settings/MenuBarIcons/RecordTab.png"
|
||||
this.TabHeader.Icon.Size = UDim2.new(0,41,0,40)
|
||||
this.TabHeader.Icon.Position = UDim2.new(0,5,0.5,-20)
|
||||
|
||||
this.TabHeader.Icon.Title.Text = "Record"
|
||||
|
||||
this.TabHeader.Size = UDim2.new(0,130,1,0)
|
||||
|
||||
|
||||
------ PAGE CUSTOMIZATION -------
|
||||
this.Page.Name = "Record"
|
||||
|
||||
local function makeTextLabel(name, text, bold, size, pos, parent)
|
||||
local textLabel = utility:Create'TextLabel'
|
||||
{
|
||||
Name = name,
|
||||
BackgroundTransparency = 1,
|
||||
Text = text,
|
||||
TextWrapped = true,
|
||||
Font = Enum.Font.SourceSans,
|
||||
FontSize = Enum.FontSize.Size24,
|
||||
TextColor3 = Color3.new(1,1,1),
|
||||
Size = size,
|
||||
Position = pos,
|
||||
TextXAlignment = Enum.TextXAlignment.Left,
|
||||
TextYAlignment = Enum.TextYAlignment.Top,
|
||||
ZIndex = 2,
|
||||
Parent = parent
|
||||
};
|
||||
if bold then textLabel.Font = Enum.Font.SourceSansBold end
|
||||
|
||||
return textLabel
|
||||
end
|
||||
|
||||
-- need to override this function from SettingsPageFactory
|
||||
-- DropDown menus require hub to to be set when they are initialized
|
||||
function this:SetHub(newHubRef)
|
||||
this.HubRef = newHubRef
|
||||
|
||||
local recordEnumNames = {}
|
||||
recordEnumNames[1] = "Save To Disk"
|
||||
recordEnumNames[2] = "Upload to YouTube"
|
||||
|
||||
local startSetting = 2
|
||||
if GameSettings.VideoUploadPromptBehavior == Enum.UploadSetting["Never"] then
|
||||
startSetting = 1
|
||||
end
|
||||
|
||||
---------------------------------- SCREENSHOT -------------------------------------
|
||||
local screenshotTitle = makeTextLabel("ScreenshotTitle",
|
||||
"Screenshot",
|
||||
true, UDim2.new(1,0,0,36), UDim2.new(0,10,0.05,0), this.Page)
|
||||
screenshotTitle.FontSize = Enum.FontSize.Size36
|
||||
|
||||
local screenshotBody = makeTextLabel("ScreenshotBody",
|
||||
"By clicking the 'Take Screenshot' button, the menu will close and take a screenshot and save it to your computer.",
|
||||
false, UDim2.new(1,-10,0,70), UDim2.new(0,0,1,0), screenshotTitle)
|
||||
|
||||
local closeSettingsFunc = function()
|
||||
this.HubRef:SetVisibility(false, true)
|
||||
end
|
||||
this.ScreenshotButton = utility:MakeStyledButton("ScreenshotButton", "Take Screenshot", UDim2.new(0,300,0,44), closeSettingsFunc, this)
|
||||
|
||||
this.ScreenshotButton.Position = UDim2.new(0,400,1,0)
|
||||
this.ScreenshotButton.Parent = screenshotBody
|
||||
|
||||
|
||||
---------------------------------- VIDEO -------------------------------------
|
||||
local videoTitle = makeTextLabel("VideoTitle",
|
||||
"Video",
|
||||
true, UDim2.new(1,0,0,36), UDim2.new(0,10,0.5,0), this.Page)
|
||||
videoTitle.FontSize = Enum.FontSize.Size36
|
||||
|
||||
local videoBody = makeTextLabel("VideoBody",
|
||||
"By clicking the 'Record Video' button, the menu will close and start recording your screen.",
|
||||
false, UDim2.new(1,-10,0,70), UDim2.new(0,0,1,0), videoTitle)
|
||||
|
||||
this.VideoSettingsFrame,
|
||||
this.VideoSettingsLabel,
|
||||
this.VideoSettingsMode = utility:AddNewRow(this, "Video Settings", "Selector", recordEnumNames, startSetting, 270)
|
||||
|
||||
this.VideoSettingsMode.IndexChanged:connect(function(newIndex)
|
||||
if newIndex == 1 then
|
||||
GameSettings.VideoUploadPromptBehavior = Enum.UploadSetting.Never
|
||||
elseif newIndex == 2 then
|
||||
GameSettings.VideoUploadPromptBehavior = Enum.UploadSetting.Always
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
local recordButton = utility:MakeStyledButton("RecordButton", "Record Video", UDim2.new(0,300,0,44), closeSettingsFunc, this)
|
||||
|
||||
recordButton.Position = UDim2.new(0,410,1,10)
|
||||
recordButton.Parent = this.VideoSettingsMode.SelectorFrame.Parent
|
||||
recordButton.MouseButton1Click:connect(function()
|
||||
recordingEvent:Fire(not isRecordingVideo)
|
||||
end)
|
||||
|
||||
local gameOptions = settings():FindFirstChild("Game Options")
|
||||
if gameOptions then
|
||||
gameOptions.VideoRecordingChangeRequest:connect(function(recording)
|
||||
isRecordingVideo = recording
|
||||
if recording then
|
||||
recordButton.RecordButtonTextLabel.Text = "Stop Recording"
|
||||
else
|
||||
recordButton.RecordButtonTextLabel.Text = "Record Video"
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
recordButton:SetVerb("RecordToggle")
|
||||
this.ScreenshotButton:SetVerb("Screenshot")
|
||||
|
||||
this.Page.Size = UDim2.new(1,0,0,400)
|
||||
end
|
||||
|
||||
return this
|
||||
end
|
||||
|
||||
|
||||
----------- Public Facing API Additions --------------
|
||||
PageInstance = Initialize()
|
||||
|
||||
PageInstance.Displayed.Event:connect(function(switchedFromGamepadInput)
|
||||
if switchedFromGamepadInput then
|
||||
GuiService.SelectedCoreObject = PageInstance.ScreenshotButton
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
return PageInstance
|
||||
@@ -0,0 +1,284 @@
|
||||
--[[
|
||||
Filename: ReportAbuseMenu.lua
|
||||
Written by: jeditkacheff
|
||||
Version 1.0
|
||||
Description: Takes care of the report abuse page in Settings Menu
|
||||
--]]
|
||||
|
||||
-------------- SERVICES --------------
|
||||
local CoreGui = game:GetService("CoreGui")
|
||||
local RobloxGui = CoreGui:WaitForChild("RobloxGui")
|
||||
local GuiService = game:GetService("GuiService")
|
||||
local PlayersService = game:GetService("Players")
|
||||
|
||||
----------- UTILITIES --------------
|
||||
local utility = require(RobloxGui.Modules.Settings.Utility)
|
||||
|
||||
------------ CONSTANTS -------------------
|
||||
local ABUSE_TYPES_PLAYER = {
|
||||
"Swearing",
|
||||
"Inappropriate Username",
|
||||
"Bullying",
|
||||
"Scamming",
|
||||
"Dating",
|
||||
"Cheating/Exploiting",
|
||||
"Personal Question",
|
||||
"Offsite Links",
|
||||
}
|
||||
|
||||
local ABUSE_TYPES_GAME = {
|
||||
"Inappropriate Content",
|
||||
"Bad Model or Script",
|
||||
"Offsite Link",
|
||||
}
|
||||
local DEFAULT_ABUSE_DESC_TEXT = " Short Description (Optional)"
|
||||
if utility:IsSmallTouchScreen() then
|
||||
DEFAULT_ABUSE_DESC_TEXT = " (Optional)"
|
||||
end
|
||||
|
||||
------------ VARIABLES -------------------
|
||||
local PageInstance = nil
|
||||
|
||||
----------- CLASS DECLARATION --------------
|
||||
local function Initialize()
|
||||
local settingsPageFactory = require(RobloxGui.Modules.Settings.SettingsPageFactory)
|
||||
local this = settingsPageFactory:CreateNewPage()
|
||||
|
||||
local playerNames = {}
|
||||
local nameToRbxPlayer = {}
|
||||
|
||||
function this:GetPlayerFromIndex(index)
|
||||
local playerName = playerNames[index]
|
||||
if playerName then
|
||||
return nameToRbxPlayer[nameToRbxPlayer]
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
function this:UpdatePlayerDropDown()
|
||||
playerNames = {}
|
||||
nameToRbxPlayer = {}
|
||||
|
||||
local players = PlayersService:GetPlayers()
|
||||
local index = 1
|
||||
for i = 1, #players do
|
||||
local player = players[i]
|
||||
if player ~= PlayersService.LocalPlayer and player.UserId > 0 then
|
||||
playerNames[index] = player.Name
|
||||
nameToRbxPlayer[player.Name] = player
|
||||
index = index + 1
|
||||
end
|
||||
end
|
||||
|
||||
this.WhichPlayerMode:UpdateDropDownList(playerNames)
|
||||
|
||||
if index == 1 then
|
||||
this.GameOrPlayerMode:SetSelectionIndex(1)
|
||||
this.TypeOfAbuseMode:UpdateDropDownList(ABUSE_TYPES_GAME)
|
||||
end
|
||||
|
||||
this.WhichPlayerMode:SetInteractable(index > 1 and this.GameOrPlayerMode.CurrentIndex ~= 1)
|
||||
this.GameOrPlayerMode:SetInteractable(index > 1)
|
||||
end
|
||||
|
||||
------ TAB CUSTOMIZATION -------
|
||||
this.TabHeader.Name = "ReportAbuseTab"
|
||||
|
||||
this.TabHeader.Icon.Image = "rbxasset://textures/ui/Settings/MenuBarIcons/ReportAbuseTab.png"
|
||||
if utility:IsSmallTouchScreen() then
|
||||
this.TabHeader.Icon.Size = UDim2.new(0,27,0,32)
|
||||
this.TabHeader.Size = UDim2.new(0,120,1,0)
|
||||
else
|
||||
this.TabHeader.Size = UDim2.new(0,150,1,0)
|
||||
this.TabHeader.Icon.Size = UDim2.new(0,36,0,43)
|
||||
end
|
||||
this.TabHeader.Icon.Position = UDim2.new(this.TabHeader.Icon.Position.X.Scale, this.TabHeader.Icon.Position.X.Offset + 10, 0.5,-this.TabHeader.Icon.Size.Y.Offset/2)
|
||||
|
||||
this.TabHeader.Icon.Title.Text = "Report"
|
||||
|
||||
------ PAGE CUSTOMIZATION -------
|
||||
this.Page.Name = "ReportAbusePage"
|
||||
|
||||
-- need to override this function from SettingsPageFactory
|
||||
-- DropDown menus require hub to to be set when they are initialized
|
||||
function this:SetHub(newHubRef)
|
||||
this.HubRef = newHubRef
|
||||
|
||||
if utility:IsSmallTouchScreen() then
|
||||
this.GameOrPlayerFrame,
|
||||
this.GameOrPlayerLabel,
|
||||
this.GameOrPlayerMode = utility:AddNewRow(this, "Game or Player?", "Selector", {"Game", "Player"}, 1)
|
||||
else
|
||||
this.GameOrPlayerFrame,
|
||||
this.GameOrPlayerLabel,
|
||||
this.GameOrPlayerMode = utility:AddNewRow(this, "Game or Player?", "Selector", {"Game", "Player"}, 1, 3)
|
||||
end
|
||||
|
||||
this.WhichPlayerFrame,
|
||||
this.WhichPlayerLabel,
|
||||
this.WhichPlayerMode = utility:AddNewRow(this, "Which Player?", "DropDown", {"update me"})
|
||||
this.WhichPlayerMode:SetInteractable(false)
|
||||
this.WhichPlayerLabel.ZIndex = 1
|
||||
|
||||
this.TypeOfAbuseFrame,
|
||||
this.TypeOfAbuseLabel,
|
||||
this.TypeOfAbuseMode = utility:AddNewRow(this, "Type Of Abuse", "DropDown", ABUSE_TYPES_GAME)
|
||||
|
||||
if utility:IsSmallTouchScreen() then
|
||||
this.AbuseDescriptionFrame,
|
||||
this.AbuseDescriptionLabel,
|
||||
this.AbuseDescription = utility:AddNewRow(this, DEFAULT_ABUSE_DESC_TEXT, "TextBox", nil, nil)
|
||||
else
|
||||
this.AbuseDescriptionFrame,
|
||||
this.AbuseDescriptionLabel,
|
||||
this.AbuseDescription = utility:AddNewRow(this, DEFAULT_ABUSE_DESC_TEXT, "TextBox", nil, nil, 5)
|
||||
end
|
||||
|
||||
if utility:IsSmallTouchScreen() then
|
||||
this.AbuseDescription.Selection.Size = UDim2.new(0, 290, 0, 30)
|
||||
this.AbuseDescription.Selection.Position = UDim2.new(1,-345,this.AbuseDescription.Selection.Position.Y.Scale, this.AbuseDescription.Selection.Position.Y.Offset)
|
||||
|
||||
this.AbuseDescriptionLabel = this.TypeOfAbuseLabel:clone()
|
||||
this.AbuseDescriptionLabel.Text = "Abuse Description"
|
||||
this.AbuseDescriptionLabel.Position = UDim2.new(this.AbuseDescriptionLabel.Position.X.Scale, this.AbuseDescriptionLabel.Position.X.Offset,
|
||||
0,50)
|
||||
this.AbuseDescriptionLabel.Parent = this.Page
|
||||
end
|
||||
|
||||
local SelectionOverrideObject = utility:Create'ImageLabel'
|
||||
{
|
||||
Image = "",
|
||||
BackgroundTransparency = 1
|
||||
};
|
||||
|
||||
local submitButton, submitText = nil, nil
|
||||
|
||||
local function makeSubmitButtonActive()
|
||||
submitButton.ZIndex = 2
|
||||
submitButton.Selectable = true
|
||||
submitText.ZIndex = 2
|
||||
end
|
||||
|
||||
local function makeSubmitButtonInactive()
|
||||
submitButton.ZIndex = 1
|
||||
submitButton.Selectable = false
|
||||
submitText.ZIndex = 1
|
||||
end
|
||||
|
||||
local function updateAbuseDropDown()
|
||||
this.WhichPlayerMode:ResetSelectionIndex()
|
||||
this.TypeOfAbuseMode:ResetSelectionIndex()
|
||||
|
||||
if this.GameOrPlayerMode.CurrentIndex == 1 then
|
||||
this.TypeOfAbuseMode:UpdateDropDownList(ABUSE_TYPES_GAME)
|
||||
this.WhichPlayerMode:SetInteractable(false)
|
||||
this.WhichPlayerLabel.ZIndex = 1
|
||||
this.GameOrPlayerMode.SelectorFrame.NextSelectionDown = this.TypeOfAbuseMode.DropDownFrame
|
||||
else
|
||||
this.TypeOfAbuseMode:UpdateDropDownList(ABUSE_TYPES_PLAYER)
|
||||
this.WhichPlayerMode:SetInteractable(true)
|
||||
this.WhichPlayerLabel.ZIndex = 2
|
||||
this.GameOrPlayerMode.SelectorFrame.NextSelectionDown = this.WhichPlayerMode.DropDownFrame
|
||||
end
|
||||
makeSubmitButtonInactive()
|
||||
end
|
||||
|
||||
local function cleanupReportAbuseMenu()
|
||||
updateAbuseDropDown()
|
||||
this.AbuseDescription.Selection.Text = DEFAULT_ABUSE_DESC_TEXT
|
||||
this.HubRef:SetVisibility(false, true)
|
||||
end
|
||||
|
||||
local function onReportSubmitted()
|
||||
local abuseReason = nil
|
||||
if this.GameOrPlayerMode.CurrentIndex == 2 then
|
||||
abuseReason = ABUSE_TYPES_PLAYER[this.TypeOfAbuseMode.CurrentIndex]
|
||||
|
||||
local currentAbusingPlayer = this:GetPlayerFromIndex(this.WhichPlayerMode.CurrentIndex)
|
||||
if currentAbusingPlayer and abuseReason then
|
||||
spawn(function()
|
||||
game.Players:ReportAbuse(currentAbusingPlayer, abuseReason, this.AbuseDescription.Selection.Text)
|
||||
end)
|
||||
end
|
||||
else
|
||||
abuseReason = ABUSE_TYPES_GAME[this.TypeOfAbuseMode.CurrentIndex]
|
||||
if abuseReason then
|
||||
spawn(function()
|
||||
game.Players:ReportAbuse(nil, abuseReason, this.AbuseDescription.Selection.Text)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
if abuseReason then
|
||||
local alertText = "Thanks for your report! Our moderators will review the chat logs and evaluate what happened."
|
||||
|
||||
if abuseReason == 'Cheating/Exploiting' then
|
||||
alertText = "Thanks for your report! We've recorded your report for evaluation."
|
||||
elseif abuseReason == 'Inappropriate Username' then
|
||||
alertText = "Thanks for your report! Our moderators will evaluate the username."
|
||||
elseif abuseReason == "Bad Model or Script" or abuseReason == "Inappropriate Content" or abuseReason == "Offsite Link" or abuseReason == "Offsite Links" then
|
||||
alertText = "Thanks for your report! Our moderators will review the place and make a determination."
|
||||
end
|
||||
|
||||
utility:ShowAlert(alertText, "Ok", this.HubRef, cleanupReportAbuseMenu)
|
||||
|
||||
this.LastSelectedObject = nil
|
||||
end
|
||||
end
|
||||
|
||||
submitButton, submitText = utility:MakeStyledButton("SubmitButton", "Submit", UDim2.new(0,198,0,50), onReportSubmitted, this)
|
||||
if utility:IsSmallTouchScreen() then
|
||||
submitButton.Position = UDim2.new(1,-220,1,5)
|
||||
else
|
||||
submitButton.Position = UDim2.new(1,-194,1,5)
|
||||
end
|
||||
submitButton.Selectable = false
|
||||
submitButton.ZIndex = 1
|
||||
submitText.ZIndex = 1
|
||||
submitButton.Parent = this.AbuseDescription.Selection
|
||||
|
||||
local function playerSelectionChanged(newIndex)
|
||||
if newIndex ~= nil and this.TypeOfAbuseMode:GetSelectedIndex() ~= nil then
|
||||
makeSubmitButtonActive()
|
||||
else
|
||||
makeSubmitButtonInactive()
|
||||
end
|
||||
end
|
||||
this.WhichPlayerMode.IndexChanged:connect(playerSelectionChanged)
|
||||
|
||||
local function typeOfAbuseChanged(newIndex)
|
||||
if newIndex ~= nil then
|
||||
if this.GameOrPlayerMode.CurrentIndex == 1 or this.WhichPlayerMode:GetSelectedIndex() ~= nil then
|
||||
makeSubmitButtonActive()
|
||||
else
|
||||
makeSubmitButtonInactive()
|
||||
end
|
||||
else
|
||||
makeSubmitButtonInactive()
|
||||
end
|
||||
end
|
||||
this.TypeOfAbuseMode.IndexChanged:connect(typeOfAbuseChanged)
|
||||
|
||||
this.GameOrPlayerMode.IndexChanged:connect(updateAbuseDropDown)
|
||||
|
||||
this:AddRow(nil, nil, this.AbuseDescription)
|
||||
|
||||
this.Page.Size = UDim2.new(1,0,0,submitButton.AbsolutePosition.Y + submitButton.AbsoluteSize.Y)
|
||||
end
|
||||
|
||||
return this
|
||||
end
|
||||
|
||||
|
||||
----------- Public Facing API Additions --------------
|
||||
do
|
||||
PageInstance = Initialize()
|
||||
|
||||
PageInstance.Displayed.Event:connect(function()
|
||||
PageInstance:UpdatePlayerDropDown()
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
return PageInstance
|
||||
@@ -0,0 +1,138 @@
|
||||
--[[
|
||||
Filename: ResetCharacter.lua
|
||||
Written by: jeditkacheff
|
||||
Version 1.0
|
||||
Description: Takes care of the reseting the character in Settings Menu
|
||||
--]]
|
||||
|
||||
-------------- CONSTANTS -------------
|
||||
local RESET_CHARACTER_GAME_ACTION = "ResetCharacterAction"
|
||||
|
||||
-------------- SERVICES --------------
|
||||
local CoreGui = game:GetService("CoreGui")
|
||||
local ContextActionService = game:GetService("ContextActionService")
|
||||
local RobloxGui = CoreGui:WaitForChild("RobloxGui")
|
||||
local GuiService = game:GetService("GuiService")
|
||||
local PlayersService = game:GetService("Players")
|
||||
|
||||
----------- UTILITIES --------------
|
||||
local utility = require(RobloxGui.Modules.Settings.Utility)
|
||||
|
||||
------------ Variables -------------------
|
||||
local PageInstance = nil
|
||||
RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface")
|
||||
local isTenFootInterface = require(RobloxGui.Modules.TenFootInterface):IsEnabled()
|
||||
|
||||
----------- CLASS DECLARATION --------------
|
||||
|
||||
local function Initialize()
|
||||
local settingsPageFactory = require(RobloxGui.Modules.Settings.SettingsPageFactory)
|
||||
local this = settingsPageFactory:CreateNewPage()
|
||||
|
||||
this.DontResetCharFunc = function(isUsingGamepad)
|
||||
if this.HubRef then
|
||||
this.HubRef:PopMenu(isUsingGamepad, true)
|
||||
end
|
||||
end
|
||||
this.DontResetCharFromHotkey = function(name, state, input)
|
||||
if state == Enum.UserInputState.Begin then
|
||||
local isUsingGamepad = input.UserInputType == Enum.UserInputType.Gamepad1 or input.UserInputType == Enum.UserInputType.Gamepad2
|
||||
or input.UserInputType == Enum.UserInputType.Gamepad3 or input.UserInputType == Enum.UserInputType.Gamepad4
|
||||
|
||||
this.DontResetCharFunc(isUsingGamepad)
|
||||
end
|
||||
end
|
||||
this.DontResetCharFromButton = function(isUsingGamepad)
|
||||
this.DontResetCharFunc(isUsingGamepad)
|
||||
end
|
||||
|
||||
------ TAB CUSTOMIZATION -------
|
||||
this.TabHeader = nil -- no tab for this page
|
||||
|
||||
------ PAGE CUSTOMIZATION -------
|
||||
this.Page.Name = "ResetCharacter"
|
||||
|
||||
local resetCharacterText = utility:Create'TextLabel'
|
||||
{
|
||||
Name = "ResetCharacterText",
|
||||
Text = "Are you sure you want to reset your character?",
|
||||
Font = Enum.Font.SourceSansBold,
|
||||
FontSize = Enum.FontSize.Size36,
|
||||
TextColor3 = Color3.new(1,1,1),
|
||||
BackgroundTransparency = 1,
|
||||
Size = UDim2.new(1,0,0,200),
|
||||
TextWrapped = true,
|
||||
ZIndex = 2,
|
||||
Parent = this.Page
|
||||
};
|
||||
if utility:IsSmallTouchScreen() then
|
||||
resetCharacterText.FontSize = Enum.FontSize.Size24
|
||||
resetCharacterText.Size = UDim2.new(1,0,0,100)
|
||||
elseif isTenFootInterface then
|
||||
resetCharacterText.FontSize = Enum.FontSize.Size48
|
||||
end
|
||||
|
||||
------ Init -------
|
||||
local resetCharFunc = function()
|
||||
local player = PlayersService.LocalPlayer
|
||||
if player then
|
||||
local character = player.Character
|
||||
if character then
|
||||
local humanoid = character:FindFirstChild('Humanoid')
|
||||
if humanoid then
|
||||
humanoid.Health = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if this.HubRef then
|
||||
this.HubRef:SetVisibility(false, true)
|
||||
end
|
||||
end
|
||||
|
||||
local buttonSpacing = 20
|
||||
local buttonSize = UDim2.new(0, 200, 0, 50)
|
||||
if isTenFootInterface then
|
||||
resetCharacterText.Position = UDim2.new(0,0,0,100)
|
||||
buttonSize = UDim2.new(0, 300, 0, 80)
|
||||
end
|
||||
|
||||
this.ResetCharacterButton = utility:MakeStyledButton("ResetCharacter", "Reset", buttonSize, resetCharFunc)
|
||||
this.ResetCharacterButton.NextSelectionRight = nil
|
||||
if utility:IsSmallTouchScreen() then
|
||||
this.ResetCharacterButton.Position = UDim2.new(0.5, -buttonSize.X.Offset - buttonSpacing, 1, 0)
|
||||
else
|
||||
this.ResetCharacterButton.Position = UDim2.new(0.5, -buttonSize.X.Offset - buttonSpacing, 1, -30)
|
||||
end
|
||||
this.ResetCharacterButton.Parent = resetCharacterText
|
||||
|
||||
|
||||
local dontResetCharacterButton = utility:MakeStyledButton("DontResetCharacter", "Don't Reset", buttonSize, this.DontResetCharFromButton)
|
||||
dontResetCharacterButton.NextSelectionLeft = nil
|
||||
if utility:IsSmallTouchScreen() then
|
||||
dontResetCharacterButton.Position = UDim2.new(0.5, buttonSpacing, 1, 0)
|
||||
else
|
||||
dontResetCharacterButton.Position = UDim2.new(0.5, buttonSpacing, 1, -30)
|
||||
end
|
||||
dontResetCharacterButton.Parent = resetCharacterText
|
||||
|
||||
this.Page.Size = UDim2.new(1,0,0,dontResetCharacterButton.AbsolutePosition.Y + dontResetCharacterButton.AbsoluteSize.Y)
|
||||
|
||||
return this
|
||||
end
|
||||
|
||||
|
||||
----------- Public Facing API Additions --------------
|
||||
PageInstance = Initialize()
|
||||
|
||||
PageInstance.Displayed.Event:connect(function()
|
||||
GuiService.SelectedCoreObject = PageInstance.ResetCharacterButton
|
||||
ContextActionService:BindCoreAction(RESET_CHARACTER_GAME_ACTION, PageInstance.DontResetCharFromHotkey, false, Enum.KeyCode.ButtonB)
|
||||
end)
|
||||
|
||||
PageInstance.Hidden.Event:connect(function()
|
||||
ContextActionService:UnbindCoreAction(RESET_CHARACTER_GAME_ACTION)
|
||||
end)
|
||||
|
||||
|
||||
return PageInstance
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,276 @@
|
||||
--[[
|
||||
Filename: SettingsPageFactory.lua
|
||||
Written by: jeditkacheff
|
||||
Version 1.0
|
||||
Description: Base Page Functionality for all Settings Pages
|
||||
--]]
|
||||
----------------- SERVICES ------------------------------
|
||||
local GuiService = game:GetService("GuiService")
|
||||
local HttpService = game:GetService("HttpService")
|
||||
local UserInputService = game:GetService("UserInputService")
|
||||
|
||||
local CoreGui = game:GetService("CoreGui")
|
||||
local RobloxGui = CoreGui:WaitForChild("RobloxGui")
|
||||
|
||||
----------- UTILITIES --------------
|
||||
local utility = require(RobloxGui.Modules.Settings.Utility)
|
||||
|
||||
|
||||
----------- VARIABLES --------------
|
||||
RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface")
|
||||
local isTenFootInterface = require(RobloxGui.Modules.TenFootInterface):IsEnabled()
|
||||
|
||||
----------- CONSTANTS --------------
|
||||
local HEADER_SPACING = 5
|
||||
if utility:IsSmallTouchScreen() then
|
||||
HEADER_SPACING = 0
|
||||
end
|
||||
|
||||
----------- CLASS DECLARATION --------------
|
||||
local function Initialize()
|
||||
local this = {}
|
||||
this.HubRef = nil
|
||||
this.LastSelectedObject = nil
|
||||
this.TabPosition = 0
|
||||
this.Active = false
|
||||
this.OpenStateChangedCount = 0
|
||||
local rows = {}
|
||||
local displayed = false
|
||||
|
||||
------ TAB CREATION -------
|
||||
this.TabHeader = utility:Create'TextButton'
|
||||
{
|
||||
Name = "Header",
|
||||
Text = "",
|
||||
BackgroundTransparency = 1,
|
||||
Size = UDim2.new(0,169,1,0),
|
||||
Position = UDim2.new(0.5,0,0,0)
|
||||
};
|
||||
if utility:IsSmallTouchScreen() then
|
||||
this.TabHeader.Size = UDim2.new(0,84,1,0)
|
||||
elseif isTenFootInterface then
|
||||
this.TabHeader.Size = UDim2.new(0,220,1,0)
|
||||
end
|
||||
this.TabHeader.MouseButton1Click:connect(function()
|
||||
if this.HubRef then
|
||||
this.HubRef:SwitchToPage(this, true)
|
||||
end
|
||||
end)
|
||||
|
||||
local icon = utility:Create'ImageLabel'
|
||||
{
|
||||
Name = "Icon",
|
||||
BackgroundTransparency = 1,
|
||||
Size = UDim2.new(0,44,0,37),
|
||||
Position = UDim2.new(0,10,0.5,-18),
|
||||
Image = "",
|
||||
ImageTransparency = 0.5,
|
||||
Parent = this.TabHeader
|
||||
};
|
||||
|
||||
local title = utility:Create'TextLabel'
|
||||
{
|
||||
Name = "Title",
|
||||
Text = "Change Me",
|
||||
Font = Enum.Font.SourceSansBold,
|
||||
FontSize = Enum.FontSize.Size24,
|
||||
TextColor3 = Color3.new(1,1,1),
|
||||
BackgroundTransparency = 1,
|
||||
Size = UDim2.new(1.05,0,1,0),
|
||||
Position = UDim2.new(1.2,0,0,0),
|
||||
TextXAlignment = Enum.TextXAlignment.Left,
|
||||
TextTransparency = 0.5,
|
||||
Parent = icon
|
||||
};
|
||||
if utility:IsSmallTouchScreen() then
|
||||
title.FontSize = Enum.FontSize.Size18
|
||||
elseif isTenFootInterface then
|
||||
title.FontSize = Enum.FontSize.Size48
|
||||
end
|
||||
|
||||
local tabSelection = utility:Create'ImageLabel'
|
||||
{
|
||||
Name = "TabSelection",
|
||||
Image = "rbxasset://textures/ui/Settings/MenuBarAssets/MenuSelection.png",
|
||||
ScaleType = Enum.ScaleType.Slice,
|
||||
SliceCenter = Rect.new(3,1,4,5),
|
||||
Visible = false,
|
||||
BackgroundTransparency = 1,
|
||||
Size = UDim2.new(1,0,0,6),
|
||||
Position = UDim2.new(0,0,1,-6),
|
||||
Parent = this.TabHeader
|
||||
};
|
||||
|
||||
------ PAGE CREATION -------
|
||||
this.Page = utility:Create'Frame'
|
||||
{
|
||||
Name = "Page",
|
||||
BackgroundTransparency = 1,
|
||||
Size = UDim2.new(1,0,1,0)
|
||||
};
|
||||
|
||||
-- make sure each page has a unique selection group (for gamepad selection)
|
||||
GuiService:AddSelectionParent(HttpService:GenerateGUID(false), this.Page)
|
||||
|
||||
----------------- Events ------------------------
|
||||
|
||||
this.Displayed = Instance.new("BindableEvent")
|
||||
this.Displayed.Name = "Displayed"
|
||||
|
||||
this.Displayed.Event:connect(function()
|
||||
if not this.HubRef.Shield.Visible then return end
|
||||
|
||||
this:SelectARow()
|
||||
end)
|
||||
|
||||
this.Hidden = Instance.new("BindableEvent")
|
||||
this.Hidden.Event:connect(function()
|
||||
if GuiService.SelectedCoreObject and GuiService.SelectedCoreObject:IsDescendantOf(this.Page) then
|
||||
GuiService.SelectedCoreObject = nil
|
||||
end
|
||||
end)
|
||||
this.Hidden.Name = "Hidden"
|
||||
|
||||
----------------- FUNCTIONS ------------------------
|
||||
function this:SelectARow(forced) -- Selects the first row or the most recently selected row
|
||||
if forced or not GuiService.SelectedCoreObject or not GuiService.SelectedCoreObject:IsDescendantOf(this.Page) then
|
||||
if this.LastSelectedObject then
|
||||
GuiService.SelectedCoreObject = this.LastSelectedObject
|
||||
else
|
||||
if rows and #rows > 0 then
|
||||
local valueChangerFrame = nil
|
||||
|
||||
if type(rows[1].ValueChanger) ~= "table" then
|
||||
valueChangerFrame = rows[1].ValueChanger
|
||||
else
|
||||
valueChangerFrame = rows[1].ValueChanger.SliderFrame and
|
||||
rows[1].ValueChanger.SliderFrame or rows[1].ValueChanger.SelectorFrame
|
||||
end
|
||||
GuiService.SelectedCoreObject = valueChangerFrame
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function this:Display(pageParent, skipAnimation)
|
||||
this.OpenStateChangedCount = this.OpenStateChangedCount + 1
|
||||
|
||||
if this.TabHeader then
|
||||
this.TabHeader.TabSelection.Visible = true
|
||||
this.TabHeader.Icon.ImageTransparency = 0
|
||||
this.TabHeader.Icon.Title.TextTransparency = 0
|
||||
end
|
||||
|
||||
this.Page.Parent = pageParent
|
||||
this.Page.Visible = true
|
||||
|
||||
local endPos = UDim2.new(0,0,0,0)
|
||||
local animationComplete = function()
|
||||
this.Page.Visible = true
|
||||
displayed = true
|
||||
this.Displayed:Fire()
|
||||
end
|
||||
if skipAnimation then
|
||||
this.Page.Position = endPos
|
||||
animationComplete()
|
||||
else
|
||||
this.Page:TweenPosition(endPos, Enum.EasingDirection.In, Enum.EasingStyle.Quad, 0.1, true, animationComplete)
|
||||
end
|
||||
end
|
||||
function this:Hide(direction, newPagePos, skipAnimation, delayBeforeHiding)
|
||||
this.OpenStateChangedCount = this.OpenStateChangedCount + 1
|
||||
|
||||
if this.TabHeader then
|
||||
this.TabHeader.TabSelection.Visible = false
|
||||
this.TabHeader.Icon.ImageTransparency = 0.5
|
||||
this.TabHeader.Icon.Title.TextTransparency = 0.5
|
||||
end
|
||||
|
||||
if this.Page.Parent then
|
||||
local endPos = UDim2.new(1 * direction,0,0,0)
|
||||
local animationComplete = function()
|
||||
this.Page.Visible = false
|
||||
this.Page.Position = UDim2.new(this.TabPosition - newPagePos,0,0,0)
|
||||
displayed = false
|
||||
this.Hidden:Fire()
|
||||
end
|
||||
|
||||
local remove = function()
|
||||
if skipAnimation then
|
||||
this.Page.Position = endPos
|
||||
animationComplete()
|
||||
else
|
||||
this.Page:TweenPosition(endPos, Enum.EasingDirection.Out, Enum.EasingStyle.Quad, 0.1, true, animationComplete)
|
||||
end
|
||||
end
|
||||
|
||||
if delayBeforeHiding then
|
||||
local myOpenStateChangedCount = this.OpenStateChangedCount
|
||||
delay(delayBeforeHiding, function()
|
||||
if myOpenStateChangedCount == this.OpenStateChangedCount then
|
||||
remove()
|
||||
end
|
||||
end)
|
||||
else
|
||||
remove()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function this:GetDisplayed()
|
||||
return displayed
|
||||
end
|
||||
|
||||
function this:GetVisibility()
|
||||
return this.Page.Parent
|
||||
end
|
||||
|
||||
function this:GetTabHeader()
|
||||
return this.TabHeader
|
||||
end
|
||||
|
||||
function this:SetHub(hubRef)
|
||||
this.HubRef = hubRef
|
||||
|
||||
for i, row in next, rows do
|
||||
if type(row.ValueChanger) == 'table' then
|
||||
row.ValueChanger.HubRef = this.HubRef
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function this:GetSize()
|
||||
return this.Page.AbsoluteSize
|
||||
end
|
||||
|
||||
function this:AddRow(RowFrame, RowLabel, ValueChangerInstance, ExtraRowSpacing)
|
||||
rows[#rows + 1] = {SelectionFrame = RowFrame, Label = RowLabel, ValueChanger = ValueChangerInstance}
|
||||
|
||||
local rowFrameYSize = 0
|
||||
if RowFrame then
|
||||
rowFrameYSize = RowFrame.Size.Y.Offset
|
||||
end
|
||||
|
||||
if ExtraRowSpacing then
|
||||
this.Page.Size = UDim2.new(1, 0, 0, this.Page.Size.Y.Offset + rowFrameYSize + ExtraRowSpacing)
|
||||
else
|
||||
this.Page.Size = UDim2.new(1, 0, 0, this.Page.Size.Y.Offset + rowFrameYSize)
|
||||
end
|
||||
|
||||
if this.HubRef and type(ValueChangerInstance) == 'table' then
|
||||
ValueChangerInstance.HubRef = this.HubRef
|
||||
end
|
||||
end
|
||||
|
||||
return this
|
||||
end
|
||||
|
||||
|
||||
-------- public facing API ----------------
|
||||
local moduleApiTable = {}
|
||||
|
||||
function moduleApiTable:CreateNewPage()
|
||||
return Initialize()
|
||||
end
|
||||
|
||||
return moduleApiTable
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,345 @@
|
||||
--[[
|
||||
Filename: TenFootInterface.lua
|
||||
Written by: jeditkacheff
|
||||
Version 1.0
|
||||
Description: Setups up some special UI for ROBLOX TV gaming
|
||||
--]]
|
||||
-------------- CONSTANTS --------------
|
||||
local HEALTH_GREEN_COLOR = Color3.new(27/255, 252/255, 107/255)
|
||||
local DISPLAY_POS_INIT_INSET = 0
|
||||
local DISPLAY_ITEM_OFFSET = 4
|
||||
local FORCE_TEN_FOOT_INTERFACE = false
|
||||
|
||||
-------------- SERVICES --------------
|
||||
local CoreGui = game:GetService("CoreGui")
|
||||
local RobloxGui = CoreGui:WaitForChild("RobloxGui")
|
||||
local UserInputService = game:GetService("UserInputService")
|
||||
local GuiService = game:GetService("GuiService")
|
||||
|
||||
------------------ VARIABLES --------------------
|
||||
local tenFootInterfaceEnabled = false
|
||||
do
|
||||
local platform = UserInputService:GetPlatform()
|
||||
|
||||
tenFootInterfaceEnabled = (platform == Enum.Platform.XBoxOne or platform == Enum.Platform.WiiU or platform == Enum.Platform.PS4 or
|
||||
platform == Enum.Platform.AndroidTV or platform == Enum.Platform.XBox360 or platform == Enum.Platform.PS3 or
|
||||
platform == Enum.Platform.Ouya or platform == Enum.Platform.SteamOS)
|
||||
end
|
||||
|
||||
if FORCE_TEN_FOOT_INTERFACE then
|
||||
tenFootInterfaceEnabled = true
|
||||
end
|
||||
|
||||
local Util = {}
|
||||
do
|
||||
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
|
||||
end
|
||||
|
||||
local function CreateModule()
|
||||
local this = {}
|
||||
local nextObjectDisplayYPos = DISPLAY_POS_INIT_INSET
|
||||
local displayStack = {}
|
||||
|
||||
-- setup base gui
|
||||
local function createContainer()
|
||||
if not this.Container then
|
||||
this.Container = Util.Create'ImageButton'
|
||||
{
|
||||
Name = "TopRightContainer";
|
||||
Size = UDim2.new(0, 350, 0, 100);
|
||||
Position = UDim2.new(1,-360,0,10);
|
||||
AutoButtonColor = false;
|
||||
Image = "";
|
||||
Active = false;
|
||||
BackgroundTransparency = 1;
|
||||
Parent = RobloxGui;
|
||||
};
|
||||
end
|
||||
end
|
||||
|
||||
function removeFromDisplayStack(displayObject)
|
||||
local moveUpFromHere = nil
|
||||
|
||||
for i = 1, #displayStack do
|
||||
if displayStack[i] == displayObject then
|
||||
moveUpFromHere = i + 1
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local prevObject = displayObject
|
||||
for i = moveUpFromHere, #displayStack do
|
||||
local objectToMoveUp = displayStack[i]
|
||||
objectToMoveUp.Position = UDim2.new(objectToMoveUp.Position.X.Scale, objectToMoveUp.Position.X.Offset,
|
||||
objectToMoveUp.Position.Y.Scale, prevObject.AbsolutePosition.Y)
|
||||
prevObject = objectToMoveUp
|
||||
end
|
||||
end
|
||||
|
||||
function addBackToDisplayStack(displayObject)
|
||||
for i = 1, #displayStack do
|
||||
if displayStack[i] == displayObject then
|
||||
moveDownFromHere = i + 1
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local prevObject = displayObject
|
||||
for i = moveDownFromHere, #displayStack do
|
||||
local objectToMoveDown = displayStack[i]
|
||||
local nextDisplayPos = prevObject.AbsolutePosition.Y + prevObject.AbsoluteSize.Y + DISPLAY_ITEM_OFFSET
|
||||
objectToMoveDown.Position = UDim2.new(objectToMoveDown.Position.X.Scale, objectToMoveDown.Position.X.Offset,
|
||||
objectToMoveDown.Position.Y.Scale, nextDisplayPos)
|
||||
prevObject = objectToMoveDown
|
||||
end
|
||||
end
|
||||
|
||||
function addToDisplayStack(displayObject)
|
||||
local lastDisplayed = nil
|
||||
if #displayStack > 0 then
|
||||
lastDisplayed = displayStack[#displayStack]
|
||||
end
|
||||
displayStack[#displayStack + 1] = displayObject
|
||||
|
||||
local nextDisplayPos = DISPLAY_POS_INIT_INSET
|
||||
if lastDisplayed then
|
||||
nextDisplayPos = lastDisplayed.AbsolutePosition.Y + lastDisplayed.AbsoluteSize.Y + DISPLAY_ITEM_OFFSET
|
||||
end
|
||||
|
||||
displayObject.Position = UDim2.new(displayObject.Position.X.Scale, displayObject.Position.X.Offset,
|
||||
displayObject.Position.Y.Scale, nextDisplayPos)
|
||||
|
||||
createContainer()
|
||||
displayObject.Parent = this.Container
|
||||
|
||||
displayObject.Changed:connect(function(prop)
|
||||
if prop == "Visible" then
|
||||
if not displayObject.Visible then
|
||||
removeFromDisplayStack(displayObject)
|
||||
else
|
||||
addBackToDisplayStack(displayObject)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function this:CreateHealthBar()
|
||||
this.HealthContainer = Util.Create'Frame'{
|
||||
Name = "HealthContainer";
|
||||
Size = UDim2.new(1, -86, 0, 50);
|
||||
Position = UDim2.new(0, 92, 0, 0);
|
||||
BorderSizePixel = 0;
|
||||
BackgroundColor3 = Color3.new(0,0,0);
|
||||
BackgroundTransparency = 0.5;
|
||||
};
|
||||
|
||||
local healthFillHolder = Util.Create'Frame'{
|
||||
Name = "HealthFillHolder";
|
||||
Size = UDim2.new(1, -10, 1, -10);
|
||||
Position = UDim2.new(0, 5, 0, 5);
|
||||
BorderSizePixel = 0;
|
||||
BackgroundColor3 = Color3.new(1,1,1);
|
||||
BackgroundTransparency = 1.0;
|
||||
Parent = this.HealthContainer;
|
||||
};
|
||||
|
||||
local healthFill = Util.Create'Frame'{
|
||||
Name = "HealthFill";
|
||||
Size = UDim2.new(1, 0, 1, 0);
|
||||
Position = UDim2.new(0, 0, 0, 0);
|
||||
BorderSizePixel = 0;
|
||||
BackgroundTransparency = 0.0;
|
||||
BackgroundColor3 = HEALTH_GREEN_COLOR;
|
||||
Parent = healthFillHolder;
|
||||
};
|
||||
|
||||
local healthText = Util.Create'TextLabel'{
|
||||
Name = "HealthText";
|
||||
Size = UDim2.new(0, 98, 0, 50);
|
||||
Position = UDim2.new(0, -100, 0, 0);
|
||||
BackgroundTransparency = 0.5;
|
||||
BackgroundColor3 = Color3.new(0,0,0);
|
||||
Font = Enum.Font.SourceSans;
|
||||
FontSize = Enum.FontSize.Size36;
|
||||
Text = "Health";
|
||||
TextColor3 = Color3.new(1,1,1);
|
||||
BorderSizePixel = 0;
|
||||
Parent = this.HealthContainer;
|
||||
};
|
||||
|
||||
local username = Util.Create'TextLabel'{
|
||||
Visible = false
|
||||
}
|
||||
|
||||
addToDisplayStack(this.HealthContainer)
|
||||
createContainer()
|
||||
|
||||
return this.Container, username, this.HealthContainer, healthFill
|
||||
end
|
||||
|
||||
function this:SetupTopStat()
|
||||
local topStatEnabled = true
|
||||
local displayedStat = nil
|
||||
local displayedStatChangedCon = nil
|
||||
local displayedStatParentedCon = nil
|
||||
local leaderstatsChildAddedCon = nil
|
||||
local tenFootInterfaceStat = nil
|
||||
|
||||
local function makeTenFootInterfaceStat()
|
||||
if tenFootInterfaceStat then return end
|
||||
|
||||
tenFootInterfaceStat = Util.Create'Frame'{
|
||||
Name = "OneStatFrame";
|
||||
Size = UDim2.new(1, 0, 0, 36);
|
||||
Position = UDim2.new(0, 0, 0, 0);
|
||||
BorderSizePixel = 0;
|
||||
BackgroundTransparency = 1;
|
||||
};
|
||||
local statName = Util.Create'TextLabel'{
|
||||
Name = "StatName";
|
||||
Size = UDim2.new(0.5,0,0,36);
|
||||
BackgroundTransparency = 1;
|
||||
Font = Enum.Font.SourceSans;
|
||||
FontSize = Enum.FontSize.Size36;
|
||||
TextStrokeColor3 = Color3.new(104/255, 104/255, 104/255);
|
||||
TextStrokeTransparency = 0;
|
||||
Text = " StatName:";
|
||||
TextColor3 = Color3.new(1,1,1);
|
||||
TextXAlignment = Enum.TextXAlignment.Left;
|
||||
BorderSizePixel = 0;
|
||||
ClipsDescendants = true;
|
||||
Parent = tenFootInterfaceStat;
|
||||
};
|
||||
local statValue = statName:clone()
|
||||
statValue.Position = UDim2.new(0.5,0,0,0)
|
||||
statValue.Name = "StatValue"
|
||||
statValue.Text = "123,643,231"
|
||||
statValue.TextXAlignment = Enum.TextXAlignment.Right
|
||||
statValue.Parent = tenFootInterfaceStat
|
||||
|
||||
addToDisplayStack(tenFootInterfaceStat)
|
||||
end
|
||||
|
||||
local function setDisplayedStat(newStat)
|
||||
if displayedStatChangedCon then displayedStatChangedCon:disconnect() displayedStatChangedCon = nil end
|
||||
if displayedStatParentedCon then displayedStatParentedCon:disconnect() displayedStatParentedCon = nil end
|
||||
|
||||
displayedStat = newStat
|
||||
|
||||
if displayedStat then
|
||||
makeTenFootInterfaceStat()
|
||||
updateTenFootStat(displayedStat)
|
||||
displayedStatParentedCon = displayedStat.AncestryChanged:connect(function() updateTenFootStat(displayedStat, "Parent") end)
|
||||
displayedStatChangedCon = displayedStat.Changed:connect(function(prop) updateTenFootStat(displayedStat, prop) end)
|
||||
end
|
||||
end
|
||||
|
||||
function updateTenFootStat(statObj, property)
|
||||
if property and property == "Parent" then
|
||||
tenFootInterfaceStat.StatName.Text = ""
|
||||
tenFootInterfaceStat.StatValue.Text = ""
|
||||
setDisplayedStat(nil)
|
||||
|
||||
tenFootInterfaceChanged()
|
||||
else
|
||||
if topStatEnabled then
|
||||
tenFootInterfaceStat.StatName.Text = " " .. tostring(statObj.Name) .. ":"
|
||||
tenFootInterfaceStat.StatValue.Text = tostring(statObj.Value)
|
||||
else
|
||||
tenFootInterfaceStat.StatName.Text = ""
|
||||
tenFootInterfaceStat.StatValue.Text = ""
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function isValidStat(obj)
|
||||
return obj:IsA('StringValue') or obj:IsA('IntValue') or obj:IsA('BoolValue') or obj:IsA('NumberValue') or
|
||||
obj:IsA('DoubleConstrainedValue') or obj:IsA('IntConstrainedValue')
|
||||
end
|
||||
|
||||
local function tenFootInterfaceNewStat( newStat )
|
||||
if not displayedStat and isValidStat(newStat) then
|
||||
setDisplayedStat(newStat)
|
||||
end
|
||||
end
|
||||
|
||||
function tenFootInterfaceChanged()
|
||||
game:WaitForChild("Players")
|
||||
while not game.Players.LocalPlayer do
|
||||
wait()
|
||||
end
|
||||
|
||||
local leaderstats = game.Players.LocalPlayer:FindFirstChild('leaderstats')
|
||||
if leaderstats then
|
||||
local statChildren = leaderstats:GetChildren()
|
||||
for i = 1, #statChildren do
|
||||
tenFootInterfaceNewStat(statChildren[i])
|
||||
end
|
||||
if leaderstatsChildAddedCon then leaderstatsChildAddedCon:disconnect() end
|
||||
leaderstatsChildAddedCon = leaderstats.ChildAdded:connect(function(newStat)
|
||||
tenFootInterfaceNewStat(newStat)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
game:WaitForChild("Players")
|
||||
while not game.Players.LocalPlayer do
|
||||
wait()
|
||||
end
|
||||
|
||||
local leaderstats = game.Players.LocalPlayer:FindFirstChild('leaderstats')
|
||||
if leaderstats then
|
||||
tenFootInterfaceChanged()
|
||||
else
|
||||
game.Players.LocalPlayer.ChildAdded:connect(tenFootInterfaceChanged)
|
||||
end
|
||||
|
||||
--Top Stat Public API
|
||||
|
||||
local topStatApiTable = {}
|
||||
|
||||
function topStatApiTable:SetTopStatEnabled(value)
|
||||
topStatEnabled = value
|
||||
if displayedStat then
|
||||
updateTenFootStat(displayedStat, "")
|
||||
end
|
||||
end
|
||||
|
||||
return topStatApiTable
|
||||
end
|
||||
|
||||
return this
|
||||
end
|
||||
|
||||
|
||||
-- Public API
|
||||
|
||||
local moduleApiTable = {}
|
||||
|
||||
local TenFootInterfaceModule = CreateModule()
|
||||
|
||||
function moduleApiTable:IsEnabled()
|
||||
return tenFootInterfaceEnabled
|
||||
end
|
||||
|
||||
function moduleApiTable:CreateHealthBar()
|
||||
return TenFootInterfaceModule:CreateHealthBar()
|
||||
end
|
||||
|
||||
function moduleApiTable:SetupTopStat()
|
||||
return TenFootInterfaceModule:SetupTopStat()
|
||||
end
|
||||
|
||||
return moduleApiTable
|
||||
@@ -0,0 +1,216 @@
|
||||
--[[
|
||||
// FileName: PlayerlistModule.lua
|
||||
// Version 1.0
|
||||
// Written by: jmargh
|
||||
// Description: Implements social features that need to be ran on the server
|
||||
|
||||
// TODO
|
||||
We need to get module script working on the server. When we get that working
|
||||
This should be moved to a module, and http helper functions should be moved
|
||||
to a utility module.
|
||||
]]
|
||||
local HttpService = game:GetService('HttpService')
|
||||
local HttpRbxApiService = game:GetService('HttpRbxApiService')
|
||||
local Players = game:GetService('Players')
|
||||
local RobloxReplicatedStorage = game:GetService('RobloxReplicatedStorage')
|
||||
local RunService = game:GetService('RunService')
|
||||
|
||||
local GET_MULTI_FOLLOW = "user/multi-following-exists"
|
||||
|
||||
local PlayerToRelationshipMap = {}
|
||||
|
||||
--[[ Remotes ]]--
|
||||
local RemoteEvent_FollowRelationshipChanged = Instance.new('RemoteEvent')
|
||||
RemoteEvent_FollowRelationshipChanged.Name = "FollowRelationshipChanged"
|
||||
RemoteEvent_FollowRelationshipChanged.Parent = RobloxReplicatedStorage
|
||||
|
||||
local RemoteEvent_NewFollower = Instance.new("RemoteEvent")
|
||||
RemoteEvent_NewFollower.Name = "NewFollower"
|
||||
RemoteEvent_NewFollower.Parent = RobloxReplicatedStorage
|
||||
|
||||
local RemoteFunc_GetFollowRelationships = Instance.new('RemoteFunction')
|
||||
RemoteFunc_GetFollowRelationships.Name = "GetFollowRelationships"
|
||||
RemoteFunc_GetFollowRelationships.Parent = RobloxReplicatedStorage
|
||||
|
||||
--[[ Helper Functions ]]--
|
||||
local function decodeJSON(json)
|
||||
local success, result = pcall(function()
|
||||
return HttpService:JSONDecode(json)
|
||||
end)
|
||||
if not success then
|
||||
print("decodeJSON() failed because", result, "Input:", json)
|
||||
return nil
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
local function rbxApiPostAsync(path, params, useHttps, throttlePriority, contentType)
|
||||
local success, result = pcall(function()
|
||||
return HttpRbxApiService:PostAsync(path, params, useHttps, throttlePriority, contentType)
|
||||
end)
|
||||
--
|
||||
if not success then
|
||||
local label = string.format("%s: - path: %s, \njson: %s", tostring(result), tostring(path), tostring(params))
|
||||
return nil
|
||||
end
|
||||
|
||||
return decodeJSON(result)
|
||||
end
|
||||
|
||||
--[[
|
||||
// Return - table
|
||||
Key: FollowingDetails
|
||||
Value: Arrary of details
|
||||
Key: UserId1
|
||||
Value: number - userId of new client
|
||||
Key: UserId2
|
||||
Value: number - userId of other client
|
||||
Key: User1FollowsUser2
|
||||
Value: boolean
|
||||
Key: User2FollowsUser1
|
||||
Value: boolean
|
||||
]]
|
||||
local function getFollowRelationshipsAsync(uid)
|
||||
if RunService:IsStudio() then
|
||||
return
|
||||
end
|
||||
|
||||
local otherUserIdTable = {}
|
||||
for _,player in pairs(Players:GetPlayers()) do
|
||||
if player.UserId > 0 then
|
||||
table.insert(otherUserIdTable, player.UserId)
|
||||
end
|
||||
end
|
||||
|
||||
if #otherUserIdTable > 0 and uid and uid > 0 then
|
||||
local jsonPostBody = {
|
||||
userId = uid;
|
||||
otherUserIds = otherUserIdTable;
|
||||
}
|
||||
jsonPostBody = HttpService:JSONEncode(jsonPostBody)
|
||||
|
||||
if jsonPostBody then
|
||||
return rbxApiPostAsync(GET_MULTI_FOLLOW, jsonPostBody, true, Enum.ThrottlingPriority.Default, Enum.HttpContentType.ApplicationJson)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function createRelationshipObject(user1FollowsUser2, user2FollowsUser1)
|
||||
local object = {}
|
||||
object.IsFollower = user2FollowsUser1
|
||||
object.IsFollowing = user1FollowsUser2
|
||||
object.IsMutual = user1FollowsUser2 and user2FollowsUser1
|
||||
|
||||
return object
|
||||
end
|
||||
|
||||
local function updateAndNotifyClients(resultTable, newUserIdStr, newPlayer)
|
||||
local followingDetails = resultTable["FollowingDetails"]
|
||||
if followingDetails then
|
||||
local relationshipTable = PlayerToRelationshipMap[newUserIdStr] or {}
|
||||
|
||||
for i = 1, #followingDetails do
|
||||
local detail = followingDetails[i]
|
||||
local otherUserId = detail["UserId2"]
|
||||
local otherUserIdStr = tostring(otherUserId)
|
||||
|
||||
local followsOther = detail["User1FollowsUser2"]
|
||||
local followsNewPlayer = detail["User2FollowsUser1"]
|
||||
|
||||
relationshipTable[otherUserIdStr] = createRelationshipObject(followsOther, followsNewPlayer)
|
||||
|
||||
-- update other use
|
||||
local otherRelationshipTable = PlayerToRelationshipMap[otherUserIdStr]
|
||||
if otherRelationshipTable then
|
||||
local newRelationship = createRelationshipObject(followsNewPlayer, followsOther)
|
||||
otherRelationshipTable[newUserIdStr] = newRelationship
|
||||
|
||||
local otherPlayer = Players:GetPlayerByUserId(otherUserId)
|
||||
if otherPlayer then
|
||||
-- create single entry table (keep format same) and send to other client
|
||||
local deltaTable = {}
|
||||
deltaTable[newUserIdStr] = newRelationship
|
||||
RemoteEvent_FollowRelationshipChanged:FireClient(otherPlayer, deltaTable)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
PlayerToRelationshipMap[newUserIdStr] = relationshipTable
|
||||
RemoteEvent_FollowRelationshipChanged:FireClient(newPlayer, relationshipTable)
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Connections ]]--
|
||||
function RemoteFunc_GetFollowRelationships.OnServerInvoke(player)
|
||||
local uid = player.userId
|
||||
local uidStr = tostring(player.userId)
|
||||
if uid and uid > 0 and PlayerToRelationshipMap[uidStr] then
|
||||
return PlayerToRelationshipMap[uidStr]
|
||||
else
|
||||
return {}
|
||||
end
|
||||
end
|
||||
|
||||
-- client fires event to server on new follow
|
||||
RemoteEvent_NewFollower.OnServerEvent:connect(function(player1, player2, player1FollowsPlayer2)
|
||||
if player1FollowsPlayer2 == nil then
|
||||
return
|
||||
end
|
||||
local userId1 = tostring(player1.userId)
|
||||
local userId2 = tostring(player2.userId)
|
||||
|
||||
local user1map = PlayerToRelationshipMap[userId1]
|
||||
local user2map = PlayerToRelationshipMap[userId2]
|
||||
|
||||
if user1map then
|
||||
local relationTable = user1map[userId2]
|
||||
if relationTable then
|
||||
relationTable.IsFollowing = player1FollowsPlayer2
|
||||
relationTable.IsMutual = relationTable.IsFollowing and relationTable.IsFollower
|
||||
|
||||
local delta = {}
|
||||
delta[userId2] = relationTable
|
||||
RemoteEvent_FollowRelationshipChanged:FireClient(player1, delta)
|
||||
-- this should be updated, but current NotificationScript listens to this
|
||||
if player1FollowsPlayer2 then
|
||||
RemoteEvent_NewFollower:FireClient(player2, player1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if user2map then
|
||||
local relationTable = user2map[userId1]
|
||||
if relationTable then
|
||||
relationTable.IsFollower = player1FollowsPlayer2
|
||||
relationTable.IsMutual = relationTable.IsFollowing and relationTable.IsFollower
|
||||
|
||||
local delta = {}
|
||||
delta[userId1] = relationTable
|
||||
RemoteEvent_FollowRelationshipChanged:FireClient(player2, delta)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local function onPlayerAdded(newPlayer)
|
||||
local uid = newPlayer.UserId
|
||||
if uid > 0 then
|
||||
local uidStr = tostring(uid)
|
||||
local result = getFollowRelationshipsAsync(uid)
|
||||
if result then
|
||||
updateAndNotifyClients(result, uidStr, newPlayer)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Players.PlayerAdded:connect(onPlayerAdded)
|
||||
for _,player in pairs(Players:GetPlayers()) do
|
||||
onPlayerAdded(player)
|
||||
end
|
||||
|
||||
Players.PlayerRemoving:connect(function(prevPlayer)
|
||||
local uid = tostring(prevPlayer.UserId)
|
||||
if PlayerToRelationshipMap[uid] then
|
||||
PlayerToRelationshipMap[uid] = nil
|
||||
end
|
||||
end)
|
||||
@@ -0,0 +1,56 @@
|
||||
--[[
|
||||
// Filename: ServerStarterScript.lua
|
||||
// Version: 1.0
|
||||
// Description: Server core script that handles core script server side logic.
|
||||
]]--
|
||||
|
||||
-- Prevent server script from running in Studio when not in run mode
|
||||
local runService = nil
|
||||
while runService == nil or not runService:IsRunning() do
|
||||
wait(0.1)
|
||||
runService = game:GetService('RunService')
|
||||
end
|
||||
|
||||
--[[ Services ]]--
|
||||
local RobloxReplicatedStorage = game:GetService('RobloxReplicatedStorage')
|
||||
local ScriptContext = game:GetService('ScriptContext')
|
||||
|
||||
--[[ Fast Flags ]]--
|
||||
local serverFollowersSuccess, serverFollowersEnabled = pcall(function() return settings():GetFFlag("UserServerFollowers") end)
|
||||
local IsServerFollowers = serverFollowersSuccess and serverFollowersEnabled
|
||||
|
||||
local RemoteEvent_NewFollower = nil
|
||||
|
||||
--[[ Add Server CoreScript ]]--
|
||||
-- TODO: FFlag check
|
||||
if IsServerFollowers then
|
||||
ScriptContext:AddCoreScriptLocal("ServerCoreScripts/ServerSocialScript", script.Parent)
|
||||
else
|
||||
-- above script will create this now
|
||||
RemoteEvent_NewFollower = Instance.new('RemoteEvent')
|
||||
RemoteEvent_NewFollower.Name = "NewFollower"
|
||||
RemoteEvent_NewFollower.Parent = RobloxReplicatedStorage
|
||||
end
|
||||
|
||||
--[[ Remote Events ]]--
|
||||
local RemoteEvent_SetDialogInUse = Instance.new("RemoteEvent")
|
||||
RemoteEvent_SetDialogInUse.Name = "SetDialogInUse"
|
||||
RemoteEvent_SetDialogInUse.Parent = RobloxReplicatedStorage
|
||||
|
||||
--[[ Event Connections ]]--
|
||||
-- Params:
|
||||
-- followerRbxPlayer: player object of the new follower, this is the client who wants to follow another
|
||||
-- followedRbxPlayer: player object of the person being followed
|
||||
local function onNewFollower(followerRbxPlayer, followedRbxPlayer)
|
||||
RemoteEvent_NewFollower:FireClient(followedRbxPlayer, followerRbxPlayer)
|
||||
end
|
||||
if RemoteEvent_NewFollower then
|
||||
RemoteEvent_NewFollower.OnServerEvent:connect(onNewFollower)
|
||||
end
|
||||
|
||||
local function setDialogInUse(player, dialog, value)
|
||||
if dialog ~= nil then
|
||||
dialog.InUse = value
|
||||
end
|
||||
end
|
||||
RemoteEvent_SetDialogInUse.OnServerEvent:connect(setDialogInUse)
|
||||
@@ -0,0 +1,69 @@
|
||||
-- Creates all neccessary scripts for the gui on initial load, everything except build tools
|
||||
-- Created by Ben T. 10/29/10
|
||||
-- Please note that these are loaded in a specific order to diminish errors/perceived load time by user
|
||||
|
||||
local scriptContext = game:GetService("ScriptContext")
|
||||
local touchEnabled = game:GetService("UserInputService").TouchEnabled
|
||||
|
||||
local RobloxGui = game:GetService("CoreGui"):WaitForChild("RobloxGui")
|
||||
|
||||
local soundFolder = Instance.new("Folder")
|
||||
soundFolder.Name = "Sounds"
|
||||
soundFolder.Parent = RobloxGui
|
||||
|
||||
-- TopBar
|
||||
local topbarSuccess, topbarFlagValue = pcall(function() return settings():GetFFlag("UseInGameTopBar") end)
|
||||
local useTopBar = (topbarSuccess and topbarFlagValue == true)
|
||||
if useTopBar then
|
||||
scriptContext:AddCoreScriptLocal("CoreScripts/Topbar", RobloxGui)
|
||||
end
|
||||
|
||||
-- SettingsScript
|
||||
local luaControlsSuccess, luaControlsFlagValue = pcall(function() return settings():GetFFlag("UseLuaCameraAndControl") end)
|
||||
|
||||
-- MainBotChatScript (the Lua part of Dialogs)
|
||||
scriptContext:AddCoreScriptLocal("CoreScripts/MainBotChatScript2", RobloxGui)
|
||||
|
||||
-- Developer Console Script
|
||||
scriptContext:AddCoreScriptLocal("CoreScripts/DeveloperConsole", RobloxGui)
|
||||
|
||||
-- In-game notifications script
|
||||
scriptContext:AddCoreScriptLocal("CoreScripts/NotificationScript2", RobloxGui)
|
||||
|
||||
-- Chat script
|
||||
if useTopBar then
|
||||
spawn(function() require(RobloxGui.Modules.Chat) end)
|
||||
spawn(function() require(RobloxGui.Modules.PlayerlistModule) end)
|
||||
end
|
||||
|
||||
local luaBubbleChatSuccess, luaBubbleChatFlagValue = pcall(function() return settings():GetFFlag("LuaBasedBubbleChat") end)
|
||||
if luaBubbleChatSuccess and luaBubbleChatFlagValue then
|
||||
scriptContext:AddCoreScriptLocal("CoreScripts/BubbleChat", RobloxGui)
|
||||
end
|
||||
|
||||
-- Purchase Prompt Script
|
||||
scriptContext:AddCoreScriptLocal("CoreScripts/PurchasePromptScript2", RobloxGui)
|
||||
|
||||
-- Health Script
|
||||
if not useTopBar then
|
||||
scriptContext:AddCoreScriptLocal("CoreScripts/HealthScript", RobloxGui)
|
||||
end
|
||||
|
||||
do -- Backpack!
|
||||
spawn(function() require(RobloxGui.Modules.BackpackScript) end)
|
||||
end
|
||||
|
||||
if useTopBar then
|
||||
scriptContext:AddCoreScriptLocal("CoreScripts/VehicleHud", RobloxGui)
|
||||
end
|
||||
|
||||
scriptContext:AddCoreScriptLocal("CoreScripts/GamepadMenu", RobloxGui)
|
||||
|
||||
if touchEnabled then -- touch devices don't use same control frame
|
||||
-- only used for touch device button generation
|
||||
scriptContext:AddCoreScriptLocal("CoreScripts/ContextActionTouch", RobloxGui)
|
||||
|
||||
RobloxGui:WaitForChild("ControlFrame")
|
||||
RobloxGui.ControlFrame:WaitForChild("BottomLeftControl")
|
||||
RobloxGui.ControlFrame.BottomLeftControl.Visible = false
|
||||
end
|
||||
Reference in New Issue
Block a user