999 lines
30 KiB
Lua
999 lines
30 KiB
Lua
-- Creates the generic "ROBLOX" loading screen on startup
|
|
-- Written by ArceusInator & Ben Tkacheff, 2014
|
|
-- Updates by 0xBAADF00D, 2017
|
|
local AssetService = game:GetService("AssetService")
|
|
local MarketplaceService = game:GetService("MarketplaceService")
|
|
local UserInputService = game:GetService("UserInputService")
|
|
local VRService = game:GetService("VRService")
|
|
local GuiService = game:GetService("GuiService")
|
|
local ContextActionService = game:GetService("ContextActionService")
|
|
local RunService = game:GetService("RunService")
|
|
local Players = game:GetService("Players")
|
|
local ContentProvider = game:GetService("ContentProvider")
|
|
local CoreGui = game:GetService("CoreGui")
|
|
local ReplicatedFirst = game:GetService("ReplicatedFirst")
|
|
local ScriptContext = game:GetService("ScriptContext")
|
|
|
|
local RobloxGui = CoreGui:WaitForChild("RobloxGui")
|
|
local create = require(RobloxGui:WaitForChild("Modules"):WaitForChild("Common"):WaitForChild("Create"))
|
|
local PolicyService = require(RobloxGui.Modules.Common:WaitForChild("PolicyService"))
|
|
|
|
--FFlags
|
|
local FFlagLoadTheLoadingScreenFasterSuccess, FFlagLoadTheLoadingScreenFasterValue = pcall(function() return settings():GetFFlag("LoadTheLoadingScreenFaster") end)
|
|
local FFlagLoadTheLoadingScreenFaster = FFlagLoadTheLoadingScreenFasterSuccess and FFlagLoadTheLoadingScreenFasterValue
|
|
local FFlagLoadTheLoadingScreenEvenFaster = game:DefineFastFlag("LoadTheLoadingScreenEvenFaster", false)
|
|
local FFlagLoadingScreenDontBlockOnPolicyService = game:DefineFastFlag("LoadingScreenDontBlockOnPolicyService", false)
|
|
local FFlagBackButtonWhileLoadingGoesBackToApp = game:DefineFastFlag("BackButtonWhileLoadingGoesBackToApp", false)
|
|
local FFlagLoadingScreenShowBlankUntilPolicyServiceReturns = game:DefineFastFlag("LoadingScreenShowBlankUntilPolicyServiceReturns", false)
|
|
|
|
local FFlagShowConnectionErrorCode = settings():GetFFlag("ShowConnectionErrorCode")
|
|
local FFlagConnectionScriptEnabled = settings():GetFFlag("ConnectionScriptEnabled")
|
|
|
|
local antiAddictionNoticeStringEn = "Boycott bad games, refuse pirated games. Be aware of self-defense and being deceived. Playing games is good for your brain, but too much game play can harm your health. Manage your time well and enjoy a healthy lifestyle."
|
|
local FFlagConnectErrorHandlerInLoadingScript = require(RobloxGui.Modules.Flags.FFlagConnectErrorHandlerInLoadingScript)
|
|
local loadErrorHandlerFromEngine = game:GetEngineFeature("LoadErrorHandlerFromEngine")
|
|
|
|
local debugMode = false
|
|
|
|
local startTime = tick()
|
|
local loadingImageInputBeganConn = nil
|
|
local waitForGameIdConnection
|
|
|
|
local GAME_THUMBNAIL_URL = "rbxthumb://type=GameIcon&id=%d&w=256&h=256"
|
|
local MAX_ICON_SIZE = Vector2.new(256, 256)
|
|
local ICON_ASPECT_RATIO = 1
|
|
|
|
local COLORS = {
|
|
BACKGROUND_COLOR = Color3.fromRGB(45, 45, 45),
|
|
TEXT_COLOR = Color3.fromRGB(255, 255, 255),
|
|
ERROR = Color3.fromRGB(253, 68, 72)
|
|
}
|
|
local spinnerImageId = "rbxasset://textures/loading/robloxTilt.png"
|
|
|
|
-- Variables
|
|
local GameAssetInfo -- loaded by InfoProvider:LoadAssets()
|
|
local currScreenGui
|
|
local renderSteppedConnection
|
|
local backButtonConnection
|
|
local destroyingBackground, destroyedLoadingGui = false, false
|
|
local isTenFootInterface = GuiService:IsTenFootInterface()
|
|
|
|
local placeLabel, creatorLabel = nil, nil
|
|
local backgroundFadeStarted = false
|
|
local tweenPlaceIcon = nil
|
|
local layoutIsReady = false
|
|
|
|
local connectionHealthShown = false
|
|
local connectionHealthCon
|
|
|
|
local InfoProvider = {}
|
|
|
|
local function WaitForPlaceId()
|
|
local placeId = game.PlaceId
|
|
if placeId == 0 then
|
|
game:GetPropertyChangedSignal("PlaceId"):wait()
|
|
placeId = game.PlaceId
|
|
end
|
|
return placeId
|
|
end
|
|
|
|
function InfoProvider:GetGameName()
|
|
if GameAssetInfo ~= nil then
|
|
return GameAssetInfo.Name
|
|
else
|
|
return ''
|
|
end
|
|
end
|
|
|
|
function InfoProvider:GetCreatorName()
|
|
if GameAssetInfo ~= nil then
|
|
return GameAssetInfo.Creator.Name
|
|
else
|
|
return ''
|
|
end
|
|
end
|
|
|
|
function InfoProvider:LoadAssets()
|
|
if FFlagLoadTheLoadingScreenFaster then
|
|
coroutine.wrap(function()
|
|
local placeId = WaitForPlaceId()
|
|
local success, result = pcall(function()
|
|
GameAssetInfo = MarketplaceService:GetProductInfo(placeId)
|
|
end)
|
|
if not success then
|
|
print("LoadingScript->InfoProvider:LoadAssets:", result)
|
|
end
|
|
end)()
|
|
else
|
|
--spawn() == slowpoke.jpg
|
|
spawn(function()
|
|
local PLACEID = game.PlaceId
|
|
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 = MarketplaceService:GetProductInfo(PLACEID)
|
|
end)
|
|
if not success then
|
|
print("LoadingScript->InfoProvider:LoadAssets:", result)
|
|
end
|
|
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, 400, 0, 83),
|
|
Position = UDim2.new(1, -131, 0, 32),
|
|
AnchorPoint = Vector2.new(1, 0),
|
|
BackgroundTransparency = 1,
|
|
Font = Enum.Font.SourceSans,
|
|
TextSize = 48,
|
|
TextXAlignment = Enum.TextXAlignment.Right,
|
|
TextColor3 = COLORS.TEXT_COLOR,
|
|
Text = "Cancel"
|
|
}
|
|
|
|
if not 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, 32)
|
|
ContextActionService:UnbindCoreAction('CancelGameLoad')
|
|
game:Shutdown()
|
|
end
|
|
end,
|
|
false,
|
|
Enum.KeyCode.ButtonB)
|
|
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
|
|
|
|
local function GenerateGui()
|
|
local screenGui = create 'ScreenGui' {
|
|
Name = 'RobloxLoadingGui',
|
|
DisplayOrder = 8,
|
|
}
|
|
|
|
--
|
|
-- create descendant frames
|
|
local mainBackgroundContainer
|
|
|
|
local inGameGlobalGuiInset = settings():GetFVariable("InGameGlobalGuiInset")
|
|
mainBackgroundContainer = create 'Frame' {
|
|
Name = 'BlackFrame',
|
|
BackgroundColor3 = COLORS.BACKGROUND_COLOR,
|
|
BackgroundTransparency = 0,
|
|
Size = UDim2.new(1, 0, 1, inGameGlobalGuiInset),
|
|
Position = UDim2.new(0, 0, 0, -inGameGlobalGuiInset),
|
|
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
|
|
}
|
|
|
|
closeButton.MouseButton1Click:connect(function()
|
|
game:Shutdown()
|
|
end)
|
|
|
|
local graphicsFrame = create 'Frame' {
|
|
Name = 'GraphicsFrame',
|
|
BorderSizePixel = 0,
|
|
BackgroundTransparency = 1,
|
|
AnchorPoint = Vector2.new(1, 1),
|
|
Position = UDim2.new(0.95, 0, 0.95, 0),
|
|
Size = UDim2.new(0.15, 0, 0.15, 0),
|
|
ZIndex = 2,
|
|
Parent = mainBackgroundContainer,
|
|
|
|
create("UIAspectRatioConstraint") {
|
|
AspectRatio = 1
|
|
},
|
|
create("UISizeConstraint") {
|
|
MaxSize = Vector2.new(100, 100)
|
|
}
|
|
}
|
|
|
|
local loadingImage = create 'ImageLabel' {
|
|
Name = 'LoadingImage',
|
|
BackgroundTransparency = 1,
|
|
Image = spinnerImageId,
|
|
AnchorPoint = Vector2.new(0.5, 0.5),
|
|
Position = UDim2.new(0.5, 0, 0.5, 0),
|
|
Size = UDim2.new(1, 0, 1, 0),
|
|
ZIndex = 2,
|
|
Parent = graphicsFrame,
|
|
}
|
|
|
|
local numberOfTaps = 0
|
|
local lastTapTime = math.huge
|
|
local doubleTapTimeThreshold = 0.5
|
|
|
|
loadingImageInputBeganConn = loadingImage.InputBegan:connect(function()
|
|
if PolicyService:IsSubjectToChinaPolicies() then
|
|
return
|
|
end
|
|
|
|
if numberOfTaps == 0 then
|
|
numberOfTaps = 1
|
|
lastTapTime = tick()
|
|
return
|
|
end
|
|
|
|
if UserInputService.TouchEnabled == true and UserInputService.MouseEnabled == false then
|
|
if tick() - lastTapTime <= doubleTapTimeThreshold then
|
|
GuiService:ShowStatsBasedOnInputString("ConnectionHealth")
|
|
connectionHealthShown = not connectionHealthShown
|
|
end
|
|
end
|
|
|
|
numberOfTaps = 0
|
|
lastTapTime = math.huge
|
|
end)
|
|
|
|
local infoFrame = create 'Frame' {
|
|
Name = 'InfoFrame',
|
|
BackgroundTransparency = 1,
|
|
AnchorPoint = Vector2.new(0.5, 0.5),
|
|
Position = UDim2.new(0.5, 0, 0.5, 0),
|
|
Size = UDim2.new(0.75, 0, 1, 0),
|
|
ZIndex = 2,
|
|
Parent = mainBackgroundContainer,
|
|
create 'UIPadding' {
|
|
Name = 'UiMessagePadding',
|
|
PaddingBottom = UDim.new(0, 25),
|
|
} or nil
|
|
}
|
|
|
|
|
|
local uiMessageFrame = create 'Frame' {
|
|
Name = 'UiMessageFrame',
|
|
BackgroundTransparency = 1,
|
|
Position = UDim2.new(0.25, 0, 1, -120),
|
|
Size = UDim2.new(1, 0, 0, 35),
|
|
ZIndex = 2,
|
|
LayoutOrder = 5,
|
|
Parent = infoFrame,
|
|
|
|
create 'TextLabel' {
|
|
Name = 'UiMessage',
|
|
BackgroundTransparency = 1,
|
|
Position = UDim2.new(0, 0, 0, 5),
|
|
Size = UDim2.new(1, 0, 0, 25),
|
|
Font = Enum.Font.SourceSansLight,
|
|
TextSize = 18,
|
|
TextScaled = true,
|
|
TextWrapped = true,
|
|
TextColor3 = COLORS.TEXT_COLOR,
|
|
Text = "",
|
|
TextTransparency = 1,
|
|
ZIndex = 2,
|
|
}
|
|
}
|
|
|
|
local infoFrameAspect = create("UIAspectRatioConstraint") {
|
|
AspectRatio = 3 / 2,
|
|
Parent = infoFrame
|
|
}
|
|
local infoFrameList = create("UIListLayout") {
|
|
SortOrder = Enum.SortOrder.LayoutOrder,
|
|
FillDirection = Enum.FillDirection.Vertical,
|
|
VerticalAlignment = Enum.VerticalAlignment.Center,
|
|
HorizontalAlignment = Enum.HorizontalAlignment.Center,
|
|
Padding = UDim.new(0.05, 0),
|
|
Parent = infoFrame
|
|
}
|
|
|
|
local textContainer = create("Frame") {
|
|
BackgroundTransparency = 1,
|
|
Size = UDim2.new(2/3, 0, 1, 0),
|
|
LayoutOrder = 2,
|
|
Parent = nil,
|
|
|
|
create("UIListLayout") {
|
|
FillDirection = Enum.FillDirection.Vertical,
|
|
VerticalAlignment = Enum.VerticalAlignment.Center,
|
|
HorizontalAlignment = Enum.HorizontalAlignment.Left,
|
|
SortOrder = Enum.SortOrder.LayoutOrder
|
|
}
|
|
}
|
|
local placeIcon = create("ImageLabel") {
|
|
Name = "PlaceIcon",
|
|
BackgroundTransparency = 1,
|
|
Size = UDim2.new(1, 0, 1, 0),
|
|
Position = UDim2.new(0.5, 0, 0, 0),
|
|
AnchorPoint = Vector2.new(0.5, 0),
|
|
LayoutOrder = 1,
|
|
Parent = infoFrame,
|
|
|
|
ImageTransparency = 1,
|
|
Image = "",
|
|
|
|
create("UIAspectRatioConstraint") {
|
|
AspectRatio = FFlagLoadTheLoadingScreenEvenFaster and ICON_ASPECT_RATIO or 576 / 324,
|
|
AspectType = Enum.AspectType.ScaleWithParentSize,
|
|
DominantAxis = Enum.DominantAxis.Width
|
|
},
|
|
create("UISizeConstraint") {
|
|
MaxSize = FFlagLoadTheLoadingScreenEvenFaster and MAX_ICON_SIZE or Vector2.new(400, 400)
|
|
}
|
|
}
|
|
|
|
if FFlagLoadTheLoadingScreenEvenFaster then
|
|
local function onGameId()
|
|
local gameId = game.GameId
|
|
local imageUrl = GAME_THUMBNAIL_URL:format(gameId)
|
|
placeIcon.Image = imageUrl
|
|
ContentProvider:PreloadAsync({ placeIcon })
|
|
if not backgroundFadeStarted then
|
|
placeIcon.ImageTransparency = 0
|
|
end
|
|
end
|
|
if game.GameId > 0 then
|
|
coroutine.wrap(onGameId)()
|
|
else
|
|
waitForGameIdConnection = game:GetPropertyChangedSignal("GameId"):Connect(function ()
|
|
waitForGameIdConnection:Disconnect()
|
|
onGameId()
|
|
end)
|
|
end
|
|
else
|
|
--Start trying to load the place icon image
|
|
--Web might not have this icon size generated, so we can poll asset-thumbnail/json and check
|
|
--the JSON result for thumbnailFinal/Final to see when it's done being generated so we never
|
|
--show a N/A image. This is how the console AppShell does it!
|
|
coroutine.wrap(function()
|
|
local placeId = WaitForPlaceId()
|
|
|
|
local function tryGetFinalAsync()
|
|
local imageUrl = nil
|
|
local isGenerated = false
|
|
local success, msg = pcall(function()
|
|
imageUrl, isGenerated = AssetService:GetAssetThumbnailAsync(placeId, Vector2.new(576, 324), 1)
|
|
end)
|
|
|
|
if success and isGenerated == true and imageUrl then
|
|
ContentProvider:PreloadAsync { imageUrl }
|
|
placeIcon.Image = imageUrl
|
|
|
|
if not backgroundFadeStarted then
|
|
placeIcon.ImageTransparency = 0
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
while not tryGetFinalAsync() do end
|
|
end)()
|
|
end
|
|
|
|
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,
|
|
TextSize = isTenFootInterface and 48 or 24,
|
|
TextWrapped = true,
|
|
TextScaled = true,
|
|
TextColor3 = COLORS.TEXT_COLOR,
|
|
TextStrokeTransparency = 1,
|
|
TextTransparency = 1,
|
|
Text = "",
|
|
TextXAlignment = Enum.TextXAlignment.Center,
|
|
TextYAlignment = Enum.TextYAlignment.Bottom,
|
|
ZIndex = 2,
|
|
LayoutOrder = 2,
|
|
Parent = infoFrame
|
|
}
|
|
|
|
local creatorContainer = create 'Frame' {
|
|
Name = "Creator",
|
|
BackgroundTransparency = 1,
|
|
Size = UDim2.new(1, 0, 0, 48),
|
|
LayoutOrder = 3,
|
|
|
|
create 'UIListLayout' {
|
|
FillDirection = Enum.FillDirection.Horizontal,
|
|
HorizontalAlignment = Enum.HorizontalAlignment.Center,
|
|
VerticalAlignment = Enum.VerticalAlignment.Center,
|
|
SortOrder = Enum.SortOrder.LayoutOrder,
|
|
Padding = UDim.new(0, 5)
|
|
}
|
|
}
|
|
|
|
local byLabel, creatorIcon = nil, nil
|
|
if isTenFootInterface then
|
|
byLabel = create'TextLabel' {
|
|
Name = "ByLabel",
|
|
BackgroundTransparency = 1,
|
|
Size = UDim2.new(0, 36, 0, 30),
|
|
Position = UDim2.new(0, 0, 0, 80),
|
|
Font = Enum.Font.SourceSansLight,
|
|
TextSize = 36,
|
|
TextScaled = true,
|
|
TextColor3 = COLORS.TEXT_COLOR,
|
|
TextStrokeTransparency = 1,
|
|
Text = "By",
|
|
TextXAlignment = Enum.TextXAlignment.Left,
|
|
TextYAlignment = Enum.TextYAlignment.Top,
|
|
ZIndex = 2,
|
|
Visible = true,
|
|
Parent = infoFrame,
|
|
LayoutOrder = 1
|
|
}
|
|
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/RobloxIcon24.png',
|
|
ZIndex = 2,
|
|
Visible = true,
|
|
Parent = infoFrame,
|
|
LayoutOrder = 2
|
|
}
|
|
end
|
|
|
|
creatorLabel = create 'TextLabel' {
|
|
Name = 'CreatorLabel',
|
|
BackgroundTransparency = 1,
|
|
Size = UDim2.new(1, 0, 0, 30),
|
|
Position = UDim2.new(0, 0, 0, 80),
|
|
Font = Enum.Font.SourceSansLight,
|
|
TextSize = isTenFootInterface and 36 or 18,
|
|
TextWrapped = true,
|
|
TextScaled = true,
|
|
TextColor3 = COLORS.TEXT_COLOR,
|
|
TextStrokeTransparency = 1,
|
|
Text = "",
|
|
TextXAlignment = Enum.TextXAlignment.Center,
|
|
TextYAlignment = Enum.TextYAlignment.Center,
|
|
ZIndex = 2,
|
|
LayoutOrder = 4,
|
|
Parent = infoFrame
|
|
}
|
|
|
|
if isTenFootInterface then
|
|
creatorContainer.Parent = infoFrame
|
|
|
|
byLabel.TextScaled = false
|
|
byLabel.Parent = creatorContainer
|
|
byLabel.TextXAlignment = Enum.TextXAlignment.Center
|
|
byLabel.TextYAlignment = Enum.TextYAlignment.Center
|
|
|
|
creatorIcon.Parent = creatorContainer
|
|
|
|
creatorLabel.Parent = creatorContainer
|
|
creatorLabel.TextScaled = false
|
|
creatorLabel.TextWrapped = false
|
|
creatorLabel.Position = UDim2.new(0, 72, 0, 80)
|
|
creatorLabel.Size = UDim2.new(0, creatorLabel.TextBounds.X, 1, 0)
|
|
end
|
|
|
|
coroutine.wrap(function()
|
|
RunService.RenderStepped:wait()
|
|
RunService.RenderStepped:wait()
|
|
layoutIsReady = true
|
|
|
|
placeLabel.TextTransparency = 0
|
|
|
|
local uiMessage = uiMessageFrame.UiMessage
|
|
if uiMessage.Text ~= "" then
|
|
uiMessage.TextTransparency = 0
|
|
end
|
|
end)()
|
|
|
|
if not FFlagConnectionScriptEnabled or isTenFootInterface then
|
|
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,
|
|
|
|
create 'TextLabel' {
|
|
Name = "ErrorText",
|
|
BackgroundTransparency = 1,
|
|
Size = UDim2.new(1, 0, 1, 0),
|
|
Font = Enum.Font.SourceSansBold,
|
|
TextSize = 14,
|
|
TextWrapped = true,
|
|
TextColor3 = COLORS.TEXT_COLOR,
|
|
Text = "",
|
|
ZIndex = 8
|
|
}
|
|
}
|
|
else
|
|
if not loadErrorHandlerFromEngine and FFlagConnectErrorHandlerInLoadingScript then
|
|
ScriptContext:AddCoreScriptLocal("Connection", RobloxGui)
|
|
end
|
|
end
|
|
|
|
while not game:GetService("CoreGui") do
|
|
if FFlagLoadTheLoadingScreenFaster then
|
|
RunService.RenderStepped:wait()
|
|
else
|
|
wait()
|
|
end
|
|
end
|
|
|
|
screenGui.Parent = CoreGui
|
|
|
|
infoFrame.RootLocalizationTable = CoreGui:FindFirstChild("CoreScriptLocalization")
|
|
|
|
currScreenGui = screenGui
|
|
|
|
local function onResized()
|
|
local isPortrait = screenGui.AbsoluteSize.X < screenGui.AbsoluteSize.Y
|
|
|
|
infoFrame.Position = UDim2.new(0.5, 0, 0.5, 0)
|
|
infoFrame.AnchorPoint = Vector2.new(0.5, 0.5)
|
|
infoFrame.Size = UDim2.new(0.75, 0, 1, 0)
|
|
infoFrameAspect.AspectRatio = isPortrait and 2/3 or 3/2
|
|
|
|
placeLabel.Size = UDim2.new(1, 0, 0, isTenFootInterface and 120 or 80)
|
|
|
|
if isTenFootInterface then
|
|
creatorLabel.Size = UDim2.new(0, creatorLabel.TextBounds.X, 1, 0)
|
|
else
|
|
creatorLabel.Size = UDim2.new(1, 0, 0, 30)
|
|
end
|
|
|
|
infoFrameList.FillDirection = Enum.FillDirection.Vertical
|
|
infoFrameList.HorizontalAlignment = Enum.HorizontalAlignment.Center
|
|
infoFrameList.Padding = UDim.new(0, 0)
|
|
textContainer.Parent = nil
|
|
infoFrameList:ApplyLayout()
|
|
|
|
placeLabel.TextXAlignment = Enum.TextXAlignment.Center
|
|
placeLabel.AutoLocalize = false
|
|
end
|
|
onResized()
|
|
screenGui:GetPropertyChangedSignal("AbsoluteSize"):connect(onResized)
|
|
end
|
|
|
|
---------------------------------------------------------
|
|
-- Main Script (show something now + setup connections)
|
|
|
|
-- start loading assets asap
|
|
InfoProvider:LoadAssets()
|
|
GenerateGui()
|
|
if isTenFootInterface then
|
|
createTenfootCancelGui()
|
|
end
|
|
|
|
local fadeCycleTime = 1.7
|
|
local turnCycleTime = 2
|
|
|
|
local function spinnerEasingFunc(a, b, t)
|
|
t = t * 2
|
|
if t < 1 then
|
|
return b / 2 * t*t*t + a
|
|
else
|
|
t = t - 2
|
|
return b / 2 * (t * t * t + 2) + b
|
|
end
|
|
end
|
|
|
|
if FFlagLoadingScreenDontBlockOnPolicyService then
|
|
local showAntiAddictionNoticeStringEn = false
|
|
if FFlagLoadingScreenShowBlankUntilPolicyServiceReturns then
|
|
showAntiAddictionNoticeStringEn = "waiting"
|
|
end
|
|
-- PolicyService requires LocalPlayer to exist, which doesn't happen until
|
|
-- after we connect to the server. If the server is full, this can take a
|
|
-- very long time (like several minutes) to return a value. As a result, we
|
|
-- call it asynchronously and default to false.
|
|
coroutine.wrap(function()
|
|
showAntiAddictionNoticeStringEn = PolicyService:IsSubjectToChinaPolicies()
|
|
end)()
|
|
|
|
renderSteppedConnection = RunService.RenderStepped:connect(function(dt)
|
|
if not currScreenGui then return end
|
|
if not currScreenGui:FindFirstChild("BlackFrame") then return end
|
|
|
|
local infoFrame = currScreenGui.BlackFrame:FindFirstChild('InfoFrame')
|
|
if infoFrame then
|
|
-- set place name
|
|
if placeLabel and placeLabel.Text == "" then
|
|
placeLabel.Text = InfoProvider:GetGameName()
|
|
end
|
|
|
|
-- set creator name
|
|
if creatorLabel and creatorLabel.Text == "" then
|
|
if FFlagLoadingScreenShowBlankUntilPolicyServiceReturns and showAntiAddictionNoticeStringEn == "waiting" then
|
|
creatorLabel.Text = ""
|
|
elseif showAntiAddictionNoticeStringEn then
|
|
creatorLabel.Text = antiAddictionNoticeStringEn
|
|
else
|
|
local creatorName = InfoProvider:GetCreatorName()
|
|
if creatorName ~= "" then
|
|
if isTenFootInterface then
|
|
creatorLabel.Text = creatorName
|
|
creatorLabel.Size = UDim2.new(0, creatorLabel.TextBounds.X, 1, 0)
|
|
else
|
|
creatorLabel.Text = "By ".. creatorName
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local currentTime = tick()
|
|
local fadeAmount = dt * fadeCycleTime
|
|
|
|
local spinnerImage = currScreenGui.BlackFrame.GraphicsFrame.LoadingImage
|
|
local timeInCycle = currentTime % turnCycleTime
|
|
local cycleAlpha = spinnerEasingFunc(0, 1, timeInCycle / turnCycleTime)
|
|
spinnerImage.Rotation = cycleAlpha * 360
|
|
|
|
|
|
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)
|
|
else
|
|
coroutine.wrap(function()
|
|
local showAntiAddictionNoticeStringEn = PolicyService:IsSubjectToChinaPolicies()
|
|
|
|
renderSteppedConnection = RunService.RenderStepped:connect(function(dt)
|
|
if not currScreenGui then return end
|
|
if not currScreenGui:FindFirstChild("BlackFrame") then return end
|
|
|
|
local infoFrame = currScreenGui.BlackFrame:FindFirstChild('InfoFrame')
|
|
if infoFrame then
|
|
-- set place name
|
|
if placeLabel and placeLabel.Text == "" then
|
|
placeLabel.Text = InfoProvider:GetGameName()
|
|
end
|
|
|
|
-- set creator name
|
|
if creatorLabel and creatorLabel.Text == "" then
|
|
if showAntiAddictionNoticeStringEn then
|
|
creatorLabel.Text = antiAddictionNoticeStringEn
|
|
else
|
|
local creatorName = InfoProvider:GetCreatorName()
|
|
if creatorName ~= "" then
|
|
if isTenFootInterface then
|
|
creatorLabel.Text = creatorName
|
|
creatorLabel.Size = UDim2.new(0, creatorLabel.TextBounds.X, 1, 0)
|
|
else
|
|
creatorLabel.Text = "By ".. creatorName
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local currentTime = tick()
|
|
local fadeAmount = dt * fadeCycleTime
|
|
|
|
local spinnerImage = currScreenGui.BlackFrame.GraphicsFrame.LoadingImage
|
|
local timeInCycle = currentTime % turnCycleTime
|
|
local cycleAlpha = spinnerEasingFunc(0, 1, timeInCycle / turnCycleTime)
|
|
spinnerImage.Rotation = cycleAlpha * 360
|
|
|
|
|
|
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)
|
|
end)()
|
|
end
|
|
|
|
-- use the old error frame when on XBox
|
|
if not FFlagConnectionScriptEnabled or isTenFootInterface then
|
|
local errorImage
|
|
|
|
GuiService.ErrorMessageChanged:connect(function()
|
|
if GuiService:GetErrorMessage() ~= '' then
|
|
--TODO: Remove this reference to Utility
|
|
local utility = require(RobloxGui.Modules.Settings.Utility)
|
|
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.BACKGROUND_COLOR
|
|
currScreenGui.ErrorFrame.BackgroundTransparency = 0.5
|
|
currScreenGui.ErrorFrame.ErrorText.TextSize = 36
|
|
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
|
|
elseif utility:IsSmallTouchScreen() then
|
|
currScreenGui.ErrorFrame.Size = UDim2.new(0.5, 0, 0, 40)
|
|
end
|
|
|
|
local errorCode = GuiService:GetErrorCode()
|
|
local errorMessage = GuiService:GetErrorMessage()
|
|
if not FFlagShowConnectionErrorCode then
|
|
currScreenGui.ErrorFrame.ErrorText.Text = errorMessage
|
|
else
|
|
if not errorCode then
|
|
currScreenGui.ErrorFrame.ErrorText.Text = ("%s (Error Code: -1)"):format(errorMessage)
|
|
else
|
|
currScreenGui.ErrorFrame.ErrorText.Text = ("%s (Error Code: %d)"):format(errorMessage, errorCode.Value)
|
|
end
|
|
end
|
|
|
|
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)
|
|
end
|
|
|
|
if FFlagBackButtonWhileLoadingGoesBackToApp then
|
|
backButtonConnection = GuiService.ShowLeaveConfirmation:Connect(function()
|
|
-- When OS back button is pressed during loading screen, exit
|
|
-- immediately. Behaves the same as the close button.
|
|
game:Shutdown()
|
|
end)
|
|
end
|
|
|
|
GuiService.UiMessageChanged:connect(function(type, newMessage)
|
|
if type == Enum.UiMessageType.UiMessageInfo then
|
|
local blackFrame = currScreenGui and currScreenGui:FindFirstChild('BlackFrame')
|
|
if blackFrame then
|
|
local infoFrame = blackFrame:FindFirstChild("InfoFrame")
|
|
if infoFrame then
|
|
local uiMessage = infoFrame.UiMessageFrame.UiMessage
|
|
uiMessage.Text = newMessage
|
|
if newMessage ~= '' and layoutIsReady then
|
|
uiMessage.TextTransparency = 0
|
|
else
|
|
uiMessage.TextTransparency = 1
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
|
|
if not FFlagConnectionScriptEnabled and GuiService:GetErrorMessage() ~= '' then
|
|
currScreenGui.ErrorFrame.ErrorText.Text = GuiService:GetErrorMessage()
|
|
currScreenGui.ErrorFrame.Visible = true
|
|
end
|
|
|
|
|
|
local function stopListeningToRenderingStep()
|
|
if renderSteppedConnection then
|
|
renderSteppedConnection:disconnect()
|
|
renderSteppedConnection = nil
|
|
end
|
|
end
|
|
|
|
local function disconnectAndCloseHealthStat()
|
|
if connectionHealthCon then
|
|
connectionHealthCon:disconnect()
|
|
connectionHealthCon = nil
|
|
GuiService:CloseStatsBasedOnInputString("ConnectionHealth")
|
|
end
|
|
end
|
|
|
|
local function fadeAndDestroyBlackFrame(blackFrame)
|
|
if destroyingBackground then return end
|
|
destroyingBackground = true
|
|
spawn(function()
|
|
local infoFrame = blackFrame:FindFirstChild("InfoFrame")
|
|
local graphicsFrame = blackFrame:FindFirstChild("GraphicsFrame")
|
|
|
|
local infoFrameDescendants = infoFrame:GetDescendants()
|
|
local transparency = 0
|
|
local rateChange = 1.8
|
|
local lastUpdateTime = nil
|
|
|
|
--Notify everything else to stop messing with transparency to avoid ugly fighting effects
|
|
backgroundFadeStarted = true
|
|
if tweenPlaceIcon then
|
|
tweenPlaceIcon:Cancel()
|
|
tweenPlaceIcon = nil
|
|
end
|
|
|
|
while transparency < 1 do
|
|
RunService.RenderStepped:wait()
|
|
if not lastUpdateTime then
|
|
lastUpdateTime = tick()
|
|
else
|
|
local newTime = tick()
|
|
transparency = transparency + rateChange * (newTime - lastUpdateTime)
|
|
for i = 1, #infoFrameDescendants do
|
|
local child = infoFrameDescendants[i]
|
|
if child:IsA('TextLabel') then
|
|
child.TextTransparency = transparency
|
|
elseif child:IsA('ImageLabel') then
|
|
child.ImageTransparency = transparency
|
|
end
|
|
end
|
|
graphicsFrame.LoadingImage.ImageTransparency = transparency
|
|
blackFrame.BackgroundTransparency = transparency
|
|
|
|
lastUpdateTime = newTime
|
|
end
|
|
end
|
|
if blackFrame ~= nil then
|
|
stopListeningToRenderingStep()
|
|
blackFrame:Destroy()
|
|
end
|
|
|
|
if waitForGameIdConnection then
|
|
waitForGameIdConnection:Disconnect()
|
|
end
|
|
|
|
if loadingImageInputBeganConn then
|
|
loadingImageInputBeganConn:disconnect()
|
|
end
|
|
|
|
if backButtonConnection then
|
|
backButtonConnection:Disconnect()
|
|
end
|
|
|
|
if connectionHealthShown then
|
|
if UserInputService.TouchEnabled == true and UserInputService.MouseEnabled == false then
|
|
connectionHealthCon = game:GetService("UserInputService").InputBegan:connect(function()
|
|
disconnectAndCloseHealthStat()
|
|
end)
|
|
else
|
|
GuiService:CloseStatsBasedOnInputString("ConnectionHealth")
|
|
end
|
|
else
|
|
GuiService:CloseStatsBasedOnInputString("ConnectionHealth")
|
|
end
|
|
end)
|
|
end
|
|
|
|
local function destroyLoadingElements(instant)
|
|
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" and not instant then
|
|
fadeAndDestroyBlackFrame(guiChildren[i])
|
|
else
|
|
guiChildren[i]:Destroy()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function waitForCharacterLoaded()
|
|
if Players.CharacterAutoLoads then
|
|
local localPlayer = Players.LocalPlayer
|
|
if not localPlayer then
|
|
Players:GetPropertyChangedSignal("LocalPlayer"):wait()
|
|
localPlayer = Players.LocalPlayer
|
|
end
|
|
if not localPlayer.Character then
|
|
localPlayer.CharacterAdded:wait()
|
|
end
|
|
end
|
|
end
|
|
|
|
local function handleRemoveDefaultLoadingGui(instant)
|
|
if isTenFootInterface then
|
|
ContextActionService:UnbindCoreAction('CancelGameLoad')
|
|
end
|
|
destroyLoadingElements(instant)
|
|
ReplicatedFirst:SetDefaultLoadingGuiRemoved()
|
|
end
|
|
|
|
local function handleFinishedReplicating()
|
|
if #ReplicatedFirst:GetChildren() == 0 then
|
|
if game:IsLoaded() then
|
|
waitForCharacterLoaded()
|
|
handleRemoveDefaultLoadingGui()
|
|
else
|
|
local gameLoadedCon = nil
|
|
gameLoadedCon = game.Loaded:connect(function()
|
|
gameLoadedCon:disconnect()
|
|
gameLoadedCon = nil
|
|
waitForCharacterLoaded()
|
|
handleRemoveDefaultLoadingGui()
|
|
end)
|
|
end
|
|
else
|
|
wait(5) -- make sure after 5 seconds we remove the default gui, even if the user doesn't
|
|
handleRemoveDefaultLoadingGui()
|
|
end
|
|
end
|
|
|
|
if debugMode then
|
|
warn("Not destroying loading screen because debugMode is true")
|
|
return
|
|
end
|
|
ReplicatedFirst.FinishedReplicating:connect(handleFinishedReplicating)
|
|
if ReplicatedFirst:IsFinishedReplicating() then
|
|
handleFinishedReplicating()
|
|
end
|
|
|
|
ReplicatedFirst.RemoveDefaultLoadingGuiSignal:connect(handleRemoveDefaultLoadingGui)
|
|
if ReplicatedFirst:IsDefaultLoadingGuiRemoved() then
|
|
handleRemoveDefaultLoadingGui()
|
|
end
|
|
|
|
coroutine.wrap(function()
|
|
if not VRService.VREnabled then
|
|
VRService:GetPropertyChangedSignal("VREnabled"):Wait()
|
|
end
|
|
handleRemoveDefaultLoadingGui(true)
|
|
require(RobloxGui.Modules.LoadingScreen3D)
|
|
end)()
|