add sborka
This commit is contained in:
@@ -0,0 +1,444 @@
|
||||
-- Extended Spawnmenu - Legacy Addons (старые аддоны и загрузки)
|
||||
local PLUGIN = PLUGIN
|
||||
|
||||
language.Add("spawnmenu.category.addonslegacy", "Addons - Legacy")
|
||||
language.Add("spawnmenu.category.downloads", "Downloads")
|
||||
|
||||
local function AddRecursive( pnl, folder )
|
||||
local files, folders = file.Find( folder .. "*", "MOD" )
|
||||
|
||||
for k, v in pairs( files or {} ) do
|
||||
if ( !string.EndsWith( v, ".mdl" ) ) then continue end
|
||||
|
||||
local cp = spawnmenu.GetContentType( "model" )
|
||||
if ( cp ) then
|
||||
local mdl = folder .. v
|
||||
mdl = string.sub( mdl, string.find( mdl, "models/" ), string.len( mdl ) )
|
||||
mdl = string.gsub( mdl, "models/models/", "models/" )
|
||||
cp( pnl, { model = mdl } )
|
||||
end
|
||||
end
|
||||
|
||||
for k, v in pairs( folders or {} ) do AddRecursive( pnl, folder .. v .. "/" ) end
|
||||
end
|
||||
|
||||
local function CountRecursive( folder )
|
||||
local files, folders = file.Find( folder .. "*", "MOD" )
|
||||
local val = 0
|
||||
|
||||
for k, v in pairs( files or {} ) do if ( string.EndsWith( v, ".mdl" ) ) then val = val + 1 end end
|
||||
for k, v in pairs( folders or {} ) do val = val + CountRecursive( folder .. v .. "/" ) end
|
||||
return val
|
||||
end
|
||||
|
||||
hook.Add( "PopulateContent", "LegacyAddonProps", function( pnlContent, tree, node )
|
||||
|
||||
if ( !IsValid( node ) or !IsValid( pnlContent ) ) then
|
||||
print( "!!! Extended Spawnmenu: FAILED TO INITALIZE PopulateContent HOOK FOR LEGACY ADDONS!!!" )
|
||||
print( "!!! Extended Spawnmenu: FAILED TO INITALIZE PopulateContent HOOK FOR LEGACY ADDONS!!!" )
|
||||
print( "!!! Extended Spawnmenu: FAILED TO INITALIZE PopulateContent HOOK FOR LEGACY ADDONS!!!" )
|
||||
return
|
||||
end
|
||||
|
||||
local ViewPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
ViewPanel:SetVisible( false )
|
||||
|
||||
local addons = {}
|
||||
|
||||
local _files, folders = file.Find( "addons/*", "MOD" )
|
||||
for _, f in pairs( folders ) do
|
||||
|
||||
if ( !file.IsDir( "addons/" .. f .. "/models/", "MOD" ) ) then continue end
|
||||
|
||||
local count = CountRecursive( "addons/" .. f .. "/models/", "MOD" )
|
||||
if ( count == 0 ) then continue end
|
||||
|
||||
table.insert( addons, {
|
||||
name = f,
|
||||
count = count,
|
||||
path = "addons/" .. f .. "/models/"
|
||||
} )
|
||||
|
||||
end
|
||||
|
||||
local LegacyAddons = node:AddNode( "#spawnmenu.category.addonslegacy", "icon16/folder_database.png" )
|
||||
for _, f in SortedPairsByMemberValue( addons, "name" ) do
|
||||
|
||||
local models = LegacyAddons:AddNode( f.name .. " (" .. f.count .. ")", "icon16/bricks.png" )
|
||||
models.DoClick = function()
|
||||
ViewPanel:Clear( true )
|
||||
AddRecursive( ViewPanel, f.path )
|
||||
pnlContent:SwitchPanel( ViewPanel )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[ -------------------------- DOWNLOADS -------------------------- ]]
|
||||
|
||||
local fi, fo = file.Find( "download/models", "MOD" )
|
||||
if ( !fi && !fo ) then return end
|
||||
|
||||
local Downloads = node:AddFolder( "#spawnmenu.category.downloads", "download/models", "MOD", false, false, "*.*" )
|
||||
Downloads:SetIcon( "icon16/folder_database.png" )
|
||||
|
||||
Downloads.OnNodeSelected = function( self, selectedNode )
|
||||
ViewPanel:Clear( true )
|
||||
|
||||
local path = selectedNode:GetFolder()
|
||||
|
||||
if ( !string.EndsWith( path, "/" ) && string.len( path ) > 1 ) then path = path .. "/" end
|
||||
local path_mdl = string.sub( path, string.find( path, "/models/" ) + 1 )
|
||||
|
||||
for k, v in pairs( file.Find( path .. "/*.mdl", selectedNode:GetPathID() ) ) do
|
||||
|
||||
local cp = spawnmenu.GetContentType( "model" )
|
||||
if ( cp ) then
|
||||
cp( ViewPanel, { model = path_mdl .. "/" .. v } )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
pnlContent:SwitchPanel( ViewPanel )
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
--[[ -------------------------------------------------------------------------- The addon info -------------------------------------------------------------------------- ]]
|
||||
|
||||
concommand.Add( "extsm_addoninfo", function()
|
||||
local frame = vgui.Create( "DFrame" )
|
||||
frame:SetSize( ScrW() - 100, ScrH() - 100 )
|
||||
frame:Center()
|
||||
frame:MakePopup()
|
||||
|
||||
local sp = frame:Add( "DScrollPanel" )
|
||||
sp:Dock( FILL )
|
||||
|
||||
sp:Add( "rb655_addonInfo" )
|
||||
end )
|
||||
|
||||
hook.Add( "AddToolMenuCategories", "LegacyAddonPropsInfoCategory", function()
|
||||
spawnmenu.AddToolCategory( "Utilities", "Robotboy655", "#Robotboy655" )
|
||||
end )
|
||||
|
||||
hook.Add( "PopulateToolMenu", "LegacyAddonPropsInfoThing", function()
|
||||
spawnmenu.AddToolMenuOption( "Utilities", "Robotboy655", "LegacyInfoPanel", "Addon Information", "", "", function( panel )
|
||||
panel:ClearControls()
|
||||
panel:Button( "Open addon data window", "extsm_addoninfo" )
|
||||
end )
|
||||
end )
|
||||
|
||||
----------------------------------
|
||||
|
||||
function ScreenScaleH( size )
|
||||
return size * ( ScrH() / 480.0 )
|
||||
end
|
||||
|
||||
surface.CreateFont( "AddonInfo_Header", {
|
||||
font = "Helvetica",
|
||||
size = ScreenScaleH( 24 ),
|
||||
weight = 1000
|
||||
} )
|
||||
|
||||
surface.CreateFont( "AddonInfo_Text", {
|
||||
font = "Helvetica",
|
||||
size = ScreenScaleH( 9 ),
|
||||
weight = 1000
|
||||
} )
|
||||
|
||||
surface.CreateFont( "AddonInfo_Small", {
|
||||
font = "Helvetica",
|
||||
size = ScreenScaleH( 8 )
|
||||
} )
|
||||
|
||||
local function GetWorkshopLeftovers()
|
||||
|
||||
local subscriptions = {}
|
||||
|
||||
for id, t in pairs( engine.GetAddons() ) do
|
||||
subscriptions[ tonumber( t.wsid ) ] = true
|
||||
end
|
||||
|
||||
local t = {}
|
||||
for id, fileh in pairs( file.Find( "addons/*.gma", "MOD" ) ) do
|
||||
local a = string.StripExtension( fileh )
|
||||
a = string.Explode( "_", a )
|
||||
a = tonumber( a[ #a ] )
|
||||
if ( !subscriptions[ a ] ) then
|
||||
table.insert( t, fileh )
|
||||
end
|
||||
end
|
||||
|
||||
return t
|
||||
|
||||
end
|
||||
|
||||
local function GetSize( b )
|
||||
b = b / 1000
|
||||
|
||||
if ( b < 1000 ) then
|
||||
return math.floor( b * 10 ) / 10 .. " KB"
|
||||
end
|
||||
|
||||
b = b / 1000
|
||||
|
||||
if ( b < 1000 ) then
|
||||
return math.floor( b * 10 ) / 10 .. " MB"
|
||||
end
|
||||
|
||||
b = b / 1000
|
||||
|
||||
return math.floor( b * 10 ) / 10 .. " GB"
|
||||
end
|
||||
|
||||
local function DrawText( txt, font, x, y, clr )
|
||||
draw.SimpleText( txt, font, x, y, clr )
|
||||
|
||||
surface.SetFont( font )
|
||||
return surface.GetTextSize( txt )
|
||||
end
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self.Computed = false
|
||||
end
|
||||
|
||||
function PANEL:Compute()
|
||||
|
||||
self.WorkshopSize = 0
|
||||
for id, fle in pairs( file.Find( "addons/*.gma", "MOD" ) ) do
|
||||
self.WorkshopSize = self.WorkshopSize + ( file.Size( "addons/" .. fle, "MOD" ) or 0 )
|
||||
end
|
||||
|
||||
self.WorkshopWaste = 0
|
||||
self.WorkshopWasteFiles = {}
|
||||
for id, fle in pairs( GetWorkshopLeftovers() ) do
|
||||
self.WorkshopWaste = self.WorkshopWaste + ( file.Size( "addons/" .. fle, "MOD" ) or 0 )
|
||||
table.insert( self.WorkshopWasteFiles, { "addons/" .. fle, ( file.Size( "addons/" .. fle, "MOD" ) or 0 ) } )
|
||||
end
|
||||
|
||||
-- -------------------------------------------
|
||||
|
||||
local _files, folders = file.Find( "addons/*", "MOD" )
|
||||
|
||||
self.LegacyAddons = {}
|
||||
for k, v in pairs( folders or {} ) do
|
||||
self.LegacyAddons[ "addons/" .. v .. "/" ] = "Installed"
|
||||
|
||||
if ( file.IsDir( "addons/" .. v .. "/models/", "MOD" ) ) then
|
||||
self.LegacyAddons[ "addons/" .. v .. "/" ] = "Installed (Has Models)"
|
||||
end
|
||||
|
||||
local _fi, fo = file.Find( "addons/" .. v .. "/*", "MOD" )
|
||||
if ( table.Count( fo or {} ) < 1 ) then
|
||||
self.LegacyAddons[ "addons/" .. v .. "/" ] = "Installed (Empty)"
|
||||
end
|
||||
|
||||
if ( !file.IsDir( "addons/" .. v .. "/models/", "MOD" ) && !file.IsDir( "addons/" .. v .. "/materials/", "MOD" ) && !file.IsDir( "addons/" .. v .. "/lua/", "MOD" ) && !file.IsDir( "addons/" .. v .. "/sound/", "MOD" ) ) then
|
||||
self.LegacyAddons[ "addons/" .. v .. "/" ] = "Installed Incorrectly!"
|
||||
end
|
||||
end
|
||||
|
||||
-- -------------------------------------------
|
||||
|
||||
local luaFiles = file.Find( "cache/lua/*", "MOD" ) -- Too many files to count actual size!
|
||||
self.LuaCacheSize = #luaFiles * 1400
|
||||
self.LuaCacheFiles = #luaFiles
|
||||
|
||||
local wsFiles = file.Find( "cache/workshop/*", "MOD" )
|
||||
self.WSCacheSize = 0
|
||||
for id, fle in pairs( wsFiles ) do
|
||||
self.WSCacheSize = self.WSCacheSize + ( file.Size( "cache/workshop/" .. fle, "MOD" ) or 0 )
|
||||
end
|
||||
self.WSCacheFiles = #wsFiles
|
||||
|
||||
self.Computed = true
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Paint( w, h )
|
||||
|
||||
if ( !self.Computed ) then
|
||||
self:Compute()
|
||||
end
|
||||
|
||||
local txtW = self:GetParent():GetWide()
|
||||
local txtH = 0
|
||||
|
||||
-- -----------------------
|
||||
|
||||
local tW, tH = DrawText( "Cache Sizes", "AddonInfo_Header", 0, txtH, color_white )
|
||||
txtH = txtH + tH
|
||||
|
||||
local localH = 0
|
||||
local localW = 0
|
||||
|
||||
-- -----------------------
|
||||
|
||||
tW, tH = DrawText( "~" .. GetSize( self.LuaCacheSize or 0 ) .. " (" .. self.LuaCacheFiles .. " files)", "AddonInfo_Small", 0, txtH + localH, Color( 220, 220, 220 ) )
|
||||
localH = localH + tH
|
||||
localW = math.max( localW, tW )
|
||||
|
||||
tW, tH = DrawText( "~" .. GetSize( self.WSCacheSize or 0 ) .. " (" .. self.WSCacheFiles .. " files)", "AddonInfo_Small", 0, txtH + localH, Color( 220, 220, 220 ) )
|
||||
localH = localH + tH
|
||||
localW = math.max( localW, tW )
|
||||
|
||||
-- -----------------------
|
||||
|
||||
localW = localW + 25
|
||||
|
||||
tW, tH = DrawText( "Server Lua cache", "AddonInfo_Small", localW, txtH, color_white )
|
||||
txtH = txtH + tH
|
||||
|
||||
tW, tH = DrawText( "Workshop download cache", "AddonInfo_Small", localW, txtH, color_white )
|
||||
txtH = txtH + tH
|
||||
|
||||
-- -------------------------------------------
|
||||
|
||||
txtH = txtH + ScreenScaleH( 8 )
|
||||
tW, tH = DrawText( "Workshop Subscriptions", "AddonInfo_Header", 0, txtH, color_white )
|
||||
txtH = txtH + tH
|
||||
|
||||
-- -------------------------------------------
|
||||
|
||||
tW, tH = DrawText( "Used Size: ", "AddonInfo_Text", 0, txtH, color_white )
|
||||
local maxW = tW
|
||||
txtH = txtH + tH
|
||||
|
||||
tW, tH = DrawText( "Wasted Space: ", "AddonInfo_Text", 0, txtH, color_white )
|
||||
maxW = math.max( maxW, tW )
|
||||
txtH = txtH + tH
|
||||
|
||||
tW, tH = DrawText( "Total Size: ", "AddonInfo_Text", 0, txtH, color_white )
|
||||
maxW = math.max( maxW, tW )
|
||||
txtH = txtH - tH * 2
|
||||
|
||||
-- -------------------------------------------
|
||||
|
||||
tW, tH = DrawText( GetSize( ( self.WorkshopSize - self.WorkshopWaste ) or 0 ), "AddonInfo_Text", maxW, txtH, Color( 220, 220, 220 ) )
|
||||
txtH = txtH + tH
|
||||
|
||||
tW, tH = DrawText( GetSize( self.WorkshopWaste or 0 ), "AddonInfo_Text", maxW, txtH, Color( 220, 220, 220 ) )
|
||||
txtH = txtH + tH
|
||||
|
||||
tW, tH = DrawText( GetSize( self.WorkshopSize or 0 ), "AddonInfo_Text", maxW, txtH, Color( 220, 220, 220 ) )
|
||||
txtH = txtH + tH * 2
|
||||
|
||||
-- -------------------------------------------
|
||||
|
||||
tW, tH = DrawText( "Files that aren't used: ( Safe to delete )", "AddonInfo_Text", 0, txtH, color_white )
|
||||
txtH = txtH + tH
|
||||
|
||||
localH = 0
|
||||
localW = 0
|
||||
for id, t in pairs( self.WorkshopWasteFiles or {} ) do
|
||||
tW, tH = DrawText( GetSize( t[ 2 ] ) .. " ", "AddonInfo_Small", 0, txtH + localH, Color( 220, 220, 220 ) )
|
||||
localH = localH + tH
|
||||
localW = math.max( localW, tW )
|
||||
end
|
||||
|
||||
for id, t in pairs( self.WorkshopWasteFiles or {} ) do
|
||||
tW, tH = DrawText( t[ 1 ], "AddonInfo_Small", localW, txtH, color_white )
|
||||
txtH = txtH + tH
|
||||
end
|
||||
|
||||
-- -------------------------------------------
|
||||
|
||||
tW, tH = DrawText( "Legacy Addons", "AddonInfo_Header", 0, txtH + ScreenScaleH( 8 ), color_white )
|
||||
txtH = txtH + tH + ScreenScaleH( 8 )
|
||||
|
||||
-- -------------------------------------------
|
||||
|
||||
tW, tH = DrawText( "Legacy Addons with models:", "AddonInfo_Text", 0, txtH, color_white )
|
||||
txtH = txtH + tH
|
||||
|
||||
if ( table.Count( self.LegacyAddons or {} ) > 0 ) then
|
||||
local maxNameW = 0
|
||||
local oldH = txtH
|
||||
for path, status in pairs( self.LegacyAddons or {} ) do
|
||||
tW, tH = DrawText( path, "AddonInfo_Small", 0, txtH, color_white )
|
||||
maxNameW = math.max( maxNameW, tW )
|
||||
txtH = txtH + tH
|
||||
end
|
||||
|
||||
maxNameW = maxNameW + 25
|
||||
txtH = oldH
|
||||
|
||||
for path, status in pairs( self.LegacyAddons or {} ) do
|
||||
tW, tH = DrawText( status, "AddonInfo_Small", maxNameW, txtH, Color( 220, 220, 220 ) )
|
||||
txtH = txtH + tH
|
||||
end
|
||||
else
|
||||
tW, tH = DrawText( "None.", "AddonInfo_Small", 0, txtH, color_white )
|
||||
txtH = txtH + tH
|
||||
end
|
||||
|
||||
if ( !system.IsWindows() ) then
|
||||
txtH = txtH + tH
|
||||
|
||||
tW, tH = DrawText( "OSX AND LINUX USERS BEWARE:", "AddonInfo_Text", 0, txtH, color_white )
|
||||
txtH = txtH + tH
|
||||
tW, tH = DrawText( "MAKE SURE ALL FILE AND FOLDER NAMES", "AddonInfo_Text", 0, txtH, color_white )
|
||||
txtH = txtH + tH
|
||||
tW, tH = DrawText( "IN ALL ADDONS ARE LOWERCASE ONLY", "AddonInfo_Text", 0, txtH, color_white )
|
||||
txtH = txtH + tH
|
||||
tW, tH = DrawText( "INCLUDING ALL SUB FOLDERS", "AddonInfo_Text", 0, txtH, color_white )
|
||||
txtH = txtH + tH
|
||||
end
|
||||
|
||||
txtH = txtH + tH
|
||||
|
||||
-- -------------------------------------------
|
||||
|
||||
self:SetSize( txtW, txtH )
|
||||
end
|
||||
|
||||
vgui.Register( "rb655_addonInfo", PANEL, "Panel" )
|
||||
|
||||
--[[ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ]]
|
||||
|
||||
-- I spent too much time on this than I care to admit
|
||||
hook.Add( "PopulatePropMenu", "rb655_LoadLegacySpawnlists", function()
|
||||
|
||||
local sid = 0 --table.Count( spawnmenu.GetPropTable() )
|
||||
|
||||
--local added = false
|
||||
|
||||
for id, spawnlist in pairs( file.Find( "settings/spawnlist/*.txt", "MOD" ) ) do
|
||||
local content = file.Read( "settings/spawnlist/" .. spawnlist, "MOD" )
|
||||
if ( !content ) then continue end
|
||||
|
||||
--[[local is = string.find( content, "TableToKeyValues" )
|
||||
if ( is != nil ) then continue end
|
||||
|
||||
for id, t in pairs( spawnmenu.GetPropTable() ) do -- This somehow freezes the game when opening Q menu => FUCK THIS SHIT
|
||||
if ( t.name == "Legacy Spawnlists" ) then
|
||||
added = true
|
||||
sid = t.id
|
||||
end
|
||||
end
|
||||
|
||||
if ( !added ) then
|
||||
spawnmenu.AddPropCategory( "rb655_legacy_spawnlists", "Legacy Spawnlists", {}, "icon16/folder.png", sid, 0 )
|
||||
added = true
|
||||
end]]
|
||||
|
||||
content = util.KeyValuesToTable( content )
|
||||
|
||||
if ( !content.entries or content.contents ) then continue end
|
||||
|
||||
local contents = {}
|
||||
|
||||
for eid, entry in pairs( content.entries ) do
|
||||
if ( type( entry ) == "table" ) then entry = entry.model end
|
||||
table.insert( contents, { type = "model", model = entry } )
|
||||
end
|
||||
|
||||
if ( !content.information ) then content.information = { name = spawnlist } end
|
||||
|
||||
spawnmenu.AddPropCategory( "settings/spawnlist/" .. spawnlist, content.information.name, contents, "icon16/page.png", sid + id, sid )
|
||||
|
||||
end
|
||||
|
||||
end )
|
||||
@@ -0,0 +1,790 @@
|
||||
-- Extended Spawnmenu - Клиентская часть (звуки и материалы)
|
||||
local PLUGIN = PLUGIN
|
||||
|
||||
local cl_addTabs = CreateClientConVar("rb655_create_sm_tabs", "0", true, true)
|
||||
|
||||
--[[local function removeOldTabls()
|
||||
for k, v in pairs( g_SpawnMenu.CreateMenu.Items ) do
|
||||
if (v.Tab:GetText() == language.GetPhrase( "spawnmenu.category.npcs" ) or
|
||||
v.Tab:GetText() == language.GetPhrase( "spawnmenu.category.entities" ) or
|
||||
v.Tab:GetText() == language.GetPhrase( "spawnmenu.category.weapons" ) or
|
||||
v.Tab:GetText() == language.GetPhrase( "spawnmenu.category.vehicles" ) or
|
||||
v.Tab:GetText() == language.GetPhrase( "spawnmenu.category.postprocess" ) ) then
|
||||
g_SpawnMenu.CreateMenu:CloseTab( v.Tab, true )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
hook.Add( "PopulateContent", "rb655_extended_spawnmenu", function( pnlContent, tree, node )
|
||||
removeOldTabls() removeOldTabls() removeOldTabls() -- For some reason it doesn't work with only one call
|
||||
end )]]
|
||||
|
||||
local function getGameList()
|
||||
local games = engine.GetGames()
|
||||
table.insert( games, {
|
||||
title = "All",
|
||||
folder = "GAME",
|
||||
icon = "all",
|
||||
mounted = true
|
||||
} )
|
||||
table.insert( games, {
|
||||
title = "Garry's Mod",
|
||||
folder = "garrysmod",
|
||||
mounted = true
|
||||
} )
|
||||
return games
|
||||
end
|
||||
|
||||
--[[ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ]]
|
||||
|
||||
local theSound = nil
|
||||
|
||||
function rb655_playsound( snd )
|
||||
|
||||
if ( theSound ) then theSound:Stop() end
|
||||
|
||||
theSound = CreateSound( LocalPlayer(), snd )
|
||||
theSound:Play()
|
||||
|
||||
end
|
||||
|
||||
net.Receive( "rb655_playsound", function( len )
|
||||
rb655_playsound( net.ReadString() )
|
||||
end )
|
||||
|
||||
spawnmenu.AddContentType( "sound", function( container, obj )
|
||||
if ( !obj.nicename ) then return end
|
||||
if ( !obj.spawnname ) then return end
|
||||
|
||||
local icon = vgui.Create( "ContentIcon", container )
|
||||
icon:SetContentType( "sound" )
|
||||
icon:SetSpawnName( obj.spawnname )
|
||||
icon:SetName( obj.nicename )
|
||||
icon:SetMaterial( "icon16/sound.png" )
|
||||
|
||||
icon.DoClick = function()
|
||||
rb655_playsound( obj.spawnname )
|
||||
end
|
||||
|
||||
icon.OpenMenu = function( icn )
|
||||
local menu = DermaMenu()
|
||||
menu:AddOption( "#spawnmenu.menu.copy", function() SetClipboardText( obj.spawnname ) end ):SetIcon( "icon16/page_copy.png" )
|
||||
menu:AddOption( "Play on all clients", function() RunConsoleCommand( "rb655_playsound_all", obj.spawnname ) end ):SetIcon( "icon16/sound.png" )
|
||||
menu:AddOption( "Stop all sounds", function() RunConsoleCommand( "stopsound" ) end ):SetIcon( "icon16/sound_mute.png" )
|
||||
menu:AddSpacer()
|
||||
menu:AddOption( "#spawnmenu.menu.delete", function() icn:Remove() hook.Run( "SpawnlistContentChanged", icn ) end ):SetIcon( "icon16/bin_closed.png" )
|
||||
menu:Open()
|
||||
end
|
||||
|
||||
if ( IsValid( container ) ) then
|
||||
container:Add( icon )
|
||||
end
|
||||
|
||||
return icon
|
||||
|
||||
end )
|
||||
|
||||
local function OnSndNodeSelected( self, node, name, path, pathid, icon, ViewPanel, pnlContent )
|
||||
|
||||
ViewPanel:Clear( true )
|
||||
|
||||
local Path = node:GetFolder()
|
||||
|
||||
local files = file.Find( Path .. "/*.wav", node:GetPathID() )
|
||||
files = table.Add( files, file.Find( Path .. "/*.mp3", node:GetPathID() ) )
|
||||
files = table.Add( files, file.Find( Path .. "/*.ogg", node:GetPathID() ) )
|
||||
|
||||
local offset = 0
|
||||
local limit = 512
|
||||
if ( node.offset ) then offset = node.offset or 0 end
|
||||
|
||||
for k, v in pairs( files ) do
|
||||
if ( k > limit + offset ) then
|
||||
if ( !node.Done ) then
|
||||
offset = offset + limit
|
||||
local mats = ( self.Parent or node ):AddNode( ( self.Text or node:GetText() ) .. " (" .. offset .. " - " .. offset + limit .. ")" )
|
||||
mats:SetFolder( node:GetFolder() )
|
||||
mats.Text = self.Text or node:GetText()
|
||||
mats.Parent = self.Parent or node
|
||||
mats:SetPathID( node:GetPathID() )
|
||||
mats:SetIcon( node:GetIcon() )
|
||||
mats.offset = offset
|
||||
mats.OnNodeSelected = function( mats_self, mats_node )
|
||||
OnSndNodeSelected( mats_self, mats_node, mats_self.Text, mats_node:GetFolder(), mats_node:GetPathID(), mats_node:GetIcon(), ViewPanel, pnlContent )
|
||||
end
|
||||
end
|
||||
node.Done = true
|
||||
break end
|
||||
if ( k <= offset ) then continue end
|
||||
|
||||
local p = Path .. "/"
|
||||
if ( string.StartWith( path, "addons/" ) or string.StartWith( path, "download/" ) ) then
|
||||
p = string.sub( p, string.find( p, "/sound/" ) + 1 )
|
||||
end
|
||||
|
||||
p = string.sub( p .. v, 7 )
|
||||
|
||||
spawnmenu.CreateContentIcon( "sound", ViewPanel, { spawnname = p, nicename = string.Trim( v ) } )
|
||||
|
||||
end
|
||||
|
||||
pnlContent:SwitchPanel( ViewPanel )
|
||||
|
||||
end
|
||||
|
||||
local function AddBrowseContentSnd( node, name, icon, path, pathid )
|
||||
|
||||
local ViewPanel = node.ViewPanel
|
||||
local pnlContent = node.pnlContent
|
||||
|
||||
if ( !string.EndsWith( path, "/" ) && string.len( path ) > 1 ) then path = path .. "/" end
|
||||
|
||||
local fi, fo = file.Find( path .. "sound", pathid )
|
||||
if ( !fo && !fi ) then return end
|
||||
|
||||
local sounds = node:AddFolder( name, path .. "sound", pathid, false, false, "*.*" )
|
||||
sounds:SetIcon( icon )
|
||||
|
||||
sounds.OnNodeSelected = function( self, node_sel )
|
||||
OnSndNodeSelected( self, node_sel, name, path, pathid, icon, ViewPanel, pnlContent )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
language.Add( "spawnmenu.category.browsesounds", "Browse Sounds" )
|
||||
|
||||
local function RefreshAddonSounds( browseAddonSounds )
|
||||
for _, addon in SortedPairsByMemberValue( engine.GetAddons(), "title" ) do
|
||||
|
||||
if ( !addon.downloaded ) then continue end
|
||||
if ( !addon.mounted ) then continue end
|
||||
if ( !table.HasValue( select( 2, file.Find( "*", addon.title ) ), "sound" ) ) then continue end
|
||||
|
||||
AddBrowseContentSnd( browseAddonSounds, addon.title, "icon16/bricks.png", "", addon.title )
|
||||
end
|
||||
end
|
||||
local function RefreshGameSounds( browseGameSounds )
|
||||
local games = getGameList()
|
||||
|
||||
for _, game in SortedPairsByMemberValue( games, "title" ) do
|
||||
if ( !game.mounted ) then continue end
|
||||
AddBrowseContentSnd( browseGameSounds, game.title, "games/16/" .. ( game.icon or game.folder ) .. ".png", "", game.folder )
|
||||
end
|
||||
end
|
||||
|
||||
local browseGameSounds
|
||||
local browseAddonSounds
|
||||
hook.Add( "PopulateContent", "SpawnmenuLoadSomeSounds", function( pnlContent, tree, browseNode ) timer.Simple( 0.5, function()
|
||||
|
||||
if ( !IsValid( tree ) or !IsValid( pnlContent ) ) then
|
||||
print( "!!! Extended Spawnmenu: FAILED TO INITALIZE PopulateContent HOOK FOR SOUNDS !!!" )
|
||||
print( "!!! Extended Spawnmenu: FAILED TO INITALIZE PopulateContent HOOK FOR SOUNDS !!!" )
|
||||
print( "!!! Extended Spawnmenu: FAILED TO INITALIZE PopulateContent HOOK FOR SOUNDS !!!" )
|
||||
return
|
||||
end
|
||||
|
||||
local ViewPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
ViewPanel:SetVisible( false )
|
||||
|
||||
local browseSounds = tree:AddNode( "#spawnmenu.category.browsesounds", "icon16/sound.png" )
|
||||
browseSounds.ViewPanel = ViewPanel
|
||||
browseSounds.pnlContent = pnlContent
|
||||
|
||||
--[[ --------------------------------------------------------------------------------------- ]]
|
||||
|
||||
browseAddonSounds = browseSounds:AddNode( "#spawnmenu.category.addons", "icon16/folder_database.png" )
|
||||
browseAddonSounds.ViewPanel = ViewPanel
|
||||
browseAddonSounds.pnlContent = pnlContent
|
||||
|
||||
RefreshAddonSounds( browseAddonSounds )
|
||||
|
||||
--[[ --------------------------------------------------------------------------------------- ]]
|
||||
|
||||
local addon_sounds = {}
|
||||
local _, snd_folders = file.Find( "addons/*", "MOD" )
|
||||
for _, addon in SortedPairs( snd_folders ) do
|
||||
|
||||
if ( !file.IsDir( "addons/" .. addon .. "/sound/", "MOD" ) ) then continue end
|
||||
|
||||
table.insert( addon_sounds, addon )
|
||||
|
||||
end
|
||||
|
||||
local browseLegacySounds = browseSounds:AddNode( "#spawnmenu.category.addonslegacy", "icon16/folder_database.png" )
|
||||
browseLegacySounds.ViewPanel = ViewPanel
|
||||
browseLegacySounds.pnlContent = pnlContent
|
||||
|
||||
for _, addon in SortedPairsByValue( addon_sounds ) do
|
||||
|
||||
AddBrowseContentSnd( browseLegacySounds, addon, "icon16/bricks.png", "addons/" .. addon .. "/", "MOD" )
|
||||
|
||||
end
|
||||
|
||||
--[[ --------------------------------------------------------------------------------------- ]]
|
||||
|
||||
AddBrowseContentSnd( browseSounds, "#spawnmenu.category.downloads", "icon16/folder_database.png", "download/", "MOD" )
|
||||
|
||||
--[[ --------------------------------------------------------------------------------------- ]]
|
||||
|
||||
browseGameSounds = browseSounds:AddNode( "#spawnmenu.category.games", "icon16/folder_database.png" )
|
||||
browseGameSounds.ViewPanel = ViewPanel
|
||||
browseGameSounds.pnlContent = pnlContent
|
||||
|
||||
RefreshGameSounds( browseGameSounds )
|
||||
|
||||
end ) end )
|
||||
|
||||
hook.Add( "GameContentChanged", "ES_RefreshSpawnmenuSounds", function()
|
||||
|
||||
if ( IsValid( browseAddonSounds ) ) then
|
||||
|
||||
-- TODO: Maybe be more advaced and do not delete => recreate all the nodes, only delete nodes for addons that were removed, add only the new ones?
|
||||
browseAddonSounds:Clear()
|
||||
browseAddonSounds.ViewPanel:Clear( true )
|
||||
|
||||
RefreshAddonSounds( browseAddonSounds )
|
||||
|
||||
end
|
||||
|
||||
if ( IsValid( browseGameSounds ) ) then
|
||||
|
||||
-- TODO: Maybe be more advaced and do not delete => recreate all the nodes, only delete nodes for addons that were removed, add only the new ones?
|
||||
browseGameSounds:Clear()
|
||||
browseGameSounds.ViewPanel:Clear( true )
|
||||
|
||||
RefreshGameSounds( browseGameSounds )
|
||||
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
--[[ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ]]
|
||||
|
||||
local function IsMaterialUsableOnEntities( matPath )
|
||||
-- A png file? No thanks
|
||||
if ( string.GetExtensionFromFilename( matPath ) ) then return false end
|
||||
|
||||
local mat = Material( matPath )
|
||||
if ( !string.find( mat:GetShader(), "LightmappedGeneric" )
|
||||
&& !string.find( mat:GetShader(), "WorldVertexTransition" )
|
||||
&& !string.find( mat:GetShader(), "Spritecard" )
|
||||
&& !string.find( mat:GetShader(), "Water" )
|
||||
&& !string.find( mat:GetShader(), "Cable" )
|
||||
--&& !string.find( mat:GetShader(), "UnlitGeneric" )
|
||||
&& !string.find( mat:GetShader(), "Refract" ) ) then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local DisplayedWarning = false
|
||||
local function DisplayOneTimeWarning()
|
||||
if ( DisplayedWarning ) then return end
|
||||
DisplayedWarning = true
|
||||
|
||||
Derma_Message( "Please note that not all materials are usable on entities, such as map textures, etc.\nYou can still try though!", "Warning", "OK" )
|
||||
end
|
||||
|
||||
spawnmenu.AddContentType( "material", function( container, obj )
|
||||
if ( !obj.nicename ) then return end
|
||||
if ( !obj.spawnname ) then return end
|
||||
|
||||
local icon = vgui.Create( "ContentIcon", container )
|
||||
icon:SetContentType( "material" )
|
||||
icon:SetSpawnName( obj.spawnname )
|
||||
icon:SetName( obj.nicename )
|
||||
if ( string.GetExtensionFromFilename( obj.spawnname ) == "png" ) then
|
||||
icon:SetMaterial( obj.spawnname )
|
||||
else
|
||||
icon.Image:SetImage( obj.spawnname )
|
||||
end
|
||||
|
||||
icon.DoClick = function()
|
||||
if ( !IsMaterialUsableOnEntities( obj.spawnname ) ) then DisplayOneTimeWarning() end
|
||||
|
||||
RunConsoleCommand( "material_override", obj.spawnname )
|
||||
spawnmenu.ActivateTool( "material" )
|
||||
surface.PlaySound( "garrysmod/ui_click.wav" )
|
||||
end
|
||||
|
||||
icon.OpenMenu = function( icn )
|
||||
local menu = DermaMenu()
|
||||
menu:AddOption( "#spawnmenu.menu.copy", function() SetClipboardText( obj.spawnname ) end ):SetIcon( "icon16/page_copy.png" )
|
||||
|
||||
local str = "Use with Material Tool"
|
||||
if ( !IsMaterialUsableOnEntities( obj.spawnname ) ) then
|
||||
str = "Try to use with Material Tool (Probably won't work)"
|
||||
end
|
||||
menu:AddOption( str, function()
|
||||
RunConsoleCommand( "material_override", obj.spawnname )
|
||||
spawnmenu.ActivateTool( "material" )
|
||||
end ):SetIcon( "icon16/pencil.png" )
|
||||
|
||||
menu:AddSpacer()
|
||||
menu:AddOption( "#spawnmenu.menu.delete", function() icn:Remove() hook.Run( "SpawnlistContentChanged", icn ) end ):SetIcon( "icon16/bin_closed.png" )
|
||||
menu:Open()
|
||||
end
|
||||
|
||||
if ( IsValid( container ) ) then
|
||||
container:Add( icon )
|
||||
end
|
||||
|
||||
return icon
|
||||
|
||||
end )
|
||||
|
||||
local function OnMatNodeSelected( self, node, name, path, pathid, icon, ViewPanel, pnlContent )
|
||||
|
||||
ViewPanel:Clear( true )
|
||||
|
||||
local Path = node:GetFolder()
|
||||
|
||||
local mat_files = file.Find( Path .. "/*.vmt", node:GetPathID() )
|
||||
mat_files = table.Add( mat_files, file.Find( Path .. "/*.png", node:GetPathID() ) )
|
||||
|
||||
local offset = 0
|
||||
local limit = 512
|
||||
if ( node.offset ) then offset = node.offset or 0 end
|
||||
|
||||
for k, v in pairs( mat_files ) do
|
||||
if ( k > limit + offset ) then
|
||||
if ( !node.Done ) then
|
||||
offset = offset + limit
|
||||
local mats = ( self.Parent or node ):AddNode( ( self.Text or node:GetText() ) .. " (" .. offset .. " - " .. offset + limit .. ")" )
|
||||
mats:SetFolder( node:GetFolder() )
|
||||
mats.Text = self.Text or node:GetText()
|
||||
mats.Parent = self.Parent or node
|
||||
mats:SetPathID( node:GetPathID() )
|
||||
mats:SetIcon( node:GetIcon() )
|
||||
mats.offset = offset
|
||||
mats.OnNodeSelected = function( self_mats, node_sel )
|
||||
OnMatNodeSelected( self_mats, node_sel, self_mats.Text, node_sel:GetFolder(), node_sel:GetPathID(), node_sel:GetIcon(), ViewPanel, pnlContent )
|
||||
end
|
||||
end
|
||||
node.Done = true
|
||||
break end
|
||||
if ( k <= offset ) then continue end
|
||||
|
||||
local p = Path .. "/"
|
||||
if ( string.StartWith( path, "addons/" ) or string.StartWith( path, "download/" ) ) then
|
||||
p = string.sub( p, string.find( p, "/materials/" ) + 1 )
|
||||
end
|
||||
|
||||
p = string.sub( p .. v, 11 )
|
||||
|
||||
if ( string.GetExtensionFromFilename( p ) == "vmt" ) then
|
||||
p = string.StripExtension( p )
|
||||
v = string.StripExtension( v )
|
||||
end
|
||||
|
||||
if ( Material( p ):GetShader() == "Spritecard" ) then continue end
|
||||
|
||||
spawnmenu.CreateContentIcon( "material", ViewPanel, { spawnname = p, nicename = v } )
|
||||
end
|
||||
|
||||
pnlContent:SwitchPanel( ViewPanel )
|
||||
|
||||
end
|
||||
|
||||
local function AddBrowseContentMaterial( node, name, icon, path, pathid )
|
||||
|
||||
local ViewPanel = node.ViewPanel
|
||||
local pnlContent = node.pnlContent
|
||||
|
||||
if ( !string.EndsWith( path, "/" ) && string.len( path ) > 1 ) then path = path .. "/" end
|
||||
|
||||
local fi, fo = file.Find( path .. "materials", pathid )
|
||||
if ( !fi && !fo ) then return end
|
||||
|
||||
local materials = node:AddFolder( name, path .. "materials", pathid, false, false, "*.*" )
|
||||
materials:SetIcon( icon )
|
||||
|
||||
materials.OnNodeSelected = function( self, node_sel )
|
||||
OnMatNodeSelected( self, node_sel, name, path, pathid, icon, ViewPanel, pnlContent )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
language.Add( "spawnmenu.category.browsematerials", "Browse Materials" )
|
||||
|
||||
local function RefreshAddonMaterials( node )
|
||||
for _, addon in SortedPairsByMemberValue( engine.GetAddons(), "title" ) do
|
||||
|
||||
if ( !addon.downloaded ) then continue end
|
||||
if ( !addon.mounted ) then continue end
|
||||
if ( !table.HasValue( select( 2, file.Find( "*", addon.title ) ), "materials" ) ) then continue end
|
||||
|
||||
AddBrowseContentMaterial( node, addon.title, "icon16/bricks.png", "", addon.title )
|
||||
|
||||
end
|
||||
end
|
||||
local function RefreshGameMaterials( node )
|
||||
local games = getGameList()
|
||||
|
||||
for _, game in SortedPairsByMemberValue( games, "title" ) do
|
||||
if ( !game.mounted ) then continue end
|
||||
AddBrowseContentMaterial( node, game.title, "games/16/" .. ( game.icon or game.folder ) .. ".png", "", game.folder )
|
||||
end
|
||||
end
|
||||
|
||||
local browseAddonMaterials
|
||||
local browseGameMaterials
|
||||
hook.Add( "PopulateContent", "SpawnmenuLoadSomeMaterials", function( pnlContent, tree, browseNode ) timer.Simple( 0.5, function()
|
||||
|
||||
if ( !IsValid( tree ) or !IsValid( pnlContent ) ) then
|
||||
print( "!!! Extended Spawnmenu: FAILED TO INITALIZE PopulateContent HOOK FOR MATERIALS!!!" )
|
||||
print( "!!! Extended Spawnmenu: FAILED TO INITALIZE PopulateContent HOOK FOR MATERIALS!!!" )
|
||||
print( "!!! Extended Spawnmenu: FAILED TO INITALIZE PopulateContent HOOK FOR MATERIALS!!!" )
|
||||
return
|
||||
end
|
||||
|
||||
local ViewPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
ViewPanel:SetVisible( false )
|
||||
|
||||
local browseMaterials = tree:AddNode( "#spawnmenu.category.browsematerials", "icon16/picture_empty.png" )
|
||||
browseMaterials.ViewPanel = ViewPanel
|
||||
browseMaterials.pnlContent = pnlContent
|
||||
|
||||
--[[ --------------------------------------------------------------------------------------- ]]
|
||||
|
||||
browseAddonMaterials = browseMaterials:AddNode( "#spawnmenu.category.addons", "icon16/folder_database.png" )
|
||||
browseAddonMaterials.ViewPanel = ViewPanel
|
||||
browseAddonMaterials.pnlContent = pnlContent
|
||||
|
||||
RefreshAddonMaterials( browseAddonMaterials )
|
||||
|
||||
--[[ --------------------------------------------------------------------------------------- ]]
|
||||
|
||||
local addon_mats = {}
|
||||
local _, mat_folders = file.Find( "addons/*", "MOD" )
|
||||
for _, addon in SortedPairs( mat_folders ) do
|
||||
|
||||
if ( !file.IsDir( "addons/" .. addon .. "/materials/", "MOD" ) ) then continue end
|
||||
|
||||
table.insert( addon_mats, addon )
|
||||
|
||||
end
|
||||
|
||||
local browseLegacyMaterials = browseMaterials:AddNode( "#spawnmenu.category.addonslegacy", "icon16/folder_database.png" )
|
||||
browseLegacyMaterials.ViewPanel = ViewPanel
|
||||
browseLegacyMaterials.pnlContent = pnlContent
|
||||
|
||||
for _, addon in SortedPairsByValue( addon_mats ) do
|
||||
|
||||
AddBrowseContentMaterial( browseLegacyMaterials, addon, "icon16/bricks.png", "addons/" .. addon .. "/", "MOD" )
|
||||
|
||||
end
|
||||
|
||||
--[[ --------------------------------------------------------------------------------------- ]]
|
||||
|
||||
AddBrowseContentMaterial( browseMaterials, "#spawnmenu.category.downloads", "icon16/folder_database.png", "download/", "MOD" )
|
||||
|
||||
--[[ --------------------------------------------------------------------------------------- ]]
|
||||
|
||||
browseGameMaterials = browseMaterials:AddNode( "#spawnmenu.category.games", "icon16/folder_database.png" )
|
||||
browseGameMaterials.ViewPanel = ViewPanel
|
||||
browseGameMaterials.pnlContent = pnlContent
|
||||
|
||||
RefreshGameMaterials( browseGameMaterials )
|
||||
|
||||
end ) end )
|
||||
|
||||
hook.Add( "GameContentChanged", "ES_RefreshSpawnmenuMaterials", function()
|
||||
|
||||
if ( IsValid( browseAddonMaterials ) ) then
|
||||
|
||||
-- TODO: Maybe be more advaced and do not delete => recreate all the nodes, only delete nodes for addons that were removed, add only the new ones?
|
||||
browseAddonMaterials:Clear()
|
||||
browseAddonMaterials.ViewPanel:Clear( true )
|
||||
|
||||
RefreshAddonMaterials( browseAddonMaterials )
|
||||
|
||||
end
|
||||
|
||||
if ( IsValid( browseGameMaterials ) ) then
|
||||
|
||||
-- TODO: Maybe be more advaced and do not delete => recreate all the nodes, only delete nodes for addons that were removed, add only the new ones?
|
||||
browseGameMaterials:Clear()
|
||||
browseGameMaterials.ViewPanel:Clear( true )
|
||||
|
||||
RefreshGameMaterials( browseGameMaterials )
|
||||
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
--[[ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ]]
|
||||
--[[ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ]]
|
||||
--[[ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ]]
|
||||
--[[ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ]]
|
||||
--[[ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ]]
|
||||
|
||||
hook.Add( "PopulateContent", "rb655_extended_spawnmenu_entities", function( pnlContent, tree, node )
|
||||
if ( !cl_addTabs:GetBool() ) then return end
|
||||
|
||||
local node_w = tree:AddNode( "#spawnmenu.category.entities", "icon16/bricks.png" )
|
||||
|
||||
node_w.PropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
node_w.PropPanel:SetVisible( false )
|
||||
|
||||
function node_w:DoClick()
|
||||
pnlContent:SwitchPanel( self.PropPanel )
|
||||
end
|
||||
|
||||
local Categorised = {}
|
||||
|
||||
local SpawnableEntities = list.Get( "SpawnableEntities" )
|
||||
if ( SpawnableEntities ) then
|
||||
for k, v in pairs( SpawnableEntities ) do
|
||||
v.Category = v.Category or "Other"
|
||||
Categorised[ v.Category ] = Categorised[ v.Category ] or {}
|
||||
table.insert( Categorised[ v.Category ], v )
|
||||
end
|
||||
end
|
||||
|
||||
for CategoryName, v in SortedPairs( Categorised ) do
|
||||
|
||||
local node_new = node_w:AddNode( CategoryName, "icon16/bricks.png" )
|
||||
|
||||
local CatPropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
CatPropPanel:SetVisible( false )
|
||||
|
||||
local Header = vgui.Create("ContentHeader", node_w.PropPanel )
|
||||
Header:SetText( CategoryName )
|
||||
node_w.PropPanel:Add( Header )
|
||||
|
||||
for k, ent in SortedPairsByMemberValue( v, "PrintName" ) do
|
||||
local t = {
|
||||
nicename = ent.PrintName or ent.ClassName,
|
||||
spawnname = ent.ClassName,
|
||||
material = "entities/" .. ent.ClassName .. ".png",
|
||||
admin = ent.AdminOnly
|
||||
}
|
||||
spawnmenu.CreateContentIcon( ent.ScriptedEntityType or "entity", CatPropPanel, t )
|
||||
spawnmenu.CreateContentIcon( ent.ScriptedEntityType or "entity", node_w.PropPanel, t )
|
||||
end
|
||||
|
||||
function node_new:DoClick()
|
||||
pnlContent:SwitchPanel( CatPropPanel )
|
||||
end
|
||||
|
||||
end
|
||||
end )
|
||||
|
||||
hook.Add( "PopulateContent", "rb655_extended_spawnmenu_post_processing", function( pnlContent, tree, node )
|
||||
if ( !cl_addTabs:GetBool() ) then return end
|
||||
|
||||
local node_w = tree:AddNode( "#spawnmenu.category.postprocess", "icon16/picture.png" )
|
||||
|
||||
node_w.PropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
node_w.PropPanel:SetVisible( false )
|
||||
|
||||
function node_w:DoClick()
|
||||
pnlContent:SwitchPanel( self.PropPanel )
|
||||
end
|
||||
|
||||
-- Get the table
|
||||
|
||||
local Categorised = {}
|
||||
local PostProcess = list.Get( "PostProcess" )
|
||||
|
||||
if ( PostProcess ) then
|
||||
for k, v in pairs( PostProcess ) do
|
||||
v.category = v.category or "Other"
|
||||
v.name = k
|
||||
Categorised[ v.category ] = Categorised[ v.category ] or {}
|
||||
table.insert( Categorised[ v.category ], v )
|
||||
end
|
||||
end
|
||||
|
||||
-- Put table into panels
|
||||
for CategoryName, v in SortedPairs( Categorised ) do
|
||||
|
||||
local node_new = node_w:AddNode( CategoryName, "icon16/picture.png" )
|
||||
|
||||
local CatPropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
CatPropPanel:SetVisible( false )
|
||||
|
||||
local Header = vgui.Create( "ContentHeader", node_w.PropPanel )
|
||||
Header:SetText( CategoryName )
|
||||
node_w.PropPanel:Add( Header )
|
||||
|
||||
for k, pp in SortedPairsByMemberValue( v, "PrintName" ) do
|
||||
if ( pp.func ) then pp.func( CatPropPanel ) pp.func( node_w.PropPanel ) continue end
|
||||
|
||||
local t = {
|
||||
name = pp.name,
|
||||
icon = pp.icon
|
||||
}
|
||||
|
||||
spawnmenu.CreateContentIcon( "postprocess", CatPropPanel, t )
|
||||
spawnmenu.CreateContentIcon( "postprocess", node_w.PropPanel, t )
|
||||
end
|
||||
|
||||
function node_new:DoClick()
|
||||
pnlContent:SwitchPanel( CatPropPanel )
|
||||
end
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "PopulateContent", "rb655_extended_spawnmenu_npcs", function( pnlContent, tree, node )
|
||||
if ( !cl_addTabs:GetBool() ) then return end
|
||||
|
||||
local node_w = tree:AddNode( "#spawnmenu.category.npcs", "icon16/monkey.png" )
|
||||
|
||||
node_w.PropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
node_w.PropPanel:SetVisible( false )
|
||||
|
||||
function node_w:DoClick()
|
||||
pnlContent:SwitchPanel( self.PropPanel )
|
||||
end
|
||||
|
||||
local NPCList = list.Get( "NPC" )
|
||||
local Categories = {}
|
||||
|
||||
for k, v in pairs( NPCList ) do
|
||||
local Category = v.Category or "Other"
|
||||
local Tab = Categories[ Category ] or {}
|
||||
|
||||
Tab[ k ] = v
|
||||
|
||||
Categories[ Category ] = Tab
|
||||
end
|
||||
|
||||
for CategoryName, v in SortedPairs( Categories ) do
|
||||
|
||||
local node_new = node_w:AddNode( CategoryName, "icon16/monkey.png" )
|
||||
|
||||
local CatPropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
CatPropPanel:SetVisible( false )
|
||||
|
||||
local Header = vgui.Create("ContentHeader", node_w.PropPanel )
|
||||
Header:SetText( CategoryName )
|
||||
node_w.PropPanel:Add( Header )
|
||||
|
||||
for name, ent in SortedPairsByMemberValue( v, "Name" ) do
|
||||
local t = {
|
||||
nicename = ent.Name or name,
|
||||
spawnname = name,
|
||||
material = "entities/" .. name .. ".png",
|
||||
weapon = ent.Weapons,
|
||||
admin = ent.AdminOnly
|
||||
}
|
||||
spawnmenu.CreateContentIcon( "npc", CatPropPanel, t )
|
||||
spawnmenu.CreateContentIcon( "npc", node_w.PropPanel, t )
|
||||
end
|
||||
|
||||
function node_new:DoClick()
|
||||
pnlContent:SwitchPanel( CatPropPanel )
|
||||
end
|
||||
|
||||
end
|
||||
end )
|
||||
|
||||
hook.Add( "PopulateContent", "rb655_extended_spawnmenu_vehicles", function( pnlContent, tree, node )
|
||||
if ( !cl_addTabs:GetBool() ) then return end
|
||||
|
||||
local node_w = tree:AddNode( "#spawnmenu.category.vehicles", "icon16/car.png" )
|
||||
|
||||
node_w.PropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
node_w.PropPanel:SetVisible( false )
|
||||
|
||||
function node_w:DoClick()
|
||||
pnlContent:SwitchPanel( self.PropPanel )
|
||||
end
|
||||
|
||||
local Categorised = {}
|
||||
local Vehicles = list.Get( "Vehicles" )
|
||||
if ( Vehicles ) then
|
||||
for k, v in pairs( Vehicles ) do
|
||||
v.Category = v.Category or "Other"
|
||||
Categorised[ v.Category ] = Categorised[ v.Category ] or {}
|
||||
v.ClassName = k
|
||||
v.PrintName = v.Name
|
||||
v.ScriptedEntityType = "vehicle"
|
||||
table.insert( Categorised[ v.Category ], v )
|
||||
end
|
||||
end
|
||||
|
||||
for CategoryName, v in SortedPairs( Categorised ) do
|
||||
|
||||
local node_new = node_w:AddNode( CategoryName, "icon16/car.png" )
|
||||
|
||||
local CatPropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
CatPropPanel:SetVisible( false )
|
||||
|
||||
local Header = vgui.Create("ContentHeader", node_w.PropPanel )
|
||||
Header:SetText( CategoryName )
|
||||
node_w.PropPanel:Add( Header )
|
||||
|
||||
for k, ent in SortedPairsByMemberValue( v, "PrintName" ) do
|
||||
local t = {
|
||||
nicename = ent.PrintName or ent.ClassName,
|
||||
spawnname = ent.ClassName,
|
||||
material = "entities/" .. ent.ClassName .. ".png",
|
||||
admin = ent.AdminOnly
|
||||
}
|
||||
spawnmenu.CreateContentIcon( ent.ScriptedEntityType or "entity", node_w.PropPanel, t )
|
||||
spawnmenu.CreateContentIcon( ent.ScriptedEntityType or "entity", CatPropPanel, t )
|
||||
end
|
||||
|
||||
function node_new:DoClick()
|
||||
pnlContent:SwitchPanel( CatPropPanel )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "PopulateContent", "rb655_extended_spawnmenu_weapons", function( pnlContent, tree, node )
|
||||
if ( !cl_addTabs:GetBool() ) then return end
|
||||
|
||||
local node_w = tree:AddNode( "#spawnmenu.category.weapons", "icon16/gun.png" )
|
||||
|
||||
node_w.PropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
node_w.PropPanel:SetVisible( false )
|
||||
|
||||
function node_w:DoClick()
|
||||
pnlContent:SwitchPanel( self.PropPanel )
|
||||
end
|
||||
|
||||
local Weapons = list.Get( "Weapon" )
|
||||
local Categorised = {}
|
||||
|
||||
for k, weapon in pairs( Weapons ) do
|
||||
if ( !weapon.Spawnable && !weapon.AdminSpawnable ) then continue end
|
||||
|
||||
Categorised[ weapon.Category ] = Categorised[ weapon.Category ] or {}
|
||||
table.insert( Categorised[ weapon.Category ], weapon )
|
||||
end
|
||||
|
||||
for CategoryName, v in SortedPairs( Categorised ) do
|
||||
local node_new = node_w:AddNode( CategoryName, "icon16/gun.png" )
|
||||
|
||||
local CatPropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
CatPropPanel:SetVisible( false )
|
||||
|
||||
local Header = vgui.Create("ContentHeader", node_w.PropPanel )
|
||||
Header:SetText( CategoryName )
|
||||
node_w.PropPanel:Add( Header )
|
||||
|
||||
for k, ent in SortedPairsByMemberValue( v, "PrintName" ) do
|
||||
local t = {
|
||||
nicename = ent.PrintName or ent.ClassName,
|
||||
spawnname = ent.ClassName,
|
||||
material = "entities/" .. ent.ClassName .. ".png",
|
||||
admin = ent.AdminOnly
|
||||
}
|
||||
spawnmenu.CreateContentIcon( ent.ScriptedEntityType or "weapon", CatPropPanel, t )
|
||||
spawnmenu.CreateContentIcon( ent.ScriptedEntityType or "weapon", node_w.PropPanel, t )
|
||||
end
|
||||
|
||||
function node_new:DoClick()
|
||||
pnlContent:SwitchPanel( CatPropPanel )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end )
|
||||
@@ -0,0 +1,39 @@
|
||||
PLUGIN.name = "Extended Spawnmenu"
|
||||
PLUGIN.author = "RB655 (Портирован для Helix)"
|
||||
PLUGIN.description = "Расширенное спавн-меню с поддержкой звуков и legacy аддонов"
|
||||
|
||||
ix.util.Include("cl_spawnmenu.lua")
|
||||
ix.util.Include("cl_legacy.lua")
|
||||
-- Конфигурация
|
||||
ix.config.Add("extSpawnmenuEnabled", true, "Включить расширенное спавн-меню", nil, {
|
||||
category = "Extended Spawnmenu"
|
||||
})
|
||||
|
||||
ix.config.Add("extSpawnmenuCreateTabs", false, "Создавать отдельные вкладки для категорий", nil, {
|
||||
category = "Extended Spawnmenu"
|
||||
})
|
||||
|
||||
-- Серверная часть
|
||||
if SERVER then
|
||||
util.AddNetworkString("rb655_playsound")
|
||||
|
||||
-- Команда для проигрывания звуков всем игрокам
|
||||
concommand.Add("rb655_playsound_all", function(ply, cmd, args)
|
||||
if not ply:IsSuperAdmin() or not args[1] or string.Trim(args[1]) == "" then return end
|
||||
|
||||
net.Start("rb655_playsound")
|
||||
net.WriteString(args[1] or "")
|
||||
net.Broadcast()
|
||||
end)
|
||||
end
|
||||
|
||||
-- Клиентская часть
|
||||
if CLIENT then
|
||||
-- ConVar для совместимости
|
||||
CreateClientConVar("rb655_create_sm_tabs", "0", true, true)
|
||||
end
|
||||
|
||||
function PLUGIN:Initialize()
|
||||
print("[Extended Spawnmenu] Расширенное спавн-меню загружено!")
|
||||
print("[Extended Spawnmenu] Добавлены: Browse Sounds, Materials, Legacy Addons")
|
||||
end
|
||||
Reference in New Issue
Block a user