From aa7d729cfbc610374483db316b73e1dcc6065b6b Mon Sep 17 00:00:00 2001 From: samuelWilliams99 Date: Mon, 23 Dec 2019 01:33:12 +0000 Subject: [PATCH] Redesign --- lua/autorun/server/sv_init.lua | 2 + .../client/cl_interface.lua | 198 ++++++++++++------ materials/icons/cross.png | Bin 0 -> 4683 bytes 3 files changed, 139 insertions(+), 61 deletions(-) create mode 100644 materials/icons/cross.png diff --git a/lua/autorun/server/sv_init.lua b/lua/autorun/server/sv_init.lua index 69fa389..b80b37f 100644 --- a/lua/autorun/server/sv_init.lua +++ b/lua/autorun/server/sv_init.lua @@ -6,4 +6,6 @@ AddCSLuaFile("cfc_disconnect_interface/client/cl_ponger.lua") AddCSLuaFile("cfc_disconnect_interface/client/cl_api.lua") AddCSLuaFile("cfc_disconnect_interface/client/cl_interface.lua") +resource.AddSingleFile("materials/icons/cross.png") + include("cfc_disconnect_interface/server/sv_pinger.lua") \ No newline at end of file diff --git a/lua/cfc_disconnect_interface/client/cl_interface.lua b/lua/cfc_disconnect_interface/client/cl_interface.lua index 914b47f..5eaa2fc 100644 --- a/lua/cfc_disconnect_interface/client/cl_interface.lua +++ b/lua/cfc_disconnect_interface/client/cl_interface.lua @@ -13,7 +13,7 @@ surface.CreateFont( "CFC_Normal", surface.CreateFont( "CFC_Special", { font = "coolvetica", - size = 26, + size = 30, weight = 500 } ) @@ -33,11 +33,16 @@ local GAME_WIDTH = 1256 local interfaceDerma = false -local TIME_TO_RESTART = 10 +local TIME_TO_RESTART = 180 local timeDown = 0 local apiState local previouslyShown = false +-- Helper function +function getFrom(i, ...) + return ({...})[i] +end + -- Colors primaryCol = Color( 36, 41, 67 ) secondaryCol = Color( 42, 47, 74 ) @@ -84,7 +89,7 @@ end -- Creates and populates a title bar for the frame local function addTitleBar(frame) local frameW, frameH = frame:GetSize() - local titleBarHeight = 32 + local titleBarHeight = 70 -- The bar itself local titleBar = vgui.Create( "DPanel", frame ) @@ -96,11 +101,12 @@ local function addTitleBar(frame) 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 closeBtnSize = 32 + local closeBtnPadding = (titleBarHeight - closeBtnSize) / 2 local closeBtn = vgui.Create( "DImageButton", titleBar ) - closeBtn:SetSize( 16, 16 ) - closeBtn:SetPos( frameW - 16 - closeBtnPadding, closeBtnPadding) - closeBtn:SetImage( "icon16/cross.png" ) + closeBtn:SetSize( closeBtnSize, closeBtnSize ) + closeBtn:SetPos( frameW - closeBtnSize - closeBtnPadding, closeBtnPadding) + closeBtn:SetImage( "icons/cross.png" ) function closeBtn:DoClick() frame:Close() end @@ -109,10 +115,16 @@ local function addTitleBar(frame) local titleLabelPadding = (titleBarHeight - 26) / 2 local titleLabel = vgui.Create( "DLabel", titleBar ) titleLabel:SetFont( "CFC_Special" ) - titleLabel:SetText( "Oops! Looks like the server crashed..." ) - titleLabel:SizeToContents() - titleLabel:SetPos( 0, titleLabelPadding + 2 ) - titleLabel:CenterHorizontal() + + local function setTitle(title) + titleLabel:SetText( title ) + titleLabel:SizeToContents() + titleLabel:SetPos( 0, titleLabelPadding + 2 ) + titleLabel:CenterHorizontal() + end + + setTitle("Oops! Looks like you disconnected...") + titleBar.setTitle = setTitle return titleBar end @@ -121,18 +133,21 @@ end -- 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) - hoverFillCol = hoverFillCol or primaryCol + local frameW, frameH = frame:GetSize() local btn = vgui.Create( "DButton", frame ) + + -- Defaults for colours + btn.outlineCol = outlineCol or Color( 255, 255, 255 ) + btn.fillCol = fillCol or primaryCol + btn.hoverOutlineCol = hoverOutlineCol or Color( 255, 255, 255 ) + btn.hoverFillCol = hoverFillCol or primaryCol + btn:SetText( text ) btn:SetTextColor( Color( 255, 255, 255 ) ) btn:SetFont( "CFC_Button" ) - btn:SetSize( frameW * 0.4, frameH * 0.6 ) + btn:SetSize( frameW * 0.3, frameH ) btn:CenterHorizontal( xFraction ) btn:CenterVertical() btn.DoClick = doClick @@ -141,7 +156,7 @@ local function makeButton(frame, text, xFraction, doClick, outlineCol, fillCol, btn.fadeState = 0 btn.prevTime = CurTime() - local btnAnimSpeed = 0.05 * 60 + local btnAnimSpeed = 0.1 * 60 function btn:Think() -- Make anim same speed for all framerates @@ -160,47 +175,99 @@ local function makeButton(frame, text, xFraction, doClick, outlineCol, fillCol, function btn:Paint(w, h) local lineCol local bgCol + local borderWeight if self:GetDisabled() then lineCol = Color( 74, 74, 74 ) - bgCol = fillCol + bgCol = self.fillCol + borderWeight = btnBorderWeight self:SetCursor( "no" ) else - lineCol = lerpColor(self.fadeState, outlineCol, hoverOutlineCol) - bgCol = lerpColor(self.fadeState, fillCol, hoverFillCol) + lineCol = lerpColor(self.fadeState, self.outlineCol, self.hoverOutlineCol) + bgCol = lerpColor(self.fadeState, self.fillCol, self.hoverFillCol) + borderWeight = 1.5 * btnBorderWeight + 1.5 * self.fadeState * btnBorderWeight self:SetCursor( "hand" ) end self:SetTextColor( lineCol ) - surface.SetDrawColor( lineCol ) - surface.DrawRect( 0, 0, w, h ) - surface.SetDrawColor( bgCol ) - surface.DrawRect( btnBorderWeight, btnBorderWeight, - w - (btnBorderWeight*2), h - (btnBorderWeight*2) ) + draw.RoundedBox(h/2, 0, 0, w, h, lineCol) + + local nw, nh = w - (borderWeight*2), h - (borderWeight*2) + draw.RoundedBox(nh/2, borderWeight, borderWeight, nw, nh, bgCol) + end return btn end +local function showMessage(msg) + if interfaceDerma and (interfaceDerma.messageLabel:GetText() ~= msg or not interfaceDerma.messageLabel:IsVisible()) then + if interfaceDerma.messageLabel:IsVisible() then + interfaceDerma.messageLabel:AlphaTo(0, 0.25) + timer.Simple(0.25, function() + interfaceDerma.messageLabel:setTextAndAlign(msg) + interfaceDerma.messageLabel:AlphaTo(255, 0.25) + end) + else + interfaceDerma.messageLabel:setTextAndAlign(msg) + interfaceDerma.messageLabel:Show() + interfaceDerma.messageLabel:AlphaTo(255, 0.5) + end + end +end + +local function hideMessage(msg) + if interfaceDerma and interfaceDerma.messageLabel:IsVisible() then + interfaceDerma.messageLabel:AlphaTo(0, 0.25) + timer.Simple(0.25, function() + interfaceDerma.messageLabel:Hide() + end) + end +end + -- Create bar panel and add buttons local function addButtonsBar(frame) local frameW, frameH = frame:GetSize() - local buttonBarHeight = 64 + local buttonBarHeight = 90 + local buttonBarOffset = 90 local barPanel = vgui.Create( "DPanel", frame ) barPanel:SetSize( frameW, buttonBarHeight ) - barPanel:SetPos( 0, frameH - buttonBarHeight ) - function barPanel:Paint(w, h) - surface.SetDrawColor( accentCol ) - surface.DrawLine( 16, 0, w - 16, 0 ) - end + barPanel:SetPos( 0, frameH - buttonBarHeight - buttonBarOffset ) + barPanel.Paint = nil -- 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 )) + barPanel.reconBtn = makeButton(barPanel, "RECONNECT", 0.25, function() + if not barPanel.disconMode then + rejoin() + else + leave() + end + end) + --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) + barPanel.disconBtn = makeButton( barPanel, "DISCONNECT", 0.75, function(self) + if not barPanel.disconMode then + showMessage("Are you sure? Hang in there, the server will restart soon...") + barPanel.disconMode = true + barPanel.disconPrevDisabled = barPanel.reconBtn:GetDisabled() + barPanel.reconBtn:SetDisabled(false) + self:SetText("NO") + self.fadeState = 0 + self.hoverOutlineCol = Color( 255, 0, 0 ) + barPanel.reconBtn.hoverOutlineCol = Color( 0, 255, 0 ) + barPanel.reconBtn:SetText("YES") + else + hideMessage() + barPanel.disconMode = false + self:SetText("DISCONNECT") + self.hoverOutlineCol = Color( 255, 255, 255 ) + barPanel.reconBtn:SetText("RECONNECT") + barPanel.reconBtn.hoverOutlineCol = Color( 255, 255, 255 ) + barPanel.reconBtn:SetDisabled(barPanel.disconPrevDisabled) + end + end) return barPanel end @@ -209,26 +276,30 @@ end local function makeLabel(frame, text, top, col, xFraction) col = col or Color( 255, 255, 255 ) local label = vgui.Create( "DLabel", frame ) - label:SetText( text ) label:SetFont( "CFC_Special" ) - label:SizeToContents() - label:SetPos( 0, top ) - label:SetTextColor( col ) - label:CenterHorizontal( xFraction ) + function label:setTextAndAlign( str ) + self:SetText( str ) + self:SizeToContents() + self:SetPos( 0, top ) + self:SetTextColor( col ) + self:CenterHorizontal( xFraction ) + end + label:setTextAndAlign(text) 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) + local label1 = makeLabel(body, "Please check you're still connected to the internet.", 20) + local label2 = makeLabel(body, "In the meantime,", 80) + return "Oops, looks like you disconnected" 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 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" @@ -242,50 +313,51 @@ 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 + -- If timeDown > averageTimeDown, make it red and show the messageLabel local curTimeLabel = makeLabel(body, secondsAsTime(math.floor(timeDown)), 70, Color( 251, 191, 83 )) function curTimeLabel:Think() if apiState ~= crashApi.SERVER_UP then self:SetText(secondsAsTime(math.floor(timeDown))) if timeDown > TIME_TO_RESTART then self:SetTextColor(Color(255, 0, 0)) - if not tooLongLabel:IsVisible() then - tooLongLabel:Show() - tooLongLabel:AlphaTo(255, 1) + if not messageLabel:IsVisible() then + showMessage("Uh oh, seems it's taking a little longer than usual...") end end else self:SetTextColor(Color(0, 255, 0)) end end + + return "Oops, looks like the server crashed..." 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 + local title + local frameW, frameH = body:GetSize() + + -- Warning message label + interfaceDerma.messageLabel = makeLabel(body, "", frameH - 45, Color( 255, 255, 0 ), 0.5) + interfaceDerma.messageLabel:SetAlpha(0) + interfaceDerma.messageLabel:Hide() -- Fill top text based on crashApi state if apiState == crashApi.NO_INTERNET then - populateBodyInternetDown(body) + title = populateBodyInternetDown(body) else -- Server down or up via api, and down via net - populateBodyServerDown(body) + title = populateBodyServerDown(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:SetPos( 10, 134 ) gamePanel.Paint = nil -- HTML element rending game at GAME_URL, constantly grabs focus @@ -296,6 +368,8 @@ local function populateBody(body) function gameHtml:Think() if not gameHtml:HasFocus() then gameHtml:RequestFocus() end end + + return title end -- Entry point for creating the interface @@ -328,9 +402,10 @@ local function createInterface() -- Create body that fills the unused space local body = vgui.Create( "DPanel", frame ) - body:SetSize(frameW - 32, frameH - 32 - titlePanel:GetTall() - btnsPanel:GetTall()) + body:SetSize(frameW - 32, getFrom(2, btnsPanel:GetPos()) - 32 - titlePanel:GetTall()) body:SetPos(16, titlePanel:GetTall() + 16) - populateBody(body) + local title = populateBody(body) + titlePanel.setTitle( title ) -- If server fully recovers without crashing, close menu -- If server reboots, enabled the reconnect button @@ -340,7 +415,6 @@ local function createInterface() elseif apiState == crashApi.SERVER_UP then if btnsPanel.reconBtn:GetDisabled() == true then btnsPanel.reconBtn:SetDisabled( false ) -- Server back up - -- Maybe show a "The server is back up, click here to reconnect?" end end end @@ -350,6 +424,8 @@ local function createInterface() end end +concommand.Add("cfc_interface", createInterface) + hook.Add("cfc_di_crashTick", "cfc_di_interfaceUpdate", function(isCrashing, _timeDown, _apiState) timeDown = _timeDown or 0 apiState = _apiState @@ -362,7 +438,7 @@ hook.Add("cfc_di_crashTick", "cfc_di_interfaceUpdate", function(isCrashing, _tim if not isCrashing then previouslyShown = false if interfaceDerma then - interfaceDerma:Close() + --interfaceDerma:Close() end end end) diff --git a/materials/icons/cross.png b/materials/icons/cross.png new file mode 100644 index 0000000000000000000000000000000000000000..2b466b038d10fa1e1eb5bd272128b666f5a5b5f3 GIT binary patch literal 4683 zcmXAtdpy(a|HqN@n4Ctp)o{ycq*4yi7B@mpIUiyUceJ~$IhEvNV?vS;LSo&@VJeZ) zUD|9`lnyJ)ozvYW6=7Kpvl;eV-`^kCbv>@nAJ_GGzpwZE`FcG*MFDnQnMs&%Ql&n|>;@GBTP^z1&=a z&&TlUqf4RBbqjh89t?KLhu#=1rqf-GziK4s{WGO#;`Vx|Ao{e5-eiil1tFJIaj8_f zandl}RZdn59{7)|iMOF_;S0@9W!WsM?WdW@ML)%=#kM{N-wT{E@F<~DE9cRdg zHXXY(PiADS^_VrB|NM3kM%WNg49#ZV)gS)aY zd1r%H?>$?nz&aLKvWX8XFvSQzvaz)dO&CvHTEyUR97bPACuGGjHVWTnY<-V)4paI@ z*t!ya?%cTo%J+P|nD8L?NY!}FV^*_|EZIx%{?NGp-c<15@+SL!`LaM$NU8JEi=Cr4my~|?9Z_^N?PJbB){2qs;d^U7^L-R@ zCA+z|*_-z~vl=1Vn(Bm@LX}A~pyz(a(pjr;e_gai?^1Nr)qJ7z)IxGe4HvI?^%zX5Hqul_N>to=sC+E*+W9O#f|@E!Oood zvD#Yvx2r;3{Se$N(p~Mug;18n z*9Bye)u<_O96Uak^Oy5smCIcC5$Z9qJHK-W6j8NJ@`1u^iT7#HM?~l$CItI<2BBN8 zgQ#{o2{g^0ON)unN2$BYLi~uV0_NecjuU*9ze~|bWXkqJLpUrU=EB4_@a8c+XF!fe^x$3q%GSUD-+ z=)Ob?A==7E_t_Mt?TDUQOl7h5Gi?EI=u|8!=p6^;J z9m$k(!E$GgI`xD|t9WH65Yqbm;Dm)7$z|G3O?A~gqR*e}#LHOC#D@rb!ecM~#Tm|z zyRFg=j=lN*6zcL%Q;zA&bLC96>!AOyYLIMQwBxsre&SGJM4_)PhHo(}@VNFgasOmX zs@4gEdpz@?hmBKp#NGU8I7g>Ahu`~X$zq|*BSl7kh@+#NGPqZAp_V=*sck4r-h)9i&7LF524UP4;4wR-$SijG2NrL!HhkDmX0#*W7UI%xHh`(XCmurF_(QL#N<&)9@Rep zf=573^^Wp=`*-dU9vD&}iM#mjLiIcIUj3*Y*n_vAi$lpmE3@wX?!|P}bqYrnXwD9~ zlYccC2IJBhq*~}2SzcuX8R()Z492u`(~j;GVopbjB7~C#w~aKE)(t%6kT9zc5lx%- zJUcFj;&%v*lcl7PpEfyU!(TS*lbuqE5TQ4Xg$LS{@yEx*+#`y<^WQk&2X(fSyy=qP zzyf|o7#FpqfEry2(nXi&*CW8~swC`8gvfZw)SrtpJWPIVv=QLH`d3SK&q0P6+gSKr zJ~_lZQl!geJsrqD!biAttf}0hMvE{}y0j83xr((JGK_c?!U=kiVq|zbMTZKNk$(V& z%+-`4Ky19VaN()nxV@v5P1?fX&%4bz*4O0lWnJ01{?D6t&`zIwF@!VbCAo9E2=eAH zMqHxi(!N&bvINZ&TTP*eHTznDMTD@;d^B5*^Q7{B?QX}=bD{T~;U?$Y+L1SApAW0| z5znp#uOE1)w6T8>sAgh{=~RsBDbj%h0AePY`lW)Vk%Rpm`0YQBan_4UrgH294W$lh z1se7>$Uo~oT&e;U%w>Am$yCy<)jIdH-5@xuE}x&|#x3*~n-(I+MjeWexoy3r?i-C} zzvGkJDT^2VZ^P+pTkda=SPVaj=R|Pe*9vw^JNn!>Ni!E^#tX|w{TnA=Gb4YWVAOq2 z@EZc2Zo!*?dfal#j90F^P%U70p4wjWBYwQ)r&Rt+@ZyDtt(ucbZ&lX+SwfrfzJ7Hx zV_e9X%H>{J(4HKNM5Xffe`fj$J!Ovr87MiyxH3*8i zGZO+`nmJ}>gz>@AWi0$ay#N$OyXzVuY%cm8%swA-N6I#F>T8=oKRKXT0)MOq3~1Hy z`l~6pw(Z8ej7xbb#v=^zcx?3H6|sZM)!`$4H$24$Vsz0j`v<=TGW0?a z4LCX4eeCh^k9^-@k8%5Z8?hV~^3t>+%2yJf-H{NftfL1EbSl##bGEo?if#L?ArASIi+Bn^kT_N-nUv~oj z4#lgYOl^l;sS(ed3fA>}=jk@y;syIt)Pd zJ~I=&68)05pRP==`C_vz%@|3{sTf`1!D0LbiP>g(>vcBXZ0gl3=r12u`osu7xHmiJ z&TFqGWqb+c0dA|w)>AjJNe4)OH&3y-MyOE25_f|6wFoEkZ76HHH=F|jd6N?mbFb?J zd6N?)J(}{kqUiB&e#A`^$3-H_o;MNi^7ESDkHe#knr>R>veX}JCZ>n2?3wglEIq~zQtJ>77_gN+ZB+PCmu_F(fugf^cYUSoNQssAjKTuo@x zQaWy?lw;ERS{|+H##gJU#Akf;AoBk;L2j^O^q;CO{PjCdb0iKIK#~sa4C@# z;C+wKBRLz(%^0kAe*@@<^~8nYr5aKCM!$#OlhPr{ zNd9vKItWx$=HebR9|cQ8leFq6?(`)ZE^3##lu%&RerHD)hW7PUbxDQixh`mEFym9E z1Ya{TPyuI7xrbRb5Vl0M`RZN?5B2MIKBCqiCZB$*?Nfdsnv%|QdUQMi5X!CJ2-PNaU4Rsc!BEk$;?~> zi8A62Y2aT!xFL{AFqf@deF><&P(CV#hOZ?}6$4Lb_zdaW9zK1swEpkVttc9o zeVoL{V!O~NU3A=zwdhZilb@g2KY!M8ZD0C&wRgu-R-It1XKtt^K5dT>bC(-A)pZ|) zm`^s?r!300)^C;=#Z<1wRt!h+JtOcUhVCqPoTJzry8Q|K+NA zOT~HKGGMS_Ds3VY2t~bfIdw3A0V5lgxTteB!i_J~Im;P&{nry?Qg>xX zcoqlakKx#G*nVBmv!3B8x&moBEo&gI|L^w_L}qF`Q+968$}%7|aVMn*ZaH@zx#Fne zjXdJ|Uu^eK`jzt-N1 z-)rY1r`A)+TK