Merge pull request #2 from CFC-Servers/Initial

Mvp complete
This commit is contained in:
Samuel Williams 2019-12-15 20:28:52 +00:00 committed by GitHub
commit 4d0503ad8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 64 additions and 13 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)