This commit is contained in:
watrabi
2025-09-18 17:55:52 -04:00
commit 977f1ff4b8
15030 changed files with 17324420 additions and 0 deletions
@@ -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
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