mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-16 21:33:46 +03:00
Upload
This commit is contained in:
174
lua/menu/background.lua
Normal file
174
lua/menu/background.lua
Normal file
@@ -0,0 +1,174 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local MenuGradient = Material( "html/img/gradient.png", "nocull smooth" )
|
||||
|
||||
local FreeMaterial = nil
|
||||
|
||||
local function CreateBackgroundMaterial( path )
|
||||
if ( FreeMaterial ) then
|
||||
FreeMaterial:SetDynamicImage( path )
|
||||
|
||||
local ret = FreeMaterial
|
||||
FreeMaterial = nil
|
||||
return ret
|
||||
end
|
||||
|
||||
return DynamicMaterial( path, "0100010" ) -- nocull smooth
|
||||
end
|
||||
|
||||
local function FreeBackgroundMaterial( mat )
|
||||
if ( FreeMaterial ) then
|
||||
MsgN( "Warning! Menu shouldn't be releasing a material when one is already queued for use!" )
|
||||
end
|
||||
|
||||
FreeMaterial = mat
|
||||
end
|
||||
|
||||
local Images = {}
|
||||
|
||||
local Active = nil
|
||||
local Outgoing = nil
|
||||
|
||||
local function Think( tbl )
|
||||
|
||||
tbl.Angle = tbl.Angle + ( tbl.AngleVel * FrameTime() )
|
||||
tbl.Size = tbl.Size + ( ( tbl.SizeVel / tbl.Size) * FrameTime() )
|
||||
|
||||
if ( tbl.AlphaVel ) then
|
||||
tbl.Alpha = tbl.Alpha - tbl.AlphaVel * FrameTime()
|
||||
end
|
||||
|
||||
if ( tbl.DieTime > 0 ) then
|
||||
tbl.DieTime = tbl.DieTime - FrameTime()
|
||||
|
||||
if ( tbl.DieTime <= 0 ) then
|
||||
ChangeBackground()
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local function Render( tbl )
|
||||
|
||||
if ( !tbl.mat ) then return end
|
||||
|
||||
surface.SetMaterial( tbl.mat )
|
||||
surface.SetDrawColor( 255, 255, 255, tbl.Alpha )
|
||||
|
||||
local w = ScrH() * tbl.Size * tbl.Ratio
|
||||
local h = ScrH() * tbl.Size
|
||||
|
||||
local x = ScrW() * 0.5
|
||||
local y = ScrH() * 0.5
|
||||
|
||||
surface.DrawTexturedRectRotated( x, y, w, h, tbl.Angle )
|
||||
|
||||
end
|
||||
|
||||
local function ShouldBackgroundUpdate()
|
||||
|
||||
return !IsInGame() && !IsInLoading()
|
||||
|
||||
end
|
||||
|
||||
function DrawBackground()
|
||||
|
||||
if ( ShouldBackgroundUpdate() ) then
|
||||
|
||||
if ( Active ) then
|
||||
Think( Active )
|
||||
Render( Active )
|
||||
end
|
||||
|
||||
if ( Outgoing ) then
|
||||
Think( Outgoing )
|
||||
Render( Outgoing )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
surface.SetMaterial( MenuGradient )
|
||||
surface.SetDrawColor( 255, 255, 255, 255 )
|
||||
surface.DrawTexturedRect( 0, 0, 1024, ScrH() )
|
||||
|
||||
end
|
||||
|
||||
function ClearBackgroundImages( img )
|
||||
|
||||
Images = {}
|
||||
|
||||
end
|
||||
|
||||
function AddBackgroundImage( img )
|
||||
|
||||
table.insert( Images, img )
|
||||
|
||||
end
|
||||
|
||||
local LastGamemode = "none"
|
||||
|
||||
function ChangeBackground( currentgm )
|
||||
|
||||
if ( !ShouldBackgroundUpdate() ) then return end -- Don't try to load new images while in-game or loading
|
||||
|
||||
if ( currentgm && currentgm == LastGamemode ) then return end
|
||||
if ( currentgm ) then LastGamemode = currentgm end
|
||||
|
||||
local img = table.Random( Images )
|
||||
if ( !img ) then
|
||||
print( "No main menu backgrounds found!" )
|
||||
return
|
||||
end
|
||||
|
||||
-- We just rolled the same image, no thank you, reroll
|
||||
if ( Active && img == Active.Name && #Images > 1 ) then
|
||||
ChangeBackground()
|
||||
return
|
||||
end
|
||||
|
||||
if ( Outgoing ) then
|
||||
FreeBackgroundMaterial( Outgoing.mat )
|
||||
Outgoing.mat = nil
|
||||
end
|
||||
|
||||
Outgoing = Active
|
||||
if ( Outgoing ) then
|
||||
Outgoing.AlphaVel = 255
|
||||
end
|
||||
|
||||
local mat = CreateBackgroundMaterial( img )
|
||||
if ( !mat || mat:IsError() ) then
|
||||
print( "Failed to create material for background ", img )
|
||||
table.RemoveByValue( Images, img )
|
||||
ChangeBackground()
|
||||
return
|
||||
end
|
||||
|
||||
Active = {
|
||||
Ratio = mat:GetInt( "$realwidth" ) / mat:GetInt( "$realheight" ),
|
||||
Size = 1,
|
||||
Angle = 0,
|
||||
AngleVel = -( 5 / 30 ),
|
||||
SizeVel = 0.3 / 30,
|
||||
Alpha = 255,
|
||||
DieTime = 30,
|
||||
mat = mat,
|
||||
Name = img
|
||||
}
|
||||
|
||||
if ( Active.Ratio < ScrW() / ScrH() ) then
|
||||
|
||||
Active.Size = Active.Size + ( ( ScrW() / ScrH() ) - Active.Ratio )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
54
lua/menu/cef_credits.lua
Normal file
54
lua/menu/cef_credits.lua
Normal file
@@ -0,0 +1,54 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
PANEL.Base = "DFrame"
|
||||
|
||||
function PANEL:Init()
|
||||
self.HTML = vgui.Create( "Chromium", self )
|
||||
|
||||
-- Trying to open credits on a non-cef build?
|
||||
if ( !self.HTML ) then
|
||||
self:Remove()
|
||||
return
|
||||
end
|
||||
|
||||
self.HTML:Dock( FILL )
|
||||
self.HTML:OpenURL( "chrome://credits/" )
|
||||
self.HTML:SetOpenLinksExternally( true )
|
||||
|
||||
self:SetTitle( "Chromium Embedded Framework Credits" )
|
||||
self:SetPos( 16, 16 )
|
||||
self:SetSize( 720, 400 )
|
||||
self:SetSizable( true )
|
||||
self:MakePopup()
|
||||
end
|
||||
|
||||
concommand.Add( "cef_credits", function()
|
||||
vgui.CreateFromTable( PANEL )
|
||||
end )
|
||||
|
||||
concommand.Add( "gmod_tos", function()
|
||||
gui.OpenURL( "https://facepunch.com/legal/tos" )
|
||||
end )
|
||||
|
||||
concommand.Add( "gmod_privacy", function()
|
||||
gui.OpenURL( "https://facepunch.com/legal/privacy" )
|
||||
end )
|
||||
|
||||
concommand.Add( "gmod_modding", function()
|
||||
gui.OpenURL( "https://facepunch.com/legal/modding" )
|
||||
end )
|
||||
|
||||
concommand.Add( "gmod_servers", function()
|
||||
gui.OpenURL( "https://wiki.facepunch.com/gmod/server_operator_rules" )
|
||||
end )
|
||||
219
lua/menu/crosshair_setup.lua
Normal file
219
lua/menu/crosshair_setup.lua
Normal file
@@ -0,0 +1,219 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local crosshair_sliders = {
|
||||
{ title = "Style", cvar = "cl_crosshairstyle", values = { ["0"] = "Half-Life 2", ["1"] = "Dot Image", ["2"] = "Classic" } },
|
||||
{ title = "Gap", cvar = "cl_crosshairgap", min = 0, max = 200 },
|
||||
{ title = "Size", cvar = "cl_crosshairsize", min = 0, max = 200 },
|
||||
{ title = "Thickness", cvar = "cl_crosshairthickness", min = 0, max = 200 },
|
||||
{ title = "Dot", cvar = "cl_crosshairdot" },
|
||||
{ title = "T-Style", cvar = "cl_crosshair_t" },
|
||||
{ title = "Use Alpha", cvar = "cl_crosshairusealpha" },
|
||||
{ title = "Quick Info", cvar = "hud_quickinfo" },
|
||||
{ title = "Outline", cvar = "cl_crosshair_drawoutline" },
|
||||
{ title = "Outline Thickness", cvar = "cl_crosshair_outlinethickness", min = 0.1, max = 3 },
|
||||
}
|
||||
|
||||
local function GetCrosshairColor()
|
||||
return Color( GetConVarNumber( "cl_crosshaircolor_r" ),
|
||||
GetConVarNumber( "cl_crosshaircolor_g" ),
|
||||
GetConVarNumber( "cl_crosshaircolor_b" ),
|
||||
GetConVarNumber( "cl_crosshairalpha" )
|
||||
)
|
||||
end
|
||||
|
||||
local function DrawCrosshairRect( color, x0, y0, x1, y1, bAdditive )
|
||||
if ( GetConVarNumber( "cl_crosshair_drawoutline" ) != 0 ) then
|
||||
local flThick = GetConVarNumber( "cl_crosshair_outlinethickness" )
|
||||
surface.SetDrawColor( 0, 0, 0, color.a )
|
||||
surface.DrawRect( x0 - flThick, y0 - flThick, (x1 + flThick) - x0 + flThick, (y1 + flThick) - y0 + flThick )
|
||||
end
|
||||
|
||||
surface.SetDrawColor( color.r, color.g, color.b, color.a )
|
||||
|
||||
if ( bAdditive ) then
|
||||
surface.DrawTexturedRect( x0, y0, x1 - x0, y1 - y0 )
|
||||
else
|
||||
surface.DrawRect( x0, y0, x1 - x0, y1 - y0 )
|
||||
end
|
||||
end
|
||||
|
||||
local additiveTex = Material( "vgui/white_additive" )
|
||||
local function DrawSimpleCrosshairPreview( x, y )
|
||||
local color = GetCrosshairColor()
|
||||
|
||||
local bAdditive = GetConVarNumber( "cl_crosshairusealpha" ) == 0
|
||||
if ( bAdditive ) then
|
||||
surface.SetMaterial( additiveTex )
|
||||
color.a = 200
|
||||
end
|
||||
|
||||
local iBarSize = math.Round( ScreenScaleH( GetConVarNumber( "cl_crosshairsize" ) ))
|
||||
local iBarThickness = math.max( 1, math.Round( ScreenScaleH( GetConVarNumber( "cl_crosshairthickness" ) ) ) )
|
||||
local iInnerCrossDist = GetConVarNumber( "cl_crosshairgap" )
|
||||
|
||||
-- draw horizontal crosshair lines
|
||||
local iInnerLeft = x - iInnerCrossDist - iBarThickness / 2
|
||||
local iInnerRight = iInnerLeft + 2 * iInnerCrossDist + iBarThickness
|
||||
local iOuterLeft = iInnerLeft - iBarSize
|
||||
local iOuterRight = iInnerRight + iBarSize
|
||||
local y0 = y - iBarThickness / 2
|
||||
local y1 = y0 + iBarThickness
|
||||
DrawCrosshairRect( color, iOuterLeft, y0, iInnerLeft, y1, bAdditive )
|
||||
DrawCrosshairRect( color, iInnerRight, y0, iOuterRight, y1, bAdditive )
|
||||
|
||||
-- draw vertical crosshair lines
|
||||
local iInnerTop = y - iInnerCrossDist - iBarThickness / 2
|
||||
local iInnerBottom = iInnerTop + 2 * iInnerCrossDist + iBarThickness
|
||||
local iOuterTop = iInnerTop - iBarSize
|
||||
local iOuterBottom = iInnerBottom + iBarSize
|
||||
local x0 = x - iBarThickness / 2
|
||||
local x1 = x0 + iBarThickness
|
||||
if ( GetConVarNumber( "cl_crosshair_t" ) == 0 ) then
|
||||
DrawCrosshairRect( color, x0, iOuterTop, x1, iInnerTop, bAdditive )
|
||||
end
|
||||
DrawCrosshairRect( color, x0, iInnerBottom, x1, iOuterBottom, bAdditive )
|
||||
|
||||
-- draw dot
|
||||
if ( GetConVarNumber( "cl_crosshairdot" ) != 0 ) then
|
||||
x0 = x - iBarThickness / 2
|
||||
x1 = x0 + iBarThickness
|
||||
y0 = y - iBarThickness / 2
|
||||
y1 = y0 + iBarThickness
|
||||
DrawCrosshairRect( color, x0, y0, x1, y1, bAdditive )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
concommand.Add( "crosshair_setup", function()
|
||||
|
||||
surface.CreateFont( "QuickInfoLarge", {
|
||||
font = "HL2cross",
|
||||
size = 64,
|
||||
additive = false,
|
||||
} )
|
||||
|
||||
local frame = vgui.Create( "DFrame" )
|
||||
frame:SetSize( 600, 480 )
|
||||
frame:Center()
|
||||
frame:SetTitle( "Default Crosshair Setup" )
|
||||
frame:MakePopup()
|
||||
|
||||
local crosshairMat = Material( "gui/crosshair.png" )
|
||||
|
||||
local preview = vgui.Create( "DImage", frame )
|
||||
preview:Dock( LEFT )
|
||||
preview:DockPadding( 5, 5, 5, 5 )
|
||||
preview:SetWide( 320 )
|
||||
preview:SetMouseInputEnabled( true )
|
||||
preview:SetImage( "gui/crosshair_bg.png" )
|
||||
preview.PaintOver = function( p, w, h )
|
||||
if ( GetConVarNumber( "cl_crosshairstyle" ) == 0 ) then
|
||||
surface.SetFont( "Crosshairs" )
|
||||
surface.SetTextColor( 255, 208, 64, 255 )
|
||||
local width, height = surface.GetTextSize( "Q" )
|
||||
surface.SetTextPos( w / 2 - width / 2, h / 2 - height / 2 )
|
||||
surface.DrawText( "Q" )
|
||||
elseif ( GetConVarNumber( "cl_crosshairstyle" ) == 1 ) then
|
||||
surface.SetDrawColor( GetCrosshairColor() )
|
||||
surface.SetMaterial( crosshairMat )
|
||||
surface.DrawTexturedRect( w / 2 - 32, h / 2 - 32, 64, 64 )
|
||||
elseif ( GetConVarNumber( "cl_crosshairstyle" ) >= 2 ) then
|
||||
DrawSimpleCrosshairPreview( w / 2, h / 2 )
|
||||
end
|
||||
|
||||
if ( GetConVarNumber( "hud_quickinfo" ) != 0 ) then
|
||||
surface.SetFont( "QuickInfoLarge" )
|
||||
surface.SetTextColor( 255, 208, 64, 200 )
|
||||
local width, height = surface.GetTextSize( "{ ]" )
|
||||
surface.SetTextPos( w / 2 - width / 2, h / 2 - height / 2 )
|
||||
surface.DrawText( "{ ]" )
|
||||
end
|
||||
end
|
||||
|
||||
local previewBtns = vgui.Create( "Panel", preview )
|
||||
previewBtns:Dock( TOP )
|
||||
|
||||
local img1btn = vgui.Create( "DButton", previewBtns )
|
||||
img1btn:Dock( LEFT )
|
||||
img1btn:SetWide( 320 / 2 )
|
||||
img1btn:SetText( "Preview 1" )
|
||||
img1btn.DoClick = function() preview:SetImage( "gui/crosshair_bg.png" ) end
|
||||
local img2btn = vgui.Create( "DButton", previewBtns )
|
||||
img2btn:SetText( "Preview 2" )
|
||||
img2btn.DoClick = function() preview:SetImage( "gui/crosshair_bg2.png" ) end
|
||||
img2btn:Dock( FILL )
|
||||
|
||||
local settings = vgui.Create( "Panel", frame )
|
||||
settings:Dock( FILL )
|
||||
settings:DockPadding( 5, 0, 0, 0 )
|
||||
|
||||
local function HideUselessStuff( style )
|
||||
style = style or GetConVarNumber( "cl_crosshairstyle" )
|
||||
|
||||
for i, pnl in pairs( settings:GetChildren() ) do
|
||||
if ( pnl.ClassName == "DColorMixer" and style == 0 ) then
|
||||
pnl:SetVisible( false )
|
||||
elseif ( pnl.ClassName == "DNumSlider" and style != 2 ) then
|
||||
pnl:SetVisible( false )
|
||||
elseif ( pnl.ClassName == "DCheckBoxLabel" ) then
|
||||
pnl:SetVisible( pnl.Button.m_strConVar == "hud_quickinfo" or style == 2 )
|
||||
else
|
||||
pnl:SetVisible( true )
|
||||
end
|
||||
end
|
||||
settings:InvalidateLayout()
|
||||
end
|
||||
|
||||
for i, str in pairs( crosshair_sliders ) do
|
||||
local setting = nil
|
||||
if ( str.min ) then
|
||||
setting = vgui.Create( "DNumSlider", settings )
|
||||
setting:SetMinMax( str.min, str.max )
|
||||
setting:SetDefaultValue( GetConVar( str.cvar ):GetDefault() )
|
||||
setting:SetDecimals( 0 )
|
||||
elseif ( str.values ) then
|
||||
setting = vgui.Create( "DComboBox", settings )
|
||||
setting.OnSelect = function( pnl, indx, val, data ) pnl:ConVarChanged( data ) HideUselessStuff( tonumber( data ) ) end
|
||||
for id, title in pairs( str.values ) do setting:AddChoice( title, id ) end
|
||||
else
|
||||
setting = vgui.Create( "DCheckBoxLabel", settings )
|
||||
end
|
||||
setting:Dock( TOP )
|
||||
setting:SetText( str.title )
|
||||
setting:SetConVar( str.cvar )
|
||||
end
|
||||
|
||||
local mixer = vgui.Create( "DColorMixer", settings )
|
||||
mixer:Dock( TOP )
|
||||
mixer:SetTall( 220 )
|
||||
mixer:SetColor( GetCrosshairColor() )
|
||||
mixer:SetConVarR( "cl_crosshaircolor_r" )
|
||||
mixer:SetConVarG( "cl_crosshaircolor_g" )
|
||||
mixer:SetConVarB( "cl_crosshaircolor_b" )
|
||||
mixer:SetConVarA( "cl_crosshairalpha" )
|
||||
|
||||
HideUselessStuff()
|
||||
|
||||
local resetCrosshair = vgui.Create( "DButton", preview )
|
||||
resetCrosshair.DoClick = function()
|
||||
for i, str in pairs( crosshair_sliders ) do
|
||||
local def = GetConVar( str.cvar ):GetDefault()
|
||||
RunConsoleCommand( str.cvar, def )
|
||||
end
|
||||
mixer:SetColor( color_white ) -- hack
|
||||
HideUselessStuff()
|
||||
end
|
||||
resetCrosshair:SetText( "Reset Crosshair" )
|
||||
resetCrosshair:Dock( BOTTOM )
|
||||
|
||||
end )
|
||||
333
lua/menu/demo_to_video.lua
Normal file
333
lua/menu/demo_to_video.lua
Normal file
@@ -0,0 +1,333 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local ActiveVideo = nil
|
||||
|
||||
VideoSettings = nil
|
||||
|
||||
local stats = {
|
||||
reset = 0,
|
||||
encodetime = 0,
|
||||
|
||||
starttime = 0,
|
||||
last_encodetime = 0
|
||||
}
|
||||
|
||||
concommand.Add( "gm_demo_to_video", function( ply, cmd, args )
|
||||
|
||||
local demoname = args[ 1 ]
|
||||
if ( !demoname ) then return end
|
||||
|
||||
local settings = {
|
||||
name = "filled_in_later",
|
||||
container = "webm",
|
||||
video = "vp8",
|
||||
audio = "vorbis",
|
||||
bitrate = 25000,
|
||||
quality = 1,
|
||||
width = 640,
|
||||
height = 480,
|
||||
fps = 25,
|
||||
frameblend = 1,
|
||||
fbshutter = 0.5,
|
||||
dofsteps = 0,
|
||||
dofpasses = 0,
|
||||
doffocusspeed = 1.0,
|
||||
dofsize = 1.0,
|
||||
viewsmooth = 0.0,
|
||||
possmooth = 0.0
|
||||
}
|
||||
|
||||
local Window = vgui.Create( "DFrame" )
|
||||
Window:SetTitle( "Render Video" )
|
||||
Window:SetSize( 600, 400 )
|
||||
Window:LoadGWENFile( "resource/ui/DemoToVideo.gwen" )
|
||||
Window:Center()
|
||||
Window:MakePopup()
|
||||
|
||||
local inCodec = Window:Find( "inCodec" )
|
||||
local inQuality = Window:Find( "inQuality" )
|
||||
local inSize = Window:Find( "inSize" )
|
||||
local btnStart = Window:Find( "btnStart" )
|
||||
local inBitRate = Window:Find( "inBitRate" )
|
||||
local inFPS = Window:Find( "inFPS" )
|
||||
local inFrameBlend = Window:Find( "inFrameBlend" )
|
||||
local inFBShutter = Window:Find( "inFBShutter" )
|
||||
local inDOF = Window:Find( "inDepthOfField" )
|
||||
local inDOFSpeed = Window:Find( "inDOFFocusSpeed" )
|
||||
local inDOFSize = Window:Find( "inDOFBlurSize" )
|
||||
local inViewSmooth = Window:Find( "inViewSmooth" )
|
||||
local inPosSmooth = Window:Find( "inPosSmooth" )
|
||||
|
||||
inFPS.OnChange = function() settings.fps = inFPS:GetInt() end
|
||||
inFPS:SetText( settings.fps )
|
||||
|
||||
inBitRate.OnChange = function() settings.bitrate = inBitRate:GetInt() end
|
||||
inBitRate:SetText( settings.bitrate )
|
||||
|
||||
-- TODO!!!
|
||||
inCodec.OnSelect = function( _, index, value, data ) settings.container = data[1]; settings.video = data[2]; settings.audio = data[3] end
|
||||
inCodec:AddChoice( "webm", { "webm", "vp8", "vorbis" }, true )
|
||||
inCodec:AddChoice( "ogg", { "ogg", "theora", "vorbis" } )
|
||||
|
||||
inQuality.OnSelect = function( _, index, value, data ) settings.quality = data end
|
||||
inQuality:AddChoice( "0.0 - Low (but fast)", 0 )
|
||||
inQuality:AddChoice( "0.5 - Medium", 0.5 )
|
||||
inQuality:AddChoice( "1.0 - Highest (but slow)", 1, true )
|
||||
|
||||
-- TODO!!!
|
||||
inSize.OnSelect = function( _, index, value, data ) settings.width = data[1] settings.height = data[2] end
|
||||
local sw, sh = ScrW(), ScrH()
|
||||
inSize:AddChoice( sw .. " x " .. sh .. " (highest)", { sw, sh }, true )
|
||||
|
||||
sw, sh = sw * 0.66666, sh * 0.66666
|
||||
inSize:AddChoice( math.ceil( sw ) .. " x " .. math.ceil( sh ), { sw, sh }, true )
|
||||
|
||||
sw, sh = sw * 0.5, sh * 0.5
|
||||
inSize:AddChoice( math.ceil( sw ) .. " x " .. math.ceil( sh ), { sw, sh }, true )
|
||||
|
||||
inFrameBlend.OnSelect = function( _, index, value, data ) settings.frameblend = data end
|
||||
inFrameBlend:AddChoice( "Off", 1, true )
|
||||
inFrameBlend:AddChoice( "Draft (8 Samples)", 8 )
|
||||
inFrameBlend:AddChoice( "Good (16 Samples)", 16 )
|
||||
inFrameBlend:AddChoice( "Great (32 Samples)", 32 )
|
||||
inFrameBlend:AddChoice( "Overkill (64 Samples)", 64 )
|
||||
inFrameBlend:AddChoice( "OverOverKill (128 Samples)", 128 )
|
||||
|
||||
inFBShutter.OnSelect = function( _, index, value, data ) settings.fbshutter = data end
|
||||
inFBShutter:AddChoice( "90", 0.75 )
|
||||
inFBShutter:AddChoice( "180", 0.5, true )
|
||||
inFBShutter:AddChoice( "240", 0.25 )
|
||||
inFBShutter:AddChoice( "360", 0.0 )
|
||||
|
||||
--
|
||||
-- DOF
|
||||
--
|
||||
inDOF.OnSelect = function( _, index, value, data ) settings.dofsteps = data[1]; settings.dofpasses = data[2] end
|
||||
inDOF:AddChoice( "Off", { 0, 0 }, true )
|
||||
inDOF:AddChoice( "Draft (21 Samples)", { 6, 3 } )
|
||||
inDOF:AddChoice( "Good (72 Samples)", { 12, 6 } )
|
||||
inDOF:AddChoice( "Best (288 Samples)", { 24, 12 } )
|
||||
|
||||
inDOFSpeed.OnChange = function() settings.doffocusspeed = inDOFSpeed:GetFloat() end
|
||||
inDOFSpeed:SetText( "1.0" )
|
||||
|
||||
inDOFSize.OnChange = function() settings.dofsize = inDOFSize:GetFloat() end
|
||||
inDOFSize:SetText( "1.0" )
|
||||
|
||||
--
|
||||
-- Smoothing
|
||||
--
|
||||
inViewSmooth.OnSelect = function( _, index, value, data ) settings.viewsmooth = data end
|
||||
inViewSmooth:AddChoice( "Off", 0.0, true )
|
||||
inViewSmooth:AddChoice( "Minimal", 0.2 )
|
||||
inViewSmooth:AddChoice( "Low", 0.4 )
|
||||
inViewSmooth:AddChoice( "Medium", 0.7 )
|
||||
inViewSmooth:AddChoice( "High", 0.8 )
|
||||
inViewSmooth:AddChoice( "Lots", 0.9 )
|
||||
inViewSmooth:AddChoice( "Too Smooth", 0.97 )
|
||||
|
||||
inPosSmooth.OnSelect = function( _, index, value, data ) settings.possmooth = data end
|
||||
inPosSmooth:AddChoice( "Off", 0.0, true )
|
||||
inPosSmooth:AddChoice( "Minimal", 0.2 )
|
||||
inPosSmooth:AddChoice( "Low", 0.4 )
|
||||
inPosSmooth:AddChoice( "Medium", 0.7 )
|
||||
inPosSmooth:AddChoice( "High", 0.8 )
|
||||
inPosSmooth:AddChoice( "Lots", 0.9 )
|
||||
inPosSmooth:AddChoice( "Too Smooth", 0.97 )
|
||||
|
||||
btnStart.DoClick = function()
|
||||
|
||||
-- Fill in the name here, or we'll be overwriting the same video!
|
||||
local cleanname = string.GetFileFromFilename( demoname )
|
||||
cleanname = cleanname:Replace( ".", "_" )
|
||||
cleanname = cleanname .. " " .. util.DateStamp()
|
||||
settings.name = cleanname
|
||||
|
||||
PrintTable( settings )
|
||||
ActiveVideo, error = video.Record( settings )
|
||||
|
||||
if ( !ActiveVideo ) then
|
||||
Derma_Message( "Couldn't record video: \n" .. error, "Make Video Error", "OK" )
|
||||
return
|
||||
end
|
||||
|
||||
RunConsoleCommand( "sv_cheats", 1 )
|
||||
RunConsoleCommand( "host_framerate", settings.fps * settings.frameblend )
|
||||
RunConsoleCommand( "snd_fixed_rate", 1 )
|
||||
RunConsoleCommand( "progress_enable", 1 )
|
||||
RunConsoleCommand( "playdemo", demoname )
|
||||
|
||||
VideoSettings = table.Copy( settings )
|
||||
|
||||
Window:Remove()
|
||||
|
||||
end
|
||||
|
||||
end, nil, "", { FCVAR_DONTRECORD } )
|
||||
|
||||
local function FinishRecording()
|
||||
|
||||
VideoSettings = nil
|
||||
ActiveVideo:Finish()
|
||||
ActiveVideo = nil
|
||||
|
||||
RunConsoleCommand( "host_framerate", 0 )
|
||||
RunConsoleCommand( "sv_cheats", 0 )
|
||||
RunConsoleCommand( "snd_fixed_rate", 0 )
|
||||
|
||||
MsgN( "Rendering Finished - Took ", SysTime() - stats.starttime, " seconds" )
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function UpdateFrame()
|
||||
|
||||
if ( !engine.IsPlayingDemo() ) then
|
||||
|
||||
if ( !VideoSettings.started ) then return end
|
||||
FinishRecording()
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
if ( !VideoSettings.started ) then
|
||||
|
||||
if ( gui.IsGameUIVisible() ) then return end
|
||||
|
||||
VideoSettings.started = true
|
||||
VideoSettings.framecount = 0
|
||||
stats.starttime = SysTime()
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
local function DrawOverlay()
|
||||
|
||||
if ( !VideoSettings ) then return end
|
||||
|
||||
local complete = engine.GetDemoPlaybackTick() / engine.GetDemoPlaybackTotalTicks()
|
||||
|
||||
local x = ScrW() * 0.1
|
||||
local y = ScrH() * 0.8
|
||||
local w = ScrW() * 0.8
|
||||
local h = ScrH() * 0.05
|
||||
|
||||
surface.SetFont( "DermaDefault" )
|
||||
surface.SetTextColor( 255, 255, 255, 255 )
|
||||
|
||||
-- Static text
|
||||
local info = "Rendering " .. math.floor( VideoSettings.width ) .. "x" .. math.floor( VideoSettings.height ) .. " at " .. math.floor( VideoSettings.fps ) .. "fps "
|
||||
|
||||
local with = {}
|
||||
if ( VideoSettings.dofsteps > 0 ) then table.insert( with, "DOF" ) end
|
||||
if ( VideoSettings.frameblend > 1 ) then table.insert( with, "Frame Blending" ) end
|
||||
if ( VideoSettings.viewsmooth > 0 ) then table.insert( with, "View Smoothing" ) end
|
||||
if ( VideoSettings.possmooth > 0 ) then table.insert( with, "Position Smoothing" ) end
|
||||
|
||||
if ( #with > 0 ) then
|
||||
local withS = table.concat( with, ", " )
|
||||
info = info .. "with " .. withS
|
||||
end
|
||||
|
||||
info = info .. " (rendering " .. ( VideoSettings.frameblend * math.max( VideoSettings.dofsteps, 1 ) * math.max( VideoSettings.dofpasses, 1 ) ) .. " frames per frame)"
|
||||
|
||||
local tw, th = surface.GetTextSize( info )
|
||||
surface.SetTextPos( x, y - th - 10 )
|
||||
surface.DrawText( info )
|
||||
|
||||
-- The box
|
||||
surface.SetDrawColor( 0, 0, 0, 50 )
|
||||
surface.DrawRect( x-3, y-3, w + 6, h + 6 )
|
||||
|
||||
surface.SetDrawColor( 255, 255, 255, 200 )
|
||||
surface.DrawRect( x -2, y-2, w + 4, 2 )
|
||||
surface.DrawRect( x - 2, y, 2, h )
|
||||
surface.DrawRect( x + w, y, 2, h )
|
||||
surface.DrawRect( x-2, y + h, w + 4, 2 )
|
||||
|
||||
surface.SetDrawColor( 255, 255, 100, 150 )
|
||||
surface.DrawRect( x + 1, y + 1, w * complete - 2, h - 2 )
|
||||
|
||||
-- Demo length
|
||||
local demolength = "Demo Length: " .. string.FormattedTime( engine.GetDemoPlaybackTotalTicks() * engine.TickInterval(), "%2i:%02i" )
|
||||
local tw, th = surface.GetTextSize( demolength )
|
||||
surface.SetTextPos( x + w - tw, y - th - 10 )
|
||||
surface.DrawText( demolength )
|
||||
|
||||
if ( !VideoSettings.started ) then return end
|
||||
|
||||
-- Timers
|
||||
surface.SetTextPos( x, y + h + 10 )
|
||||
surface.DrawText( "Time Taken: " .. string.NiceTime( SysTime() - stats.starttime ) )
|
||||
|
||||
local tw, th = surface.GetTextSize( "Time Left: " .. string.NiceTime( stats.timeremaining ) )
|
||||
surface.SetTextPos( x + w - tw, y + h + 10 )
|
||||
surface.DrawText( "Time Left: " .. string.NiceTime( stats.timeremaining ) )
|
||||
|
||||
|
||||
local demotime = string.FormattedTime( engine.GetDemoPlaybackTick() * engine.TickInterval(), "%2i:%02i" )
|
||||
local tw, th = surface.GetTextSize( demotime )
|
||||
if ( w * complete > tw + 20 ) then
|
||||
surface.SetTextColor( 0, 0, 0, 200 )
|
||||
surface.SetTextPos( x + w * complete - tw - 10, y + h * 0.5 - th * 0.5 )
|
||||
surface.DrawText( demotime )
|
||||
end
|
||||
|
||||
local demotime = string.FormattedTime( ( engine.GetDemoPlaybackTotalTicks() - engine.GetDemoPlaybackTick() ) * engine.TickInterval(), "%2i:%02i" )
|
||||
local tw, th = surface.GetTextSize( demotime )
|
||||
if ( w - w * complete > tw + 20 ) then
|
||||
surface.SetTextColor( 255, 255, 255, 200 )
|
||||
surface.SetTextPos( x + w * complete + 10, y + h * 0.5 - th * 0.5 )
|
||||
surface.DrawText( demotime )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "CaptureVideo", "CaptureDemoFrames", function()
|
||||
|
||||
if ( !ActiveVideo ) then return end
|
||||
if ( !VideoSettings ) then return end
|
||||
|
||||
UpdateFrame()
|
||||
|
||||
DrawOverlay()
|
||||
|
||||
if ( stats.reset < SysTime() ) then
|
||||
|
||||
stats.reset = SysTime() + 1
|
||||
|
||||
stats.last_encodetime = stats.encodetime
|
||||
stats.encodetime = 0
|
||||
|
||||
local timetaken = SysTime() - stats.starttime
|
||||
local fractioncomplete = engine.GetDemoPlaybackTotalTicks() / engine.GetDemoPlaybackTick()
|
||||
|
||||
stats.timeremaining = ( timetaken * fractioncomplete ) - timetaken
|
||||
if ( stats.timeremaining < 0 ) then stats.timeremaining = 0 end
|
||||
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
function RecordDemoFrame()
|
||||
|
||||
if ( !ActiveVideo ) then return end
|
||||
if ( !VideoSettings ) then return end
|
||||
if ( !VideoSettings.started ) then return end
|
||||
|
||||
ActiveVideo:AddFrame( 1 / VideoSettings.fps, true )
|
||||
VideoSettings.framecount = VideoSettings.framecount + 1
|
||||
|
||||
end
|
||||
153
lua/menu/derma_icon_browser.lua
Normal file
153
lua/menu/derma_icon_browser.lua
Normal file
@@ -0,0 +1,153 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
function Derma_OpenIconBrowser()
|
||||
-- Because the icon browser will be part of the menu, activate the menu so that it definitely shows up otherwise a derma_icon_browser bind does nothing
|
||||
gui.ActivateGameUI()
|
||||
|
||||
if ( IsValid( Derma_IconBrowser ) ) then
|
||||
Derma_IconBrowser:SetVisible( true )
|
||||
Derma_IconBrowser:MakePopup()
|
||||
return
|
||||
end
|
||||
|
||||
Derma_IconBrowser = vgui.Create( "DFrame" )
|
||||
Derma_IconBrowser:SetTitle( "Derma Icon Browser" )
|
||||
Derma_IconBrowser:SetIcon( "icon16/pictures.png" )
|
||||
Derma_IconBrowser:SetScreenLock( true ) -- Don't let the icon browser out of the screen bounds, we don't want it to get lost
|
||||
Derma_IconBrowser:SetSizable( true )
|
||||
|
||||
-- Minimum size the user can resize the icon browser to
|
||||
local minFrameW, minFrameH = 250, 200
|
||||
|
||||
-- Remember the user's custom size for the icon browser
|
||||
-- If any dimension of the custom size is bigger than the screen bounds, or smaller than the minimum bounds, forget about it
|
||||
local frameW, frameH = cookie.GetNumber( "Derma_IconBrowser_W", 400 ), cookie.GetNumber( "Derma_IconBrowser_H", 400 )
|
||||
if ( frameW > ScrW() || frameH > ScrH() ) then
|
||||
frameW, frameH = 400, 400
|
||||
cookie.Delete( "Derma_IconBrowser_W" )
|
||||
cookie.Delete( "Derma_IconBrowser_H" )
|
||||
end
|
||||
|
||||
Derma_IconBrowser.OnScreenSizeChanged = function( self )
|
||||
-- Make sure if the screen resolution changes we keep the icon browser within its bounds
|
||||
self:SetSize( math.min( self:GetWide(), ScrW() ), math.min( self:GetTall(), ScrH() ) )
|
||||
|
||||
-- Store changes
|
||||
cookie.Set( "Derma_IconBrowser_W", self:GetWide() )
|
||||
cookie.Set( "Derma_IconBrowser_H", self:GetTall() )
|
||||
|
||||
-- Prevent changes being stored twice
|
||||
self.m_bStoreResize = false
|
||||
end
|
||||
Derma_IconBrowser.OnSizeChanged = function( self )
|
||||
-- Don't store the custom size in the database yet, we don't want to spam it
|
||||
if ( self.m_bStoreResize != false ) then
|
||||
self.m_bStoreResize = true
|
||||
else
|
||||
-- The screen resolution just changed, we already stored that in the database
|
||||
self.m_bStoreResize = nil
|
||||
end
|
||||
end
|
||||
Derma_IconBrowser.OnMouseReleased = function( self )
|
||||
if ( self.m_bStoreResize ) then
|
||||
self.m_bStoreResize = nil
|
||||
-- Now we can store it - the user has finished dragging
|
||||
cookie.Set( "Derma_IconBrowser_W", self:GetWide() )
|
||||
cookie.Set( "Derma_IconBrowser_H", self:GetTall() )
|
||||
end
|
||||
|
||||
-- Call the function we had overridden
|
||||
DFrame.OnMouseReleased( self )
|
||||
end
|
||||
|
||||
-- Set the size of the icon browser and pop it up on the screen
|
||||
Derma_IconBrowser:SetSize( frameW, frameH )
|
||||
Derma_IconBrowser:SetMinimumSize( minFrameW, minFrameH )
|
||||
Derma_IconBrowser:Center()
|
||||
Derma_IconBrowser:MakePopup()
|
||||
|
||||
-- Some variables for our "copied" icon
|
||||
local copyIconSize = 16
|
||||
local copyIconSpacing = 5
|
||||
local matCopyIcon = Material( "icon16/page_copy.png" )
|
||||
Derma_IconBrowser.PaintOver = function( self )
|
||||
-- Nice animation for feedback when copying an icon
|
||||
if ( self.m_nCopiedTime && SysTime() <= self.m_nCopiedTime ) then
|
||||
local wasEnabled = DisableClipping( true )
|
||||
|
||||
-- Animation lasts 1 second (the fade starts after .25 seconds)
|
||||
local slideAnimFrac = 1 - math.TimeFraction( self.m_nCopiedTime - 1, self.m_nCopiedTime, SysTime() )
|
||||
local fadeAnimFrac = 1 - math.max( math.TimeFraction( self.m_nCopiedTime - .75, self.m_nCopiedTime, SysTime() ), 0 )
|
||||
|
||||
-- Draw a small label underneath the mouse cursor that gradually slides down and fades away
|
||||
surface.SetFont( "BudgetLabel" )
|
||||
surface.SetTextColor( 255, 255, 255, fadeAnimFrac * 255 )
|
||||
|
||||
local mouseX, mouseY = self:ScreenToLocal( input.GetCursorPos() )
|
||||
local textW, textH = surface.GetTextSize( self.m_strCopiedIcon )
|
||||
|
||||
local textX = mouseX - ( ( textW - copyIconSize - copyIconSpacing ) / 2 ) -- Draw it center-aligned at the cursor, subtract 16px for the page_copy icon and 5px for its spacing
|
||||
local textY = mouseY + textH + ( ( 1 - slideAnimFrac ) * textH ) + 5 -- Animate it to slide down plus a further 5px for spacing
|
||||
surface.SetTextPos( textX, textY )
|
||||
|
||||
surface.DrawText( self.m_strCopiedIcon )
|
||||
|
||||
-- Draw a small page_copy icon next to the label
|
||||
local copyIconX = textX - copyIconSize - copyIconSpacing
|
||||
local copyIconY = textY - ( ( math.max( textH, copyIconSize ) - math.min( textH, copyIconSize ) ) / 2 ) -- Center align the icon to the text (ambigious to whether the text or the icon is bigger)
|
||||
surface.SetDrawColor( 255, 255, 255, fadeAnimFrac * 255 )
|
||||
surface.SetMaterial( matCopyIcon )
|
||||
surface.DrawTexturedRect( copyIconX, copyIconY, copyIconSize, copyIconSize )
|
||||
|
||||
DisableClipping( wasEnabled )
|
||||
end
|
||||
end
|
||||
|
||||
local IconBrowser = Derma_IconBrowser:Add( "DIconBrowser" )
|
||||
IconBrowser:Dock( FILL )
|
||||
IconBrowser.OnChange = function( self )
|
||||
-- Label animation data
|
||||
Derma_IconBrowser.m_nCopiedTime = SysTime() + 1
|
||||
Derma_IconBrowser.m_strCopiedIcon = self:GetSelectedIcon()
|
||||
|
||||
-- Set the clipboard text to the icon path
|
||||
SetClipboardText( Derma_IconBrowser.m_strCopiedIcon )
|
||||
|
||||
-- Play a nice sound
|
||||
surface.PlaySound( "garrysmod/content_downloaded.wav" )
|
||||
end
|
||||
|
||||
-- Create our search box
|
||||
local Search = Derma_IconBrowser:Add( "DTextEntry" )
|
||||
Search:MoveToBefore( IconBrowser ) -- We need it to be above the icon browser itself
|
||||
Search:Dock( TOP )
|
||||
Search:DockMargin( 0, 0, 0, 5 )
|
||||
Search:SetPlaceholderText( "#spawnmenu.search" )
|
||||
Search:SetTall( 24 )
|
||||
Search:SetUpdateOnType( true )
|
||||
Search.OnValueChange = function( self )
|
||||
local str = Search:GetValue():Trim():gsub( "^icon16/(.+)", "%1" )
|
||||
IconBrowser:FilterByText( str ) -- If the user typed icon16/ at the start, get rid of it for them and trim any whitespace
|
||||
end
|
||||
|
||||
-- Add a little magnifying glass icon in the right corner of the search box
|
||||
local SearchIcon = Search:Add( "DImage" )
|
||||
SearchIcon:SetImage( "icon16/magnifier.png" )
|
||||
SearchIcon:Dock( RIGHT )
|
||||
SearchIcon:DockMargin( 4, 4, 4, 4 )
|
||||
SearchIcon:SetSize( 16, 16 )
|
||||
|
||||
-- Keep this line at the bottom otherwise an error could zombify the icon browser
|
||||
Derma_IconBrowser:SetDeleteOnClose( false )
|
||||
end
|
||||
|
||||
concommand.Add( "derma_icon_browser", Derma_OpenIconBrowser, nil, "Opens the Derma Icon Browser", FCVAR_DONTRECORD )
|
||||
126
lua/menu/errors.lua
Normal file
126
lua/menu/errors.lua
Normal file
@@ -0,0 +1,126 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
--
|
||||
-- Here we get a callback from the game/client code on Lua errors, and display a nice notification.
|
||||
--
|
||||
-- This should help `newbs` find out which addons are crashing.
|
||||
--
|
||||
|
||||
local Errors = {}
|
||||
|
||||
hook.Add( "OnLuaError", "MenuErrorHandler", function( str, realm, stack, addontitle, addonid )
|
||||
|
||||
-- This error is caused by a specific workshop addon
|
||||
--[[if ( isstring( addonid ) ) then
|
||||
|
||||
-- Down Vote
|
||||
steamworks.Vote( addonid, false )
|
||||
|
||||
-- Disable Naughty Addon
|
||||
timer.Simple( 5, function()
|
||||
MsgN( "Disabling addon '", addontitle, "' due to lua errors" )
|
||||
steamworks.SetShouldMountAddon( addonid, false )
|
||||
steamworks.ApplyAddons()
|
||||
end )
|
||||
|
||||
end]]
|
||||
|
||||
if ( addonid == nil ) then addonid = 0 end
|
||||
|
||||
if ( Errors[ addonid ] ) then
|
||||
Errors[ addonid ].times = Errors[ addonid ].times + 1
|
||||
Errors[ addonid ].last = SysTime()
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local text = language.GetPhrase( "errors.something_p" )
|
||||
|
||||
-- We know the name, display it to the user
|
||||
if ( isstring( addontitle ) ) then
|
||||
text = string.format( language.GetPhrase( "errors.addon_p" ), addontitle )
|
||||
end
|
||||
|
||||
local error = {
|
||||
first = SysTime(),
|
||||
last = SysTime(),
|
||||
times = 1,
|
||||
title = addontitle,
|
||||
x = 32,
|
||||
text = text
|
||||
}
|
||||
|
||||
Errors[ addonid ] = error
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "OnPauseMenuBlockedTooManyTimes", "TellAboutShiftEsc", function()
|
||||
|
||||
Errors[ "internal_shift+esc" ] = {
|
||||
first = SysTime(),
|
||||
last = SysTime(),
|
||||
times = 1,
|
||||
title = "",
|
||||
x = 32,
|
||||
text = "You can force open the main menu by holding Shift when pressing the Escape key."
|
||||
}
|
||||
|
||||
end )
|
||||
|
||||
local matAlert = Material( "icon16/error.png" )
|
||||
|
||||
local cl_drawhud = GetConVar( "cl_drawhud" )
|
||||
|
||||
hook.Add( "DrawOverlay", "MenuDrawLuaErrors", function()
|
||||
|
||||
if ( table.IsEmpty( Errors ) ) then return end
|
||||
if ( !cl_drawhud:GetBool() ) then return end
|
||||
|
||||
local idealy = 32
|
||||
local height = 30
|
||||
local EndTime = SysTime() - 10
|
||||
local Recent = SysTime() - 0.5
|
||||
|
||||
for k, v in SortedPairsByMemberValue( Errors, "last" ) do
|
||||
|
||||
surface.SetFont( "DermaDefaultBold" )
|
||||
if ( v.y == nil ) then v.y = idealy end
|
||||
if ( v.w == nil ) then v.w = surface.GetTextSize( v.text ) + 48 end
|
||||
|
||||
draw.RoundedBox( 2, v.x + 2, v.y + 2, v.w, height, Color( 40, 40, 40, 255 ) )
|
||||
draw.RoundedBox( 2, v.x, v.y, v.w, height, Color( 240, 240, 240, 255 ) )
|
||||
|
||||
if ( v.last > Recent ) then
|
||||
|
||||
draw.RoundedBox( 2, v.x, v.y, v.w, height, Color( 255, 200, 0, ( v.last - Recent ) * 510 ) )
|
||||
|
||||
end
|
||||
|
||||
surface.SetTextColor( 90, 90, 90, 255 )
|
||||
surface.SetTextPos( v.x + 34, v.y + 8 )
|
||||
surface.DrawText( v.text )
|
||||
|
||||
surface.SetDrawColor( 255, 255, 255, 150 + math.sin( v.y + SysTime() * 30 ) * 100 )
|
||||
surface.SetMaterial( matAlert )
|
||||
surface.DrawTexturedRect( v.x + 6, v.y + 6, 16, 16 )
|
||||
|
||||
v.y = idealy
|
||||
|
||||
idealy = idealy + 40
|
||||
|
||||
if ( v.last < EndTime ) then
|
||||
Errors[ k ] = nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end )
|
||||
453
lua/menu/getmaps.lua
Normal file
453
lua/menu/getmaps.lua
Normal file
@@ -0,0 +1,453 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local MapPatterns = {}
|
||||
local MapNames = {}
|
||||
|
||||
local AddonMaps = {}
|
||||
|
||||
local function UpdateMaps()
|
||||
|
||||
MapPatterns = {}
|
||||
MapNames = {}
|
||||
|
||||
MapNames[ "aoc_" ] = "Age of Chivalry"
|
||||
MapNames[ "infra_" ] = "INFRA"
|
||||
|
||||
MapPatterns[ "^asi-" ] = "Alien Swarm"
|
||||
MapNames[ "lobby" ] = "Alien Swarm"
|
||||
|
||||
MapNames[ "cp_docks" ] = "Blade Symphony"
|
||||
MapNames[ "cp_parkour" ] = "Blade Symphony"
|
||||
MapNames[ "cp_sequence" ] = "Blade Symphony"
|
||||
MapNames[ "cp_terrace" ] = "Blade Symphony"
|
||||
MapNames[ "cp_test" ] = "Blade Symphony"
|
||||
MapNames[ "duel_" ] = "Blade Symphony"
|
||||
MapNames[ "ffa_community" ] = "Blade Symphony"
|
||||
MapNames[ "free_" ] = "Blade Symphony"
|
||||
MapNames[ "practice_box" ] = "Blade Symphony"
|
||||
MapNames[ "tut_training" ] = "Blade Symphony"
|
||||
MapNames[ "lightstyle_test" ] = "Blade Symphony"
|
||||
|
||||
MapNames[ "ar_" ] = "Counter-Strike"
|
||||
MapNames[ "cs_" ] = "Counter-Strike"
|
||||
MapNames[ "de_" ] = "Counter-Strike"
|
||||
MapNames[ "es_" ] = "Counter-Strike"
|
||||
MapNames[ "fy_" ] = "Counter-Strike"
|
||||
MapNames[ "gd_" ] = "Counter-Strike"
|
||||
MapNames[ "dz_" ] = "Counter-Strike"
|
||||
MapNames[ "training1" ] = "Counter-Strike"
|
||||
MapNames[ "lobby_mapveto" ] = "Counter-Strike"
|
||||
|
||||
-- Various custom cs maps
|
||||
MapNames[ "35hp_" ] = "Counter-Strike (Custom)"
|
||||
MapNames[ "aim_" ] = "Counter-Strike (Custom)"
|
||||
MapNames[ "awp_" ] = "Counter-Strike (Custom)"
|
||||
MapNames[ "am_" ] = "Counter-Strike (Custom)"
|
||||
MapNames[ "fy_" ] = "Counter-Strike (Custom)"
|
||||
MapNames[ "1v1_" ] = "Counter-Strike (Custom)"
|
||||
|
||||
MapNames[ "dod_" ] = "Day Of Defeat"
|
||||
|
||||
MapNames[ "ddd_" ] = "Dino D-Day"
|
||||
|
||||
MapNames[ "de_dam" ] = "DIPRIP"
|
||||
MapNames[ "dm_city" ] = "DIPRIP"
|
||||
MapNames[ "dm_refinery" ] = "DIPRIP"
|
||||
MapNames[ "dm_supermarket" ] = "DIPRIP"
|
||||
MapNames[ "dm_village" ] = "DIPRIP"
|
||||
MapNames[ "ur_city" ] = "DIPRIP"
|
||||
MapNames[ "ur_refinery" ] = "DIPRIP"
|
||||
MapNames[ "ur_supermarket" ] = "DIPRIP"
|
||||
MapNames[ "ur_village" ] = "DIPRIP"
|
||||
|
||||
MapNames[ "dys_" ] = "Dystopia"
|
||||
MapNames[ "pb_dojo" ] = "Dystopia"
|
||||
MapNames[ "pb_rooftop" ] = "Dystopia"
|
||||
MapNames[ "pb_round" ] = "Dystopia"
|
||||
MapNames[ "pb_urbandome" ] = "Dystopia"
|
||||
MapNames[ "sav_dojo6" ] = "Dystopia"
|
||||
MapNames[ "varena" ] = "Dystopia"
|
||||
|
||||
-- Do these manually, so edits of these maps don't end up in the same category.
|
||||
local HL2Maps = {
|
||||
"d1_trainstation_01", "d1_trainstation_02", "d1_trainstation_03", "d1_trainstation_04", "d1_trainstation_05", "d1_trainstation_06",
|
||||
"d1_canals_01", "d1_canals_01a", "d1_canals_02", "d1_canals_03", "d1_canals_05", "d1_canals_06", "d1_canals_07", "d1_canals_08", "d1_canals_09",
|
||||
"d1_canals_10", "d1_canals_11","d1_canals_12", "d1_canals_13", "d1_eli_01", "d1_eli_02",
|
||||
"d1_town_01", "d1_town_01a", "d1_town_02", "d1_town_02a", "d1_town_03", "d1_town_04","d1_town_05",
|
||||
"d2_coast_01", "d2_coast_03", "d2_coast_04", "d2_coast_05","d2_coast_07", "d2_coast_08", "d2_coast_09", "d2_coast_10", "d2_coast_11", "d2_coast_12",
|
||||
"d2_prison_01", "d2_prison_02", "d2_prison_03", "d2_prison_04", "d2_prison_05", "d2_prison_06", "d2_prison_07", "d2_prison_08",
|
||||
"d3_c17_01", "d3_c17_02", "d3_c17_03", "d3_c17_04", "d3_c17_05", "d3_c17_06a", "d3_c17_06b", "d3_c17_07", "d3_c17_08",
|
||||
"d3_c17_09", "d3_c17_10a", "d3_c17_10b", "d3_c17_11", "d3_c17_12", "d3_c17_12b", "d3_c17_13",
|
||||
"d3_citadel_01", "d3_citadel_02", "d3_citadel_03", "d3_citadel_04", "d3_citadel_05", "d3_breen_01"
|
||||
}
|
||||
for _, map in ipairs( HL2Maps ) do MapNames[ map ] = "Half-Life 2" end
|
||||
|
||||
local EP1Maps = {
|
||||
"ep1_citadel_00", "ep1_citadel_01", "ep1_citadel_02", "ep1_citadel_02b", "ep1_citadel_03", "ep1_citadel_04", "ep1_c17_00",
|
||||
"ep1_c17_00a", "ep1_c17_01", "ep1_c17_01a", "ep1_c17_02", "ep1_c17_02b", "ep1_c17_02a", "ep1_c17_05", "ep1_c17_06"
|
||||
}
|
||||
for _, map in ipairs( EP1Maps ) do MapNames[ map ] = "Half-Life 2: Episode 1" end
|
||||
|
||||
local EP2Maps = {
|
||||
"ep2_outland_01", "ep2_outland_01a", "ep2_outland_02", "ep2_outland_03", "ep2_outland_04", "ep2_outland_05", "ep2_outland_06", "ep2_outland_06a", "ep2_outland_07",
|
||||
"ep2_outland_08", "ep2_outland_09", "ep2_outland_10", "ep2_outland_10a", "ep2_outland_11", "ep2_outland_11a", "ep2_outland_11b", "ep2_outland_12", "ep2_outland_12a"
|
||||
}
|
||||
for _, map in ipairs( EP2Maps ) do MapNames[ map ] = "Half-Life 2: Episode 2" end
|
||||
|
||||
MapNames[ "dm_" ] = "Half-Life 2: Deathmatch"
|
||||
MapNames[ "halls3" ] = "Half-Life 2: Deathmatch"
|
||||
|
||||
MapNames[ "d2_lostcoast" ] = "Half-Life 2: Lost Coast"
|
||||
|
||||
MapPatterns[ "^c[%d]a" ] = "Half-Life"
|
||||
MapPatterns[ "^t0a" ] = "Half-Life"
|
||||
|
||||
MapNames[ "boot_camp" ] = "Half-Life Deathmatch"
|
||||
MapNames[ "bounce" ] = "Half-Life Deathmatch"
|
||||
MapNames[ "crossfire" ] = "Half-Life Deathmatch"
|
||||
MapNames[ "datacore" ] = "Half-Life Deathmatch"
|
||||
MapNames[ "frenzy" ] = "Half-Life Deathmatch"
|
||||
MapNames[ "lambda_bunker" ] = "Half-Life Deathmatch"
|
||||
MapNames[ "rapidcore" ] = "Half-Life Deathmatch"
|
||||
MapNames[ "snarkpit" ] = "Half-Life Deathmatch"
|
||||
MapNames[ "stalkyard" ] = "Half-Life Deathmatch"
|
||||
MapNames[ "subtransit" ] = "Half-Life Deathmatch"
|
||||
MapNames[ "undertow" ] = "Half-Life Deathmatch"
|
||||
|
||||
MapNames[ "ins_" ] = "Insurgency"
|
||||
|
||||
MapNames[ "l4d_" ] = "Left 4 Dead"
|
||||
|
||||
MapPatterns[ "^c[%d]m" ] = "Left 4 Dead 2"
|
||||
MapPatterns[ "^c1[%d]m" ] = "Left 4 Dead 2"
|
||||
MapNames[ "curling_stadium" ] = "Left 4 Dead 2"
|
||||
MapNames[ "tutorial_standards" ] = "Left 4 Dead 2"
|
||||
MapNames[ "tutorial_standards_vs" ] = "Left 4 Dead 2"
|
||||
|
||||
MapNames[ "clocktower" ] = "Nuclear Dawn"
|
||||
MapNames[ "coast" ] = "Nuclear Dawn"
|
||||
MapNames[ "downtown" ] = "Nuclear Dawn"
|
||||
MapNames[ "gate" ] = "Nuclear Dawn"
|
||||
MapNames[ "hydro" ] = "Nuclear Dawn"
|
||||
MapNames[ "metro" ] = "Nuclear Dawn"
|
||||
MapNames[ "metro_training" ] = "Nuclear Dawn"
|
||||
MapNames[ "oasis" ] = "Nuclear Dawn"
|
||||
MapNames[ "oilfield" ] = "Nuclear Dawn"
|
||||
MapNames[ "silo" ] = "Nuclear Dawn"
|
||||
MapNames[ "sk_metro" ] = "Nuclear Dawn"
|
||||
MapNames[ "training" ] = "Nuclear Dawn"
|
||||
|
||||
MapNames[ "bt_" ] = "Pirates, Vikings, & Knights II"
|
||||
MapNames[ "lts_" ] = "Pirates, Vikings, & Knights II"
|
||||
MapNames[ "te_" ] = "Pirates, Vikings, & Knights II"
|
||||
MapNames[ "tw_" ] = "Pirates, Vikings, & Knights II"
|
||||
|
||||
MapNames[ "escape_" ] = "Portal"
|
||||
MapNames[ "testchmb_" ] = "Portal"
|
||||
|
||||
MapNames[ "e1912" ] = "Portal 2"
|
||||
MapPatterns[ "^mp_coop_" ] = "Portal 2"
|
||||
MapPatterns[ "^sp_a" ] = "Portal 2"
|
||||
|
||||
MapNames[ "achievement_" ] = "Team Fortress 2"
|
||||
MapNames[ "arena_" ] = "Team Fortress 2"
|
||||
MapNames[ "cp_" ] = "Team Fortress 2"
|
||||
MapNames[ "ctf_" ] = "Team Fortress 2"
|
||||
MapNames[ "itemtest" ] = "Team Fortress 2"
|
||||
MapNames[ "koth_" ] = "Team Fortress 2"
|
||||
MapNames[ "mvm_" ] = "Team Fortress 2"
|
||||
MapNames[ "pl_" ] = "Team Fortress 2"
|
||||
MapNames[ "plr_" ] = "Team Fortress 2"
|
||||
MapNames[ "rd_" ] = "Team Fortress 2"
|
||||
MapNames[ "pd_" ] = "Team Fortress 2"
|
||||
MapNames[ "sd_" ] = "Team Fortress 2"
|
||||
MapNames[ "tc_" ] = "Team Fortress 2"
|
||||
MapNames[ "tr_" ] = "Team Fortress 2"
|
||||
MapNames[ "trade_" ] = "Team Fortress 2"
|
||||
MapNames[ "pass_" ] = "Team Fortress 2"
|
||||
MapNames[ "vsh_" ] = "Team Fortress 2"
|
||||
MapNames[ "zi_" ] = "Team Fortress 2"
|
||||
|
||||
MapNames[ "zpa_" ] = "Zombie Panic! Source"
|
||||
MapNames[ "zpl_" ] = "Zombie Panic! Source"
|
||||
MapNames[ "zpo_" ] = "Zombie Panic! Source"
|
||||
MapNames[ "zps_" ] = "Zombie Panic! Source"
|
||||
MapNames[ "zph_" ] = "Zombie Panic! Source"
|
||||
|
||||
MapNames[ "fof_" ] = "Fistful of Frags"
|
||||
MapNames[ "fofhr_" ] = "Fistful of Frags"
|
||||
MapNames[ "cm_" ] = "Fistful of Frags"
|
||||
MapNames[ "gt_" ] = "Fistful of Frags"
|
||||
MapNames[ "tp_" ] = "Fistful of Frags"
|
||||
MapNames[ "vs_" ] = "Fistful of Frags"
|
||||
|
||||
MapNames[ "bhop_" ] = "Bunny Hop"
|
||||
MapNames[ "cinema_" ] = "Cinema"
|
||||
MapNames[ "theater_" ] = "Cinema"
|
||||
MapNames[ "xc_" ] = "Climb"
|
||||
MapNames[ "deathrun_" ] = "Deathrun"
|
||||
MapNames[ "dr_" ] = "Deathrun"
|
||||
MapNames[ "fm_" ] = "Flood"
|
||||
MapNames[ "gmt_" ] = "GMod Tower"
|
||||
MapNames[ "gg_" ] = "Gun Game"
|
||||
MapNames[ "scoutzknivez" ] = "Gun Game"
|
||||
MapNames[ "ba_" ] = "Jailbreak"
|
||||
MapNames[ "jail_" ] = "Jailbreak"
|
||||
MapNames[ "jb_" ] = "Jailbreak"
|
||||
MapNames[ "mg_" ] = "Minigames"
|
||||
MapNames[ "pw_" ] = "Pirate Ship Wars"
|
||||
MapNames[ "ph_" ] = "Prop Hunt"
|
||||
MapNames[ "rp_" ] = "Roleplay"
|
||||
MapNames[ "slb_" ] = "Sled Build"
|
||||
MapNames[ "sb_" ] = "Spacebuild"
|
||||
MapNames[ "slender_" ] = "Stop it Slender"
|
||||
MapNames[ "gms_" ] = "Stranded"
|
||||
MapNames[ "surf_" ] = "Surf"
|
||||
MapNames[ "ts_" ] = "The Stalker"
|
||||
MapNames[ "zm_" ] = "Zombie Survival"
|
||||
MapNames[ "zombiesurvival_" ] = "Zombie Survival"
|
||||
MapNames[ "zs_" ] = "Zombie Survival"
|
||||
MapNames[ "coop_" ] = "Cooperative"
|
||||
|
||||
local GamemodeList = engine.GetGamemodes()
|
||||
|
||||
for k, gm in ipairs( GamemodeList ) do
|
||||
|
||||
local Name = gm.title or "Unnammed Gamemode"
|
||||
local Maps = string.Split( gm.maps, "|" )
|
||||
|
||||
if ( Maps and gm.maps != "" ) then
|
||||
|
||||
for _, pattern in ipairs( Maps ) do
|
||||
-- When in doubt, just try to match it with string.find
|
||||
MapPatterns[ string.lower( pattern ) ] = Name
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
AddonMaps = {}
|
||||
for k, addon in ipairs( engine.GetAddons() ) do
|
||||
|
||||
local name = addon.title or "Unnammed Addon"
|
||||
|
||||
local files = file.Find( "maps/*.bsp", name )
|
||||
if ( #files > 0 ) then AddonMaps[ name ] = files end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local favmaps
|
||||
|
||||
local function LoadFavourites()
|
||||
|
||||
local cookiestr = cookie.GetString( "favmaps" )
|
||||
favmaps = favmaps or ( cookiestr and string.Explode( ";", cookiestr ) or {} )
|
||||
|
||||
end
|
||||
|
||||
function UpdateAddonMapList()
|
||||
|
||||
local json = util.TableToJSON( AddonMaps )
|
||||
if ( !json ) then return end
|
||||
|
||||
pnlMainMenu:Call( "UpdateAddonMaps(" .. json .. ")" )
|
||||
|
||||
end
|
||||
|
||||
-- Called from JS when starting a new game
|
||||
function UpdateMapList()
|
||||
|
||||
UpdateAddonMapList()
|
||||
|
||||
local mapList = GetMapList()
|
||||
if ( !mapList ) then return end
|
||||
|
||||
local json = util.TableToJSON( mapList )
|
||||
if ( !json ) then return end
|
||||
|
||||
pnlMainMenu:Call( "UpdateMaps(" .. json .. ")" )
|
||||
|
||||
end
|
||||
|
||||
local IgnorePatterns = {
|
||||
"^background",
|
||||
"^devtest",
|
||||
"^ep1_background",
|
||||
"^ep2_background",
|
||||
"^styleguide",
|
||||
}
|
||||
|
||||
local IgnoreMaps = {
|
||||
-- Prefixes
|
||||
[ "sdk_" ] = true,
|
||||
[ "test_" ] = true,
|
||||
[ "vst_" ] = true,
|
||||
|
||||
-- Maps
|
||||
[ "c4a1y" ] = true,
|
||||
[ "credits" ] = true,
|
||||
[ "d2_coast_02" ] = true,
|
||||
[ "d3_c17_02_camera" ] = true,
|
||||
[ "ep1_citadel_00_demo" ] = true,
|
||||
[ "c5m1_waterfront_sndscape" ] = true,
|
||||
[ "intro" ] = true,
|
||||
[ "test" ] = true
|
||||
}
|
||||
|
||||
local MapList = {}
|
||||
|
||||
local function RefreshMaps( skip )
|
||||
|
||||
if ( !skip ) then UpdateMaps() end
|
||||
|
||||
MapList = {}
|
||||
|
||||
local maps = file.Find( "maps/*.bsp", "GAME" )
|
||||
LoadFavourites()
|
||||
|
||||
for k, v in ipairs( maps ) do
|
||||
local name = string.lower( string.gsub( v, "%.bsp$", "" ) )
|
||||
local prefix = string.match( name, "^(.-_)" )
|
||||
|
||||
local Ignore = IgnoreMaps[ name ] or IgnoreMaps[ prefix ]
|
||||
|
||||
-- Don't loop if it's already ignored
|
||||
if ( Ignore ) then continue end
|
||||
|
||||
for _, ignore in ipairs( IgnorePatterns ) do
|
||||
if ( string.find( name, ignore ) ) then
|
||||
Ignore = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- Don't add useless maps
|
||||
if ( Ignore ) then continue end
|
||||
|
||||
-- Check if the map has a simple name or prefix
|
||||
local Category = MapNames[ name ] or MapNames[ prefix ]
|
||||
|
||||
-- Check if the map has an embedded prefix, or is TTT/Sandbox
|
||||
if ( !Category ) then
|
||||
for pattern, category in pairs( MapPatterns ) do
|
||||
if ( string.find( name, pattern ) ) then
|
||||
Category = category
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Throw all uncategorised maps into Other
|
||||
Category = Category or "Other"
|
||||
|
||||
local fav
|
||||
|
||||
if ( table.HasValue( favmaps, name ) ) then
|
||||
fav = true
|
||||
end
|
||||
|
||||
local csgo = false
|
||||
|
||||
if ( Category == "Counter-Strike" and file.Exists( "maps/" .. name .. ".bsp", "csgo" ) ) then
|
||||
if ( file.Exists( "maps/" .. name .. ".bsp", "cstrike" ) ) then -- Map also exists in CS:GO
|
||||
csgo = true
|
||||
else
|
||||
Category = "Counter-Strike: GO"
|
||||
end
|
||||
end
|
||||
|
||||
if ( !MapList[ Category ] ) then
|
||||
MapList[ Category ] = {}
|
||||
end
|
||||
|
||||
table.insert( MapList[ Category ], name )
|
||||
|
||||
if ( fav ) then
|
||||
if ( !MapList[ "Favourites" ] ) then
|
||||
MapList[ "Favourites" ] = {}
|
||||
end
|
||||
|
||||
table.insert( MapList[ "Favourites" ], name )
|
||||
end
|
||||
|
||||
if ( csgo ) then
|
||||
if ( !MapList[ "Counter-Strike: GO" ] ) then
|
||||
MapList[ "Counter-Strike: GO" ] = {}
|
||||
end
|
||||
-- HACK: We have to make the CS:GO name different from the CS:S name to prevent Favourites conflicts
|
||||
table.insert( MapList[ "Counter-Strike: GO" ], name .. " " )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Send the new list to the HTML menu
|
||||
UpdateMapList()
|
||||
|
||||
end
|
||||
|
||||
-- Update only after a short while for when these hooks are called very rapidly back to back
|
||||
local function DelayedRefreshMaps()
|
||||
timer.Create( "menu_refreshmaps", 0.1, 1, RefreshMaps )
|
||||
end
|
||||
|
||||
hook.Add( "MenuStart", "FindMaps", DelayedRefreshMaps )
|
||||
hook.Add( "GameContentChanged", "RefreshMaps", DelayedRefreshMaps )
|
||||
|
||||
-- Nice maplist accessor instead of a global table
|
||||
function GetMapList()
|
||||
return MapList
|
||||
end
|
||||
|
||||
function ToggleFavourite( map )
|
||||
|
||||
LoadFavourites()
|
||||
|
||||
if ( table.HasValue( favmaps, map ) ) then -- is favourite, remove it
|
||||
table.remove( favmaps, table.KeysFromValue( favmaps, map )[1] )
|
||||
else -- not favourite, add it
|
||||
table.insert( favmaps, map )
|
||||
end
|
||||
|
||||
cookie.Set( "favmaps", table.concat( favmaps, ";" ) )
|
||||
|
||||
RefreshMaps( true )
|
||||
|
||||
UpdateMapList()
|
||||
|
||||
end
|
||||
|
||||
function SaveLastMap( map, cat )
|
||||
|
||||
local t = string.Explode( ";", cookie.GetString( "lastmap", "" ) )
|
||||
if ( !map ) then map = t[ 1 ] or "gm_flatgrass" end
|
||||
if ( !cat ) then cat = t[ 2 ] or "Sandbox" end
|
||||
|
||||
cookie.Set( "lastmap", map .. ";" .. cat )
|
||||
|
||||
end
|
||||
|
||||
function LoadLastMap()
|
||||
|
||||
local t = string.Explode( ";", cookie.GetString( "lastmap", "" ) )
|
||||
|
||||
local map = t[ 1 ] or "gm_flatgrass"
|
||||
local cat = t[ 2 ] or "Sandbox"
|
||||
|
||||
cat = string.gsub( cat, "'", "\\'" )
|
||||
|
||||
if ( !file.Exists( "maps/" .. map .. ".bsp", "GAME" ) ) then return end
|
||||
|
||||
pnlMainMenu:Call( "SetLastMap('" .. map:JavascriptSafe() .. "','" .. cat:JavascriptSafe() .. "')" )
|
||||
|
||||
end
|
||||
287
lua/menu/loading.lua
Normal file
287
lua/menu/loading.lua
Normal file
@@ -0,0 +1,287 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
g_ServerName = ""
|
||||
g_MapName = ""
|
||||
g_ServerURL = ""
|
||||
g_MaxPlayers = ""
|
||||
g_SteamID = ""
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:SetSize( ScrW(), ScrH() )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ShowURL( url, force )
|
||||
|
||||
if ( string.len( url ) < 5 ) then
|
||||
return
|
||||
end
|
||||
|
||||
if ( IsValid( self.HTML ) ) then
|
||||
if ( !force ) then return end
|
||||
self.HTML:Remove()
|
||||
end
|
||||
|
||||
self:SetSize( ScrW(), ScrH() )
|
||||
|
||||
self.HTML = vgui.Create( "DHTML", self )
|
||||
self.HTML:SetSize( ScrW(), ScrH() )
|
||||
self.HTML:Dock( FILL )
|
||||
self.HTML:OpenURL( url )
|
||||
|
||||
self:InvalidateLayout()
|
||||
self:SetMouseInputEnabled( false )
|
||||
|
||||
self.LoadedURL = url
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout()
|
||||
|
||||
self:SetSize( ScrW(), ScrH() )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Paint()
|
||||
|
||||
surface.SetDrawColor( 30, 30, 30, 255 )
|
||||
surface.DrawRect( 0, 0, self:GetWide(), self:GetTall() )
|
||||
|
||||
if ( self.JavascriptRun && IsValid( self.HTML ) && !self.HTML:IsLoading() ) then
|
||||
|
||||
self:RunJavascript( self.JavascriptRun )
|
||||
self.JavascriptRun = nil
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:RunJavascript( str )
|
||||
|
||||
if ( !IsValid( self.HTML ) ) then return end
|
||||
if ( self.HTML:IsLoading() ) then return end
|
||||
|
||||
self.HTML:RunJavascript( str )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OnActivate()
|
||||
|
||||
g_ServerName = ""
|
||||
g_MapName = ""
|
||||
g_ServerURL = ""
|
||||
g_MaxPlayers = ""
|
||||
g_SteamID = ""
|
||||
|
||||
self:ShowURL( GetDefaultLoadingHTML() )
|
||||
|
||||
self.NumDownloadables = 0
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OnDeactivate()
|
||||
|
||||
if ( IsValid( self.HTML ) ) then self.HTML:Remove() end
|
||||
self.LoadedURL = nil
|
||||
self.NumDownloadables = 0
|
||||
|
||||
-- Notify the user that the game is ready.
|
||||
-- TODO: A convar for this?
|
||||
system.FlashWindow()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OnScreenSizeChanged( oldW, oldH, newW, newH )
|
||||
|
||||
self:InvalidateLayout( true )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Think()
|
||||
|
||||
self:CheckForStatusChanges()
|
||||
self:CheckDownloadTables()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:StatusChanged( strStatus )
|
||||
|
||||
-- new FastDL/ServerDL format
|
||||
local matchedFileName = string.match( strStatus, "%w+/%w+ [-] (.+) is downloading" )
|
||||
if ( matchedFileName ) then
|
||||
|
||||
self:RunJavascript( "if ( window.DownloadingFile ) DownloadingFile( '" .. matchedFileName:JavascriptSafe() .. "' )" )
|
||||
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
-- WorkshopDL and old FastDL
|
||||
local startPos, _ = string.find( strStatus, "Downloading " )
|
||||
if ( startPos ) then
|
||||
-- Snip everything before the Download part
|
||||
strStatus = string.sub( strStatus, startPos )
|
||||
|
||||
-- Special case needed for workshop, snip the "' via Workshop" part
|
||||
if ( string.EndsWith( strStatus, "via Workshop" ) ) then
|
||||
strStatus = string.gsub( strStatus, "' via Workshop", "" )
|
||||
strStatus = string.gsub( strStatus, "Downloading '", "" ) -- We need to handle the quote marks
|
||||
end
|
||||
|
||||
local fileName = string.gsub( strStatus, "Downloading ", "" )
|
||||
|
||||
self:RunJavascript( "if ( window.DownloadingFile ) DownloadingFile( '" .. fileName:JavascriptSafe() .. "' )" )
|
||||
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
self:RunJavascript( "if ( window.SetStatusChanged ) SetStatusChanged( '" .. strStatus:JavascriptSafe() .. "' )" )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:CheckForStatusChanges()
|
||||
|
||||
local str = GetLoadStatus()
|
||||
if ( !str ) then return end
|
||||
|
||||
str = string.Trim( str )
|
||||
str = string.Trim( str, "\n" )
|
||||
str = string.Trim( str, "\t" )
|
||||
|
||||
str = string.gsub( str, ".bz2", "" )
|
||||
str = string.gsub( str, ".ztmp", "" )
|
||||
str = string.gsub( str, "\\", "/" )
|
||||
|
||||
if ( self.OldStatus && self.OldStatus == str ) then return end
|
||||
|
||||
self.OldStatus = str
|
||||
self:StatusChanged( str )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:RefreshDownloadables()
|
||||
|
||||
self.Downloadables = GetDownloadables()
|
||||
if ( !self.Downloadables ) then return end
|
||||
|
||||
local iDownloading = 0
|
||||
local iFileCount = 0
|
||||
for k, v in pairs( self.Downloadables ) do
|
||||
|
||||
v = string.gsub( v, ".bz2", "" )
|
||||
v = string.gsub( v, ".ztmp", "" )
|
||||
v = string.gsub( v, "\\", "/" )
|
||||
|
||||
iDownloading = iDownloading + self:FileNeedsDownload( v )
|
||||
iFileCount = iFileCount + 1
|
||||
|
||||
end
|
||||
|
||||
if ( iDownloading == 0 ) then return end
|
||||
|
||||
self:RunJavascript( "if ( window.SetFilesNeeded ) SetFilesNeeded( " .. iDownloading .. ")" )
|
||||
self:RunJavascript( "if ( window.SetFilesTotal ) SetFilesTotal( " .. iFileCount .. ")" )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:FileNeedsDownload( filename )
|
||||
|
||||
local bExists = file.Exists( filename, "GAME" )
|
||||
if ( bExists ) then return 0 end
|
||||
|
||||
return 1
|
||||
|
||||
end
|
||||
|
||||
function PANEL:CheckDownloadTables()
|
||||
|
||||
local NumDownloadables = NumDownloadables()
|
||||
if ( !NumDownloadables ) then return end
|
||||
|
||||
if ( self.NumDownloadables && NumDownloadables == self.NumDownloadables ) then return end
|
||||
|
||||
self.NumDownloadables = NumDownloadables
|
||||
self:RefreshDownloadables()
|
||||
|
||||
end
|
||||
|
||||
local PanelType_Loading = vgui.RegisterTable( PANEL, "EditablePanel" )
|
||||
|
||||
local pnlLoading = nil
|
||||
|
||||
function GetLoadPanel()
|
||||
|
||||
if ( !IsValid( pnlLoading ) ) then
|
||||
pnlLoading = vgui.CreateFromTable( PanelType_Loading )
|
||||
end
|
||||
|
||||
return pnlLoading
|
||||
|
||||
end
|
||||
|
||||
|
||||
function IsInLoading()
|
||||
|
||||
if ( !IsValid( pnlLoading ) || !IsValid( pnlLoading.HTML ) ) then
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function GameDetails( servername, serverurl, mapname, maxplayers, steamid, gamemode )
|
||||
|
||||
if ( engine.IsPlayingDemo() ) then return end
|
||||
|
||||
g_ServerName = servername
|
||||
g_MapName = mapname
|
||||
g_ServerURL = serverurl
|
||||
g_MaxPlayers = maxplayers
|
||||
g_SteamID = steamid
|
||||
g_GameMode = gamemode
|
||||
|
||||
MsgN( servername )
|
||||
MsgN( serverurl )
|
||||
MsgN( gamemode )
|
||||
MsgN( mapname )
|
||||
MsgN( maxplayers )
|
||||
MsgN( steamid )
|
||||
|
||||
serverurl = serverurl:Replace( "%s", steamid )
|
||||
serverurl = serverurl:Replace( "%m", mapname )
|
||||
|
||||
if ( maxplayers > 1 && GetConVar( "cl_enable_loadingurl" ):GetBool() && ( serverurl:StartsWith( "http" ) || serverurl:StartsWith( "asset://" ) ) ) then
|
||||
pnlLoading:ShowURL( serverurl, true )
|
||||
end
|
||||
|
||||
-- TODO: This should be pulled from the server
|
||||
local niceGamemode = g_GameMode
|
||||
for k, v in pairs( engine.GetGamemodes() ) do
|
||||
if ( niceGamemode == v.name ) then
|
||||
niceGamemode = v.title
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
pnlLoading.JavascriptRun = string.format( [[if ( window.GameDetails ) GameDetails( "%s", "%s", "%s", %i, "%s", "%s", %.2f, "%s", "%s" );]],
|
||||
servername:JavascriptSafe(), serverurl:JavascriptSafe(), mapname:JavascriptSafe(), maxplayers, steamid:JavascriptSafe(), g_GameMode:JavascriptSafe(),
|
||||
GetConVarNumber( "snd_musicvolume" ), GetConVarString( "gmod_language" ), niceGamemode:JavascriptSafe() )
|
||||
|
||||
end
|
||||
684
lua/menu/mainmenu.lua
Normal file
684
lua/menu/mainmenu.lua
Normal file
@@ -0,0 +1,684 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
include( "background.lua" )
|
||||
include( "cef_credits.lua" )
|
||||
include( "crosshair_setup.lua" )
|
||||
include( "openurl.lua" )
|
||||
include( "ugcpublish.lua" )
|
||||
|
||||
pnlMainMenu = nil
|
||||
local pnlMainMenuFallback = nil
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:Dock( FILL )
|
||||
self:SetKeyboardInputEnabled( true )
|
||||
self:SetMouseInputEnabled( true )
|
||||
|
||||
self.HTML = vgui.Create( "DHTML", self )
|
||||
|
||||
JS_Language( self.HTML )
|
||||
JS_Utility( self.HTML )
|
||||
JS_Workshop( self.HTML )
|
||||
|
||||
-- Detect whenther the HTML engine is even there
|
||||
self.menuLoaded = false
|
||||
self.HTML.OnBeginLoadingDocument = function()
|
||||
self.menuLoaded = true
|
||||
if ( IsValid( pnlMainMenuFallback ) ) then pnlMainMenuFallback:Remove() end
|
||||
end
|
||||
|
||||
self.HTML:Dock( FILL )
|
||||
self.HTML:OpenURL( "asset://garrysmod/html/menu.html" )
|
||||
self.HTML:SetKeyboardInputEnabled( true )
|
||||
self.HTML:SetMouseInputEnabled( true )
|
||||
self.HTML:SetAllowLua( true )
|
||||
self.HTML:RequestFocus()
|
||||
|
||||
ws_dupe.HTML = self.HTML
|
||||
ws_save.HTML = self.HTML
|
||||
addon.HTML = self.HTML
|
||||
demo.HTML = self.HTML
|
||||
|
||||
self:MakePopup()
|
||||
self:SetPopupStayAtBack( true )
|
||||
|
||||
-- If the console is already open, we've got in its way.
|
||||
if ( gui.IsConsoleVisible() ) then
|
||||
gui.ShowConsole()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ScreenshotScan( folder )
|
||||
|
||||
local bReturn = false
|
||||
|
||||
local Screenshots = file.Find( folder .. "*.*", "GAME" )
|
||||
for k, v in RandomPairs( Screenshots ) do
|
||||
|
||||
AddBackgroundImage( folder .. v )
|
||||
bReturn = true
|
||||
|
||||
end
|
||||
|
||||
return bReturn
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Paint()
|
||||
|
||||
DrawBackground()
|
||||
|
||||
if ( self.IsInGame != IsInGame() ) then
|
||||
|
||||
self.IsInGame = IsInGame()
|
||||
|
||||
if ( self.IsInGame ) then
|
||||
|
||||
if ( IsValid( self.InnerPanel ) ) then self.InnerPanel:Remove() end
|
||||
self:Call( "SetInGame( true )" )
|
||||
|
||||
else
|
||||
|
||||
self:Call( "SetInGame( false )" )
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
if ( !self.IsInGame ) then return end
|
||||
|
||||
local canAdd = CanAddServerToFavorites()
|
||||
local isFav = serverlist.IsCurrentServerFavorite()
|
||||
if ( self.CanAddServerToFavorites != canAdd or self.IsCurrentServerFavorite != isFav ) then
|
||||
|
||||
self.CanAddServerToFavorites = canAdd
|
||||
self.IsCurrentServerFavorite = isFav
|
||||
|
||||
self:Call( "SetShowFavButton( " .. tostring( self.CanAddServerToFavorites ) .. ", " .. tostring( self.IsCurrentServerFavorite ) .. " )" )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:RefreshContent()
|
||||
|
||||
self:RefreshGamemodes()
|
||||
self:RefreshAddons()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:RefreshGamemodes()
|
||||
|
||||
local json = util.TableToJSON( engine.GetGamemodes() )
|
||||
|
||||
self:Call( "UpdateGamemodes( " .. json .. " )" )
|
||||
self:UpdateBackgroundImages()
|
||||
self:Call( "UpdateCurrentGamemode( '" .. engine.ActiveGamemode():JavascriptSafe() .. "' )" )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:RefreshAddons()
|
||||
|
||||
-- TODO
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetProblemCount( problems, severity )
|
||||
|
||||
self:Call( "SetProblemCount(" .. problems .. ", " .. severity .. ")" )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:UpdateBackgroundImages()
|
||||
|
||||
ClearBackgroundImages()
|
||||
|
||||
--
|
||||
-- If there's screenshots in gamemodes/<gamemode>/backgrounds/*.jpg use them
|
||||
--
|
||||
if ( !self:ScreenshotScan( "gamemodes/" .. engine.ActiveGamemode() .. "/backgrounds/" ) ) then
|
||||
|
||||
--
|
||||
-- If there's no gamemode specific here we'll use the default backgrounds
|
||||
--
|
||||
self:ScreenshotScan( "backgrounds/" )
|
||||
|
||||
end
|
||||
|
||||
ChangeBackground( engine.ActiveGamemode() )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Call( js )
|
||||
|
||||
self.HTML:QueueJavascript( js )
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "MainMenuPanel", PANEL, "EditablePanel" )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:SetText( txt )
|
||||
self.Text = txt
|
||||
end
|
||||
|
||||
function PANEL:Paint( w, h )
|
||||
-- Draw the text
|
||||
local parsed = markup.Parse( self.Text, self:GetParent():GetWide() )
|
||||
parsed:Draw( 0, 0 )
|
||||
|
||||
-- Size to contents. Ew.
|
||||
self:SetSize( parsed:GetWidth(), parsed:GetHeight() )
|
||||
end
|
||||
|
||||
-- TODO: Maybe this panel belongs in client realm as well?
|
||||
local markupPanel = vgui.RegisterTable( PANEL, "Panel" )
|
||||
|
||||
function OnMenuFailedToLoad()
|
||||
local frame = vgui.Create( "DFrame" )
|
||||
frame:SetSize( ScrW() / 2, ScrH() / 2 )
|
||||
frame:Center()
|
||||
frame:SetDraggable( false )
|
||||
frame:ShowCloseButton( false )
|
||||
frame:SetTitle( "Menu failed to load" )
|
||||
frame:MakePopup()
|
||||
|
||||
pnlMainMenuFallback = frame
|
||||
|
||||
local lbl = vgui.CreateFromTable( markupPanel, frame )
|
||||
lbl:Dock( TOP )
|
||||
lbl:DockMargin( 0, 0, 0, 5 )
|
||||
lbl:SetText( "Looks like the main menu failed to load.\n\nThis could be due to missing game files (run verification of game file integrity through Steam), or the HTML engine failed to load.\n\nBelow are some simple options to exit the game." )
|
||||
|
||||
local btn_srv = frame:Add( "DButton" )
|
||||
btn_srv:Dock( TOP )
|
||||
btn_srv:DockMargin( 0, 0, 0, 5 )
|
||||
btn_srv:SetText( "Open legacy server browser" )
|
||||
btn_srv:SetConsoleCommand( "gamemenucommand", "OpenServerBrowser" )
|
||||
|
||||
local btn_opt = frame:Add( "DButton" )
|
||||
btn_opt:Dock( TOP )
|
||||
btn_opt:DockMargin( 0, 0, 0, 5 )
|
||||
btn_opt:SetText( "Open Settings" )
|
||||
btn_opt:SetConsoleCommand( "gamemenucommand", "OpenOptionsDialog" )
|
||||
|
||||
local btn_exit = frame:Add( "DButton" )
|
||||
btn_exit:Dock( TOP )
|
||||
btn_exit:DockMargin( 0, 0, 0, 5 )
|
||||
btn_exit:SetText( "Exit the game" )
|
||||
btn_exit.DoClick = function() RunGameUICommand( "quit" ) end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Called from JS when starting a new game
|
||||
--
|
||||
function UpdateServerSettings()
|
||||
|
||||
local array = {
|
||||
hostname = GetConVarString( "hostname" ),
|
||||
sv_lan = GetConVarString( "sv_lan" ),
|
||||
p2p_enabled = GetConVarString( "p2p_enabled" )
|
||||
}
|
||||
|
||||
local settings_file = file.Read( "gamemodes/" .. engine.ActiveGamemode() .. "/" .. engine.ActiveGamemode() .. ".txt", true )
|
||||
|
||||
if ( settings_file ) then
|
||||
|
||||
local Settings = util.KeyValuesToTable( settings_file )
|
||||
|
||||
if ( istable( Settings.settings ) ) then
|
||||
|
||||
array.settings = {}
|
||||
for k, v in pairs( Settings.settings ) do
|
||||
local cvar = GetConVar( v.name )
|
||||
if ( !cvar ) then continue end
|
||||
|
||||
array.settings[ k ] = v
|
||||
array.settings[ k ].Value = cvar:GetString()
|
||||
array.settings[ k ].Singleplayer = v.singleplayer and true or false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local json = util.TableToJSON( array )
|
||||
pnlMainMenu:Call( "UpdateServerSettings(" .. json .. ")" )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Get the player list for this server
|
||||
--
|
||||
function GetPlayerList( serverip )
|
||||
|
||||
serverlist.PlayerList( serverip, function( tbl )
|
||||
|
||||
local json = util.TableToJSON( tbl )
|
||||
pnlMainMenu:Call( "SetPlayerList( '" .. serverip:JavascriptSafe() .. "', " .. json .. ")" )
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
local BlackList = {
|
||||
Addresses = {},
|
||||
Hostnames = {},
|
||||
Descripts = {},
|
||||
Gamemodes = {},
|
||||
Maps = {},
|
||||
}
|
||||
|
||||
local NewsList = {}
|
||||
|
||||
GetAPIManifest( function( result )
|
||||
result = util.JSONToTable( result )
|
||||
if ( !result ) then return end
|
||||
|
||||
NewsList = result.News and result.News.Blogs or {}
|
||||
LoadNewsList()
|
||||
|
||||
for k, v in pairs( result.Servers and result.Servers.Banned or {} ) do
|
||||
if ( v:StartsWith( "map:" ) ) then
|
||||
table.insert( BlackList.Maps, v:sub( 5 ) )
|
||||
elseif ( v:StartsWith( "host:" ) or v:StartsWith( "name:" ) ) then
|
||||
table.insert( BlackList.Hostnames, v:sub( 6 ) )
|
||||
elseif ( v:StartsWith( "desc:" ) ) then
|
||||
table.insert( BlackList.Descripts, v:sub( 6 ) )
|
||||
elseif ( v:StartsWith( "gm:" ) ) then
|
||||
table.insert( BlackList.Gamemodes, v:sub( 4 ) )
|
||||
else
|
||||
table.insert( BlackList.Addresses, v )
|
||||
end
|
||||
end
|
||||
end )
|
||||
|
||||
function LoadNewsList()
|
||||
if ( !pnlMainMenu ) then return end
|
||||
|
||||
local json = util.TableToJSON( NewsList )
|
||||
local bHide = cookie.GetString( "hide_newslist", "false" ) == "true"
|
||||
|
||||
pnlMainMenu:Call( "UpdateNewsList(" .. json .. ", " .. tostring( bHide ) .. " )" )
|
||||
end
|
||||
|
||||
function SaveHideNews( bHide )
|
||||
cookie.Set( "hide_newslist", tostring( bHide ) )
|
||||
end
|
||||
|
||||
function IsServerBlacklisted( address, hostname, description, gm, map )
|
||||
local addressNoPort = address:match( "[^:]*" )
|
||||
|
||||
for k, v in ipairs( BlackList.Addresses ) do
|
||||
if ( address == v or addressNoPort == v ) then
|
||||
return v
|
||||
end
|
||||
|
||||
if ( v:EndsWith( "*" ) and address:sub( 1, v:len() - 1 ) == v:sub( 1, v:len() - 1 ) ) then return v end
|
||||
|
||||
-- IP Ranges
|
||||
if ( string.find( v, "/", 1, false ) ) then
|
||||
local o1, o2, o3, o4, o5 = string.match( v, "(%d%d?%d?)%.(%d%d?%d?)%.(%d%d?%d?)%.(%d%d?%d?)/(%d%d?)" )
|
||||
local blacklistedIP = 2 ^ 24 * o1 + 2 ^ 16 * o2 + 2 ^ 8 * o3 + o4
|
||||
|
||||
local mask = bit.lshift( 0xFFFFFFFF, 32-o5 )
|
||||
|
||||
o1, o2, o3, o4 = string.match( address, "(%d%d?%d?)%.(%d%d?%d?)%.(%d%d?%d?)%.(%d%d?%d?)" )
|
||||
local testIP = 2 ^ 24 * o1 + 2 ^ 16 * o2 + 2 ^ 8 * o3 + o4
|
||||
|
||||
if ( bit.band( testIP, mask ) == bit.band( blacklistedIP, mask ) ) then return v end
|
||||
end
|
||||
end
|
||||
|
||||
for k, v in ipairs( BlackList.Hostnames ) do
|
||||
if ( string.match( hostname, v ) or string.match( hostname:lower(), v ) ) then
|
||||
return "host: " .. v
|
||||
end
|
||||
end
|
||||
|
||||
for k, v in ipairs( BlackList.Descripts ) do
|
||||
if ( string.match( description, v ) or string.match( description:lower(), v ) ) then
|
||||
return "desc: " .. v
|
||||
end
|
||||
end
|
||||
|
||||
for k, v in ipairs( BlackList.Gamemodes ) do
|
||||
if ( string.match( gm, v ) or string.match( gm:lower(), v ) ) then
|
||||
return "gm: " .. v
|
||||
end
|
||||
end
|
||||
|
||||
for k, v in ipairs( BlackList.Maps ) do
|
||||
if ( string.match( map, v ) or string.match( map:lower(), v ) ) then
|
||||
return "map: " .. v
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
local Servers = {}
|
||||
local ShouldStop = {}
|
||||
|
||||
local function SendServer( pnlMainMenu, category, id,
|
||||
ping, name, desc, map, players, maxplayers, botplayers, pass, lastplayed, address, gm, workshopid, isAnon, netVersion, luaVersion, loc, gmcat )
|
||||
|
||||
name = string.JavascriptSafe( name )
|
||||
desc = string.JavascriptSafe( desc )
|
||||
map = string.JavascriptSafe( map )
|
||||
address = string.JavascriptSafe( address )
|
||||
gm = string.JavascriptSafe( gm )
|
||||
workshopid = string.JavascriptSafe( workshopid )
|
||||
netVersion = string.JavascriptSafe( tostring( netVersion ) )
|
||||
loc = string.JavascriptSafe( loc )
|
||||
gmcat = string.JavascriptSafe( gmcat )
|
||||
|
||||
pnlMainMenu:Call( string.format( [[AddServer( "%s", "%s", %i, "%s", "%s", "%s", %i, %i, %i, %s, %i, "%s", "%s", "%s", %s, "%s", "%s", "%s" , "%s" );]],
|
||||
category, id, ping, name, desc, map, players, maxplayers, botplayers, tostring( pass ), lastplayed, address, gm, workshopid,
|
||||
tostring( isAnon ), netVersion, tostring( serverlist.IsServerFavorite( address ) ), loc, gmcat ) )
|
||||
|
||||
|
||||
end
|
||||
|
||||
function GetServers( category, id )
|
||||
|
||||
category = string.JavascriptSafe( category )
|
||||
id = string.JavascriptSafe( id )
|
||||
|
||||
ShouldStop[ category ] = false
|
||||
Servers[ category ] = {}
|
||||
|
||||
local data = {
|
||||
Callback = function( ping, name, desc, map, players, maxplayers, botplayers, pass, lastplayed, address, gm, workshopid, isAnon, netVersion, luaVersion, loc, gmcat )
|
||||
|
||||
if ( Servers[ category ] and Servers[ category ][ address ] ) then print( "Server Browser Error!", address, category ) return end
|
||||
Servers[ category ][ address ] = true
|
||||
|
||||
local blackListMatch = IsServerBlacklisted( address, name, desc, gm, map )
|
||||
if ( blackListMatch == nil ) then
|
||||
|
||||
SendServer( pnlMainMenu, category, id,
|
||||
ping, name, desc, map, players, maxplayers, botplayers, pass, lastplayed, address, gm, workshopid,
|
||||
isAnon, netVersion, luaVersion, loc, gmcat )
|
||||
|
||||
else
|
||||
|
||||
Msg( "Ignoring server '", name, "' @ ", address, " - ", blackListMatch, " is blacklisted\n" )
|
||||
|
||||
end
|
||||
|
||||
return !ShouldStop[ category ]
|
||||
|
||||
end,
|
||||
|
||||
CallbackFailed = function( address )
|
||||
|
||||
if ( Servers[ category ] and Servers[ category ][ address ] ) then print( "Server Browser Error!", address, category ) return end
|
||||
Servers[ category ][ address ] = true
|
||||
|
||||
local version = string.JavascriptSafe( tostring( VERSION ) )
|
||||
|
||||
SendServer( pnlMainMenu, category, id,
|
||||
2000, "The server at address " .. address .. " failed to respond", "Unreachable Servers", "no_map", 0, 2, 0, "false", 0, address, "unkn", "0",
|
||||
"true", version, tostring( serverlist.IsServerFavorite( address ) ), "", "" )
|
||||
|
||||
return !ShouldStop[ category ]
|
||||
|
||||
end,
|
||||
|
||||
Finished = function()
|
||||
pnlMainMenu:Call( "FinishedServeres( '" .. category:JavascriptSafe() .. "' )" )
|
||||
Servers[ category ] = {}
|
||||
end,
|
||||
|
||||
Type = category,
|
||||
GameDir = "garrysmod",
|
||||
AppID = 4000,
|
||||
}
|
||||
|
||||
serverlist.Query( data )
|
||||
|
||||
end
|
||||
|
||||
function DoStopServers( category )
|
||||
pnlMainMenu:Call( "FinishedServeres( '" .. category:JavascriptSafe() .. "' )" )
|
||||
ShouldStop[ category ] = true
|
||||
Servers[ category ] = {}
|
||||
end
|
||||
|
||||
function PingServer( srvAddress )
|
||||
|
||||
serverlist.PingServer( srvAddress, function( ping, name, desc, map, players, maxplayers, botplayers, pass, lastplayed, address, gm, workshopid, isAnon, netVersion, luaVersion, loc, gmcat )
|
||||
|
||||
if ( !name ) then return end
|
||||
|
||||
name = string.JavascriptSafe( name )
|
||||
map = string.JavascriptSafe( map )
|
||||
address = string.JavascriptSafe( address )
|
||||
|
||||
pnlMainMenu:Call( string.format( [[UpdateServer( "%s", %i, "%s", "%s", %i, %i, %i, %s );]],
|
||||
address, ping, name, map, players, maxplayers, botplayers, tostring( pass ) ) )
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
function FindServersAtAddress( inputStr )
|
||||
|
||||
local hasPort = string.find( inputStr, ":", 0, true )
|
||||
|
||||
local addresses = {}
|
||||
if ( hasPort ) then
|
||||
table.insert( addresses, inputStr )
|
||||
else
|
||||
for i = 0, 5 do
|
||||
table.insert( addresses, inputStr .. ":" .. tostring( 27015 + i ) )
|
||||
table.insert( addresses, inputStr .. ":" .. tostring( 26900 + i ) )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local output = {}
|
||||
for i, addr in ipairs( addresses ) do
|
||||
|
||||
serverlist.PingServer( addr, function( ping, name, desc, map, players, maxplayers, botplayers, pass, lastplayed, address, gm, ... )
|
||||
|
||||
if ( !name ) then
|
||||
table.insert( output, { name = "Server at " .. addr .. " did not respond", address = addr, ping = 2000, favorite = false, players = 0, maxplayers = 0, botplayers = 0, map = "", gamemode = "" } )
|
||||
else
|
||||
name = string.JavascriptSafe( name )
|
||||
map = string.JavascriptSafe( map )
|
||||
address = string.JavascriptSafe( address )
|
||||
gm = string.JavascriptSafe( gm )
|
||||
|
||||
table.insert( output, {
|
||||
address = address,
|
||||
name = name,
|
||||
ping = ping,
|
||||
map = map,
|
||||
gamemode = gm,
|
||||
favorite = serverlist.IsServerFavorite( address ),
|
||||
players = players,
|
||||
botplayers = botplayers,
|
||||
maxplayers = maxplayers,
|
||||
} )
|
||||
end
|
||||
|
||||
//if ( #output == #addresses ) then
|
||||
|
||||
local json = util.TableToJSON( output )
|
||||
pnlMainMenu:Call( "ReceiveFoundServers(" .. json .. ")" )
|
||||
//end
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Called from JS
|
||||
--
|
||||
function UpdateLanguages()
|
||||
|
||||
local f = file.Find( "resource/localization/*.png", "MOD" )
|
||||
local json = util.TableToJSON( f )
|
||||
pnlMainMenu:Call( "UpdateLanguages(" .. json .. ")" )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Called from the engine any time the language changes
|
||||
--
|
||||
function LanguageChanged( lang )
|
||||
|
||||
if ( !IsValid( pnlMainMenu ) ) then return end
|
||||
|
||||
UpdateLanguages()
|
||||
pnlMainMenu:Call( "UpdateLanguage( \"" .. lang:JavascriptSafe() .. "\" )" )
|
||||
|
||||
end
|
||||
|
||||
function UpdateGames()
|
||||
|
||||
local games = engine.GetGames()
|
||||
local json = util.TableToJSON( games )
|
||||
|
||||
pnlMainMenu:Call( "UpdateGames( " .. json .. ")" )
|
||||
|
||||
end
|
||||
|
||||
function UpdateSubscribedAddons()
|
||||
|
||||
local subscriptions = engine.GetAddons()
|
||||
local json = util.TableToJSON( subscriptions )
|
||||
pnlMainMenu:Call( "subscriptions.Update( " .. json .. " )" )
|
||||
|
||||
local UGCsubs = engine.GetUserContent()
|
||||
local jsonUGC = util.TableToJSON( UGCsubs )
|
||||
pnlMainMenu:Call( "subscriptions.UpdateUGC( " .. jsonUGC .. " )" )
|
||||
|
||||
end
|
||||
|
||||
function UpdateAddonDisabledState()
|
||||
local noaddons, noworkshop = GetAddonStatus()
|
||||
pnlMainMenu:Call( "UpdateAddonDisabledState( " .. tostring( noaddons ) .. ", " .. tostring( noworkshop ) .. " )" )
|
||||
end
|
||||
|
||||
function MenuGetAddonData( wsid )
|
||||
steamworks.FileInfo( wsid, function( data )
|
||||
local json = util.TableToJSON( data ) or ""
|
||||
pnlMainMenu:Call( "ReceivedChildAddonInfo( " .. json .. " )" )
|
||||
end )
|
||||
end
|
||||
|
||||
local presetCache = {}
|
||||
local function EnsurePresetsLoaded()
|
||||
if ( table.IsEmpty( presetCache ) ) then
|
||||
presetCache = util.JSONToTable( LoadAddonPresets() or "", true, true ) or {}
|
||||
end
|
||||
end
|
||||
function CreateNewAddonPreset( json )
|
||||
EnsurePresetsLoaded()
|
||||
|
||||
local data = util.JSONToTable( json )
|
||||
presetCache[ data.name ] = data
|
||||
|
||||
SaveAddonPresets( util.TableToJSON( presetCache ) )
|
||||
end
|
||||
function ImportAddonPreset( id, json )
|
||||
EnsurePresetsLoaded()
|
||||
|
||||
steamworks.FileInfo( id, function( fileInfo )
|
||||
|
||||
if ( !fileInfo.children or #fileInfo.children < 1 ) then
|
||||
pnlMainMenu:Call( "OnImportPresetFailed()" )
|
||||
return
|
||||
end
|
||||
|
||||
local data = util.JSONToTable( json )
|
||||
presetCache[ data.name ] = data
|
||||
presetCache[ data.name ].enabled = fileInfo.children
|
||||
|
||||
SaveAddonPresets( util.TableToJSON( presetCache ) )
|
||||
ListAddonPresets()
|
||||
end )
|
||||
end
|
||||
function DeleteAddonPreset( name )
|
||||
EnsurePresetsLoaded()
|
||||
|
||||
presetCache[ name ] = {}
|
||||
presetCache[ name ] = nil
|
||||
|
||||
SaveAddonPresets( util.TableToJSON( presetCache ) )
|
||||
|
||||
ListAddonPresets()
|
||||
end
|
||||
function ListAddonPresets()
|
||||
EnsurePresetsLoaded()
|
||||
|
||||
pnlMainMenu:Call( "OnReceivePresetList(" .. util.TableToJSON( presetCache ) .. ")" )
|
||||
end
|
||||
|
||||
-- Called when UGC subscription status changes
|
||||
hook.Add( "WorkshopSubscriptionsChanged", "WorkshopSubscriptionsChanged", function( msg )
|
||||
|
||||
UpdateSubscribedAddons()
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "GameContentChanged", "RefreshMainMenu", function()
|
||||
|
||||
if ( !IsValid( pnlMainMenu ) ) then return end
|
||||
|
||||
pnlMainMenu:RefreshContent()
|
||||
|
||||
UpdateGames()
|
||||
UpdateServerSettings()
|
||||
UpdateSubscribedAddons()
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "LoadGModSaveFailed", "LoadGModSaveFailed", function( str, wsid )
|
||||
local button2 = nil
|
||||
if ( wsid and wsid:len() > 0 and wsid != "0" ) then button2 = "Open map on Steam Workshop" end
|
||||
|
||||
Derma_Query( str, "Failed to load save!", "OK", nil, button2, function() steamworks.ViewFile( wsid ) end )
|
||||
gui.ActivateGameUI()
|
||||
end )
|
||||
|
||||
--
|
||||
-- Initialize
|
||||
--
|
||||
timer.Simple( 0, function()
|
||||
|
||||
pnlMainMenu = vgui.Create( "MainMenuPanel" )
|
||||
pnlMainMenu:Call( "UpdateVersion( '" .. VERSIONSTR:JavascriptSafe() .. "', '" .. NETVERSIONSTR:JavascriptSafe() .. "', '" .. BRANCH:JavascriptSafe() .. "' )" )
|
||||
|
||||
local lang = GetConVarString( "gmod_language" )
|
||||
LanguageChanged( lang )
|
||||
|
||||
hook.Run( "GameContentChanged" )
|
||||
|
||||
if ( !file.Exists( "html/menu.html", "MOD" ) ) then
|
||||
OnMenuFailedToLoad()
|
||||
end
|
||||
|
||||
timer.Simple( 5, function()
|
||||
if ( !pnlMainMenu.menuLoaded ) then OnMenuFailedToLoad() end
|
||||
end )
|
||||
end )
|
||||
27
lua/menu/menu.lua
Normal file
27
lua/menu/menu.lua
Normal file
@@ -0,0 +1,27 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
include( "mount/mount.lua" )
|
||||
include( "getmaps.lua" )
|
||||
include( "loading.lua" )
|
||||
include( "mainmenu.lua" )
|
||||
include( "video.lua" )
|
||||
include( "demo_to_video.lua" )
|
||||
|
||||
include( "menu_save.lua" )
|
||||
include( "menu_demo.lua" )
|
||||
include( "menu_addon.lua" )
|
||||
include( "menu_dupe.lua" )
|
||||
include( "errors.lua" )
|
||||
include( "problems/problems.lua" )
|
||||
|
||||
include( "motionsensor.lua" )
|
||||
include( "util.lua" )
|
||||
12
lua/menu/menu_addon.lua
Normal file
12
lua/menu/menu_addon.lua
Normal file
@@ -0,0 +1,12 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
addon = WorkshopFileBase( "addon", {} )
|
||||
89
lua/menu/menu_demo.lua
Normal file
89
lua/menu/menu_demo.lua
Normal file
@@ -0,0 +1,89 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
demo = WorkshopFileBase( "demo", { "demo" } )
|
||||
|
||||
function demo:FetchLocal( offset, perpage )
|
||||
|
||||
local f = file.Find( "demos/*.dem", "MOD", "datedesc" )
|
||||
|
||||
local saves = {}
|
||||
|
||||
for k, v in ipairs( f ) do
|
||||
|
||||
if ( k <= offset ) then continue end
|
||||
if ( k > offset + perpage ) then break end
|
||||
|
||||
local entry = {
|
||||
file = "demos/" .. v,
|
||||
name = v:StripExtension(),
|
||||
preview = "demos/" .. v:StripExtension() .. ".jpg",
|
||||
description = "Local demo stored on your computer. Local content can be deleted in the main menu."
|
||||
}
|
||||
|
||||
table.insert( saves, entry )
|
||||
|
||||
end
|
||||
|
||||
local results = {
|
||||
totalresults = #f,
|
||||
results = saves
|
||||
}
|
||||
|
||||
local json = util.TableToJSON( results, false )
|
||||
pnlMainMenu:Call( "demo.ReceiveLocal( " .. json .. " )" )
|
||||
|
||||
end
|
||||
|
||||
function demo:DownloadAndPlay( id )
|
||||
|
||||
steamworks.DownloadUGC( id, function( name )
|
||||
if ( !name ) then hook.Call( "LoadGModSaveFailed", nil, "Failed to download demo from Steam Workshop!" ) return end
|
||||
|
||||
self:Play( name )
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
function demo:Play( filename )
|
||||
|
||||
RunConsoleCommand( "progress_enable", "1" )
|
||||
RunConsoleCommand( "playdemo", filename )
|
||||
|
||||
end
|
||||
|
||||
function demo:DownloadAndToVideo( id )
|
||||
|
||||
steamworks.DownloadUGC( id, function( name )
|
||||
if ( !name ) then hook.Call( "LoadGModSaveFailed", nil, "Failed to download demo from Steam Workshop!" ) return end
|
||||
|
||||
self:ToVideo( name )
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
|
||||
function demo:ToVideo( filename )
|
||||
|
||||
RunConsoleCommand( "gm_demo_to_video", filename )
|
||||
|
||||
end
|
||||
|
||||
function demo:FinishPublish( filename, imagename, name, desc, chosenTag, other )
|
||||
|
||||
local info = GetDemoFileDetails( filename )
|
||||
if ( !info ) then return "Couldn't get demo information!" end
|
||||
|
||||
steamworks.Publish( filename, imagename, name, desc, { "demo", info.mapname }, other.Callback, other.WorkshopID, other.ChangeNotes )
|
||||
|
||||
end
|
||||
60
lua/menu/menu_dupe.lua
Normal file
60
lua/menu/menu_dupe.lua
Normal file
@@ -0,0 +1,60 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
ws_dupe = WorkshopFileBase( "dupe", { "dupe" } )
|
||||
|
||||
function ws_dupe:FetchLocal( offset, perpage )
|
||||
|
||||
local f = file.Find( "dupes/*.dupe", "MOD", "datedesc" )
|
||||
|
||||
local saves = {}
|
||||
|
||||
for k, v in ipairs( f ) do
|
||||
|
||||
if ( k <= offset ) then continue end
|
||||
if ( k > offset + perpage ) then break end
|
||||
|
||||
local entry = {
|
||||
file = "dupes/" .. v,
|
||||
name = v:StripExtension(),
|
||||
preview = "dupes/" .. v:StripExtension() .. ".jpg",
|
||||
description = "Local duplication stored on your computer. Local content can be deleted in the main menu."
|
||||
}
|
||||
|
||||
table.insert( saves, entry )
|
||||
|
||||
end
|
||||
|
||||
local results = {
|
||||
totalresults = #f,
|
||||
results = saves
|
||||
}
|
||||
|
||||
local json = util.TableToJSON( results, false )
|
||||
pnlMainMenu:Call( "dupe.ReceiveLocal( " .. json .. " )" )
|
||||
|
||||
end
|
||||
|
||||
function ws_dupe:FinishPublish( filename, imagename, name, desc, chosenTag, other )
|
||||
|
||||
steamworks.Publish( filename, imagename, name, desc, { "dupe", chosenTag }, other.Callback, other.WorkshopID, other.ChangeNotes )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Called from the engine!
|
||||
--
|
||||
concommand.Add( "dupe_publish", function( ply, cmd, args )
|
||||
|
||||
ws_dupe:Publish( args[1], args[2] )
|
||||
gui.ActivateGameUI()
|
||||
|
||||
end, nil, "", { FCVAR_DONTRECORD } )
|
||||
81
lua/menu/menu_save.lua
Normal file
81
lua/menu/menu_save.lua
Normal file
@@ -0,0 +1,81 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
ws_save = WorkshopFileBase( "save", { "save" } )
|
||||
|
||||
function ws_save:FetchLocal( offset, perpage )
|
||||
|
||||
local f = file.Find( "saves/*.gms", "MOD", "datedesc" )
|
||||
|
||||
local saves = {}
|
||||
|
||||
for k, v in ipairs( f ) do
|
||||
|
||||
if ( k <= offset ) then continue end
|
||||
if ( k > offset + perpage ) then break end
|
||||
|
||||
local entry = {
|
||||
file = "saves/" .. v,
|
||||
name = v:StripExtension(),
|
||||
preview = "saves/" .. v:StripExtension() .. ".jpg",
|
||||
description = "Local map save stored on your computer. Local content can be deleted in the main menu."
|
||||
}
|
||||
|
||||
table.insert( saves, entry )
|
||||
|
||||
end
|
||||
|
||||
local results = {
|
||||
totalresults = #f,
|
||||
results = saves
|
||||
}
|
||||
|
||||
local json = util.TableToJSON( results, false )
|
||||
pnlMainMenu:Call( "save.ReceiveLocal( " .. json .. " )" )
|
||||
|
||||
end
|
||||
|
||||
function ws_save:DownloadAndLoad( id )
|
||||
|
||||
steamworks.DownloadUGC( id, function( name )
|
||||
|
||||
if ( !name ) then hook.Call( "LoadGModSaveFailed", nil, "Failed to download save from Steam Workshop!" ) return end
|
||||
|
||||
ws_save:Load( name )
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
function ws_save:Load( filename )
|
||||
|
||||
RunConsoleCommand( "gm_load", filename )
|
||||
|
||||
end
|
||||
|
||||
function ws_save:FinishPublish( filename, imagename, name, desc, chosenTag, other )
|
||||
|
||||
local info = GetSaveFileDetails( filename )
|
||||
if ( !info ) then return "Couldn't get save information!" end
|
||||
|
||||
steamworks.Publish( filename, imagename, name, desc, { "save", info.map, chosenTag }, other.Callback, other.WorkshopID, other.ChangeNotes )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Called from the engine!
|
||||
--
|
||||
concommand.Add( "save_publish", function( ply, cmd, args )
|
||||
|
||||
ws_save:Publish( args[1], args[2] )
|
||||
gui.ActivateGameUI()
|
||||
|
||||
end, nil, "", { FCVAR_DONTRECORD } )
|
||||
68
lua/menu/motionsensor.lua
Normal file
68
lua/menu/motionsensor.lua
Normal file
@@ -0,0 +1,68 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local sensor_color_show = CreateConVar( "sensor_color_show", "0", FCVAR_DONTRECORD )
|
||||
local sensor_color_scale = CreateConVar( "sensor_color_scale", "0.5", FCVAR_ARCHIVE + FCVAR_DONTRECORD )
|
||||
local sensor_color_x = CreateConVar( "sensor_color_x", "32", FCVAR_ARCHIVE + FCVAR_DONTRECORD )
|
||||
local sensor_color_y = CreateConVar( "sensor_color_y", "-32", FCVAR_ARCHIVE + FCVAR_DONTRECORD )
|
||||
|
||||
local function DrawColorBox()
|
||||
|
||||
if ( !sensor_color_show:GetBool() ) then return end
|
||||
|
||||
local mat = motionsensor.GetColourMaterial()
|
||||
if ( !mat ) then return end
|
||||
|
||||
local size = sensor_color_scale:GetFloat()
|
||||
local w = 640 * size
|
||||
local h = 480 * size
|
||||
|
||||
local x = sensor_color_x:GetInt()
|
||||
if ( x < 0 ) then
|
||||
x = x * -1
|
||||
x = ScrW() - x - w
|
||||
end
|
||||
|
||||
local y = sensor_color_y:GetInt()
|
||||
if ( y < 0 ) then
|
||||
y = y * -1
|
||||
y = ScrH() - y - h
|
||||
end
|
||||
|
||||
local alpha = 255
|
||||
|
||||
--
|
||||
-- fade the box down if we get close, so we can click on stuff that's under it.
|
||||
--
|
||||
if ( vgui.CursorVisible() ) then
|
||||
local mx, my = input.GetCursorPos()
|
||||
local dist = Vector( mx, my, 0 ):Distance( Vector( x + w * 0.5, y + h * 0.5, 0 ) )
|
||||
alpha = math.Clamp( alpha - ( 512 - dist ), 10, 255 )
|
||||
end
|
||||
|
||||
surface.SetDrawColor( 0, 0, 0, alpha )
|
||||
surface.DrawRect( x - 3, y - 3, 3, h + 6 )
|
||||
surface.DrawRect( w + x, y - 3, 3, h + 6 )
|
||||
surface.DrawRect( x, y - 3, w, 3 )
|
||||
surface.DrawRect( x, y + h, w, 3 )
|
||||
|
||||
surface.SetDrawColor( 255, 255, 255, alpha )
|
||||
surface.DrawRect( x - 1, y - 1, 1, h + 2 )
|
||||
surface.DrawRect( w + x, y - 1, 1, h + 2 )
|
||||
surface.DrawRect( x, y - 1, w, 1 )
|
||||
surface.DrawRect( x, y + h, w, 1 )
|
||||
|
||||
surface.SetMaterial( mat )
|
||||
surface.DrawTexturedRectUV( x, y, w, h, 640 / 1024, 0, 0, 480 / 512 )
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "DrawOverlay", "DrawMotionSensor", DrawColorBox )
|
||||
114
lua/menu/mount/mount.lua
Normal file
114
lua/menu/mount/mount.lua
Normal file
@@ -0,0 +1,114 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local pnlWorkshop = vgui.RegisterFile( "vgui/workshop.lua" )
|
||||
local vgui_workshop = nil
|
||||
|
||||
hook.Add( "WorkshopStart", "WorkshopStart", function()
|
||||
|
||||
if ( IsValid( vgui_workshop ) ) then vgui_workshop:Remove() end
|
||||
|
||||
vgui_workshop = GetOverlayPanel():Add( pnlWorkshop )
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "WorkshopEnd", "WorkshopEnd", function()
|
||||
|
||||
if ( !IsValid( vgui_workshop ) ) then return end
|
||||
|
||||
vgui_workshop:Remove()
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "WorkshopDownloadFile", "WorkshopDownloadFile", function( id, iImageID, title, iSize )
|
||||
|
||||
if ( !IsValid( vgui_workshop ) ) then
|
||||
vgui_workshop = GetOverlayPanel():Add( pnlWorkshop )
|
||||
end
|
||||
|
||||
vgui_workshop:PrepareDownloading()
|
||||
vgui_workshop:StartDownloading( id, iImageID, title, iSize )
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "WorkshopDownloadedFile", "WorkshopDownloadedFile", function( id )
|
||||
|
||||
if ( !IsValid( vgui_workshop ) ) then return end
|
||||
|
||||
vgui_workshop:FinishedDownloading( id )
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "WorkshopDownloadProgress", "WorkshopDownloadProgress", function( id, iImageID, title, downloaded, expected )
|
||||
|
||||
if ( !IsValid( vgui_workshop ) ) then
|
||||
vgui_workshop = GetOverlayPanel():Add( pnlWorkshop )
|
||||
vgui_workshop:PrepareDownloading()
|
||||
vgui_workshop:StartDownloading( id, iImageID, title, expected )
|
||||
end
|
||||
|
||||
vgui_workshop:UpdateProgress( downloaded, expected )
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "WorkshopExtractProgress", "WorkshopExtractProgress", function( id, iImageID, title, percent )
|
||||
|
||||
if ( !IsValid( vgui_workshop ) ) then
|
||||
vgui_workshop = GetOverlayPanel():Add( pnlWorkshop )
|
||||
vgui_workshop:PrepareDownloading()
|
||||
vgui_workshop:StartDownloading( id, iImageID, title, percent )
|
||||
end
|
||||
|
||||
vgui_workshop:ExtractProgress( title, percent )
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "WorkshopDownloadTotals", "WorkshopDownloadTotals", function( iRemain, iTotal )
|
||||
|
||||
if ( !IsValid( vgui_workshop ) ) then
|
||||
vgui_workshop = GetOverlayPanel():Add( pnlWorkshop )
|
||||
end
|
||||
|
||||
--
|
||||
-- Finished..
|
||||
--
|
||||
if ( iRemain == iTotal ) then
|
||||
return
|
||||
end
|
||||
|
||||
local completed = ( iTotal - iRemain )
|
||||
|
||||
if ( IsValid( vgui_workshop ) ) then
|
||||
vgui_workshop:UpdateTotalProgress( completed, iTotal )
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "WorkshopSubscriptionsProgress", "WorkshopSubscriptionsProgress", function( iCurrent, iMax )
|
||||
|
||||
if ( !IsValid( vgui_workshop ) ) then
|
||||
vgui_workshop = GetOverlayPanel():Add( pnlWorkshop )
|
||||
end
|
||||
|
||||
vgui_workshop:SubscriptionsProgress( iCurrent, iMax )
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "WorkshopSubscriptionsMessage", "WorkshopSubscriptionsMessage", function( msg )
|
||||
|
||||
if ( !IsValid( vgui_workshop ) ) then
|
||||
vgui_workshop = GetOverlayPanel():Add( pnlWorkshop )
|
||||
end
|
||||
|
||||
vgui_workshop:SetMessage( msg )
|
||||
|
||||
end )
|
||||
|
||||
86
lua/menu/mount/vgui/addon_rocket.lua
Normal file
86
lua/menu/mount/vgui/addon_rocket.lua
Normal file
@@ -0,0 +1,86 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
PANEL.Base = "DPanel"
|
||||
|
||||
local matWorkshopRocket = Material( "gui/workshop_rocket.png", "nocull smooth" )
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:SetSize( 64, 64 )
|
||||
self.Size = 64
|
||||
|
||||
end
|
||||
|
||||
--[[
|
||||
function PANEL:Think()
|
||||
|
||||
if ( self.Blasting ) then
|
||||
|
||||
self.VelY = self.VelY - FrameTime()
|
||||
self.PosY = self.PosY + self.VelY * FrameTime() * 500
|
||||
|
||||
self.VelX = self.VelX + FrameTime() * self.VelX
|
||||
self.PosX = self.PosX + self.VelX * FrameTime() * 500
|
||||
|
||||
self:SetPos( self.PosX, self.PosY )
|
||||
|
||||
if ( self.PosY < -70 ) then self:Remove() end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
]]
|
||||
|
||||
function PANEL:Paint()
|
||||
|
||||
if ( !self.Material ) then return end
|
||||
|
||||
local angle = 0
|
||||
|
||||
DisableClipping( true )
|
||||
|
||||
surface.SetDrawColor( 255, 255, 255, 255 )
|
||||
surface.SetMaterial( matWorkshopRocket )
|
||||
surface.DrawTexturedRectRotated( self:GetWide() * 0.5, self:GetTall() * 0.5, self.Size * 2, self.Size * 2, angle )
|
||||
|
||||
if ( self.Material ) then
|
||||
|
||||
surface.SetMaterial( self.Material )
|
||||
surface.DrawTexturedRectRotated( self:GetWide() * 0.5, self:GetTall() * 0.5, self.Size, self.Size, angle )
|
||||
|
||||
end
|
||||
|
||||
DisableClipping( false )
|
||||
|
||||
end
|
||||
|
||||
|
||||
function PANEL:Charging( id, iImageID )
|
||||
|
||||
self.Material = nil
|
||||
|
||||
steamworks.Download( iImageID, false, function( name )
|
||||
|
||||
if ( name == nil ) then return end
|
||||
if ( !IsValid( self ) ) then return end
|
||||
|
||||
self.Material = AddonMaterial( name )
|
||||
|
||||
end)
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Blast()
|
||||
|
||||
self:Remove()
|
||||
|
||||
end
|
||||
223
lua/menu/mount/vgui/workshop.lua
Normal file
223
lua/menu/mount/vgui/workshop.lua
Normal file
@@ -0,0 +1,223 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
PANEL.Base = "DPanel"
|
||||
|
||||
local wsFont
|
||||
if ( system.IsLinux() ) then
|
||||
wsFont = "DejaVu Sans"
|
||||
elseif ( system.IsWindows() ) then
|
||||
wsFont = "Tahoma"
|
||||
else
|
||||
wsFont = "Helvetica"
|
||||
end
|
||||
|
||||
surface.CreateFont( "WorkshopLarge", {
|
||||
font = wsFont,
|
||||
size = 19,
|
||||
antialias = true,
|
||||
weight = 800
|
||||
})
|
||||
|
||||
local pnlRocket = vgui.RegisterFile( "addon_rocket.lua" )
|
||||
local matProgressCog = Material( "gui/progress_cog.png", "nocull smooth" )
|
||||
local matHeader = Material( "gui/steamworks_header.png" )
|
||||
|
||||
AccessorFunc( PANEL, "m_bDrawProgress", "DrawProgress", FORCE_BOOL )
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self.Label = self:Add( "DLabel" )
|
||||
self.Label:SetText( "..." )
|
||||
self.Label:SetFont( "WorkshopLarge" )
|
||||
self.Label:SetTextColor( Color( 255, 255, 255, 200 ) )
|
||||
self.Label:Dock( TOP )
|
||||
self.Label:DockMargin( 16, 10, 16, 8 )
|
||||
self.Label:SetContentAlignment( 5 )
|
||||
|
||||
self.ProgressLabel = self:Add( "DLabel" )
|
||||
self.ProgressLabel:SetText( "" )
|
||||
self.ProgressLabel:SetContentAlignment( 7 )
|
||||
self.ProgressLabel:SetVisible( false )
|
||||
self.ProgressLabel:SetTextColor( Color( 255, 255, 255, 50 ) )
|
||||
|
||||
self.TotalsLabel = self:Add( "DLabel" )
|
||||
self.TotalsLabel:SetText( "" )
|
||||
self.TotalsLabel:SetContentAlignment( 7 )
|
||||
self.TotalsLabel:SetVisible( false )
|
||||
self.TotalsLabel:SetTextColor( Color( 255, 255, 255, 50 ) )
|
||||
|
||||
self:SetDrawProgress( false )
|
||||
|
||||
self.Progress = 0
|
||||
self.TotalProgress = 0
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout()
|
||||
|
||||
self:SetSize( 500, 80 )
|
||||
self:Center()
|
||||
self:AlignBottom( 16 )
|
||||
|
||||
self.ProgressLabel:SetSize( 100, 20 )
|
||||
self.ProgressLabel:SetPos( self:GetWide() - 100, 40 )
|
||||
|
||||
self.TotalsLabel:SetSize( 100, 20 )
|
||||
self.TotalsLabel:SetPos( self:GetWide() - 100, 60 )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Spawn()
|
||||
|
||||
self:InvalidateLayout( true )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PrepareDownloading()
|
||||
|
||||
if ( self.Rocket ) then self.Rocket:Remove() end
|
||||
|
||||
self.Rocket = self:Add( pnlRocket )
|
||||
self.Rocket:Dock( LEFT )
|
||||
self.Rocket:MoveToBack()
|
||||
self.Rocket:DockMargin( 8, 0, 8, 0 )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:StartDownloading( id, iImageID, title, iSize )
|
||||
|
||||
self.Label:SetText( language.GetPhrase( "ugc.downloadingX" ):format( title ) )
|
||||
|
||||
self.Rocket:Charging( id, iImageID )
|
||||
self:SetDrawProgress( true )
|
||||
self.ProgressLabel:Show()
|
||||
self.ProgressLabel:SetText( "" )
|
||||
|
||||
self.TotalsLabel:Show()
|
||||
|
||||
self:UpdateProgress( 0, iSize )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:FinishedDownloading( id )
|
||||
|
||||
self.Progress = -1
|
||||
--self:SetDrawProgress( false )
|
||||
--self.ProgressLabel:Hide()
|
||||
--self.TotalsLabel:Hide()
|
||||
--self.Rocket:Blast()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetMessage( msg )
|
||||
|
||||
self.Label:SetText( msg )
|
||||
|
||||
self:SetDrawProgress( false )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Paint()
|
||||
|
||||
DisableClipping( true )
|
||||
draw.RoundedBox( 4, -1, -1, self:GetWide() + 2, self:GetTall() + 2, color_black )
|
||||
DisableClipping( false )
|
||||
|
||||
draw.RoundedBox( 4, 0, 0, self:GetWide(), self:GetTall(), Color( 50, 50, 50, 255 ) )
|
||||
|
||||
surface.SetDrawColor( 0, 0, 0, 100 )
|
||||
surface.SetMaterial( matProgressCog )
|
||||
surface.DrawTexturedRectRotated( 0, 32, 64 * 4, 64 * 4, SysTime() * -20 )
|
||||
|
||||
if ( self:GetDrawProgress() ) then
|
||||
|
||||
-- Overall progress
|
||||
local off = 0
|
||||
local w = (self:GetWide() - 64 - 64 - 100)
|
||||
local x = 80
|
||||
|
||||
draw.RoundedBox( 4, x + 32 + off, 44 + 18, w, 10, Color( 0, 0, 0, 150 ) )
|
||||
draw.RoundedBox( 4, x + 33 + off, 45 + 18, w * math.Clamp( self.TotalProgress, 0.05, 1 ) - 2, 8, Color( 255, 255, 255, 200 ) )
|
||||
|
||||
-- Current file Progress
|
||||
if ( self.Progress >= 0 ) then
|
||||
draw.RoundedBox( 4, x + 32, 40, w, 15, Color( 0, 0, 0, 150 ) )
|
||||
draw.RoundedBox( 4, x + 33, 41, w * math.Clamp( self.Progress, 0.05, 1 ) - 2, 15-2, Color( 255, 255, 255, 200 ) )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Workshop LOGO
|
||||
DisableClipping( true )
|
||||
|
||||
local x = -8
|
||||
|
||||
surface.SetDrawColor( 255, 255, 255, 255 )
|
||||
surface.SetMaterial( matHeader )
|
||||
surface.DrawTexturedRect( x, -22, 128, 32 )
|
||||
|
||||
surface.SetDrawColor( 255, 255, 255, math.random( 0, 255 ) )
|
||||
surface.DrawTexturedRect( x, -22, 128, 32 )
|
||||
|
||||
DisableClipping( false )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:UpdateProgress( downloaded, expected )
|
||||
|
||||
if ( expected <= 0 ) then
|
||||
self.Progress = 0
|
||||
self.ProgressLabel:SetText( "" )
|
||||
return
|
||||
end
|
||||
|
||||
self.Progress = downloaded / expected
|
||||
|
||||
if ( self.Progress > 0 ) then
|
||||
self.ProgressLabel:SetText( language.GetPhrase( "ugc.XoutofY" ):format( Format( "%.0f%%", self.Progress * 100 ), string.NiceSize( expected ) ) )
|
||||
else
|
||||
self.ProgressLabel:SetText( string.NiceSize( expected ) )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ExtractProgress( title, percent )
|
||||
|
||||
self.Label:SetText( language.GetPhrase( "ugc.extractingX" ):format( title ) )
|
||||
self.Progress = percent / 100
|
||||
|
||||
if ( self.Progress > 0 ) then
|
||||
self.ProgressLabel:SetText( Format( "%.0f%%", percent ) )
|
||||
else
|
||||
self.ProgressLabel:SetText( "0%" )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:UpdateTotalProgress( iCurrent, iTotal )
|
||||
|
||||
self.TotalsLabel:SetText( language.GetPhrase( "ugc.addonXofY" ):format( iCurrent, iTotal ) )
|
||||
self.TotalProgress = iCurrent / iTotal
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SubscriptionsProgress( iCurrent, iTotal )
|
||||
|
||||
self.Label:SetText( "#ugc.fetching" )
|
||||
self:SetDrawProgress( true )
|
||||
|
||||
self.Progress = iCurrent / iTotal
|
||||
|
||||
self.ProgressLabel:Show()
|
||||
self.ProgressLabel:SetText( language.GetPhrase( "ugc.XofY" ):format( iCurrent, iTotal ) )
|
||||
|
||||
end
|
||||
303
lua/menu/openurl.lua
Normal file
303
lua/menu/openurl.lua
Normal file
@@ -0,0 +1,303 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local PANEL_Browser = {}
|
||||
|
||||
PANEL_Browser.Base = "DFrame"
|
||||
|
||||
function PANEL_Browser:Init()
|
||||
|
||||
self.HTML = vgui.Create( "HTML", self )
|
||||
|
||||
if ( !self.HTML ) then
|
||||
print( "SteamOverlayReplace: Failed to create HTML element" )
|
||||
self:Remove()
|
||||
return
|
||||
end
|
||||
|
||||
self.HTML:Dock( FILL )
|
||||
--self.HTML:SetOpenLinksExternally( true )
|
||||
|
||||
self:SetTitle( "Steam overlay replacement" )
|
||||
self:SetSize( ScrW() * 0.75, ScrH() * 0.75 )
|
||||
self:SetSizable( true )
|
||||
self:Center()
|
||||
self:MakePopup()
|
||||
|
||||
end
|
||||
|
||||
function PANEL_Browser:SetURL( url )
|
||||
|
||||
self.HTML:OpenURL( url )
|
||||
|
||||
end
|
||||
|
||||
-- Called from the engine
|
||||
function GMOD_OpenURLNoOverlay( url )
|
||||
|
||||
local BrowserInst = vgui.CreateFromTable( PANEL_Browser )
|
||||
BrowserInst:SetURL( url )
|
||||
|
||||
timer.Simple( 0, function()
|
||||
if ( !gui.IsGameUIVisible() ) then gui.ActivateGameUI() end
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
local RememberedDenials = {}
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
PANEL.Base = "DFrame"
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self.Type = "openurl"
|
||||
|
||||
self:SetTitle( "#openurl.title" )
|
||||
|
||||
self.Garble = vgui.Create( "DLabel", self )
|
||||
self.Garble:SetText( "#openurl.text" )
|
||||
self.Garble:SetContentAlignment( 5 )
|
||||
self.Garble:Dock( TOP )
|
||||
|
||||
self.URL = vgui.Create( "DTextEntry", self )
|
||||
self.URL:SetEnabled( false )
|
||||
self.URL:Dock( TOP )
|
||||
|
||||
self.CustomPanel = vgui.Create( "DLabel", self )
|
||||
self.CustomPanel:Dock( TOP )
|
||||
self.CustomPanel:SetContentAlignment( 5 )
|
||||
self.CustomPanel:DockMargin( 0, 5, 0, 0 )
|
||||
self.CustomPanel:SetVisible( false )
|
||||
self.CustomPanel.Color = Color( 0, 0, 0, 0 )
|
||||
self.CustomPanel.Paint = function( s, w, h )
|
||||
draw.RoundedBox( 0, 0, 0, w, h, s.Color )
|
||||
end
|
||||
|
||||
self.Buttons = vgui.Create( "Panel", self )
|
||||
self.Buttons:Dock( TOP )
|
||||
self.Buttons:DockMargin( 0, 5, 0, 0 )
|
||||
|
||||
self.Disconnect = vgui.Create( "DButton", self.Buttons )
|
||||
self.Disconnect:SetText( "#openurl.disconnect" )
|
||||
self.Disconnect.DoClick = function() self:DoNope() RunConsoleCommand( "disconnect" ) end
|
||||
self.Disconnect:Dock( LEFT )
|
||||
self.Disconnect:SizeToContents()
|
||||
self.Disconnect:SetWide( self.Disconnect:GetWide() + 10 )
|
||||
|
||||
self.Nope = vgui.Create( "DButton", self.Buttons )
|
||||
self.Nope:SetText( "#openurl.nope" )
|
||||
self.Nope.DoClick = function() self:DoNope() end
|
||||
self.Nope:DockMargin( 0, 0, 0, 0 )
|
||||
self.Nope:Dock( RIGHT )
|
||||
|
||||
self.Yes = vgui.Create( "DButton", self.Buttons )
|
||||
self.Yes:SetText( "#openurl.yes" )
|
||||
self.Yes.DoClick = function() self:DoYes() end
|
||||
self.Yes:DockMargin( 0, 0, 20, 0 )
|
||||
self.Yes:Dock( RIGHT )
|
||||
|
||||
self.YesPerma = vgui.Create( "DCheckBoxLabel", self.Buttons )
|
||||
self.YesPerma:SetText( "#openurl.yes_remember" )
|
||||
self.YesPerma:DockMargin( 0, 0, 20, 0 )
|
||||
self.YesPerma:Dock( RIGHT )
|
||||
self.YesPerma:SetVisible( false )
|
||||
|
||||
self:SetSize( 680, 104 )
|
||||
self:Center()
|
||||
self:MakePopup()
|
||||
self:DoModal()
|
||||
|
||||
hook.Add( "Think", self, self.AlwaysThink )
|
||||
|
||||
if ( !IsInGame() ) then self.Disconnect:SetVisible( false ) end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:LoadServerInfo()
|
||||
|
||||
self.CustomPanel:SetVisible( true )
|
||||
self.CustomPanel:SetText( "#askconnect.loading" )
|
||||
self.CustomPanel:SizeToContents()
|
||||
|
||||
serverlist.PingServer( self:GetURL(), function( ping, name, desc, map, players, maxplayers, bot, pass, lp, ip, gamemode )
|
||||
if ( !IsValid( self ) ) then return end
|
||||
|
||||
if ( !ping ) then
|
||||
self.CustomPanel.Color = Color( 200, 50, 50 )
|
||||
self.CustomPanel:SetText( "#askconnect.no_response" )
|
||||
else
|
||||
self.CustomPanel:SetText( string.format( "%s\n%i/%i players | %s | %s | %ims", name, players, maxplayers, map, desc, ping ) )
|
||||
end
|
||||
self.CustomPanel:SizeToContents()
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:DisplayPermissionInfo()
|
||||
|
||||
self.CustomPanel.Color = Color( 200, 200, 200 )
|
||||
self.CustomPanel:SetVisible( true )
|
||||
self.CustomPanel:SetDark( true )
|
||||
self.CustomPanel:SetText( "\n" .. language.GetPhrase( "permission." .. self:GetURL() ) .. "\n" .. language.GetPhrase( "permission." .. self:GetURL() .. ".help" ) .. "\n" )
|
||||
self.CustomPanel:SizeToContents()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:AlwaysThink()
|
||||
|
||||
-- Ping the server for details
|
||||
if ( SysTime() - self.StartTime > 0.1 and self.Type == "askconnect" and !self.CustomPanel:IsVisible() ) then
|
||||
self:LoadServerInfo()
|
||||
end
|
||||
|
||||
if ( self.StartTime + 1 > SysTime() ) then
|
||||
return
|
||||
end
|
||||
|
||||
if ( !self.Yes:IsEnabled() ) then
|
||||
self.Yes:SetEnabled( true )
|
||||
end
|
||||
|
||||
if ( !gui.IsGameUIVisible() ) then
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout( w, h )
|
||||
|
||||
DFrame.PerformLayout( self, w, h )
|
||||
|
||||
self:SizeToChildren( false, true )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetURL( url )
|
||||
|
||||
self.URL:SetText( url )
|
||||
|
||||
self.StartTime = SysTime()
|
||||
self.Yes:SetEnabled( false )
|
||||
self.CustomPanel:SetVisible( false )
|
||||
self.CustomPanel.Color = Color( 0, 0, 0, 0 )
|
||||
self:InvalidateLayout()
|
||||
|
||||
if ( self.Type == "permission" ) then
|
||||
self:DisplayPermissionInfo()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:GetURL()
|
||||
|
||||
return self.URL:GetText()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:DoNope()
|
||||
|
||||
self:Remove()
|
||||
gui.HideGameUI()
|
||||
|
||||
-- Keep track of what the player wants to ignore, but only for this session.
|
||||
local remember = self.YesPerma:GetChecked()
|
||||
if ( remember ) then
|
||||
RememberedDenials[ self.uniquePermID ] = true
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:DoYes()
|
||||
|
||||
if ( self.StartTime + 1 > SysTime() ) then
|
||||
return
|
||||
end
|
||||
|
||||
local saveYes = self.YesPerma:GetChecked()
|
||||
self:DoYesAction( !saveYes )
|
||||
self:Remove()
|
||||
gui.HideGameUI()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:DoYesAction( bSessionOnly )
|
||||
|
||||
if ( self.Type == "openurl" ) then
|
||||
gui.OpenURL( self.URL:GetText() )
|
||||
elseif ( self.Type == "askconnect" ) then
|
||||
permissions.Grant( "connect", bSessionOnly )
|
||||
permissions.Connect( self.URL:GetText() )
|
||||
elseif ( self.Type == "permission" ) then
|
||||
permissions.Grant( self.URL:GetText(), bSessionOnly )
|
||||
else
|
||||
ErrorNoHaltWithStack( "Unhandled confirmation type '" .. tostring( self.Type ) .. "'!" )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetType( t )
|
||||
|
||||
self.Type = t
|
||||
|
||||
self:SetTitle( "#" .. t .. ".title" )
|
||||
self.Garble:SetText( "#" .. t .. ".text" )
|
||||
|
||||
if ( self.Type == "permission" or self.Type == "askconnect" ) then
|
||||
self.YesPerma:SetVisible( true )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local PanelInst = nil
|
||||
local function OpenConfirmationDialog( address, confirm_type )
|
||||
|
||||
local permID = tostring( confirm_type ) .. "|" .. tostring( address ) .. "|" .. tostring( engine.CurrentServerAddress() )
|
||||
if ( RememberedDenials[ permID ] ) then
|
||||
print( "Ignoring request for denied permission " .. tostring( confirm_type ) .. " to " .. tostring( address ) ) -- Debug
|
||||
return
|
||||
end
|
||||
|
||||
if ( IsValid( PanelInst ) and PanelInst:GetURL() == address ) then return end
|
||||
if ( !IsValid( PanelInst ) ) then PanelInst = vgui.CreateFromTable( PANEL ) end
|
||||
|
||||
PanelInst.uniquePermID = permID
|
||||
PanelInst:SetType( confirm_type )
|
||||
PanelInst:SetURL( address )
|
||||
|
||||
timer.Simple( 0, function()
|
||||
if ( !gui.IsGameUIVisible() ) then gui.ActivateGameUI() end
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
-- Called from the engine
|
||||
function RequestOpenURL( url )
|
||||
|
||||
OpenConfirmationDialog( url, "openurl" )
|
||||
|
||||
end
|
||||
function RequestConnectToServer( serverip )
|
||||
|
||||
if ( permissions.IsGranted( "connect" ) ) then
|
||||
permissions.Connect( serverip )
|
||||
else
|
||||
OpenConfirmationDialog( serverip, "askconnect" )
|
||||
end
|
||||
|
||||
end
|
||||
function RequestPermission( perm )
|
||||
|
||||
OpenConfirmationDialog( perm, "permission" )
|
||||
|
||||
end
|
||||
241
lua/menu/problems/permissions.lua
Normal file
241
lua/menu/problems/permissions.lua
Normal file
@@ -0,0 +1,241 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:Dock( TOP )
|
||||
self:DockMargin( 0, 0, 0, 1 )
|
||||
|
||||
self.RemoveBtn = self:Add( "DImageButton" )
|
||||
self.RemoveBtn:SetImage( "icon16/cross.png" )
|
||||
self.RemoveBtn:SetSize( 16, 16 )
|
||||
self.RemoveBtn.DoClick = function( btm )
|
||||
if ( !self.Permission ) then return end
|
||||
|
||||
permissions.Revoke( self.Permission, self:GetParent():GetParent().Title )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local textPaddingX = 5
|
||||
local textPaddingY = 5
|
||||
local buttonPad = 8
|
||||
|
||||
-- lua_run_cl permissions.AskToConnect( "da" )
|
||||
function PANEL:PerformLayout( w, h )
|
||||
|
||||
local txt = "<font=DermaLarge>" .. language.GetPhrase( "permission." .. self.Permission ) .. ( self.IsTemporary and " <color=255,128,0>(TEMPORARY)</color>" or "" ) .. "</font>\n <font=DermaDefault>" .. language.GetPhrase( "permission." .. self.Permission .. ".help" ) .. "</font>"
|
||||
self.Markup = markup.Parse( txt, self:GetWide() - self.RemoveBtn:GetWide() - buttonPad * 2 - textPaddingX * 2 )
|
||||
|
||||
self:SetTall( textPaddingY + self.Markup:GetHeight() + textPaddingY )
|
||||
|
||||
local bW, bH = self.RemoveBtn:GetSize()
|
||||
self.RemoveBtn:SetPos( w - bW - buttonPad, self:GetTall() / 2 - bH / 2 )
|
||||
|
||||
end
|
||||
|
||||
local bgClr = Color( 75, 75, 75, 255 )
|
||||
function PANEL:Paint( w, h )
|
||||
|
||||
bgClr.a = self:GetAlpha()
|
||||
draw.RoundedBox( 0, 0, 0, w, h, bgClr )
|
||||
|
||||
-- No info yet
|
||||
if ( !self.Permission ) then return end
|
||||
|
||||
-- The error
|
||||
self.Markup:Draw( textPaddingX, textPaddingY, nil, nil, self:GetAlpha() )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Think()
|
||||
end
|
||||
|
||||
function PANEL:SetPermission( perm, temp )
|
||||
|
||||
self.Permission = perm
|
||||
self.IsTemporary = temp
|
||||
|
||||
self:InvalidateLayout( true )
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "Permission", PANEL, "Panel" )
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
local arrowMat = Material( "gui/point.png" )
|
||||
local collapsedCache = {}
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:Dock( TOP )
|
||||
self:SetTall( 20 )
|
||||
self:DockMargin( 0, 0, 0, 5 )
|
||||
|
||||
self.PermissionPanels = {}
|
||||
|
||||
self.PermissionList = self:Add( "Panel" )
|
||||
|
||||
self.Collapsed = false
|
||||
|
||||
end
|
||||
|
||||
local white = Color( 255, 255, 255, 255 )
|
||||
local bg = Color( 50, 50, 50, 255 )
|
||||
function PANEL:Paint( w, h )
|
||||
|
||||
white.a = self:GetAlpha()
|
||||
bg.a = self:GetAlpha()
|
||||
|
||||
draw.RoundedBox( 4, 0, 0, w, h, bg )
|
||||
draw.SimpleText( self.Title, "DermaLarge", 4, 2, white, draw.TEXT_ALIGN_LEFT, draw.TEXT_ALIGN_TOP )
|
||||
|
||||
surface.SetMaterial( arrowMat )
|
||||
surface.SetDrawColor( white )
|
||||
surface.DrawTexturedRectRotated( w - 20, 20, 20, 20, self.Collapsed and 180 or 0 )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OnMousePressed()
|
||||
|
||||
self.Collapsed = !self.Collapsed
|
||||
self:InvalidateLayout()
|
||||
|
||||
collapsedCache[ self.Title ] = self.Collapsed
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetGroup( groupID )
|
||||
|
||||
self.Title = groupID
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout( w, h )
|
||||
|
||||
self.PermissionList:InvalidateLayout( true )
|
||||
self.PermissionList:SizeToChildren( false, true )
|
||||
|
||||
surface.SetFont( "DermaLarge" )
|
||||
local _, headerSize = surface.GetTextSize( self.Title )
|
||||
|
||||
self.PermissionList:SetPos( 4, 4 + headerSize )
|
||||
self.PermissionList:SetWide( self:GetWide() - 8 )
|
||||
|
||||
if ( self.Collapsed ) then
|
||||
self:SetTall( headerSize + 5 )
|
||||
return
|
||||
end
|
||||
|
||||
self:SetTall( self.PermissionList:GetTall() + ( 8 + headerSize ) )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ReceivePerm( perm, temp )
|
||||
local pnl = self.PermissionPanels[ perm ]
|
||||
|
||||
if ( !IsValid( pnl ) ) then
|
||||
pnl = self.PermissionList:Add( "Permission" )
|
||||
self.PermissionPanels[ perm ] = pnl
|
||||
self:InvalidateLayout()
|
||||
end
|
||||
|
||||
pnl:SetPermission( perm, temp )
|
||||
end
|
||||
|
||||
function PANEL:ReceivePerms( perms, temp )
|
||||
|
||||
for id, str in pairs( string.Explode( ",", perms ) ) do
|
||||
self:ReceivePerm( str, temp )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "ServerPermissionsPanel", PANEL, "Panel" )
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
local PANEL = {}
|
||||
local g_Permissions = nil
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self.ServerPanels = {}
|
||||
|
||||
self:DoPermissions()
|
||||
|
||||
g_Permissions = self
|
||||
|
||||
end
|
||||
|
||||
function PANEL:AddServerGroup( address, perms, temp )
|
||||
local pnl = self.ServerPanels[ address ]
|
||||
|
||||
if ( !IsValid( pnl ) ) then
|
||||
pnl = self:Add( "ServerPermissionsPanel" )
|
||||
pnl:SetGroup( address )
|
||||
self.ServerPanels[ address ] = pnl
|
||||
|
||||
self:InvalidateLayout()
|
||||
end
|
||||
|
||||
pnl:ReceivePerms( perms, temp )
|
||||
end
|
||||
|
||||
function PANEL:DoPermissions()
|
||||
|
||||
for id, pnl in pairs( self.ServerPanels ) do
|
||||
pnl:Remove()
|
||||
end
|
||||
|
||||
local perms = permissions.GetAll()
|
||||
for address, perm in pairs( perms.temporary ) do
|
||||
self:AddServerGroup( address, perm, true )
|
||||
end
|
||||
for address, perm in pairs( perms.permanent ) do
|
||||
self:AddServerGroup( address, perm )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Think()
|
||||
|
||||
if ( self:GetCanvas():ChildCount() < 1 and !IsValid( self.NoPermissionsLabel ) ) then
|
||||
self.NoPermissionsLabel = self.ParentFrame:AddEmptyWarning( "#permissions.none", self )
|
||||
elseif ( self:GetCanvas():ChildCount() > 1 and IsValid( self.NoPermissionsLabel ) ) then
|
||||
self.NoPermissionsLabel:Remove()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "PermissionViewer", PANEL, "DScrollPanel" )
|
||||
|
||||
hook.Add( "OnPermissionsChanged", "OnPermissionsChanged", function()
|
||||
|
||||
if ( IsValid( g_Permissions ) ) then
|
||||
g_Permissions:DoPermissions()
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
204
lua/menu/problems/problem_generic.lua
Normal file
204
lua/menu/problems/problem_generic.lua
Normal file
@@ -0,0 +1,204 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:Dock( TOP )
|
||||
self:DockMargin( 0, 0, 0, 1 )
|
||||
|
||||
self.CopyBtn = self:Add( "DImageButton" )
|
||||
self.CopyBtn:SetImage( "icon16/page_copy.png" )
|
||||
self.CopyBtn:SetSize( 16, 16 )
|
||||
self.CopyBtn.DoClick = function( btm )
|
||||
if ( !self.Problem ) then return end
|
||||
|
||||
SetClipboardText( language.GetPhrase( self.Problem.text ) )
|
||||
end
|
||||
|
||||
self.FixBtn = self:Add( "DButton" )
|
||||
self.FixBtn.DoClick = function( btm )
|
||||
if ( !self.Problem or !self.Problem.fix ) then return end
|
||||
|
||||
self.Problem.fix()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local severityWidth = 8
|
||||
local severityOffset = severityWidth + 4
|
||||
local textPaddingX = 5
|
||||
local textPaddingY = 10
|
||||
local copyIconPad = 8
|
||||
|
||||
local severityColors = {}
|
||||
severityColors[ 0 ] = Color( 217, 217, 217 )
|
||||
severityColors[ 1 ] = Color( 255, 200, 0 )
|
||||
severityColors[ 2 ] = Color( 255, 64, 0 )
|
||||
|
||||
function PANEL:PerformLayout( w, h )
|
||||
|
||||
self.Markup = markup.Parse( "<font=DermaDefault>" .. language.GetPhrase( self.Problem.text ) .. "</font>", w - self.CopyBtn:GetWide() - copyIconPad * 2 - severityOffset - textPaddingX * 2 )
|
||||
|
||||
local targetH = textPaddingY
|
||||
|
||||
if ( self.Problem ) then
|
||||
targetH = targetH + self.Markup:GetHeight() + textPaddingY
|
||||
end
|
||||
|
||||
local fixW, fixH = self.FixBtn:GetSize()
|
||||
self.FixBtn:SetPos( textPaddingX + severityOffset, targetH )
|
||||
targetH = targetH + fixH + textPaddingY
|
||||
|
||||
self:SetTall( targetH )
|
||||
|
||||
local bW, bH = self.CopyBtn:GetSize()
|
||||
self.CopyBtn:SetPos( w - bW - copyIconPad, targetH / 2 - bH / 2 )
|
||||
|
||||
end
|
||||
|
||||
local bgClr = Color( 75, 75, 75, 255 )
|
||||
function PANEL:Paint( w, h )
|
||||
|
||||
bgClr.a = self:GetAlpha()
|
||||
|
||||
-- No info yet
|
||||
if ( !self.Problem ) then
|
||||
draw.RoundedBox( 0, 0, 0, w, h, bgClr )
|
||||
return
|
||||
end
|
||||
|
||||
-- Background
|
||||
local bgClrH = bgClr
|
||||
if ( self.Problem.lastOccurence ) then
|
||||
local add = 75 + math.max( 25 - ( SysTime() - self.Problem.lastOccurence ) * 25, 0 )
|
||||
bgClrH = Color( add, add, add, self:GetAlpha() )
|
||||
end
|
||||
|
||||
draw.RoundedBox( 0, 0, 0, w, h, bgClrH )
|
||||
|
||||
-- Severity indicator
|
||||
local color = severityColors[ self.Problem.severity ]
|
||||
if ( color == nil ) then color = severityColors[ 0 ] end
|
||||
draw.RoundedBox( 0, 0, 0, severityWidth, h, color )
|
||||
|
||||
-- The error
|
||||
self.Markup:Draw( textPaddingX + severityOffset, textPaddingY, nil, nil, self:GetAlpha() )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Think()
|
||||
end
|
||||
|
||||
function PANEL:Setup( problem )
|
||||
|
||||
self.Problem = problem
|
||||
|
||||
self.Markup = markup.Parse( "<font=DermaDefault>" .. language.GetPhrase( self.Problem.text ) .. "</font>", self:GetWide() - self.CopyBtn:GetWide() - copyIconPad * 2 - severityOffset - textPaddingX * 2 )
|
||||
|
||||
self.FixBtn:SetEnabled( problem.fix != nil )
|
||||
self.FixBtn:SetText( problem.fix and "#problems.quick_fix" or "#problems.no_quick_fix" )
|
||||
self.FixBtn:SizeToContentsX( 10 )
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "GenericProblem", PANEL, "Panel" )
|
||||
|
||||
--[[
|
||||
ProblemGroup
|
||||
]]
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
local arrowMat = Material( "gui/point.png" )
|
||||
local collapsedCache = {}
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:Dock( TOP )
|
||||
self:SetTall( 20 )
|
||||
self:DockMargin( 0, 0, 0, 5 )
|
||||
|
||||
self.ProblemPanels = {}
|
||||
|
||||
self.ProblemList = self:Add( "Panel" )
|
||||
|
||||
self.Collapsed = false
|
||||
|
||||
end
|
||||
|
||||
local white = Color( 255, 255, 255, 255 )
|
||||
local bg = Color( 50, 50, 50, 255 )
|
||||
function PANEL:Paint( w, h )
|
||||
|
||||
white.a = self:GetAlpha()
|
||||
bg.a = self:GetAlpha()
|
||||
|
||||
draw.RoundedBox( 4, 0, 0, w, h, bg )
|
||||
draw.SimpleText( language.GetPhrase( "problem_grp." .. self.Title ), "DermaLarge", 4, 2, white, draw.TEXT_ALIGN_LEFT, draw.TEXT_ALIGN_TOP )
|
||||
|
||||
surface.SetMaterial( arrowMat )
|
||||
surface.SetDrawColor( white )
|
||||
surface.DrawTexturedRectRotated( w - 20, 20, 20, 20, self.Collapsed and 180 or 0 )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OnMousePressed()
|
||||
|
||||
self.Collapsed = !self.Collapsed
|
||||
self:InvalidateLayout()
|
||||
|
||||
collapsedCache[ self.Title ] = self.Collapsed
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetGroup( groupID )
|
||||
|
||||
self.Title = groupID
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout( w, h )
|
||||
|
||||
self.ProblemList:InvalidateLayout( true )
|
||||
self.ProblemList:SizeToChildren( false, true )
|
||||
|
||||
surface.SetFont( "DermaLarge" )
|
||||
local _, headerSize = surface.GetTextSize( self.Title )
|
||||
|
||||
self.ProblemList:SetPos( 4, 4 + headerSize )
|
||||
self.ProblemList:SetWide( self:GetWide() - 8 )
|
||||
|
||||
if ( self.Collapsed ) then
|
||||
self:SetTall( headerSize + 5 )
|
||||
return
|
||||
end
|
||||
|
||||
self:SetTall( self.ProblemList:GetTall() + ( 8 + headerSize ) )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ReceivedProblem( uid, prob )
|
||||
|
||||
local pnl = self.ProblemPanels[ uid ]
|
||||
|
||||
if ( !IsValid( pnl ) ) then
|
||||
pnl = self.ProblemList:Add( "GenericProblem" )
|
||||
self.ProblemPanels[ uid ] = pnl
|
||||
self:InvalidateLayout()
|
||||
end
|
||||
|
||||
pnl:Setup( prob )
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "GenericProblemGroup", PANEL, "Panel" )
|
||||
296
lua/menu/problems/problem_lua.lua
Normal file
296
lua/menu/problems/problem_lua.lua
Normal file
@@ -0,0 +1,296 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local realmColors = {}
|
||||
realmColors[ "menu" ] = Color( 121, 221, 100 )
|
||||
realmColors[ "client" ] = Color( 255, 222, 102 )
|
||||
realmColors[ "server" ] = Color( 137, 222, 255 )
|
||||
|
||||
surface.CreateFont( "DermaMedium", {
|
||||
font = "Roboto",
|
||||
size = 24,
|
||||
weight = 500
|
||||
} )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:Dock( TOP )
|
||||
self:DockMargin( 0, 0, 0, 1 )
|
||||
|
||||
self.CopyBtn = self:Add( "DImageButton" )
|
||||
self.CopyBtn:SetImage( "icon16/page_copy.png" )
|
||||
self.CopyBtn:SetSize( 16, 16 )
|
||||
self.CopyBtn.DoClick = function( btm )
|
||||
if ( !self.Problem ) then return end
|
||||
|
||||
local prepend = ""
|
||||
if ( self.Problem.title and self.Problem.title:len() > 0 and self.Problem.title != "Other" ) then prepend = "[" .. self.Problem.title .. "] " end
|
||||
SetClipboardText( prepend .. self.Problem.text )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout( w, h )
|
||||
|
||||
surface.SetFont( "DermaDefault" )
|
||||
|
||||
if ( self.Problem ) then
|
||||
local _, th = surface.GetTextSize( self.Problem.text )
|
||||
self:SetTall( th + 10 )
|
||||
end
|
||||
|
||||
local bW, bH = self.CopyBtn:GetSize()
|
||||
self.CopyBtn:SetPos( w - bW - 8, h / 2 - bH / 2 )
|
||||
|
||||
end
|
||||
|
||||
local bgClr = Color( 75, 75, 75, 255 )
|
||||
local fgClr = Color( 255, 255, 255, 255 )
|
||||
function PANEL:Paint( w, h )
|
||||
|
||||
bgClr.a = self:GetAlpha()
|
||||
|
||||
-- No info yet
|
||||
if ( !self.Problem ) then
|
||||
draw.RoundedBox( 0, 0, 0, w, h, bgClr )
|
||||
return
|
||||
end
|
||||
|
||||
-- Get the colors
|
||||
local clr = table.Copy( realmColors[ self.Problem.realm ] or fgClr )
|
||||
clr.a = self:GetAlpha()
|
||||
|
||||
-- Background color
|
||||
local bgClrH = bgClr
|
||||
if ( self.Problem.lastOccurence ) then
|
||||
local add = 75 + math.max( 25 - ( SysTime() - self.Problem.lastOccurence ) * 25, 0 )
|
||||
bgClrH = Color( add, add, add, self:GetAlpha() )
|
||||
end
|
||||
|
||||
draw.RoundedBox( 0, 0, 0, w, h, bgClrH )
|
||||
|
||||
-- Draw background
|
||||
local count = 0
|
||||
if ( self.Problem and self.Problem.count ) then count = self.Problem.count end
|
||||
|
||||
-- The error count
|
||||
if ( count > 0 ) then
|
||||
local txt = "x" .. count
|
||||
surface.SetFont( "DermaMedium" )
|
||||
local tW, tH = surface.GetTextSize( txt )
|
||||
tW = tW
|
||||
|
||||
draw.SimpleText( txt, "DermaMedium", w - 16 - 16, h / 2, clr, draw.TEXT_ALIGN_RIGHT, draw.TEXT_ALIGN_CENTER )
|
||||
end
|
||||
|
||||
-- The error
|
||||
draw.DrawText( self.Problem.text, "DermaDefault", 5, 5, clr )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Setup( problem )
|
||||
|
||||
self.Problem = problem
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "LuaProblem", PANEL, "Panel" )
|
||||
|
||||
--[[ ////////////////////////////////////////////////// GROUP ////////////////////////////////////////////////// ]] --
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
local arrowMat = Material( "gui/point.png" )
|
||||
local collapsedCache = {}
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:Dock( TOP )
|
||||
self:SetTall( 20 )
|
||||
self:DockMargin( 0, 0, 0, 5 )
|
||||
|
||||
self.ErrorPanels = {}
|
||||
|
||||
self.LuaErrorList = self:Add( "Panel" )
|
||||
|
||||
self.ClearButton = self:Add( "DImageButton" )
|
||||
self.ClearButton:SetImage( "gui/cross.png" )
|
||||
self.ClearButton:SetSize( 18, 18 )
|
||||
self.ClearButton.DoClick = function( s ) self:ClearThisGroup() end
|
||||
|
||||
self.Collapsed = false
|
||||
|
||||
end
|
||||
|
||||
local white = Color( 255, 255, 255, 255 )
|
||||
local bg = Color( 50, 50, 50, 255 )
|
||||
function PANEL:Paint( w, h )
|
||||
|
||||
white.a = self:GetAlpha()
|
||||
bg.a = self:GetAlpha()
|
||||
|
||||
draw.RoundedBox( 4, 0, 0, w, h, bg )
|
||||
draw.SimpleText( self.Title, "DermaLarge", 4, 2, white, draw.TEXT_ALIGN_LEFT, draw.TEXT_ALIGN_TOP )
|
||||
|
||||
surface.SetMaterial( arrowMat )
|
||||
surface.SetDrawColor( white )
|
||||
surface.DrawTexturedRectRotated( w - 20, 18, 20, 12, self.Collapsed and 180 or 0 )
|
||||
|
||||
local h2 = self.LuaErrorList:GetTall()
|
||||
local _, lY = self.LuaErrorList:GetPos()
|
||||
|
||||
draw.DrawText( self:GetExplainerText(), "DermaDefault", w / 2, lY + h2 + 5, white, draw.TEXT_ALIGN_CENTER )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ClearThisGroup()
|
||||
|
||||
ClearLuaErrorGroup( self.GroupID )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OnMousePressed( code )
|
||||
|
||||
if ( code != MOUSE_LEFT ) then return end
|
||||
|
||||
self.Collapsed = !self.Collapsed
|
||||
self:InvalidateLayout()
|
||||
|
||||
collapsedCache[ self.Title ] = self.Collapsed
|
||||
|
||||
end
|
||||
|
||||
function PANEL:GetExplainerText()
|
||||
|
||||
if ( self.Title == "Other" and self.AddonID and self.AddonID:len() < 2 ) then
|
||||
return language.GetPhrase( "problems.generic_lua_error" )
|
||||
end
|
||||
|
||||
-- Not a workshop addon, or a floating .gma (WSID=0)
|
||||
if ( self.AddonID and self.AddonID:len() < 2 ) then
|
||||
return language.GetPhrase( "problems.addon_lua_error" ):format( self.Title )
|
||||
end
|
||||
|
||||
return language.GetPhrase( "problems.workshop_lua_error" ):format( self.Title )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetTitleAndID( title, id, groupid )
|
||||
|
||||
self.Title = title
|
||||
self.AddonID = id
|
||||
self.GroupID = groupid
|
||||
|
||||
self.Collapsed = collapsedCache[ self.Title ]
|
||||
|
||||
if ( self.AddonID and self.AddonID:len() > 1 ) then
|
||||
self.DisableBtn = self:Add( "DButton" )
|
||||
self.DisableBtn:SetText( "#problems.disable" )
|
||||
self.DisableBtn:SizeToContentsX( 10 )
|
||||
self.DisableBtn.DoClick = function() steamworks.SetShouldMountAddon( self.AddonID, false ) steamworks.ApplyAddons() end
|
||||
|
||||
self.OpenWSBtn = self:Add( "DButton" )
|
||||
self.OpenWSBtn:SetText( "#problems.open_on_workshop" )
|
||||
self.OpenWSBtn:SizeToContentsX( 10 )
|
||||
self.OpenWSBtn.DoClick = function() steamworks.ViewFile( self.AddonID ) end
|
||||
|
||||
self.UninstallBtn = self:Add( "DButton" )
|
||||
self.UninstallBtn:SetText( "#problems.uninstall" )
|
||||
self.UninstallBtn:SizeToContentsX( 10 )
|
||||
self.UninstallBtn.DoClick = function() steamworks.Unsubscribe( self.AddonID ) end
|
||||
|
||||
local maxS = math.max( self.DisableBtn:GetWide(), self.OpenWSBtn:GetWide(), self.UninstallBtn:GetWide() )
|
||||
self.DisableBtn:SetWide( maxS )
|
||||
self.OpenWSBtn:SetWide( maxS )
|
||||
self.UninstallBtn:SetWide( maxS )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout( w, h )
|
||||
|
||||
self.ClearButton:SetPos( w - 56, 9 )
|
||||
|
||||
self.LuaErrorList:InvalidateLayout( true )
|
||||
self.LuaErrorList:SizeToChildren( false, true )
|
||||
|
||||
surface.SetFont( "DermaLarge" )
|
||||
local _, headerSize = surface.GetTextSize( self.Title )
|
||||
|
||||
self.LuaErrorList:SetPos( 4, 4 + headerSize )
|
||||
self.LuaErrorList:SetWide( self:GetWide() - 8 )
|
||||
|
||||
|
||||
surface.SetFont( "DermaDefault" )
|
||||
local _, etH = surface.GetTextSize( self:GetExplainerText() )
|
||||
|
||||
if ( IsValid( self.DisableBtn ) ) then
|
||||
local h2 = self.LuaErrorList:GetTall()
|
||||
local _, lY = self.LuaErrorList:GetPos()
|
||||
local y = lY + h2 + 5 + etH + 5
|
||||
|
||||
self.OpenWSBtn:SetPos( w * 0.25 - self.OpenWSBtn:GetWide() / 2, y )
|
||||
self.DisableBtn:SetPos( w * 0.5 - self.DisableBtn:GetWide() / 2, y )
|
||||
self.UninstallBtn:SetPos( w * 0.75 - self.UninstallBtn:GetWide() / 2, y )
|
||||
etH = etH + self.DisableBtn:GetTall() + 5
|
||||
end
|
||||
|
||||
if ( self.Collapsed ) then
|
||||
self:SetTall( headerSize + 5 )
|
||||
return
|
||||
end
|
||||
|
||||
self:SetTall( self.LuaErrorList:GetTall() + ( 8 + headerSize ) + ( etH + 5 ) )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Think()
|
||||
|
||||
if ( IsValid( self.DisableBtn ) ) then
|
||||
self.DisableBtn:SetEnabled( steamworks.IsSubscribed( self.AddonID ) and steamworks.ShouldMountAddon( self.AddonID ) )
|
||||
self.UninstallBtn:SetEnabled( steamworks.IsSubscribed( self.AddonID ) )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ReceivedError( uid, err )
|
||||
|
||||
local pnl = self.ErrorPanels[ uid ]
|
||||
|
||||
local shouldSort = false
|
||||
if ( !IsValid( pnl ) ) then
|
||||
pnl = self.LuaErrorList:Add( "LuaProblem" )
|
||||
self.ErrorPanels[ uid ] = pnl
|
||||
self:InvalidateLayout()
|
||||
|
||||
shouldSort = true
|
||||
end
|
||||
|
||||
pnl:Setup( err )
|
||||
|
||||
if ( shouldSort ) then
|
||||
local sorted = {}
|
||||
for gid, epnl in pairs( self.ErrorPanels ) do
|
||||
sorted[ epnl.Problem.firstOccurence ] = epnl
|
||||
end
|
||||
|
||||
local z = 0
|
||||
for sort, spnl in SortedPairs( sorted ) do
|
||||
spnl:SetZPos( z )
|
||||
z = z + 1
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "LuaProblemGroup", PANEL, "Panel" )
|
||||
352
lua/menu/problems/problems.lua
Normal file
352
lua/menu/problems/problems.lua
Normal file
@@ -0,0 +1,352 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
include( "problems_pnl.lua" )
|
||||
|
||||
local ProblemsPanel
|
||||
local ProblemsCount = 0
|
||||
local ProblemSeverity = 0
|
||||
local MenuUpdated = false
|
||||
|
||||
Problems = Problems or {}
|
||||
ErrorLog = ErrorLog or {}
|
||||
|
||||
local function RefreshGenericProblemList()
|
||||
if ( IsValid( ProblemsPanel ) ) then
|
||||
ProblemsPanel.ProblemsList:Clear()
|
||||
ProblemsPanel.ProblemPanels = {}
|
||||
for id, prob in pairs( Problems ) do
|
||||
ProblemsPanel:ReceivedProblem( id, prob )
|
||||
end
|
||||
ProblemsPanel:InvalidateLayout()
|
||||
end
|
||||
end
|
||||
|
||||
local function RefreshLuaErrorList()
|
||||
if ( IsValid( ProblemsPanel ) ) then
|
||||
ProblemsPanel.LuaErrorList:Clear()
|
||||
ProblemsPanel.ErrorPanels = {}
|
||||
for id, err in pairs( ErrorLog ) do
|
||||
ProblemsPanel:ReceivedError( id, err )
|
||||
end
|
||||
ProblemsPanel:InvalidateLayout()
|
||||
end
|
||||
end
|
||||
|
||||
local function CountProblem( severity )
|
||||
|
||||
ProblemsCount = ProblemsCount + 1
|
||||
ProblemSeverity = math.max( ProblemSeverity, severity or 0 )
|
||||
|
||||
if ( IsValid( pnlMainMenu ) ) then
|
||||
pnlMainMenu:SetProblemCount( ProblemsCount, ProblemSeverity )
|
||||
MenuUpdated = true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local function RecountProblems()
|
||||
|
||||
ProblemsCount = 0
|
||||
ProblemSeverity = 0
|
||||
|
||||
for id, err in pairs( ErrorLog ) do
|
||||
ProblemsCount = ProblemsCount + 1
|
||||
ProblemSeverity = math.max( err.severity or 0, ProblemSeverity )
|
||||
end
|
||||
|
||||
for id, prob in pairs( Problems ) do
|
||||
ProblemsCount = ProblemsCount + 1
|
||||
ProblemSeverity = math.max( prob.severity or 0, ProblemSeverity )
|
||||
end
|
||||
|
||||
if ( IsValid( pnlMainMenu ) ) then
|
||||
pnlMainMenu:SetProblemCount( ProblemsCount, ProblemSeverity )
|
||||
MenuUpdated = true
|
||||
end
|
||||
end
|
||||
|
||||
timer.Create( "menu_problem_counter", 1, 0, function()
|
||||
if ( MenuUpdated ) then timer.Remove( "menu_problem_counter" ) return end
|
||||
|
||||
RecountProblems()
|
||||
end )
|
||||
|
||||
function ClearLuaErrorGroup( group_id )
|
||||
|
||||
-- pairs should guard us against changing the array we are looping through
|
||||
for id, err in pairs( ErrorLog ) do
|
||||
if ( err.type == group_id ) then
|
||||
ErrorLog[ id ] = nil
|
||||
end
|
||||
end
|
||||
|
||||
RecountProblems()
|
||||
|
||||
RefreshLuaErrorList()
|
||||
|
||||
end
|
||||
|
||||
function ClearProblem( id )
|
||||
|
||||
if ( !Problems[ id ] ) then return end
|
||||
|
||||
Problems[ id ] = nil
|
||||
|
||||
RecountProblems()
|
||||
|
||||
RefreshGenericProblemList()
|
||||
|
||||
end
|
||||
|
||||
function FireProblem( prob )
|
||||
|
||||
local probID = prob.id or prob.text
|
||||
|
||||
if ( !Problems[ probID ] ) then
|
||||
CountProblem( prob.severity )
|
||||
end
|
||||
|
||||
Problems[ probID ] = prob
|
||||
if ( IsValid( ProblemsPanel ) ) then ProblemsPanel:ReceivedProblem( probID, prob ) end
|
||||
|
||||
end
|
||||
|
||||
local function FireError( str, realm, stack, addontitle, addonid )
|
||||
|
||||
-- Reconstruct the stack trace
|
||||
local errorText = str
|
||||
errorText = string.Replace( errorText, "\t", ( " " ):rep( 12 ) ) -- Ew
|
||||
|
||||
for i, t in pairs( stack ) do
|
||||
if ( !t.Function or t.Function == "" ) then t.Function = "unknown" end
|
||||
|
||||
errorText = errorText .. "\n" .. (" "):rep( i ) .. i .. ". " .. t.Function .. " - " .. t.File .. ":" .. t.Line
|
||||
end
|
||||
|
||||
local errorUniqueID = errorText .. realm
|
||||
|
||||
if ( !addontitle or addontitle == "" ) then addontitle = "Other" end
|
||||
|
||||
if ( !ErrorLog[ errorUniqueID ] ) then
|
||||
local newErr = {
|
||||
text = errorText,
|
||||
realm = realm,
|
||||
addonid = addonid or "",
|
||||
title = addontitle,
|
||||
count = 1,
|
||||
severity = 1,
|
||||
lastOccurence = SysTime(),
|
||||
firstOccurence = SysTime()
|
||||
}
|
||||
newErr.type = newErr.title .. "-" .. newErr.addonid
|
||||
|
||||
CountProblem( newErr.severity )
|
||||
ErrorLog[ errorUniqueID ] = newErr
|
||||
else
|
||||
ErrorLog[ errorUniqueID ].count = ErrorLog[ errorUniqueID ].count + 1
|
||||
ErrorLog[ errorUniqueID ].lastOccurence = SysTime()
|
||||
end
|
||||
|
||||
if ( IsValid( ProblemsPanel ) ) then ProblemsPanel:ReceivedError( errorUniqueID, ErrorLog[ errorUniqueID ] ) end
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "OnLuaError", "MenuErrorLogger", function( str, realm, stack, addontitle, addonid )
|
||||
|
||||
local good, err = pcall( function()
|
||||
FireError( str, realm, stack, addontitle, addonid )
|
||||
end )
|
||||
|
||||
if ( !good ) then
|
||||
print( "Failed to log a Lua error!\n", err)
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
function OpenProblemsPanel()
|
||||
|
||||
if ( IsValid( ProblemsPanel ) ) then ProblemsPanel:Remove() end
|
||||
|
||||
ProblemsPanel = vgui.Create( "ProblemsPanel" )
|
||||
|
||||
local anyErrors = false
|
||||
for id, err in pairs( table.Copy( ErrorLog ) ) do
|
||||
ProblemsPanel:ReceivedError( id, err )
|
||||
anyErrors = true
|
||||
end
|
||||
|
||||
for id, prob in pairs( Problems ) do
|
||||
ProblemsPanel:ReceivedProblem( id, prob )
|
||||
end
|
||||
|
||||
if ( !anyErrors ) then
|
||||
ProblemsPanel.Tabs:SwitchToName( "#problems.problems" )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Called from the engine to notify the player about a problem in a more user friendly way compared to a console message
|
||||
function FireProblemFromEngine( id, severity, params )
|
||||
if ( id == "menu_cleanupgmas" ) then
|
||||
local text = language.GetPhrase( "problem." .. id ) .. "\n\n" .. params:Replace( ";", "\n" )
|
||||
FireProblem( { id = id, text = text, severity = severity, type = "addons", fix = function() RunConsoleCommand( "menu_cleanupgmas" ) ClearProblem( id ) end } )
|
||||
elseif ( id == "readonly_file" ) then
|
||||
local text = params
|
||||
FireProblem( { id = id .. params, text = text, severity = severity, type = "config" } )
|
||||
else
|
||||
-- missing_addon_file
|
||||
-- addon_download_failed = title;reason
|
||||
local text = language.GetPhrase( "problem." .. id )
|
||||
text = text:format( unpack( string.Explode( ";", params ) ) )
|
||||
|
||||
FireProblem( { id = id .. params, text = text, severity = severity, type = "addons" } )
|
||||
end
|
||||
end
|
||||
|
||||
timer.Create( "menu_check_for_problems", 1, 0, function()
|
||||
|
||||
if ( math.floor( GetConVarNumber( "mat_hdr_level" ) ) != 2 ) then
|
||||
FireProblem( { id = "mat_hdr_level", text = "#problem.mat_hdr_level", type = "config", fix = function() RunConsoleCommand( "mat_hdr_level", "2" ) end, severity = 1 } )
|
||||
else
|
||||
ClearProblem( "mat_hdr_level" )
|
||||
end
|
||||
|
||||
if ( math.floor( math.abs( GetConVarNumber( "mat_bumpmap" ) ) ) == 0 ) then
|
||||
FireProblem( { id = "mat_bumpmap", text = "#problem.mat_bumpmap", type = "config", fix = function() RunConsoleCommand( "mat_bumpmap", "1" ) end } )
|
||||
else
|
||||
ClearProblem( "mat_bumpmap" )
|
||||
end
|
||||
|
||||
if ( math.floor( math.abs( GetConVarNumber( "mat_specular" ) ) ) == 0 ) then
|
||||
FireProblem( { id = "mat_specular", text = "#problem.mat_specular", type = "config", fix = function() RunConsoleCommand( "mat_specular", "1" ) end } )
|
||||
else
|
||||
ClearProblem( "mat_specular" )
|
||||
end
|
||||
|
||||
if ( math.floor( math.abs( GetConVarNumber( "gmod_mcore_test" ) ) ) != 0 ) then
|
||||
FireProblem( { id = "gmod_mcore_test", text = "#problem.gmod_mcore_test", type = "config" } )
|
||||
else
|
||||
ClearProblem( "gmod_mcore_test" )
|
||||
end
|
||||
|
||||
if ( math.abs( GetConVarNumber( "voice_fadeouttime" ) - 0.1 ) > 0.001 ) then
|
||||
FireProblem( { id = "voice_fadeouttime", text = "#problem.voice_fadeouttime", type = "config", fix = function() RunConsoleCommand( "voice_fadeouttime", "0.1" ) ClearProblem( "voice_fadeouttime" ) end } )
|
||||
else
|
||||
ClearProblem( "voice_fadeouttime" )
|
||||
end
|
||||
|
||||
if ( GetConVarNumber( "mat_viewportscale" ) < 0.1 ) then
|
||||
FireProblem( { id = "mat_viewportscale", text = "#problem.mat_viewportscale", type = "config", fix = function() RunConsoleCommand( "mat_viewportscale", "1" ) ClearProblem( "mat_viewportscale" ) end } )
|
||||
else
|
||||
ClearProblem( "mat_viewportscale" )
|
||||
end
|
||||
|
||||
if ( ScrW() < 1000 or ScrH() < 700 ) then
|
||||
FireProblem( { id = "screen_res", text = "#problem.screen_res", type = "config" } )
|
||||
else
|
||||
ClearProblem( "screen_res" )
|
||||
end
|
||||
|
||||
-- These are not saved, but still affect gameplay
|
||||
if ( GetConVarNumber( "cl_forwardspeed" ) != 10000 or GetConVarNumber( "cl_sidespeed" ) != 10000 or GetConVarNumber( "cl_backspeed" ) != 10000 ) then
|
||||
FireProblem( { id = "cl_speeds", text = "#problem.cl_speeds", type = "config", fix = function()
|
||||
RunConsoleCommand( "cl_forwardspeed", "10000" )
|
||||
RunConsoleCommand( "cl_sidespeed", "10000" )
|
||||
RunConsoleCommand( "cl_backspeed", "10000" )
|
||||
end } )
|
||||
else
|
||||
ClearProblem( "cl_speeds" )
|
||||
end
|
||||
|
||||
if ( render.GetDXLevel() != 95 and render.GetDXLevel() != 90 ) then
|
||||
FireProblem( { id = "mat_dxlevel", text = language.GetPhrase( "problem.mat_dxlevel" ):format( render.GetDXLevel() ), type = "config" } )
|
||||
else
|
||||
ClearProblem( "mat_dxlevel" )
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
-- Problems that we only need to check on startup
|
||||
if ( !render.SupportsHDR() ) then FireProblem( { text = "#problem.no_hdr", type = "hardware" } ) end
|
||||
if ( !render.SupportsPixelShaders_1_4() ) then FireProblem( { text = "#problem.no_ps14", type = "hardware" } ) end
|
||||
if ( !render.SupportsPixelShaders_2_0() ) then FireProblem( { text = "#problem.no_ps20", type = "hardware" } ) end
|
||||
if ( !render.SupportsVertexShaders_2_0() ) then FireProblem( { text = "#problem.no_vs20", type = "hardware" } ) end
|
||||
|
||||
|
||||
|
||||
local AddonConflicts = {}
|
||||
|
||||
hook.Add( "OnNotifyAddonConflict", "AddonConflictNotification", function( addon1, addon2, fileName )
|
||||
|
||||
local id = addon1 .. "vs" .. addon2
|
||||
local id1 = addon2 .. "vs" .. addon1
|
||||
if ( AddonConflicts[ id1 ] ) then id = id1 end
|
||||
|
||||
if ( AddonConflicts[ id ] == nil ) then
|
||||
AddonConflicts[ id ] = {
|
||||
addon1 = addon1,
|
||||
addon2 = addon2,
|
||||
files = {}
|
||||
}
|
||||
|
||||
steamworks.FileInfo( addon1, function( result )
|
||||
|
||||
if ( !result ) then return end
|
||||
|
||||
AddonConflicts[ id ].addon1 = result.title
|
||||
RefreshAddonConflicts()
|
||||
|
||||
end )
|
||||
|
||||
steamworks.FileInfo( addon2, function( result )
|
||||
|
||||
if ( !result ) then return end
|
||||
|
||||
AddonConflicts[ id ].addon2 = result.title
|
||||
RefreshAddonConflicts()
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
AddonConflicts[ id ].files[ fileName ] = true
|
||||
|
||||
RefreshAddonConflicts()
|
||||
|
||||
end )
|
||||
|
||||
function RefreshAddonConflicts()
|
||||
timer.Create( "addon_conflicts", 1, 1, FireAddonConflicts )
|
||||
end
|
||||
|
||||
function FireAddonConflicts()
|
||||
|
||||
for id, tbl in pairs( AddonConflicts ) do
|
||||
|
||||
local files = ""
|
||||
for file, _ in pairs( tbl.files ) do
|
||||
files = files .. file .. "\n"
|
||||
end
|
||||
|
||||
local text = language.GetPhrase( "problem.addon_conflict" )
|
||||
text = text:format( "<color=255,128,0>" .. tbl.addon1 .. "</color>", "<color=255,128,0>" .. tbl.addon2 .. "</color>", files )
|
||||
|
||||
FireProblem( {
|
||||
id = id,
|
||||
type = "addons",
|
||||
severity = 0,
|
||||
text = text
|
||||
} )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
139
lua/menu/problems/problems_pnl.lua
Normal file
139
lua/menu/problems/problems_pnl.lua
Normal file
@@ -0,0 +1,139 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
include( "problem_lua.lua" )
|
||||
include( "problem_generic.lua" )
|
||||
include( "permissions.lua" )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:SetSize( ScrW(), ScrH() )
|
||||
self:MakePopup()
|
||||
|
||||
self.ErrorPanels = {}
|
||||
self.ProblemPanels = {}
|
||||
|
||||
local ProblemsFrame = vgui.Create( "DFrame", self )
|
||||
ProblemsFrame:SetSize( ScrW() * 0.75, ScrH() * 0.75 )
|
||||
ProblemsFrame:Center()
|
||||
ProblemsFrame:SetTitle( "" )
|
||||
ProblemsFrame:SetDraggable( false )
|
||||
ProblemsFrame:SetBackgroundBlur( true )
|
||||
ProblemsFrame.OnRemove = function( frm ) self:Remove() end
|
||||
ProblemsFrame.Paint = function( frm ) end
|
||||
ProblemsFrame:DockPadding( 5, 3, 5, 0 )
|
||||
|
||||
local sheet = vgui.Create( "DPropertySheet", ProblemsFrame )
|
||||
sheet:Dock( FILL )
|
||||
self.Tabs = sheet
|
||||
|
||||
-- Lua errors
|
||||
local luaErrorList = ProblemsFrame:Add( "DScrollPanel" )
|
||||
sheet:AddSheet( "#problems.lua_errors", luaErrorList, "icon16/error.png" )
|
||||
self.LuaErrorList = luaErrorList
|
||||
|
||||
-- Generic problems
|
||||
local problemsList = ProblemsFrame:Add( "DScrollPanel" )
|
||||
sheet:AddSheet( "#problems.problems", problemsList, "icon16/tick.png" )
|
||||
self.ProblemsList = problemsList
|
||||
|
||||
-- Permissions
|
||||
local permissionList = ProblemsFrame:Add( "PermissionViewer" )
|
||||
permissionList.ParentFrame = self
|
||||
sheet:AddSheet( "#permissions.title", permissionList, "icon16/lock.png" )
|
||||
|
||||
ProblemsFrame.btnClose:MoveToFront()
|
||||
ProblemsFrame.btnMaxim:MoveToFront()
|
||||
ProblemsFrame.btnMinim:MoveToFront()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:AddEmptyWarning( txt, parent )
|
||||
|
||||
local lab = parent:Add( "DLabel" )
|
||||
lab:SetText( txt )
|
||||
lab:SetBright( true )
|
||||
lab:SetFont( "DermaLarge" )
|
||||
lab:SetContentAlignment( 5 )
|
||||
lab:Dock( FILL )
|
||||
|
||||
-- Horrible hack
|
||||
lab.Paint = function( s, w, h )
|
||||
s:SetTall( parent:GetTall() )
|
||||
end
|
||||
|
||||
return lab
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Paint( w, h )
|
||||
|
||||
draw.RoundedBox( 0, 0, 0, w, h, Color( 0, 0, 0, 240 ) )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout()
|
||||
|
||||
if ( self.LuaErrorList:GetCanvas():ChildCount() < 1 ) then
|
||||
self.NoErrorsLabel = self:AddEmptyWarning( "#problems.no_lua_errors", self.LuaErrorList )
|
||||
end
|
||||
|
||||
if ( self.ProblemsList:GetCanvas():ChildCount() < 1 ) then
|
||||
self.NoProblemsLabel = self:AddEmptyWarning( "#problems.no_problems", self.ProblemsList )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ReceivedError( uid, err )
|
||||
|
||||
if ( IsValid( self.NoErrorsLabel ) ) then self.NoErrorsLabel:Remove() end
|
||||
|
||||
local groupID = err.type or "Other"
|
||||
local pnl = self.ErrorPanels[ groupID ]
|
||||
if ( !IsValid( pnl ) ) then
|
||||
pnl = self.LuaErrorList:Add( "LuaProblemGroup" )
|
||||
pnl:SetTitleAndID( err.title, err.addonid, groupID )
|
||||
self.ErrorPanels[ groupID ] = pnl
|
||||
|
||||
-- Sort
|
||||
local z = 0
|
||||
for gid, epnl in SortedPairs( self.ErrorPanels ) do
|
||||
epnl:SetZPos( z )
|
||||
z = z + 1
|
||||
end
|
||||
self:InvalidateLayout()
|
||||
end
|
||||
|
||||
pnl:ReceivedError( uid, err )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ReceivedProblem( uid, prob )
|
||||
|
||||
if ( IsValid( self.NoProblemsLabel ) ) then self.NoProblemsLabel:Remove() end
|
||||
|
||||
local groupID = prob.type or "other"
|
||||
local pnl = self.ProblemPanels[ groupID ]
|
||||
if ( !IsValid( pnl ) ) then
|
||||
pnl = self.ProblemsList:Add( "GenericProblemGroup" )
|
||||
pnl:SetGroup( groupID )
|
||||
self.ProblemPanels[ groupID ] = pnl
|
||||
|
||||
self:InvalidateLayout()
|
||||
end
|
||||
|
||||
pnl:ReceivedProblem( uid, prob )
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "ProblemsPanel", PANEL, "EditablePanel" )
|
||||
325
lua/menu/ugcpublish.lua
Normal file
325
lua/menu/ugcpublish.lua
Normal file
@@ -0,0 +1,325 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetSize( 700, 200 )
|
||||
self:Center()
|
||||
self:DockPadding( 10, 24 + 10, 10, 10 )
|
||||
self:SetTitle( "#ugc_upload.frametitle" )
|
||||
self:SetBackgroundBlur( true ) -- Indicate that the background elements won't be usable
|
||||
--self:SetSizable( true )
|
||||
|
||||
self.AddonList = self:Add( "DListView" )
|
||||
self.AddonList:Dock( RIGHT )
|
||||
self.AddonList:SetWide( 200 )
|
||||
self.AddonList:AddColumn( "#ugc_upload.existing" )
|
||||
self.AddonList:DockMargin( 10, 0, 0, 0 )
|
||||
self.AddonList:SetMultiSelect( false )
|
||||
self.AddonList:SetMouseInputEnabled( false )
|
||||
self.AddonList.OnRowSelected = function( s, ... ) self:OnRowSelected( ... ) end
|
||||
|
||||
self.AddonListLabel = self.AddonList:Add( "DLabel" )
|
||||
self.AddonListLabel:Dock( FILL )
|
||||
self.AddonListLabel:SetTextColor( color_black )
|
||||
self.AddonListLabel:SetContentAlignment( 5 )
|
||||
self.AddonListLabel:SetZPos( 100 )
|
||||
self.AddonListLabel.Paint = function( s, w, h ) draw.RoundedBox( 0, 0, 0, w, h, Color( 0, 0, 0, 100 ) ) end -- TODO: Prolly should be hooked to skin
|
||||
|
||||
local topContainer = self:Add( "Panel" )
|
||||
topContainer:Dock( TOP )
|
||||
topContainer:SetTall( 200 )
|
||||
|
||||
self.Image = topContainer:Add( "DImage" )
|
||||
self.Image:Dock( LEFT )
|
||||
self.Image:SetWide( 200 )
|
||||
self.Image:DockMargin( 0, 0, 5, 0 )
|
||||
|
||||
local titleLabel = topContainer:Add( "DLabel" )
|
||||
titleLabel:Dock( TOP )
|
||||
titleLabel:SetText( "#ugc_upload.title" )
|
||||
|
||||
self.Title = topContainer:Add( "DTextEntry" )
|
||||
self.Title:Dock( TOP )
|
||||
self.Title:SetUpdateOnType( true )
|
||||
self.Title.OnTextChanged = function( s ) self:CheckInput() end
|
||||
|
||||
local descLabel = topContainer:Add( "DLabel" )
|
||||
descLabel:Dock( TOP )
|
||||
descLabel:SetText( "#ugc_upload.description" )
|
||||
|
||||
self.Description = topContainer:Add( "DTextEntry" )
|
||||
self.Description:Dock( FILL )
|
||||
self.Description:SetMultiline( true )
|
||||
|
||||
self.TagsLabel = self:Add( "DLabel" )
|
||||
self.TagsLabel:Dock( TOP )
|
||||
self.TagsLabel:SetText( "#ugc_upload.tags" )
|
||||
|
||||
self.Tags = self:Add( "Panel" )
|
||||
self.Tags:Dock( TOP )
|
||||
|
||||
self.ChangeNotesLabel = self:Add( "DLabel" )
|
||||
self.ChangeNotesLabel:Dock( TOP )
|
||||
self.ChangeNotesLabel:DockMargin( 0, 5, 0, 0 )
|
||||
self.ChangeNotesLabel:SetText( "#ugc_upload.changenotes" )
|
||||
|
||||
self.ChangeNotes = self:Add( "DTextEntry" )
|
||||
self.ChangeNotes:Dock( TOP )
|
||||
self.ChangeNotes:SetPlaceholderText( "ugc_upload.changenotes.help" )
|
||||
self.ChangeNotes:SetVisible( false )
|
||||
self.ChangeNotes:SetUpdateOnType( true )
|
||||
self.ChangeNotes:SetMultiline( true )
|
||||
self.ChangeNotes:SetTall( 80 )
|
||||
|
||||
self.Publish = self:Add( "DButton" )
|
||||
self.Publish:Dock( TOP )
|
||||
self.Publish:SetEnabled( false )
|
||||
self.Publish:SetText( "#ugc_upload.publish" )
|
||||
self.Publish:DockMargin( 0, 5, 0, 0 )
|
||||
self.Publish.DoClick = function( s ) self:DoPublish() end
|
||||
|
||||
self.UpdateProgress = self:Add( "DLabel" )
|
||||
self.UpdateProgress:SetText( "Publising your content, please wait..." )
|
||||
self.UpdateProgress:SetTextColor( color_black )
|
||||
self.UpdateProgress:SetContentAlignment( 5 )
|
||||
self.UpdateProgress:SetZPos( 100 )
|
||||
self.UpdateProgress:SetVisible( false )
|
||||
self.UpdateProgress.Paint = function( s, w, h )
|
||||
s:StretchToParent( 4, 4, 4, 4 )
|
||||
draw.RoundedBox( 0, 0, 0, w, h, Color( 200, 200, 200, 255 ) ) -- TODO: Prolly should be hooked to skin
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
PANEL.TagsPerType = {
|
||||
save = {
|
||||
scenes = "#ugc_upload.tag_scenes_save",
|
||||
courses = "#ugc_upload.tag_courses",
|
||||
machines = "#ugc_upload.tag_machines",
|
||||
buildings = "#ugc_upload.tag_buildings",
|
||||
others = "#ugc_upload.tag_others"
|
||||
},
|
||||
dupe = {
|
||||
posed = "#ugc_upload.tag_posed",
|
||||
scenes = "#ugc_upload.tag_scenes",
|
||||
vehicles = "#ugc_upload.tag_vehicles",
|
||||
machines = "#ugc_upload.tag_machines",
|
||||
buildings = "#ugc_upload.tag_buildings",
|
||||
others = "#ugc_upload.tag_others"
|
||||
}
|
||||
}
|
||||
|
||||
function PANEL:FitContents()
|
||||
-- Make this panel smaller, stuff below won't shrink it, only expand it
|
||||
self:SetTall( 200 )
|
||||
|
||||
-- Set the window height to nicely fit everything, no extra space anywhere
|
||||
self:InvalidateLayout( true )
|
||||
self:SizeToChildren( false, true )
|
||||
end
|
||||
|
||||
function PANEL:OnRowSelected( rowID, row )
|
||||
-- Create new node, reset the fields
|
||||
if ( !row.WorkshopData ) then
|
||||
self.Publish:SetText( "#ugc_upload.publish" )
|
||||
self.ChangeNotes:SetVisible( false )
|
||||
self.ChangeNotesLabel:SetVisible( false )
|
||||
self.Title:SetText( "" )
|
||||
self.Description:SetText( "" )
|
||||
for k, v in pairs( self.Tags:GetChildren() ) do v:SetChecked( false ) end -- SetChecked to not invoke OnChange
|
||||
self:FitContents()
|
||||
self:CheckInput()
|
||||
return
|
||||
end
|
||||
|
||||
local dat = row.WorkshopData
|
||||
|
||||
self.Title:SetText( dat.title )
|
||||
self.Description:SetText( dat.description )
|
||||
for k, v in pairs( self.Tags:GetChildren() ) do
|
||||
if ( dat.tags:find( v:GetName() ) ) then v:SetValue( true ) break end
|
||||
end
|
||||
|
||||
self.Publish:SetText( "#ugc_upload.update" )
|
||||
self.ChangeNotes:SetVisible( true )
|
||||
self.ChangeNotesLabel:SetVisible( true )
|
||||
self:FitContents()
|
||||
self:CheckInput()
|
||||
end
|
||||
|
||||
function PANEL:Setup( ugcType, file, imageFile, handler )
|
||||
self.ugcType = ugcType
|
||||
self.ugcFile = file
|
||||
self.ugcImage = imageFile
|
||||
self.ugcHandler = handler
|
||||
|
||||
self.Image:SetImage( "../" .. self.ugcImage )
|
||||
|
||||
if ( self.TagsPerType[ self.ugcType ] ) then
|
||||
for k, v in pairs( self.TagsPerType[ self.ugcType ] ) do
|
||||
local rb = self.Tags:Add( "DCheckBoxLabel" )
|
||||
rb:Dock( TOP )
|
||||
rb:SetText( v )
|
||||
rb:SetName( k )
|
||||
rb:DockMargin( 4, 0, 0, 2 )
|
||||
|
||||
rb.OnChange = function( s, val )
|
||||
self:CheckInput()
|
||||
|
||||
local num = 0
|
||||
for id, pnl in pairs( s:GetParent():GetChildren() ) do
|
||||
if ( pnl:GetChecked() ) then num = num + 1 end
|
||||
if ( pnl == s or !val ) then continue end
|
||||
pnl:SetValue( false ) -- Validate that only 1 is selected
|
||||
end
|
||||
if ( !val && num == 0 ) then s:SetValue( true ) end -- Don't allow to unselect the only 1 selected
|
||||
end
|
||||
|
||||
Derma_Hook( rb.Button, "Paint", "Paint", "RadioButton" )
|
||||
end
|
||||
|
||||
self.Tags:InvalidateChildren( false ) -- Update position of all the docked elements
|
||||
self.Tags:SizeToChildren( false, true ) -- Set nice size for the tags container
|
||||
else
|
||||
self.TagsLabel:SetVisible( false )
|
||||
self.Tags:SetVisible( false )
|
||||
end
|
||||
|
||||
self:FitContents()
|
||||
|
||||
self:UpdateWorkshopItems()
|
||||
end
|
||||
|
||||
function PANEL:UpdateWorkshopItems()
|
||||
self.AddonListLabel:SetVisible( true )
|
||||
self.AddonListLabel:SetText( "#ugc_upload.loading" )
|
||||
|
||||
self.AddonList:Clear()
|
||||
self.AddonList:AddLine( "#ugc_upload.createnew" )
|
||||
self.AddonList:SelectFirstItem()
|
||||
|
||||
steamworks.GetList( "mine", { self.ugcType }, 0, 9999, 0, "1", function( data )
|
||||
for i, id in pairs( data.results ) do
|
||||
steamworks.FileInfo( id, function( info )
|
||||
local a = self.AddonList:AddLine( info.title )
|
||||
a:SetTooltip( "#ugc_upload.rightclickopen" )
|
||||
a.WorkshopID = id
|
||||
a.WorkshopData = info
|
||||
a.OnRightClick = function( s )
|
||||
if ( !s.WorkshopID ) then return end
|
||||
|
||||
steamworks.ViewFile( s.WorkshopID )
|
||||
end
|
||||
|
||||
self.AddonList:SetMouseInputEnabled( true )
|
||||
self.AddonListLabel:SetVisible( false )
|
||||
end )
|
||||
end
|
||||
|
||||
if ( data.totalresults == 0 ) then
|
||||
self.AddonListLabel:SetText( "#ugc_upload.nothingfound" )
|
||||
end
|
||||
end )
|
||||
end
|
||||
|
||||
function PANEL:GetChosenTag()
|
||||
for k, v in pairs( self.Tags:GetChildren() ) do
|
||||
if ( v:GetChecked() ) then
|
||||
return v:GetName()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:CheckInput()
|
||||
if ( self.TagsPerType[ self.ugcType ] && !self:GetChosenTag() ) then return self.Publish:SetEnabled( false ) end
|
||||
if ( self.Title:GetText() == "" ) then return self.Publish:SetEnabled( false ) end
|
||||
|
||||
self.Publish:SetEnabled( true )
|
||||
end
|
||||
|
||||
local errors = {}
|
||||
errors[ "badhandle" ] = "Generic error while trying to create item."
|
||||
errors[ "createid" ] = "Generic error while trying to create workshop item ID."
|
||||
errors[ "badupdatehandle" ] = "Generic error while trying to update item."
|
||||
errors[ "badsubmitupdatehandle" ] = "Could not submit update to Steam."
|
||||
errors[ "cantupdate" ] = "Failed to upload workshop files to Steam."
|
||||
errors[ "badwords" ] = "Please refrain from uploading spam, vulgar, sexual or offensive content to Steam Workshop."
|
||||
|
||||
function PANEL:DisplayError( err )
|
||||
-- Unlock the UI and allow user to try again/make changes
|
||||
self.UpdateProgress:SetVisible( false )
|
||||
self:SetMouseInputEnabled( true )
|
||||
|
||||
if ( err == "termsofservice" ) then
|
||||
err = "You must accept Steam Workshop Terms of Service before you can upload content!\nWould you like to open it right now?"
|
||||
Derma_Query( err, "Error while publishing content!", "Yes", function()
|
||||
gui.OpenURL( "http://steamcommunity.com/sharedfiles/workshoplegalagreement" )
|
||||
end, "Nah" )
|
||||
return
|
||||
end
|
||||
|
||||
if ( errors[ err ] ) then err = errors[ err ] end
|
||||
|
||||
Derma_Message( err or "UNKNOWN ERROR", "Error while publishing content!", "OK" )
|
||||
end
|
||||
|
||||
function PANEL:OnPublishFinished( wsid, err )
|
||||
if ( !wsid ) then
|
||||
self:DisplayError( err )
|
||||
return
|
||||
end
|
||||
|
||||
-- TODO: Show "View item"/"Close" buttons instead?
|
||||
|
||||
steamworks.ViewFile( wsid )
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
function PANEL:DoPublish()
|
||||
local ChosenTag = self:GetChosenTag()
|
||||
|
||||
if ( self.TagsPerType[ self.ugcType ] && ChosenTag == nil ) then
|
||||
self:DisplayError( "You must choose a tag!")
|
||||
return
|
||||
end
|
||||
|
||||
if ( self.Title:GetText() == "" ) then
|
||||
self:DisplayError( "You must provide a title!" )
|
||||
return
|
||||
end
|
||||
|
||||
local workshopUpdateID = nil
|
||||
local updateButtonID, updateButton = self.AddonList:GetSelectedLine()
|
||||
if ( IsValid( updateButton ) ) then
|
||||
workshopUpdateID = updateButton.WorkshopID
|
||||
end
|
||||
|
||||
-- Lock down the UI
|
||||
self.UpdateProgress:SetVisible( true )
|
||||
self:SetMouseInputEnabled( false )
|
||||
|
||||
-- TODO: Display update progress?
|
||||
-- TODO: Confirmation dialog?
|
||||
|
||||
-- Start the process
|
||||
local err = self.ugcHandler:FinishPublish( self.ugcFile, self.ugcImage, self.Title:GetText(), self.Description:GetText(), ChosenTag, {
|
||||
WorkshopID = workshopUpdateID,
|
||||
ChangeNotes = self.ChangeNotes:GetText(),
|
||||
Callback = function( wsid, erro ) self:OnPublishFinished( wsid, erro ) end
|
||||
} )
|
||||
if ( err ) then self:DisplayError( err ) end
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "UGCPublishWindow", PANEL, "DFrame" )
|
||||
42
lua/menu/util.lua
Normal file
42
lua/menu/util.lua
Normal file
@@ -0,0 +1,42 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
concommand.Add( "whereis", function( _, _, _, path )
|
||||
|
||||
local absolutePath = util.RelativePathToFull_Menu( path, "GAME" )
|
||||
|
||||
if ( !absolutePath or !file.Exists( path, "GAME" ) ) then
|
||||
MsgN "File not found."
|
||||
return
|
||||
end
|
||||
|
||||
local relativePath = util.FullPathToRelative_Menu( absolutePath, "MOD" )
|
||||
|
||||
-- If the relative path is inside the workshop dir, it's part of a workshop addon
|
||||
if ( relativePath && relativePath:match( "^workshop[\\/].*" ) ) then
|
||||
|
||||
local addonInfo = util.RelativePathToGMA_Menu( path )
|
||||
|
||||
-- Not here? Maybe somebody just put their own file in ./workshop
|
||||
if ( addonInfo ) then
|
||||
|
||||
local addonRelativePath = util.RelativePathToFull_Menu( addonInfo.File )
|
||||
|
||||
MsgN( "'", addonInfo.Title, "' - ", addonRelativePath or addonInfo.File )
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
MsgN( absolutePath )
|
||||
|
||||
end, nil, "Searches for the highest priority instance of a file within the GAME mount path." )
|
||||
70
lua/menu/video.lua
Normal file
70
lua/menu/video.lua
Normal file
@@ -0,0 +1,70 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local vid_width = CreateConVar( "vid_width", "640", { FCVAR_ARCHIVE + FCVAR_DONTRECORD }, "Specifies the width of the recorded video. The height will be adjusted automatically based on your aspect ratio" )
|
||||
local vid_fps = CreateConVar( "vid_fps", "30", { FCVAR_ARCHIVE + FCVAR_DONTRECORD }, "The FPS of the recorded video" )
|
||||
local vid_sound = CreateConVar( "vid_sound", "1", { FCVAR_ARCHIVE + FCVAR_DONTRECORD }, "Enable sound recording" )
|
||||
|
||||
local activeVideo
|
||||
local videoStart
|
||||
|
||||
concommand.Add( "gm_video", function()
|
||||
if ( activeVideo ) then
|
||||
activeVideo:Finish()
|
||||
activeVideo = nil
|
||||
|
||||
local time = SysTime() - videoStart
|
||||
MsgN( string.format( "Finished recording. Length: %.1fs", time ) )
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local dynamic_name = game.GetMap() .. " " .. util.DateStamp()
|
||||
|
||||
local width = math.Round( vid_width:GetFloat() )
|
||||
local height = math.Round( ScrH() * ( width / ScrW() ) )
|
||||
local fps = math.Round( vid_fps:GetFloat() )
|
||||
|
||||
local err
|
||||
|
||||
activeVideo, err = video.Record( {
|
||||
name = dynamic_name,
|
||||
container = "webm",
|
||||
video = "vp8",
|
||||
audio = "vorbis",
|
||||
quality = 0,
|
||||
bitrate = 1024 * 64,
|
||||
width = width,
|
||||
height = height,
|
||||
fps = fps,
|
||||
lockfps = true
|
||||
} )
|
||||
|
||||
if ( !activeVideo ) then
|
||||
MsgN( "Couldn't record video: ", err )
|
||||
return
|
||||
end
|
||||
|
||||
activeVideo:SetRecordSound( vid_sound:GetBool() )
|
||||
|
||||
videoStart = SysTime()
|
||||
|
||||
MsgN( string.format( "Recording %ix%i@%iFPS video to \"videos/%s.webm\"...", width, height, fps, dynamic_name ) )
|
||||
|
||||
end, nil, "Starts and stops the recording of a .webm (VP8/Vorbis) video. See vid_* convars for settings.", { FCVAR_DONTRECORD } )
|
||||
|
||||
hook.Add( "DrawOverlay", "CaptureFrames", function()
|
||||
|
||||
if ( !activeVideo ) then return end
|
||||
|
||||
activeVideo:AddFrame( FrameTime(), true )
|
||||
|
||||
end )
|
||||
Reference in New Issue
Block a user