commit
4d0503ad8c
@ -1,5 +1,7 @@
|
||||
crashApi = {}
|
||||
|
||||
local http = http
|
||||
|
||||
local cfc_endpoint = "https://scripting.cfcservers.org/cfc3-ping"
|
||||
local global_endpoint = "https://www.google.com"
|
||||
|
||||
@ -21,6 +23,7 @@ local function getState()
|
||||
return state
|
||||
end
|
||||
|
||||
-- Check both websites responded, set state accordingly
|
||||
local function handleResponses()
|
||||
if pingCancelled then -- Ignore responses if ping was cancelled
|
||||
return
|
||||
@ -40,6 +43,7 @@ local function handleResponses()
|
||||
end
|
||||
end
|
||||
|
||||
-- Fetch cfc and global end points
|
||||
local function triggerPing()
|
||||
pingCancelled = false
|
||||
state = api.PINGING_API
|
||||
@ -48,6 +52,7 @@ local function triggerPing()
|
||||
http.Fetch(cfc_endpoint,
|
||||
function(body, size, headers, code)
|
||||
local data = util.JSONToTable( body )
|
||||
-- If response is malformed, or empty, set cfc false
|
||||
if not data or data["server-is-up"] == nil then -- Can't use dot notation cuz api field has dashes >:(
|
||||
responses.cfc = false
|
||||
handleResponses()
|
||||
@ -57,6 +62,7 @@ local function triggerPing()
|
||||
end
|
||||
end,
|
||||
function(err)
|
||||
-- If cfc doesn't respond, set cfc false, might want to do something special here, as this means cfcservers had a heart attack
|
||||
responses.cfc = false
|
||||
handleResponses()
|
||||
end
|
||||
|
@ -1,5 +1,7 @@
|
||||
include("cfc_disconnect_interface/client/cl_api.lua")
|
||||
|
||||
local vgui, timer, hook = vgui, timer, hook
|
||||
|
||||
surface.CreateFont( "CFC_Normal",
|
||||
{
|
||||
font = "arial",
|
||||
@ -24,10 +26,15 @@ surface.CreateFont( "CFC_Button",
|
||||
}
|
||||
)
|
||||
|
||||
local GAME_URL = "https://cdn.cfcservers.org/media/dinosaur/index.html"
|
||||
-- local GAME_URL = "http://local:8080/"
|
||||
-- Width of the game on the website in pixels, needed as I didn't write the dinosaur game, and it doesn't like centering nicely
|
||||
local GAME_WIDTH = 1256
|
||||
|
||||
local interfaceDerma = false
|
||||
|
||||
local TIME_TO_RESTART = 10
|
||||
local timeDown
|
||||
local timeDown = 0
|
||||
local apiState
|
||||
local previouslyShown = false
|
||||
|
||||
@ -47,6 +54,7 @@ local function secondsAsTime(s)
|
||||
end
|
||||
|
||||
-- Delay Function
|
||||
-- Delays a function call until the next "tick", gm_crashsys does this, and I'm assuming its for a reason
|
||||
local delayId = 0
|
||||
local function delaycall(time, callback)
|
||||
local wait = RealTime() + time
|
||||
@ -61,8 +69,8 @@ local function delaycall(time, callback)
|
||||
end
|
||||
|
||||
local function rejoin()
|
||||
delaycall(1, function() -- gm_crashsys does this, I don't feel like going through finding out why, so I'm just gonna do the same :)
|
||||
RunConsoleCommand( "snd_restart" )
|
||||
delaycall(1, function()
|
||||
RunConsoleCommand( "snd_restart" ) -- Restarts sound engine, good practice?
|
||||
RunConsoleCommand( "retry" )
|
||||
end)
|
||||
end
|
||||
@ -73,9 +81,12 @@ local function leave()
|
||||
end)
|
||||
end
|
||||
|
||||
-- Creates and populates a title bar for the frame
|
||||
local function addTitleBar(frame)
|
||||
local frameW, frameH = frame:GetSize()
|
||||
local titleBarHeight = 32
|
||||
|
||||
-- The bar itself
|
||||
local titleBar = vgui.Create( "DPanel", frame )
|
||||
titleBar:SetSize( frameW, titleBarHeight )
|
||||
titleBar:SetPos( 0, 0 )
|
||||
@ -84,8 +95,8 @@ local function addTitleBar(frame)
|
||||
surface.DrawRect( 0, 0, w, h )
|
||||
end
|
||||
|
||||
-- Close button, could be removed, but I personally think it should stay, allows you to save e2/sf files
|
||||
local closeBtnPadding = (titleBarHeight - 16) / 2
|
||||
|
||||
local closeBtn = vgui.Create( "DImageButton", titleBar )
|
||||
closeBtn:SetSize( 16, 16 )
|
||||
closeBtn:SetPos( frameW - 16 - closeBtnPadding, closeBtnPadding)
|
||||
@ -94,8 +105,8 @@ local function addTitleBar(frame)
|
||||
frame:Close()
|
||||
end
|
||||
|
||||
-- Title label
|
||||
local titleLabelPadding = (titleBarHeight - 26) / 2
|
||||
|
||||
local titleLabel = vgui.Create( "DLabel", titleBar )
|
||||
titleLabel:SetFont( "CFC_Special" )
|
||||
titleLabel:SetText( "Oops! Looks like the server crashed..." )
|
||||
@ -106,7 +117,11 @@ local function addTitleBar(frame)
|
||||
return titleBar
|
||||
end
|
||||
|
||||
-- Create a button in specific format for button bar
|
||||
-- xFraction is 0-1 for how far across the button should be
|
||||
-- Colours are self explan
|
||||
local function makeButton(frame, text, xFraction, doClick, outlineCol, fillCol, hoverOutlineCol, hoverFillCol)
|
||||
-- Defaults for colours
|
||||
outlineCol = outlineCol or Color( 255, 255, 255 )
|
||||
fillCol = fillCol or primaryCol
|
||||
hoverOutlineCol = hoverOutlineCol or Color(155,241,255)
|
||||
@ -122,6 +137,7 @@ local function makeButton(frame, text, xFraction, doClick, outlineCol, fillCol,
|
||||
btn:CenterVertical()
|
||||
btn.DoClick = doClick
|
||||
|
||||
-- Fade animation state and time for consistant animation speed on different FPS
|
||||
btn.fadeState = 0
|
||||
btn.prevTime = CurTime()
|
||||
|
||||
@ -131,7 +147,7 @@ local function makeButton(frame, text, xFraction, doClick, outlineCol, fillCol,
|
||||
-- Make anim same speed for all framerates
|
||||
local dt = CurTime() - self.prevTime
|
||||
self.prevTime = CurTime()
|
||||
if dt > 1 then dt = 0 end
|
||||
if dt > 1 then dt = 0 end -- This happens on first Think after being Shown, dt ends up being very large
|
||||
|
||||
if self:IsHovered() and self.fadeState < 1 then
|
||||
self.fadeState = math.Clamp(self.fadeState + btnAnimSpeed * dt, 0, 1)
|
||||
@ -155,7 +171,6 @@ local function makeButton(frame, text, xFraction, doClick, outlineCol, fillCol,
|
||||
end
|
||||
|
||||
self:SetTextColor( lineCol )
|
||||
|
||||
surface.SetDrawColor( lineCol )
|
||||
surface.DrawRect( 0, 0, w, h )
|
||||
surface.SetDrawColor( bgCol )
|
||||
@ -166,6 +181,7 @@ local function makeButton(frame, text, xFraction, doClick, outlineCol, fillCol,
|
||||
return btn
|
||||
end
|
||||
|
||||
-- Create bar panel and add buttons
|
||||
local function addButtonsBar(frame)
|
||||
local frameW, frameH = frame:GetSize()
|
||||
|
||||
@ -179,14 +195,17 @@ local function addButtonsBar(frame)
|
||||
surface.DrawLine( 16, 0, w - 16, 0 )
|
||||
end
|
||||
|
||||
-- Put buttons onto the panel as members for easy access
|
||||
barPanel.reconBtn = makeButton(barPanel, "RECONNECT", 0.25, rejoin,
|
||||
Color( 74, 251, 191 ), nil, Color( 74, 251, 191 ), Color( 64, 141, 131 ))
|
||||
-- Reconnect button will usually start as disabled
|
||||
barPanel.reconBtn:SetDisabled( true )
|
||||
barPanel.disconBtn = makeButton(barPanel, "DISCONNECT", 0.75, leave)
|
||||
|
||||
return barPanel
|
||||
end
|
||||
|
||||
-- Making lines of text for body
|
||||
local function makeLabel(frame, text, top, col, xFraction)
|
||||
col = col or Color( 255, 255, 255 )
|
||||
local label = vgui.Create( "DLabel", frame )
|
||||
@ -199,17 +218,21 @@ local function makeLabel(frame, text, top, col, xFraction)
|
||||
return label
|
||||
end
|
||||
|
||||
-- Text for internet down on body
|
||||
local function populateBodyInternetDown(body)
|
||||
local label1 = makeLabel(body, "Looks like your internet has gone down!", 20)
|
||||
local label2 = makeLabel(body, "Stick around for when it comes back", 64)
|
||||
end
|
||||
|
||||
-- Text for server down on body
|
||||
local function populateBodyServerDown(body)
|
||||
|
||||
local frameW, frameH = body:GetSize()
|
||||
local restartTimeStr = "The server normally takes about " .. secondsAsTime(TIME_TO_RESTART) .. " to restart!"
|
||||
local restartTimeLabel = makeLabel(body, restartTimeStr, 0)
|
||||
local curTimePreLabel = makeLabel(body, "It has been down for", 32)
|
||||
-- When the server comes back up, "It has been down for" => "It was down for"
|
||||
-- Then resize and move
|
||||
function curTimePreLabel:Think()
|
||||
if apiState == crashApi.SERVER_UP and not self.backUp then
|
||||
self:SetText( "It was down for" )
|
||||
@ -219,10 +242,15 @@ local function populateBodyServerDown(body)
|
||||
end
|
||||
end
|
||||
|
||||
-- Label for when timeDown > averageTimeDown
|
||||
-- Currently on the right, change the 0.8 at the end to move it horizontally
|
||||
local tooLongLabel = makeLabel(body, "Uh oh, seems it's taking a little longer than usual!", 70, Color( 251, 191, 83 ), 0.8)
|
||||
tooLongLabel:SetAlpha(0)
|
||||
tooLongLabel:Hide()
|
||||
|
||||
-- Text for downTime, update its value in Think
|
||||
-- If server comes back up, make it green and stop updating it
|
||||
-- If timeDown > averageTimeDown, make it red and show the tooLongLabel
|
||||
local curTimeLabel = makeLabel(body, secondsAsTime(math.floor(timeDown)), 70, Color( 251, 191, 83 ))
|
||||
function curTimeLabel:Think()
|
||||
if apiState ~= crashApi.SERVER_UP then
|
||||
@ -240,8 +268,11 @@ local function populateBodyServerDown(body)
|
||||
end
|
||||
end
|
||||
|
||||
-- Fill the body with elements, body created elsewhere as it's size relies on size of titleBar and buttonsBar
|
||||
local function populateBody(body)
|
||||
body.Paint = nil
|
||||
|
||||
-- Fill top text based on crashApi state
|
||||
if apiState == crashApi.NO_INTERNET then
|
||||
populateBodyInternetDown(body)
|
||||
else -- Server down or up via api, and down via net
|
||||
@ -249,28 +280,33 @@ local function populateBody(body)
|
||||
end
|
||||
|
||||
local frameW, frameH = 0.8 * ScrW(), 0.8 * ScrH()
|
||||
|
||||
local playGameLabel = makeLabel(body, "Why not play a game while you wait? (Press space)", 108)
|
||||
|
||||
-- Game wrapper, in case we ever want to make a game that runs in lua
|
||||
local gamePanel = vgui.Create( "DPanel", body )
|
||||
gamePanel:SetSize( frameW - 20, frameH - 134 - 15 )
|
||||
gamePanel:SetPos( -6, 134 + 10 )
|
||||
gamePanel.Paint = nil
|
||||
|
||||
-- HTML element rending game at GAME_URL, constantly grabs focus
|
||||
local gameHtml = vgui.Create( "DHTML", gamePanel )
|
||||
gameHtml:Dock( FILL )
|
||||
gameHtml:OpenURL("https://cdn.cfcservers.org/media/dinosaur/index.html")
|
||||
gameHtml:SetSize( gamePanel:GetSize() )
|
||||
gameHtml:SetPos( (gamePanel:GetWide() - GAME_WIDTH) / 2, 0 )
|
||||
gameHtml:OpenURL( GAME_URL )
|
||||
function gameHtml:Think()
|
||||
if not gameHtml:HasFocus() then gameHtml:RequestFocus() end
|
||||
end
|
||||
end
|
||||
|
||||
-- Entry point for creating the interface
|
||||
local function createInterface()
|
||||
|
||||
-- Sized at 80% of the screen
|
||||
local frameW, frameH = 0.8 * ScrW(), 0.8 * ScrH()
|
||||
|
||||
-- Needed for bg blur
|
||||
local startTime = SysTime()
|
||||
|
||||
-- Main frame
|
||||
local frame = vgui.Create( "DFrame" )
|
||||
interfaceDerma = frame
|
||||
frame:SetSize( frameW, frameH )
|
||||
@ -286,14 +322,18 @@ local function createInterface()
|
||||
surface.DrawRect( 0, 0, w, h )
|
||||
end
|
||||
|
||||
-- Generate title and buttons bars
|
||||
local titlePanel = addTitleBar(frame)
|
||||
local btnsPanel = addButtonsBar(frame)
|
||||
|
||||
-- Create body that fills the unused space
|
||||
local body = vgui.Create( "DPanel", frame )
|
||||
body:SetSize(frameW - 32, frameH - 32 - titlePanel:GetTall() - btnsPanel:GetTall())
|
||||
body:SetPos(16, titlePanel:GetTall() + 16)
|
||||
populateBody(body)
|
||||
|
||||
-- If server fully recovers without crashing, close menu
|
||||
-- If server reboots, enabled the reconnect button
|
||||
function frame:Think()
|
||||
if apiState == crashApi.INACTIVE then
|
||||
frame:Close() -- Server recovered without ever closing
|
||||
@ -313,10 +353,12 @@ end
|
||||
hook.Add("cfc_di_crashTick", "cfc_di_interfaceUpdate", function(isCrashing, _timeDown, _apiState)
|
||||
timeDown = _timeDown or 0
|
||||
apiState = _apiState
|
||||
-- Open interface if server is crashing, API has responded, interface isn't already open, and interface has not yet been opened
|
||||
if isCrashing and apiState ~= crashApi.PINGING_API and not interfaceDerma and not previouslyShown then
|
||||
createInterface()
|
||||
previouslyShown = true
|
||||
end
|
||||
-- Close menu if server stops crashing
|
||||
if not isCrashing then
|
||||
previouslyShown = false
|
||||
if interfaceDerma then
|
||||
|
@ -1,9 +1,11 @@
|
||||
include("cfc_disconnect_interface/client/cl_api.lua")
|
||||
|
||||
local net, hook, timer = net, hook, timer
|
||||
|
||||
local GRACE_TIME = 3.5 -- How many seconds of lag should we have before showing the panel?
|
||||
local PING_MISS = 2 -- How many pings can we miss on join?
|
||||
|
||||
local API_TIMEOUT = 15 -- How often to call the api
|
||||
local API_TIMEOUT = 5 -- How often to call the api
|
||||
|
||||
local lastPing
|
||||
local lastApiCall
|
||||
@ -45,6 +47,7 @@ local function checkCrashTick()
|
||||
if timeout > GRACE_TIME then
|
||||
crashTick(timeout)
|
||||
else
|
||||
-- Server recovered while crashApi was running, cancel the request
|
||||
if crashApi.getState() ~= crashApi.INACTIVE then
|
||||
crashApi.cancelPing();
|
||||
end
|
||||
|
@ -16,7 +16,7 @@ net.Receive("cfc_di_loaded", function(len, ply)
|
||||
end)
|
||||
|
||||
hook.Add("PlayerDisconnected", "crashsys", function(ply)
|
||||
ping(ply)
|
||||
ping(ply) -- Stop menu popping up while they are leaving
|
||||
table.RemoveByValue(players, ply)
|
||||
end)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user