forked from TeamUlysses/ulx
Normalizing line endings
This commit is contained in:
parent
73abcc103d
commit
37771eb26b
22
addon.txt
22
addon.txt
@ -1,11 +1,11 @@
|
||||
"AddonInfo"
|
||||
{
|
||||
"name" "ULX"
|
||||
"version" "3.70"
|
||||
"up_date" "00/00/00"
|
||||
"author_name" "Team Ulysses"
|
||||
"author_email" "teamulysses@ulyssesmod.net"
|
||||
"author_url" "http://www.ulyssesmod.net/"
|
||||
"info" "Advanced Admin Mod"
|
||||
"override" "0"
|
||||
}
|
||||
"AddonInfo"
|
||||
{
|
||||
"name" "ULX"
|
||||
"version" "3.70"
|
||||
"up_date" "00/00/00"
|
||||
"author_name" "Team Ulysses"
|
||||
"author_email" "teamulysses@ulyssesmod.net"
|
||||
"author_url" "http://www.ulyssesmod.net/"
|
||||
"info" "Advanced Admin Mod"
|
||||
"override" "0"
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
;ATTENTION! /ADDONS/ulx/data/ulx/<this file> is a DEFAULT file. DO NOT EDIT THE /ADDONS/ULX/DATA/ULX FOLDER FILE!!!
|
||||
; Instead, edit the version in <garrysmod root>/data/ulx/ if it exists. If it doesn't, copy this file to <gmod root>/data/ulx/ to create it.
|
||||
; You can add forced downloads here. Add as many as you want, one file or
|
||||
; folder per line. You can also add these to your map- or game-specific files.
|
||||
; You can add a folder to add all files inside that folder recursively.
|
||||
; Any line starting with ';' is a comment and WILL NOT be processed!!!
|
||||
; Examples:
|
||||
;sound/cheeseman.mp3 <-- Adds the file 'cheeseman.mp3' under the sound folder
|
||||
;ATTENTION! /ADDONS/ulx/data/ulx/<this file> is a DEFAULT file. DO NOT EDIT THE /ADDONS/ULX/DATA/ULX FOLDER FILE!!!
|
||||
; Instead, edit the version in <garrysmod root>/data/ulx/ if it exists. If it doesn't, copy this file to <gmod root>/data/ulx/ to create it.
|
||||
; You can add forced downloads here. Add as many as you want, one file or
|
||||
; folder per line. You can also add these to your map- or game-specific files.
|
||||
; You can add a folder to add all files inside that folder recursively.
|
||||
; Any line starting with ';' is a comment and WILL NOT be processed!!!
|
||||
; Examples:
|
||||
;sound/cheeseman.mp3 <-- Adds the file 'cheeseman.mp3' under the sound folder
|
||||
;sound/my_music <-- Adds all files within the my_music folder, inside the sound folder
|
@ -1,5 +1,5 @@
|
||||
if SERVER then
|
||||
include( "ulx/init.lua" )
|
||||
else
|
||||
include( "ulx/cl_init.lua" )
|
||||
end
|
||||
if SERVER then
|
||||
include( "ulx/init.lua" )
|
||||
else
|
||||
include( "ulx/cl_init.lua" )
|
||||
end
|
||||
|
240
lua/ulx/base.lua
240
lua/ulx/base.lua
@ -1,120 +1,120 @@
|
||||
--[[
|
||||
Title: Base
|
||||
|
||||
Sets up some things for ulx.
|
||||
]]
|
||||
|
||||
ulx.cvars = ulx.cvars or {} -- Used to decipher spaced cvars into actual implementation of underscored cvars (see below)
|
||||
|
||||
--[[
|
||||
Function: convar
|
||||
|
||||
This is what will set up ULX's convars, it makes them under the command "ulx"
|
||||
|
||||
Parameters:
|
||||
|
||||
command - The console command. IE, "sv_kickminge".
|
||||
value - The value to start off at.
|
||||
help - *(Optional)* A help string for using the command.
|
||||
access - *(Optional, defaults to ACCESS_ALL)* Restricted access.
|
||||
]]
|
||||
function ulx.convar( command, value, help, access )
|
||||
help = help or ""
|
||||
access = access or ULib.ACCESS_ALL
|
||||
ULib.ucl.registerAccess( "ulx " .. command, access, help, "Cvar" )
|
||||
|
||||
-- table.insert( ulx.convarhelp[ currentCategory ], { cmd=command, access=access, help=help } ) -- TODO
|
||||
|
||||
local nospaceCommand = command:gsub( " ", "_" )
|
||||
ulx.cvars[ command:lower() ] = { help=help, cvar=nospaceCommand, original=command }
|
||||
local cvarName = "ulx_" .. nospaceCommand
|
||||
local obj = ULib.replicatedWritableCvar( cvarName, cvarName, value, false, false, "ulx " .. command )
|
||||
|
||||
return obj
|
||||
end
|
||||
|
||||
function ulx.addToHelpManually( category, cmd, string, access_tag )
|
||||
ulx.cmdsByCategory[ category ] = ulx.cmdsByCategory[ category ] or {}
|
||||
for i, existingCmd in pairs( ulx.cmdsByCategory[ category ]) do
|
||||
if existingCmd.cmd == cmd and existingCmd.manual == true then
|
||||
table.remove( ulx.cmdsByCategory[ category ], i)
|
||||
break
|
||||
end
|
||||
end
|
||||
table.insert( ulx.cmdsByCategory[ category ], { access_tag=access_tag, cmd=cmd, helpStr=string, manual=true } )
|
||||
end
|
||||
|
||||
--------------------------------------
|
||||
--Now for boring initilization stuff--
|
||||
--------------------------------------
|
||||
|
||||
-- Setup the maps table
|
||||
do
|
||||
ulx.maps = {}
|
||||
local maps = file.Find( "maps/*.bsp", "GAME" )
|
||||
|
||||
for _, map in ipairs( maps ) do
|
||||
table.insert( ulx.maps, map:sub( 1, -5 ):lower() ) -- Take off the .bsp
|
||||
end
|
||||
table.sort( ulx.maps ) -- Make sure it's alphabetical
|
||||
|
||||
ulx.gamemodes = {}
|
||||
local fromEngine = engine.GetGamemodes()
|
||||
for i=1, #fromEngine do
|
||||
table.insert( ulx.gamemodes, fromEngine[ i ].name:lower() )
|
||||
end
|
||||
|
||||
table.sort( ulx.gamemodes ) -- Alphabetize
|
||||
end
|
||||
|
||||
ulx.common_kick_reasons = ulx.common_kick_reasons or {}
|
||||
function ulx.addKickReason( reason )
|
||||
table.insert( ulx.common_kick_reasons, reason )
|
||||
table.sort( ulx.common_kick_reasons )
|
||||
end
|
||||
|
||||
local function sendAutocompletes( ply )
|
||||
if ply:query( "ulx map" ) or ply:query( "ulx votemap2" ) then -- Only send if they have access to this.
|
||||
ULib.clientRPC( ply, "ulx.populateClMaps", ulx.maps )
|
||||
ULib.clientRPC( ply, "ulx.populateClGamemodes", ulx.gamemodes )
|
||||
end
|
||||
|
||||
ULib.clientRPC( ply, "ulx.populateClVotemaps", ulx.votemaps )
|
||||
ULib.clientRPC( ply, "ulx.populateKickReasons", ulx.common_kick_reasons )
|
||||
end
|
||||
hook.Add( ULib.HOOK_UCLAUTH, "sendAutoCompletes", sendAutocompletes )
|
||||
hook.Add( "PlayerInitialSpawn", "sendAutoCompletes", sendAutocompletes )
|
||||
|
||||
-- This will load ULX client side
|
||||
local function playerInit( ply )
|
||||
local _, v, r = ulx.getVersion()
|
||||
ULib.clientRPC( ply, "ulx.clInit", v, r )
|
||||
end
|
||||
hook.Add( "PlayerInitialSpawn", "ULXInitPlayer", playerInit )
|
||||
|
||||
-- Cvar saving
|
||||
function cvarChanged( sv_cvar, cl_cvar, ply, old_value, new_value )
|
||||
if not sv_cvar:find( "^ulx_" ) then return end
|
||||
local command = sv_cvar:gsub( "^ulx_", "" ):lower() -- Strip it off for lookup below
|
||||
if not ulx.cvars[ command ] then return end
|
||||
sv_cvar = ulx.cvars[ command ].original -- Make sure we have intended casing
|
||||
local path = "data/ulx/config.txt"
|
||||
if not ULib.fileExists( path ) then
|
||||
Msg( "[ULX ERROR] Config doesn't exist at " .. path .. "\n" )
|
||||
return
|
||||
end
|
||||
|
||||
sv_cvar = sv_cvar:gsub( "_", " " ) -- Convert back to space notation
|
||||
|
||||
if new_value:find( "[%s:']" ) then new_value = string.format( "%q", new_value ) end
|
||||
local replacement = string.format( "%s %s ", sv_cvar, new_value:gsub( "%%", "%%%%" ) ) -- Because we're feeding it through gsub below, need to expand '%'s
|
||||
local config = ULib.fileRead( path )
|
||||
config, found = config:gsub( ULib.makePatternSafe( sv_cvar ):gsub( "%a", function( c ) return "[" .. c:lower() .. c:upper() .. "]" end ) .. "%s+[^;\r\n]*", replacement ) -- The gsub makes us case neutral
|
||||
if found == 0 then -- Configuration option does not exist in config- append it
|
||||
newline = config:match("\r?\n")
|
||||
if not config:find("\r?\n$") then config = config .. newline end
|
||||
config = config .. "ulx " .. replacement .. "; " .. ulx.cvars[ command ].help .. newline
|
||||
end
|
||||
ULib.fileWrite( path, config )
|
||||
end
|
||||
hook.Add( ulx.HOOK_ULXDONELOADING, "AddCvarHook", function() hook.Add( ULib.HOOK_REPCVARCHANGED, "ULXCheckCvar", cvarChanged ) end ) -- We're not interested in changing cvars till after load
|
||||
--[[
|
||||
Title: Base
|
||||
|
||||
Sets up some things for ulx.
|
||||
]]
|
||||
|
||||
ulx.cvars = ulx.cvars or {} -- Used to decipher spaced cvars into actual implementation of underscored cvars (see below)
|
||||
|
||||
--[[
|
||||
Function: convar
|
||||
|
||||
This is what will set up ULX's convars, it makes them under the command "ulx"
|
||||
|
||||
Parameters:
|
||||
|
||||
command - The console command. IE, "sv_kickminge".
|
||||
value - The value to start off at.
|
||||
help - *(Optional)* A help string for using the command.
|
||||
access - *(Optional, defaults to ACCESS_ALL)* Restricted access.
|
||||
]]
|
||||
function ulx.convar( command, value, help, access )
|
||||
help = help or ""
|
||||
access = access or ULib.ACCESS_ALL
|
||||
ULib.ucl.registerAccess( "ulx " .. command, access, help, "Cvar" )
|
||||
|
||||
-- table.insert( ulx.convarhelp[ currentCategory ], { cmd=command, access=access, help=help } ) -- TODO
|
||||
|
||||
local nospaceCommand = command:gsub( " ", "_" )
|
||||
ulx.cvars[ command:lower() ] = { help=help, cvar=nospaceCommand, original=command }
|
||||
local cvarName = "ulx_" .. nospaceCommand
|
||||
local obj = ULib.replicatedWritableCvar( cvarName, cvarName, value, false, false, "ulx " .. command )
|
||||
|
||||
return obj
|
||||
end
|
||||
|
||||
function ulx.addToHelpManually( category, cmd, string, access_tag )
|
||||
ulx.cmdsByCategory[ category ] = ulx.cmdsByCategory[ category ] or {}
|
||||
for i, existingCmd in pairs( ulx.cmdsByCategory[ category ]) do
|
||||
if existingCmd.cmd == cmd and existingCmd.manual == true then
|
||||
table.remove( ulx.cmdsByCategory[ category ], i)
|
||||
break
|
||||
end
|
||||
end
|
||||
table.insert( ulx.cmdsByCategory[ category ], { access_tag=access_tag, cmd=cmd, helpStr=string, manual=true } )
|
||||
end
|
||||
|
||||
--------------------------------------
|
||||
--Now for boring initilization stuff--
|
||||
--------------------------------------
|
||||
|
||||
-- Setup the maps table
|
||||
do
|
||||
ulx.maps = {}
|
||||
local maps = file.Find( "maps/*.bsp", "GAME" )
|
||||
|
||||
for _, map in ipairs( maps ) do
|
||||
table.insert( ulx.maps, map:sub( 1, -5 ):lower() ) -- Take off the .bsp
|
||||
end
|
||||
table.sort( ulx.maps ) -- Make sure it's alphabetical
|
||||
|
||||
ulx.gamemodes = {}
|
||||
local fromEngine = engine.GetGamemodes()
|
||||
for i=1, #fromEngine do
|
||||
table.insert( ulx.gamemodes, fromEngine[ i ].name:lower() )
|
||||
end
|
||||
|
||||
table.sort( ulx.gamemodes ) -- Alphabetize
|
||||
end
|
||||
|
||||
ulx.common_kick_reasons = ulx.common_kick_reasons or {}
|
||||
function ulx.addKickReason( reason )
|
||||
table.insert( ulx.common_kick_reasons, reason )
|
||||
table.sort( ulx.common_kick_reasons )
|
||||
end
|
||||
|
||||
local function sendAutocompletes( ply )
|
||||
if ply:query( "ulx map" ) or ply:query( "ulx votemap2" ) then -- Only send if they have access to this.
|
||||
ULib.clientRPC( ply, "ulx.populateClMaps", ulx.maps )
|
||||
ULib.clientRPC( ply, "ulx.populateClGamemodes", ulx.gamemodes )
|
||||
end
|
||||
|
||||
ULib.clientRPC( ply, "ulx.populateClVotemaps", ulx.votemaps )
|
||||
ULib.clientRPC( ply, "ulx.populateKickReasons", ulx.common_kick_reasons )
|
||||
end
|
||||
hook.Add( ULib.HOOK_UCLAUTH, "sendAutoCompletes", sendAutocompletes )
|
||||
hook.Add( "PlayerInitialSpawn", "sendAutoCompletes", sendAutocompletes )
|
||||
|
||||
-- This will load ULX client side
|
||||
local function playerInit( ply )
|
||||
local _, v, r = ulx.getVersion()
|
||||
ULib.clientRPC( ply, "ulx.clInit", v, r )
|
||||
end
|
||||
hook.Add( "PlayerInitialSpawn", "ULXInitPlayer", playerInit )
|
||||
|
||||
-- Cvar saving
|
||||
function cvarChanged( sv_cvar, cl_cvar, ply, old_value, new_value )
|
||||
if not sv_cvar:find( "^ulx_" ) then return end
|
||||
local command = sv_cvar:gsub( "^ulx_", "" ):lower() -- Strip it off for lookup below
|
||||
if not ulx.cvars[ command ] then return end
|
||||
sv_cvar = ulx.cvars[ command ].original -- Make sure we have intended casing
|
||||
local path = "data/ulx/config.txt"
|
||||
if not ULib.fileExists( path ) then
|
||||
Msg( "[ULX ERROR] Config doesn't exist at " .. path .. "\n" )
|
||||
return
|
||||
end
|
||||
|
||||
sv_cvar = sv_cvar:gsub( "_", " " ) -- Convert back to space notation
|
||||
|
||||
if new_value:find( "[%s:']" ) then new_value = string.format( "%q", new_value ) end
|
||||
local replacement = string.format( "%s %s ", sv_cvar, new_value:gsub( "%%", "%%%%" ) ) -- Because we're feeding it through gsub below, need to expand '%'s
|
||||
local config = ULib.fileRead( path )
|
||||
config, found = config:gsub( ULib.makePatternSafe( sv_cvar ):gsub( "%a", function( c ) return "[" .. c:lower() .. c:upper() .. "]" end ) .. "%s+[^;\r\n]*", replacement ) -- The gsub makes us case neutral
|
||||
if found == 0 then -- Configuration option does not exist in config- append it
|
||||
newline = config:match("\r?\n")
|
||||
if not config:find("\r?\n$") then config = config .. newline end
|
||||
config = config .. "ulx " .. replacement .. "; " .. ulx.cvars[ command ].help .. newline
|
||||
end
|
||||
ULib.fileWrite( path, config )
|
||||
end
|
||||
hook.Add( ulx.HOOK_ULXDONELOADING, "AddCvarHook", function() hook.Add( ULib.HOOK_REPCVARCHANGED, "ULXCheckCvar", cvarChanged ) end ) -- We're not interested in changing cvars till after load
|
||||
|
@ -1,28 +1,28 @@
|
||||
if not ulx then
|
||||
ulx = {}
|
||||
include( "ulx/sh_defines.lua" )
|
||||
include( "ulx/cl_lib.lua" )
|
||||
include( "ulx/sh_base.lua" )
|
||||
|
||||
local sh_modules = file.Find( "ulx/modules/sh/*.lua", "LUA" )
|
||||
local cl_modules = file.Find( "ulx/modules/cl/*.lua", "LUA" )
|
||||
|
||||
for _, file in ipairs( cl_modules ) do
|
||||
Msg( "[ULX] Loading CLIENT module: " .. file .. "\n" )
|
||||
include( "ulx/modules/cl/" .. file )
|
||||
end
|
||||
|
||||
for _, file in ipairs( sh_modules ) do
|
||||
Msg( "[ULX] Loading SHARED module: " .. file .. "\n" )
|
||||
include( "ulx/modules/sh/" .. file )
|
||||
end
|
||||
end
|
||||
|
||||
function ulx.clInit( v, r )
|
||||
-- Number conversion to ensure we're not getting an incredibly complex floating number
|
||||
ulx.version = tonumber( string.format( "%.2f", v ) ) -- Yah, I know, we should have the version from shared anyways.... but doesn't make sense to send one and not the other.
|
||||
ulx.revision = r
|
||||
|
||||
Msg( "ULX version " .. ulx.getVersion() .. " loaded.\n" )
|
||||
end
|
||||
usermessage.Hook( "ulx_initplayer", init )
|
||||
if not ulx then
|
||||
ulx = {}
|
||||
include( "ulx/sh_defines.lua" )
|
||||
include( "ulx/cl_lib.lua" )
|
||||
include( "ulx/sh_base.lua" )
|
||||
|
||||
local sh_modules = file.Find( "ulx/modules/sh/*.lua", "LUA" )
|
||||
local cl_modules = file.Find( "ulx/modules/cl/*.lua", "LUA" )
|
||||
|
||||
for _, file in ipairs( cl_modules ) do
|
||||
Msg( "[ULX] Loading CLIENT module: " .. file .. "\n" )
|
||||
include( "ulx/modules/cl/" .. file )
|
||||
end
|
||||
|
||||
for _, file in ipairs( sh_modules ) do
|
||||
Msg( "[ULX] Loading SHARED module: " .. file .. "\n" )
|
||||
include( "ulx/modules/sh/" .. file )
|
||||
end
|
||||
end
|
||||
|
||||
function ulx.clInit( v, r )
|
||||
-- Number conversion to ensure we're not getting an incredibly complex floating number
|
||||
ulx.version = tonumber( string.format( "%.2f", v ) ) -- Yah, I know, we should have the version from shared anyways.... but doesn't make sense to send one and not the other.
|
||||
ulx.revision = r
|
||||
|
||||
Msg( "ULX version " .. ulx.getVersion() .. " loaded.\n" )
|
||||
end
|
||||
usermessage.Hook( "ulx_initplayer", init )
|
||||
|
@ -1,127 +1,127 @@
|
||||
ulx.common_kick_reasons = ulx.common_kick_reasons or {}
|
||||
function ulx.populateKickReasons( reasons )
|
||||
table.Empty( ulx.common_kick_reasons )
|
||||
table.Merge( ulx.common_kick_reasons, reasons )
|
||||
end
|
||||
|
||||
ulx.maps = ulx.maps or {}
|
||||
function ulx.populateClMaps( maps )
|
||||
table.Empty( ulx.maps )
|
||||
table.Merge( ulx.maps, maps )
|
||||
end
|
||||
|
||||
ulx.gamemodes = ulx.gamemodes or {}
|
||||
function ulx.populateClGamemodes( gamemodes )
|
||||
table.Empty( ulx.gamemodes )
|
||||
table.Merge( ulx.gamemodes, gamemodes )
|
||||
end
|
||||
|
||||
ulx.votemaps = ulx.votemaps or {}
|
||||
function ulx.populateClVotemaps( votemaps )
|
||||
table.Empty( ulx.votemaps )
|
||||
table.Merge( ulx.votemaps, votemaps )
|
||||
end
|
||||
|
||||
function ulx.soundComplete( ply, args )
|
||||
local targs = string.Trim( args )
|
||||
local soundList = {}
|
||||
|
||||
local relpath = targs:GetPathFromFilename()
|
||||
local sounds = file.Find( "sound/" .. relpath .. "*", "GAME" )
|
||||
for _, sound in ipairs( sounds ) do
|
||||
if targs:len() == 0 or (relpath .. sound):sub( 1, targs:len() ) == targs then
|
||||
table.insert( soundList, relpath .. sound )
|
||||
end
|
||||
end
|
||||
|
||||
return soundList
|
||||
end
|
||||
|
||||
function ulx.blindUser( bool, amt )
|
||||
if bool then
|
||||
local function blind()
|
||||
draw.RoundedBox( 0, 0, 0, ScrW(), ScrH(), Color( 255, 255, 255, amt ) )
|
||||
end
|
||||
hook.Add( "HUDPaint", "ulx_blind", blind )
|
||||
else
|
||||
hook.Remove( "HUDPaint", "ulx_blind" )
|
||||
end
|
||||
end
|
||||
|
||||
local function rcvBlind( um )
|
||||
local bool = um:ReadBool()
|
||||
local amt = um:ReadShort()
|
||||
ulx.blindUser( bool, amt )
|
||||
end
|
||||
usermessage.Hook( "ulx_blind", rcvBlind )
|
||||
|
||||
|
||||
local curVote
|
||||
|
||||
local function optionsDraw()
|
||||
if not curVote then return end
|
||||
|
||||
local title = curVote.title
|
||||
local options = curVote.options
|
||||
local endtime = curVote.endtime
|
||||
|
||||
if CurTime() > endtime then return end -- Expired
|
||||
|
||||
surface.SetFont( "Default" )
|
||||
local w, h = surface.GetTextSize( title )
|
||||
w = math.max( 200, w )
|
||||
local totalh = h * 12 + 20
|
||||
draw.RoundedBox( 8, 10, ScrH()*0.4 - 10, w + 20, totalh, Color( 111, 124, 138, 200 ) )
|
||||
|
||||
optiontxt = ""
|
||||
for i=1, 10 do
|
||||
if options[ i ] and options[ i ] ~= "" then
|
||||
optiontxt = optiontxt .. math.modf( i, 10 ) .. ". " .. options[ i ]
|
||||
end
|
||||
optiontxt = optiontxt .. "\n"
|
||||
end
|
||||
draw.DrawText( title .. "\n\n" .. optiontxt, "Default", 20, ScrH()*0.4, Color( 255, 255, 255, 255 ), TEXT_ALIGN_LEFT )
|
||||
end
|
||||
|
||||
local function rcvVote( um )
|
||||
local title = um:ReadString()
|
||||
local timeout = um:ReadShort()
|
||||
local options = ULib.umsgRcv( um )
|
||||
|
||||
local function callback( id )
|
||||
if id == 0 then id = 10 end
|
||||
|
||||
if not options[ id ] then
|
||||
return -- Returning nil will keep our hook
|
||||
end
|
||||
|
||||
RunConsoleCommand( "ulx_vote", id )
|
||||
curVote = nil
|
||||
return true -- Let it know we're done here
|
||||
end
|
||||
LocalPlayer():AddPlayerOption( title, timeout, callback, optionsDraw )
|
||||
|
||||
curVote = { title=title, options=options, endtime=CurTime()+timeout }
|
||||
end
|
||||
usermessage.Hook( "ulx_vote", rcvVote )
|
||||
|
||||
function ulx.getVersion() -- This exists on the server as well, so feel free to use it!
|
||||
if ulx.release then
|
||||
version = string.format( "%.02f", ulx.version )
|
||||
elseif ulx.revision > 0 then -- SVN version?
|
||||
version = string.format( "<SVN> revision %i", ulx.revision )
|
||||
else
|
||||
version = string.format( "<SVN> unknown revision" )
|
||||
end
|
||||
|
||||
return version, ulx.version, ulx.revision
|
||||
|
||||
end
|
||||
|
||||
function ulx.addToMenu( menuid, label, data ) -- TODO, remove
|
||||
Msg( "Warning: ulx.addToMenu was called, which is being phased out!\n" )
|
||||
end
|
||||
|
||||
-- Any language stuff for ULX should go here...
|
||||
|
||||
language.Add( "Undone_ulx_ent", "Undone ulx ent command" )
|
||||
ulx.common_kick_reasons = ulx.common_kick_reasons or {}
|
||||
function ulx.populateKickReasons( reasons )
|
||||
table.Empty( ulx.common_kick_reasons )
|
||||
table.Merge( ulx.common_kick_reasons, reasons )
|
||||
end
|
||||
|
||||
ulx.maps = ulx.maps or {}
|
||||
function ulx.populateClMaps( maps )
|
||||
table.Empty( ulx.maps )
|
||||
table.Merge( ulx.maps, maps )
|
||||
end
|
||||
|
||||
ulx.gamemodes = ulx.gamemodes or {}
|
||||
function ulx.populateClGamemodes( gamemodes )
|
||||
table.Empty( ulx.gamemodes )
|
||||
table.Merge( ulx.gamemodes, gamemodes )
|
||||
end
|
||||
|
||||
ulx.votemaps = ulx.votemaps or {}
|
||||
function ulx.populateClVotemaps( votemaps )
|
||||
table.Empty( ulx.votemaps )
|
||||
table.Merge( ulx.votemaps, votemaps )
|
||||
end
|
||||
|
||||
function ulx.soundComplete( ply, args )
|
||||
local targs = string.Trim( args )
|
||||
local soundList = {}
|
||||
|
||||
local relpath = targs:GetPathFromFilename()
|
||||
local sounds = file.Find( "sound/" .. relpath .. "*", "GAME" )
|
||||
for _, sound in ipairs( sounds ) do
|
||||
if targs:len() == 0 or (relpath .. sound):sub( 1, targs:len() ) == targs then
|
||||
table.insert( soundList, relpath .. sound )
|
||||
end
|
||||
end
|
||||
|
||||
return soundList
|
||||
end
|
||||
|
||||
function ulx.blindUser( bool, amt )
|
||||
if bool then
|
||||
local function blind()
|
||||
draw.RoundedBox( 0, 0, 0, ScrW(), ScrH(), Color( 255, 255, 255, amt ) )
|
||||
end
|
||||
hook.Add( "HUDPaint", "ulx_blind", blind )
|
||||
else
|
||||
hook.Remove( "HUDPaint", "ulx_blind" )
|
||||
end
|
||||
end
|
||||
|
||||
local function rcvBlind( um )
|
||||
local bool = um:ReadBool()
|
||||
local amt = um:ReadShort()
|
||||
ulx.blindUser( bool, amt )
|
||||
end
|
||||
usermessage.Hook( "ulx_blind", rcvBlind )
|
||||
|
||||
|
||||
local curVote
|
||||
|
||||
local function optionsDraw()
|
||||
if not curVote then return end
|
||||
|
||||
local title = curVote.title
|
||||
local options = curVote.options
|
||||
local endtime = curVote.endtime
|
||||
|
||||
if CurTime() > endtime then return end -- Expired
|
||||
|
||||
surface.SetFont( "Default" )
|
||||
local w, h = surface.GetTextSize( title )
|
||||
w = math.max( 200, w )
|
||||
local totalh = h * 12 + 20
|
||||
draw.RoundedBox( 8, 10, ScrH()*0.4 - 10, w + 20, totalh, Color( 111, 124, 138, 200 ) )
|
||||
|
||||
optiontxt = ""
|
||||
for i=1, 10 do
|
||||
if options[ i ] and options[ i ] ~= "" then
|
||||
optiontxt = optiontxt .. math.modf( i, 10 ) .. ". " .. options[ i ]
|
||||
end
|
||||
optiontxt = optiontxt .. "\n"
|
||||
end
|
||||
draw.DrawText( title .. "\n\n" .. optiontxt, "Default", 20, ScrH()*0.4, Color( 255, 255, 255, 255 ), TEXT_ALIGN_LEFT )
|
||||
end
|
||||
|
||||
local function rcvVote( um )
|
||||
local title = um:ReadString()
|
||||
local timeout = um:ReadShort()
|
||||
local options = ULib.umsgRcv( um )
|
||||
|
||||
local function callback( id )
|
||||
if id == 0 then id = 10 end
|
||||
|
||||
if not options[ id ] then
|
||||
return -- Returning nil will keep our hook
|
||||
end
|
||||
|
||||
RunConsoleCommand( "ulx_vote", id )
|
||||
curVote = nil
|
||||
return true -- Let it know we're done here
|
||||
end
|
||||
LocalPlayer():AddPlayerOption( title, timeout, callback, optionsDraw )
|
||||
|
||||
curVote = { title=title, options=options, endtime=CurTime()+timeout }
|
||||
end
|
||||
usermessage.Hook( "ulx_vote", rcvVote )
|
||||
|
||||
function ulx.getVersion() -- This exists on the server as well, so feel free to use it!
|
||||
if ulx.release then
|
||||
version = string.format( "%.02f", ulx.version )
|
||||
elseif ulx.revision > 0 then -- SVN version?
|
||||
version = string.format( "<SVN> revision %i", ulx.revision )
|
||||
else
|
||||
version = string.format( "<SVN> unknown revision" )
|
||||
end
|
||||
|
||||
return version, ulx.version, ulx.revision
|
||||
|
||||
end
|
||||
|
||||
function ulx.addToMenu( menuid, label, data ) -- TODO, remove
|
||||
Msg( "Warning: ulx.addToMenu was called, which is being phased out!\n" )
|
||||
end
|
||||
|
||||
-- Any language stuff for ULX should go here...
|
||||
|
||||
language.Add( "Undone_ulx_ent", "Undone ulx ent command" )
|
||||
|
284
lua/ulx/end.lua
284
lua/ulx/end.lua
@ -1,142 +1,142 @@
|
||||
-- Load our configs
|
||||
|
||||
local function init()
|
||||
-- Load our banned users
|
||||
if ULib.fileExists( "cfg/banned_user.cfg", true ) then
|
||||
ULib.execFile( "cfg/banned_user.cfg", "ULX-EXEC", true )
|
||||
end
|
||||
end
|
||||
hook.Add( "Initialize", "ULXInitialize", init )
|
||||
|
||||
local function doMainCfg( path, noMount )
|
||||
ULib.execString( ULib.stripComments( ULib.fileRead( path, noMount ), ";" ), "ULXConfigExec" )
|
||||
end
|
||||
|
||||
local function doDownloadCfg( path, noMount )
|
||||
-- Does the module exist for this?
|
||||
if not ulx.addForcedDownload then
|
||||
return
|
||||
end
|
||||
|
||||
local lines = ULib.explode( "\n+", ULib.stripComments( ULib.fileRead( path, noMount ), ";" ) )
|
||||
for _, line in ipairs( lines ) do
|
||||
line = line:Trim()
|
||||
if line:len() > 0 then
|
||||
ulx.addForcedDownload( ULib.stripQuotes( line ) )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function doGimpCfg( path, noMount )
|
||||
-- Does the module exist for this?
|
||||
if not ulx.clearGimpSays then
|
||||
return
|
||||
end
|
||||
|
||||
ulx.clearGimpSays()
|
||||
local lines = ULib.explode( "\n+", ULib.stripComments( ULib.fileRead( path, noMount ), ";" ) )
|
||||
for _, line in ipairs( lines ) do
|
||||
line = line:Trim()
|
||||
if line:len() > 0 then
|
||||
ulx.addGimpSay( ULib.stripQuotes( line ) )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function doAdvertCfg( path, noMount )
|
||||
-- Does the module exist for this?
|
||||
if not ulx.addAdvert then
|
||||
return
|
||||
end
|
||||
|
||||
local data_root, err = ULib.parseKeyValues( ULib.stripComments( ULib.fileRead( path, noMount ), ";" ) )
|
||||
if not data_root then Msg( "[ULX] Error in advert config: " .. err .. "\n" ) return end
|
||||
|
||||
for group_name, row in pairs( data_root ) do
|
||||
if type( group_name ) == "number" then -- Must not be a group
|
||||
local color = Color( tonumber( row.red ) or ULib.DEFAULT_TSAY_COLOR.r, tonumber( row.green ) or ULib.DEFAULT_TSAY_COLOR.g, tonumber( row.blue ) or ULib.DEFAULT_TSAY_COLOR.b )
|
||||
ulx.addAdvert( row.text or "NO TEXT SUPPLIED FOR THIS ADVERT", tonumber( row.time ) or 300, _, color, tonumber( row.time_on_screen ) )
|
||||
else -- Must be a group
|
||||
if type( row ) ~= "table" then Msg( "[ULX] Error in advert config: Adverts are not properly formatted!\n" ) return end
|
||||
for i=1, #row do
|
||||
local row2 = row[ i ]
|
||||
local color = Color( tonumber( row2.red ) or 151, tonumber( row2.green ) or 211, tonumber( row2.blue ) or 255 )
|
||||
ulx.addAdvert( row2.text or "NO TEXT SUPPLIED FOR THIS ADVERT", tonumber( row2.time ) or 300, group_name, color, tonumber( row2.time_on_screen ) )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function doVotemapsCfg( path, noMount )
|
||||
-- Does the module exist for this?
|
||||
if not ulx.clearVotemaps then
|
||||
return
|
||||
end
|
||||
|
||||
ulx.clearVotemaps()
|
||||
local lines = ULib.explode( "\n+", ULib.stripComments( ULib.fileRead( path, noMount ), ";" ) )
|
||||
for _, line in ipairs( lines ) do
|
||||
line = line:Trim()
|
||||
if line:len() > 0 then
|
||||
ulx.votemapAddMap( line )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function doReasonsCfg( path, noMount )
|
||||
-- Does the module exist for this?
|
||||
if not ulx.addKickReason then
|
||||
return
|
||||
end
|
||||
|
||||
local lines = ULib.explode( "\n+", ULib.stripComments( ULib.fileRead( path, noMount ), ";" ) )
|
||||
for _, line in ipairs( lines ) do
|
||||
line = line:Trim()
|
||||
if line:len() > 0 then
|
||||
ulx.addKickReason( ULib.stripQuotes( line ) )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function doCfg()
|
||||
local things_to_execute = { -- Indexed by name, value of function to execute
|
||||
["config.txt"] = doMainCfg,
|
||||
["downloads.txt"] = doDownloadCfg,
|
||||
["gimps.txt"] = doGimpCfg,
|
||||
["adverts.txt"] = doAdvertCfg,
|
||||
["votemaps.txt"] = doVotemapsCfg,
|
||||
["banreasons.txt"] = doReasonsCfg,
|
||||
}
|
||||
|
||||
local gamemode_name = GAMEMODE.Name:lower()
|
||||
local map_name = game.GetMap()
|
||||
|
||||
for filename, fn in pairs( things_to_execute ) do
|
||||
-- Global config
|
||||
if ULib.fileExists( "data/ulx/" .. filename ) then
|
||||
fn( "data/ulx/" .. filename )
|
||||
end
|
||||
|
||||
-- Per gamemode config
|
||||
if ULib.fileExists( "data/ulx/gamemodes/" .. gamemode_name .. "/" .. filename, true ) then
|
||||
fn( "data/ulx/gamemodes/" .. gamemode_name .. "/" .. filename, true )
|
||||
end
|
||||
|
||||
-- Per map config
|
||||
if ULib.fileExists( "data/ulx/maps/" .. map_name .. "/" .. filename, true ) then
|
||||
fn( "data/ulx/maps/" .. map_name .. "/" .. filename, true )
|
||||
end
|
||||
end
|
||||
|
||||
ULib.queueFunctionCall( hook.Call, ulx.HOOK_ULXDONELOADING, _ ) -- We're done loading! Wait a tick so the configs load.
|
||||
|
||||
if not game.IsDedicated() then
|
||||
hook.Remove( "PlayerInitialSpawn", "ULXDoCfg" )
|
||||
end
|
||||
end
|
||||
|
||||
if game.IsDedicated() then
|
||||
hook.Add( "Initialize", "ULXDoCfg", doCfg, HOOK_MONITOR_HIGH )
|
||||
else
|
||||
hook.Add( "PlayerInitialSpawn", "ULXDoCfg", doCfg, HOOK_MONITOR_HIGH ) -- TODO can we make this initialize too?
|
||||
end
|
||||
-- Load our configs
|
||||
|
||||
local function init()
|
||||
-- Load our banned users
|
||||
if ULib.fileExists( "cfg/banned_user.cfg", true ) then
|
||||
ULib.execFile( "cfg/banned_user.cfg", "ULX-EXEC", true )
|
||||
end
|
||||
end
|
||||
hook.Add( "Initialize", "ULXInitialize", init )
|
||||
|
||||
local function doMainCfg( path, noMount )
|
||||
ULib.execString( ULib.stripComments( ULib.fileRead( path, noMount ), ";" ), "ULXConfigExec" )
|
||||
end
|
||||
|
||||
local function doDownloadCfg( path, noMount )
|
||||
-- Does the module exist for this?
|
||||
if not ulx.addForcedDownload then
|
||||
return
|
||||
end
|
||||
|
||||
local lines = ULib.explode( "\n+", ULib.stripComments( ULib.fileRead( path, noMount ), ";" ) )
|
||||
for _, line in ipairs( lines ) do
|
||||
line = line:Trim()
|
||||
if line:len() > 0 then
|
||||
ulx.addForcedDownload( ULib.stripQuotes( line ) )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function doGimpCfg( path, noMount )
|
||||
-- Does the module exist for this?
|
||||
if not ulx.clearGimpSays then
|
||||
return
|
||||
end
|
||||
|
||||
ulx.clearGimpSays()
|
||||
local lines = ULib.explode( "\n+", ULib.stripComments( ULib.fileRead( path, noMount ), ";" ) )
|
||||
for _, line in ipairs( lines ) do
|
||||
line = line:Trim()
|
||||
if line:len() > 0 then
|
||||
ulx.addGimpSay( ULib.stripQuotes( line ) )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function doAdvertCfg( path, noMount )
|
||||
-- Does the module exist for this?
|
||||
if not ulx.addAdvert then
|
||||
return
|
||||
end
|
||||
|
||||
local data_root, err = ULib.parseKeyValues( ULib.stripComments( ULib.fileRead( path, noMount ), ";" ) )
|
||||
if not data_root then Msg( "[ULX] Error in advert config: " .. err .. "\n" ) return end
|
||||
|
||||
for group_name, row in pairs( data_root ) do
|
||||
if type( group_name ) == "number" then -- Must not be a group
|
||||
local color = Color( tonumber( row.red ) or ULib.DEFAULT_TSAY_COLOR.r, tonumber( row.green ) or ULib.DEFAULT_TSAY_COLOR.g, tonumber( row.blue ) or ULib.DEFAULT_TSAY_COLOR.b )
|
||||
ulx.addAdvert( row.text or "NO TEXT SUPPLIED FOR THIS ADVERT", tonumber( row.time ) or 300, _, color, tonumber( row.time_on_screen ) )
|
||||
else -- Must be a group
|
||||
if type( row ) ~= "table" then Msg( "[ULX] Error in advert config: Adverts are not properly formatted!\n" ) return end
|
||||
for i=1, #row do
|
||||
local row2 = row[ i ]
|
||||
local color = Color( tonumber( row2.red ) or 151, tonumber( row2.green ) or 211, tonumber( row2.blue ) or 255 )
|
||||
ulx.addAdvert( row2.text or "NO TEXT SUPPLIED FOR THIS ADVERT", tonumber( row2.time ) or 300, group_name, color, tonumber( row2.time_on_screen ) )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function doVotemapsCfg( path, noMount )
|
||||
-- Does the module exist for this?
|
||||
if not ulx.clearVotemaps then
|
||||
return
|
||||
end
|
||||
|
||||
ulx.clearVotemaps()
|
||||
local lines = ULib.explode( "\n+", ULib.stripComments( ULib.fileRead( path, noMount ), ";" ) )
|
||||
for _, line in ipairs( lines ) do
|
||||
line = line:Trim()
|
||||
if line:len() > 0 then
|
||||
ulx.votemapAddMap( line )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function doReasonsCfg( path, noMount )
|
||||
-- Does the module exist for this?
|
||||
if not ulx.addKickReason then
|
||||
return
|
||||
end
|
||||
|
||||
local lines = ULib.explode( "\n+", ULib.stripComments( ULib.fileRead( path, noMount ), ";" ) )
|
||||
for _, line in ipairs( lines ) do
|
||||
line = line:Trim()
|
||||
if line:len() > 0 then
|
||||
ulx.addKickReason( ULib.stripQuotes( line ) )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function doCfg()
|
||||
local things_to_execute = { -- Indexed by name, value of function to execute
|
||||
["config.txt"] = doMainCfg,
|
||||
["downloads.txt"] = doDownloadCfg,
|
||||
["gimps.txt"] = doGimpCfg,
|
||||
["adverts.txt"] = doAdvertCfg,
|
||||
["votemaps.txt"] = doVotemapsCfg,
|
||||
["banreasons.txt"] = doReasonsCfg,
|
||||
}
|
||||
|
||||
local gamemode_name = GAMEMODE.Name:lower()
|
||||
local map_name = game.GetMap()
|
||||
|
||||
for filename, fn in pairs( things_to_execute ) do
|
||||
-- Global config
|
||||
if ULib.fileExists( "data/ulx/" .. filename ) then
|
||||
fn( "data/ulx/" .. filename )
|
||||
end
|
||||
|
||||
-- Per gamemode config
|
||||
if ULib.fileExists( "data/ulx/gamemodes/" .. gamemode_name .. "/" .. filename, true ) then
|
||||
fn( "data/ulx/gamemodes/" .. gamemode_name .. "/" .. filename, true )
|
||||
end
|
||||
|
||||
-- Per map config
|
||||
if ULib.fileExists( "data/ulx/maps/" .. map_name .. "/" .. filename, true ) then
|
||||
fn( "data/ulx/maps/" .. map_name .. "/" .. filename, true )
|
||||
end
|
||||
end
|
||||
|
||||
ULib.queueFunctionCall( hook.Call, ulx.HOOK_ULXDONELOADING, _ ) -- We're done loading! Wait a tick so the configs load.
|
||||
|
||||
if not game.IsDedicated() then
|
||||
hook.Remove( "PlayerInitialSpawn", "ULXDoCfg" )
|
||||
end
|
||||
end
|
||||
|
||||
if game.IsDedicated() then
|
||||
hook.Add( "Initialize", "ULXDoCfg", doCfg, HOOK_MONITOR_HIGH )
|
||||
else
|
||||
hook.Add( "PlayerInitialSpawn", "ULXDoCfg", doCfg, HOOK_MONITOR_HIGH ) -- TODO can we make this initialize too?
|
||||
end
|
||||
|
108
lua/ulx/init.lua
108
lua/ulx/init.lua
@ -1,54 +1,54 @@
|
||||
if not ulx then
|
||||
ulx = {}
|
||||
|
||||
ULib.fileCreateDir( "data/ulx" )
|
||||
|
||||
local sv_modules = file.Find( "ulx/modules/*.lua", "LUA" )
|
||||
local sh_modules = file.Find( "ulx/modules/sh/*.lua", "LUA" )
|
||||
local cl_modules = file.Find( "ulx/modules/cl/*.lua", "LUA" )
|
||||
|
||||
Msg( "///////////////////////////////\n" )
|
||||
Msg( "// ULX Admin Mod //\n" )
|
||||
Msg( "///////////////////////////////\n" )
|
||||
Msg( "// Loading... //\n" )
|
||||
|
||||
Msg( "// sh_defines.lua //\n" )
|
||||
include( "sh_defines.lua" )
|
||||
Msg( "// lib.lua //\n" )
|
||||
include( "lib.lua" )
|
||||
Msg( "// base.lua //\n" )
|
||||
include( "base.lua" )
|
||||
Msg( "// sh_base.lua //\n" )
|
||||
include( "sh_base.lua" )
|
||||
Msg( "// log.lua //\n" )
|
||||
include( "log.lua" )
|
||||
|
||||
for _, file in ipairs( sv_modules ) do
|
||||
Msg( "// MODULE: " .. file .. string.rep( " ", 17 - file:len() ) .. "//\n" )
|
||||
include( "modules/" .. file )
|
||||
end
|
||||
|
||||
for _, file in ipairs( sh_modules ) do
|
||||
Msg( "// MODULE: " .. file .. string.rep( " ", 17 - file:len() ) .. "//\n" )
|
||||
include( "modules/sh/" .. file )
|
||||
end
|
||||
|
||||
Msg( "// end.lua //\n" )
|
||||
include( "end.lua" )
|
||||
Msg( "// Load Complete! //\n" )
|
||||
Msg( "///////////////////////////////\n" )
|
||||
|
||||
AddCSLuaFile( "ulx/cl_init.lua" )
|
||||
AddCSLuaFile( "ulx/sh_defines.lua" )
|
||||
AddCSLuaFile( "ulx/sh_base.lua" )
|
||||
AddCSLuaFile( "ulx/cl_lib.lua" )
|
||||
|
||||
-- Find c-side modules and load them
|
||||
for _, file in ipairs( cl_modules ) do
|
||||
AddCSLuaFile( "ulx/modules/cl/" .. file )
|
||||
end
|
||||
|
||||
for _, file in ipairs( sh_modules ) do
|
||||
AddCSLuaFile( "ulx/modules/sh/" .. file )
|
||||
end
|
||||
end
|
||||
if not ulx then
|
||||
ulx = {}
|
||||
|
||||
ULib.fileCreateDir( "data/ulx" )
|
||||
|
||||
local sv_modules = file.Find( "ulx/modules/*.lua", "LUA" )
|
||||
local sh_modules = file.Find( "ulx/modules/sh/*.lua", "LUA" )
|
||||
local cl_modules = file.Find( "ulx/modules/cl/*.lua", "LUA" )
|
||||
|
||||
Msg( "///////////////////////////////\n" )
|
||||
Msg( "// ULX Admin Mod //\n" )
|
||||
Msg( "///////////////////////////////\n" )
|
||||
Msg( "// Loading... //\n" )
|
||||
|
||||
Msg( "// sh_defines.lua //\n" )
|
||||
include( "sh_defines.lua" )
|
||||
Msg( "// lib.lua //\n" )
|
||||
include( "lib.lua" )
|
||||
Msg( "// base.lua //\n" )
|
||||
include( "base.lua" )
|
||||
Msg( "// sh_base.lua //\n" )
|
||||
include( "sh_base.lua" )
|
||||
Msg( "// log.lua //\n" )
|
||||
include( "log.lua" )
|
||||
|
||||
for _, file in ipairs( sv_modules ) do
|
||||
Msg( "// MODULE: " .. file .. string.rep( " ", 17 - file:len() ) .. "//\n" )
|
||||
include( "modules/" .. file )
|
||||
end
|
||||
|
||||
for _, file in ipairs( sh_modules ) do
|
||||
Msg( "// MODULE: " .. file .. string.rep( " ", 17 - file:len() ) .. "//\n" )
|
||||
include( "modules/sh/" .. file )
|
||||
end
|
||||
|
||||
Msg( "// end.lua //\n" )
|
||||
include( "end.lua" )
|
||||
Msg( "// Load Complete! //\n" )
|
||||
Msg( "///////////////////////////////\n" )
|
||||
|
||||
AddCSLuaFile( "ulx/cl_init.lua" )
|
||||
AddCSLuaFile( "ulx/sh_defines.lua" )
|
||||
AddCSLuaFile( "ulx/sh_base.lua" )
|
||||
AddCSLuaFile( "ulx/cl_lib.lua" )
|
||||
|
||||
-- Find c-side modules and load them
|
||||
for _, file in ipairs( cl_modules ) do
|
||||
AddCSLuaFile( "ulx/modules/cl/" .. file )
|
||||
end
|
||||
|
||||
for _, file in ipairs( sh_modules ) do
|
||||
AddCSLuaFile( "ulx/modules/sh/" .. file )
|
||||
end
|
||||
end
|
||||
|
210
lua/ulx/lib.lua
210
lua/ulx/lib.lua
@ -1,105 +1,105 @@
|
||||
-- Set exclusive command. Commands can check if an exclusive command is set with getExclusive()
|
||||
-- and process no further. Only "big" things like jail, maul, etc should be checking and setting this.
|
||||
function ulx.setExclusive( ply, action )
|
||||
ply.ULXExclusive = action
|
||||
end
|
||||
|
||||
function ulx.getExclusive( target, ply )
|
||||
if not target.ULXExclusive then return end
|
||||
|
||||
if target == ply then
|
||||
return "You are " .. target.ULXExclusive .. "!"
|
||||
else
|
||||
return target:Nick() .. " is " .. target.ULXExclusive .. "!"
|
||||
end
|
||||
end
|
||||
|
||||
function ulx.clearExclusive( ply )
|
||||
ply.ULXExclusive = nil
|
||||
end
|
||||
|
||||
--- No die. Don't allow the player to die!
|
||||
function ulx.setNoDie( ply, bool )
|
||||
ULib.getSpawnInfo( ply )
|
||||
ply.ulxNoDie = bool
|
||||
end
|
||||
|
||||
local function checkDeath( ply, weapon, killer )
|
||||
if ply.frozen then
|
||||
ULib.queueFunctionCall( function()
|
||||
if ply and ply:IsValid() then
|
||||
ply:UnLock()
|
||||
ply:Lock()
|
||||
end
|
||||
end )
|
||||
end
|
||||
|
||||
if ply.ulxNoDie then
|
||||
ply:AddDeaths( -1 ) -- Won't show on scoreboard
|
||||
if killer == ply then -- Suicide
|
||||
ply:AddFrags( 1 ) -- Won't show on scoreboard
|
||||
end
|
||||
|
||||
local pos = ply:GetPos()
|
||||
local ang = ply:EyeAngles()
|
||||
ULib.queueFunctionCall( function() -- Run next frame
|
||||
if not ply:IsValid() then return end -- Gotta make sure it's still valid since this is a timer
|
||||
ULib.spawn( ply, true )
|
||||
ply:SetPos( pos )
|
||||
ply:SetEyeAngles( ang )
|
||||
end )
|
||||
return true -- Don't register their death on HUD
|
||||
end
|
||||
end
|
||||
hook.Add( "PlayerDeath", "ULXCheckDeath", checkDeath, HOOK_HIGH ) -- Hook it first because we're blocking their death.
|
||||
|
||||
local function checkSuicide( ply )
|
||||
if ply.ulxNoDie then
|
||||
return false
|
||||
end
|
||||
end
|
||||
hook.Add( "CanPlayerSuicide", "ULXCheckSuicide", checkSuicide, HOOK_HIGH )
|
||||
|
||||
function ulx.getVersion() -- This exists on the client as well, so feel free to use it!
|
||||
local version
|
||||
local r = 0
|
||||
|
||||
if ulx.release then
|
||||
version = string.format( "%.02f", ulx.version )
|
||||
else
|
||||
if ULib.fileExists( "addons/ulx/.svn/wc.db" ) then -- SVN's new format
|
||||
-- The following code would probably work if garry allowed us to read this file...
|
||||
--[[local raw = ULib.fileRead( "addons/ulx/.svn/wc.db" )
|
||||
local highest = 0
|
||||
for rev in string.gmatch( raw, "/ulx/!svn/ver/%d+/" ) do
|
||||
if rev > highest then
|
||||
highest = rev
|
||||
end
|
||||
end
|
||||
r = highest]]
|
||||
elseif ULib.fileExists( "addons/ulx/lua/ulx/.svn/entries" ) then
|
||||
-- Garry broke the following around 05/11/2010, then fixed it again around 11/10/2010!
|
||||
local lines = string.Explode( "\n", ULib.fileRead( "lua/ulx/.svn/entries" ) )
|
||||
r = tonumber( lines[ 4 ] )
|
||||
end
|
||||
|
||||
if r and r > 0 then
|
||||
version = string.format( "<SVN> revision %i", r )
|
||||
else
|
||||
version = string.format( "<SVN> unknown revision" )
|
||||
end
|
||||
end
|
||||
|
||||
return version, ulx.version, r
|
||||
end
|
||||
|
||||
function ulx.addToMenu( menuid, label, data ) -- TODO: Remove
|
||||
Msg( "Warning: ulx.addToMenu was called, which is being phased out!\n" )
|
||||
end
|
||||
|
||||
function ulx.standardizeModel( model ) -- This will convert all model strings to be of the same type, using linux notation and single dashes.
|
||||
model = model:lower()
|
||||
model = model:gsub( "\\", "/" )
|
||||
model = model:gsub( "/+", "/" ) -- Multiple dashes
|
||||
return model
|
||||
end
|
||||
-- Set exclusive command. Commands can check if an exclusive command is set with getExclusive()
|
||||
-- and process no further. Only "big" things like jail, maul, etc should be checking and setting this.
|
||||
function ulx.setExclusive( ply, action )
|
||||
ply.ULXExclusive = action
|
||||
end
|
||||
|
||||
function ulx.getExclusive( target, ply )
|
||||
if not target.ULXExclusive then return end
|
||||
|
||||
if target == ply then
|
||||
return "You are " .. target.ULXExclusive .. "!"
|
||||
else
|
||||
return target:Nick() .. " is " .. target.ULXExclusive .. "!"
|
||||
end
|
||||
end
|
||||
|
||||
function ulx.clearExclusive( ply )
|
||||
ply.ULXExclusive = nil
|
||||
end
|
||||
|
||||
--- No die. Don't allow the player to die!
|
||||
function ulx.setNoDie( ply, bool )
|
||||
ULib.getSpawnInfo( ply )
|
||||
ply.ulxNoDie = bool
|
||||
end
|
||||
|
||||
local function checkDeath( ply, weapon, killer )
|
||||
if ply.frozen then
|
||||
ULib.queueFunctionCall( function()
|
||||
if ply and ply:IsValid() then
|
||||
ply:UnLock()
|
||||
ply:Lock()
|
||||
end
|
||||
end )
|
||||
end
|
||||
|
||||
if ply.ulxNoDie then
|
||||
ply:AddDeaths( -1 ) -- Won't show on scoreboard
|
||||
if killer == ply then -- Suicide
|
||||
ply:AddFrags( 1 ) -- Won't show on scoreboard
|
||||
end
|
||||
|
||||
local pos = ply:GetPos()
|
||||
local ang = ply:EyeAngles()
|
||||
ULib.queueFunctionCall( function() -- Run next frame
|
||||
if not ply:IsValid() then return end -- Gotta make sure it's still valid since this is a timer
|
||||
ULib.spawn( ply, true )
|
||||
ply:SetPos( pos )
|
||||
ply:SetEyeAngles( ang )
|
||||
end )
|
||||
return true -- Don't register their death on HUD
|
||||
end
|
||||
end
|
||||
hook.Add( "PlayerDeath", "ULXCheckDeath", checkDeath, HOOK_HIGH ) -- Hook it first because we're blocking their death.
|
||||
|
||||
local function checkSuicide( ply )
|
||||
if ply.ulxNoDie then
|
||||
return false
|
||||
end
|
||||
end
|
||||
hook.Add( "CanPlayerSuicide", "ULXCheckSuicide", checkSuicide, HOOK_HIGH )
|
||||
|
||||
function ulx.getVersion() -- This exists on the client as well, so feel free to use it!
|
||||
local version
|
||||
local r = 0
|
||||
|
||||
if ulx.release then
|
||||
version = string.format( "%.02f", ulx.version )
|
||||
else
|
||||
if ULib.fileExists( "addons/ulx/.svn/wc.db" ) then -- SVN's new format
|
||||
-- The following code would probably work if garry allowed us to read this file...
|
||||
--[[local raw = ULib.fileRead( "addons/ulx/.svn/wc.db" )
|
||||
local highest = 0
|
||||
for rev in string.gmatch( raw, "/ulx/!svn/ver/%d+/" ) do
|
||||
if rev > highest then
|
||||
highest = rev
|
||||
end
|
||||
end
|
||||
r = highest]]
|
||||
elseif ULib.fileExists( "addons/ulx/lua/ulx/.svn/entries" ) then
|
||||
-- Garry broke the following around 05/11/2010, then fixed it again around 11/10/2010!
|
||||
local lines = string.Explode( "\n", ULib.fileRead( "lua/ulx/.svn/entries" ) )
|
||||
r = tonumber( lines[ 4 ] )
|
||||
end
|
||||
|
||||
if r and r > 0 then
|
||||
version = string.format( "<SVN> revision %i", r )
|
||||
else
|
||||
version = string.format( "<SVN> unknown revision" )
|
||||
end
|
||||
end
|
||||
|
||||
return version, ulx.version, r
|
||||
end
|
||||
|
||||
function ulx.addToMenu( menuid, label, data ) -- TODO: Remove
|
||||
Msg( "Warning: ulx.addToMenu was called, which is being phased out!\n" )
|
||||
end
|
||||
|
||||
function ulx.standardizeModel( model ) -- This will convert all model strings to be of the same type, using linux notation and single dashes.
|
||||
model = model:lower()
|
||||
model = model:gsub( "\\", "/" )
|
||||
model = model:gsub( "/+", "/" ) -- Multiple dashes
|
||||
return model
|
||||
end
|
||||
|
1030
lua/ulx/log.lua
1030
lua/ulx/log.lua
File diff suppressed because it is too large
Load Diff
@ -1,49 +1,49 @@
|
||||
ulx.motdmenu_exists = true
|
||||
|
||||
local isUrl
|
||||
local url
|
||||
|
||||
function ulx.showMotdMenu( steamid )
|
||||
local window = vgui.Create( "DFrame" )
|
||||
if ScrW() > 640 then -- Make it larger if we can.
|
||||
window:SetSize( ScrW()*0.9, ScrH()*0.9 )
|
||||
else
|
||||
window:SetSize( 640, 480 )
|
||||
end
|
||||
window:Center()
|
||||
window:SetTitle( "ULX MOTD" )
|
||||
window:SetVisible( true )
|
||||
window:MakePopup()
|
||||
|
||||
local html = vgui.Create( "DHTML", window )
|
||||
--html:SetAllowLua( true ) -- Too much of a security risk for us to enable. Feel free to uncomment if you know what you're doing.
|
||||
|
||||
local button = vgui.Create( "DButton", window )
|
||||
button:SetText( "Close" )
|
||||
button.DoClick = function() window:Close() end
|
||||
button:SetSize( 100, 40 )
|
||||
button:SetPos( (window:GetWide() - button:GetWide()) / 2, window:GetTall() - button:GetTall() - 10 )
|
||||
|
||||
html:SetSize( window:GetWide() - 20, window:GetTall() - button:GetTall() - 50 )
|
||||
html:SetPos( 10, 30 )
|
||||
if not isUrl then
|
||||
html:SetHTML( ULib.fileRead( "data/ulx_motd.txt" ) or "" )
|
||||
else
|
||||
url = string.gsub( url, "%%curmap%%", game.GetMap() )
|
||||
url = string.gsub( url, "%%steamid%%", steamid )
|
||||
html:OpenURL( url )
|
||||
end
|
||||
end
|
||||
|
||||
function ulx.rcvMotd( isUrl_, text )
|
||||
isUrl = isUrl_
|
||||
if not isUrl then
|
||||
ULib.fileWrite( "data/ulx_motd.txt", text )
|
||||
else
|
||||
if text:find( "://", 1, true ) then
|
||||
url = text
|
||||
else
|
||||
url = "http://" .. text
|
||||
end
|
||||
end
|
||||
end
|
||||
ulx.motdmenu_exists = true
|
||||
|
||||
local isUrl
|
||||
local url
|
||||
|
||||
function ulx.showMotdMenu( steamid )
|
||||
local window = vgui.Create( "DFrame" )
|
||||
if ScrW() > 640 then -- Make it larger if we can.
|
||||
window:SetSize( ScrW()*0.9, ScrH()*0.9 )
|
||||
else
|
||||
window:SetSize( 640, 480 )
|
||||
end
|
||||
window:Center()
|
||||
window:SetTitle( "ULX MOTD" )
|
||||
window:SetVisible( true )
|
||||
window:MakePopup()
|
||||
|
||||
local html = vgui.Create( "DHTML", window )
|
||||
--html:SetAllowLua( true ) -- Too much of a security risk for us to enable. Feel free to uncomment if you know what you're doing.
|
||||
|
||||
local button = vgui.Create( "DButton", window )
|
||||
button:SetText( "Close" )
|
||||
button.DoClick = function() window:Close() end
|
||||
button:SetSize( 100, 40 )
|
||||
button:SetPos( (window:GetWide() - button:GetWide()) / 2, window:GetTall() - button:GetTall() - 10 )
|
||||
|
||||
html:SetSize( window:GetWide() - 20, window:GetTall() - button:GetTall() - 50 )
|
||||
html:SetPos( 10, 30 )
|
||||
if not isUrl then
|
||||
html:SetHTML( ULib.fileRead( "data/ulx_motd.txt" ) or "" )
|
||||
else
|
||||
url = string.gsub( url, "%%curmap%%", game.GetMap() )
|
||||
url = string.gsub( url, "%%steamid%%", steamid )
|
||||
html:OpenURL( url )
|
||||
end
|
||||
end
|
||||
|
||||
function ulx.rcvMotd( isUrl_, text )
|
||||
isUrl = isUrl_
|
||||
if not isUrl then
|
||||
ULib.fileWrite( "data/ulx_motd.txt", text )
|
||||
else
|
||||
if text:find( "://", 1, true ) then
|
||||
url = text
|
||||
else
|
||||
url = "http://" .. text
|
||||
end
|
||||
end
|
||||
end
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,406 +1,406 @@
|
||||
--xgui_helpers -- by Stickly Man!
|
||||
--A set of generic functions to help with various XGUI-related things.
|
||||
|
||||
function xgui.load_helpers()
|
||||
--These handle keyboard focus for textboxes within XGUI.
|
||||
local function getKeyboardFocus( pnl )
|
||||
if pnl:HasParent( xgui.base ) then
|
||||
xgui.anchor:SetKeyboardInputEnabled( true )
|
||||
end
|
||||
if pnl.selectAll then
|
||||
pnl:SelectAllText()
|
||||
end
|
||||
end
|
||||
hook.Add( "OnTextEntryGetFocus", "XGUI_GetKeyboardFocus", getKeyboardFocus )
|
||||
|
||||
local function loseKeyboardFocus( pnl )
|
||||
if pnl:HasParent( xgui.base ) then
|
||||
xgui.anchor:SetKeyboardInputEnabled( false )
|
||||
end
|
||||
end
|
||||
hook.Add( "OnTextEntryLoseFocus", "XGUI_LoseKeyboardFocus", loseKeyboardFocus )
|
||||
|
||||
|
||||
---------------------------------
|
||||
--Code for creating the XGUI base
|
||||
---------------------------------
|
||||
function xgui.makeXGUIbase()
|
||||
xgui.anchor = xlib.makeXpanel{ w=600, h=420, x=ScrW()/2-300, y=ScrH()/2-270 }
|
||||
xgui.anchor:SetVisible( false )
|
||||
xgui.anchor:SetKeyboardInputEnabled( false )
|
||||
xgui.anchor.Paint = function( self, w, h ) hook.Call( "XLIBDoAnimation" ) end
|
||||
xgui.anchor:SetAlpha( 0 )
|
||||
|
||||
xgui.base = xlib.makepropertysheet{ x=0, y=0, w=600, h=400, parent=xgui.anchor, offloadparent=xgui.null }
|
||||
xgui.base.animOpen = function() --First 4 are fade animations, last (or invalid choice) is the default fade animation.
|
||||
xgui.settings.animIntype = tonumber( xgui.settings.animIntype )
|
||||
if xgui.settings.animIntype == 2 then
|
||||
xlib.addToAnimQueue( function() xgui.anchor:SetAlpha(255) end )
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=xgui.anchor, startx=xgui.x, starty=-490, endx=xgui.x, endy=xgui.y, setvisible=true } )
|
||||
elseif xgui.settings.animIntype == 3 then
|
||||
xlib.addToAnimQueue( function() xgui.anchor:SetAlpha(255) end )
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=xgui.anchor, startx=-610, starty=xgui.y, endx=xgui.x, endy=xgui.y, setvisible=true } )
|
||||
elseif xgui.settings.animIntype == 4 then
|
||||
xlib.addToAnimQueue( function() xgui.anchor:SetAlpha(255) end )
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=xgui.anchor, startx=xgui.x, starty=ScrH(), endx=xgui.x, endy=xgui.y, setvisible=true } )
|
||||
elseif xgui.settings.animIntype == 5 then
|
||||
xlib.addToAnimQueue( function() xgui.anchor:SetAlpha(255) end )
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=xgui.anchor, startx=ScrW(), starty=xgui.y, endx=xgui.x, endy=xgui.y, setvisible=true } )
|
||||
else
|
||||
xlib.addToAnimQueue( function() xgui.anchor:SetPos( xgui.x, xgui.y ) end )
|
||||
xlib.addToAnimQueue( "pnlFade", { panelIn=xgui.anchor } )
|
||||
end
|
||||
xlib.animQueue_start()
|
||||
end
|
||||
xgui.base.animClose = function()
|
||||
xgui.settings.animOuttype = tonumber( xgui.settings.animOuttype )
|
||||
if xgui.settings.animOuttype == 2 then
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=xgui.anchor, startx=xgui.x, starty=xgui.y, endx=xgui.x, endy=-490, setvisible=false } )
|
||||
xlib.addToAnimQueue( function() xgui.anchor:SetAlpha(0) end )
|
||||
elseif xgui.settings.animOuttype == 3 then
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=xgui.anchor, startx=xgui.x, starty=xgui.y, endx=-610, endy=xgui.y, setvisible=false } )
|
||||
xlib.addToAnimQueue( function() xgui.anchor:SetAlpha(0) end )
|
||||
elseif xgui.settings.animOuttype == 4 then
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=xgui.anchor, startx=xgui.x, starty=xgui.y, endx=xgui.x, endy=ScrH(), setvisible=false } )
|
||||
xlib.addToAnimQueue( function() xgui.anchor:SetAlpha(0) end )
|
||||
elseif xgui.settings.animOuttype == 5 then
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=xgui.anchor, startx=xgui.x, starty=xgui.y, endx=ScrW(), endy=xgui.y, setvisible=false } )
|
||||
xlib.addToAnimQueue( function() xgui.anchor:SetAlpha(0) end )
|
||||
else
|
||||
xlib.addToAnimQueue( function() xgui.anchor:SetPos( xgui.x, xgui.y ) end )
|
||||
xlib.addToAnimQueue( "pnlFade", { panelOut=xgui.anchor } )
|
||||
end
|
||||
xlib.animQueue_start()
|
||||
end
|
||||
|
||||
function xgui.SetPos( pos, xoff, yoff, ignoreanim ) --Sets the position of XGUI based on "pos", and checks to make sure that with whatever offset and pos combination, XGUI does not go off the screen.
|
||||
pos = tonumber( pos )
|
||||
xoff = tonumber( xoff )
|
||||
yoff = tonumber( yoff )
|
||||
if not xoff then xoff = 0 end
|
||||
if not yoff then yoff = 0 end
|
||||
if not pos then pos = 5 end
|
||||
if pos == 1 or pos == 4 or pos == 7 then --Left side of the screen
|
||||
if xoff < -10 then
|
||||
xoff = -10
|
||||
elseif xoff > ScrW()-610 then
|
||||
xoff = ScrW()-610
|
||||
end
|
||||
xgui.x = 10+xoff
|
||||
elseif pos == 3 or pos == 6 or pos == 9 then --Right side of the screen
|
||||
if xoff < -ScrW()+610 then
|
||||
xoff = -ScrW()+610
|
||||
elseif xoff > 10 then
|
||||
xoff = 10
|
||||
end
|
||||
xgui.x = ScrW()-610+xoff
|
||||
else --Center
|
||||
if xoff < -ScrW()/2+300 then
|
||||
xoff = -ScrW()/2+300
|
||||
elseif xoff > ScrW()/2-300 then
|
||||
xoff = ScrW()/2-300
|
||||
end
|
||||
xgui.x = ScrW()/2-300+xoff
|
||||
end
|
||||
|
||||
if pos == 1 or pos == 2 or pos == 3 then --Bottom of the screen
|
||||
if yoff < -ScrH()+430 then
|
||||
yoff = -ScrH()+430
|
||||
elseif yoff > 30 then
|
||||
yoff = 30
|
||||
end
|
||||
xgui.y = ScrH()-430+yoff
|
||||
elseif pos == 7 or pos == 8 or pos == 9 then --Top of the screen
|
||||
if yoff < -10 then
|
||||
yoff = -10
|
||||
elseif yoff > ScrH()-410 then
|
||||
yoff = ScrH()-410
|
||||
end
|
||||
xgui.y = yoff+10
|
||||
else --Center
|
||||
if yoff < -ScrH()/2+210 then
|
||||
yoff = -ScrH()/2+210
|
||||
elseif yoff > ScrH()/2-190 then
|
||||
yoff = ScrH()/2-190
|
||||
end
|
||||
xgui.y = ScrH()/2-210+yoff
|
||||
end
|
||||
if ignoreanim then
|
||||
xgui.anchor:SetPos( xgui.x, xgui.y )
|
||||
else
|
||||
local curx, cury = xgui.anchor:GetPos()
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=xgui.anchor, startx=curx, starty=cury, endx=xgui.x, endy=xgui.y } )
|
||||
xlib.animQueue_start()
|
||||
end
|
||||
end
|
||||
xgui.SetPos( xgui.settings.xguipos.pos, xgui.settings.xguipos.xoff, xgui.settings.xguipos.yoff )
|
||||
|
||||
function xgui.base:SetActiveTab( active, ignoreAnim )
|
||||
if ( self.m_pActiveTab == active ) then return end
|
||||
if ( self.m_pActiveTab ) then
|
||||
if not ignoreAnim then
|
||||
xlib.addToAnimQueue( "pnlFade", { panelOut=self.m_pActiveTab:GetPanel(), panelIn=active:GetPanel() } )
|
||||
else
|
||||
--Run this when module permissions have changed.
|
||||
xlib.addToAnimQueue( "pnlFade", { panelOut=nil, panelIn=active:GetPanel() }, 0 )
|
||||
end
|
||||
xlib.animQueue_start()
|
||||
end
|
||||
self.m_pActiveTab = active
|
||||
self:InvalidateLayout()
|
||||
end
|
||||
|
||||
--Progress bar
|
||||
xgui.chunkbox = xlib.makeprogressbar{ x=420, w=180, h=20, visible=false, skin=xgui.settings.skin, parent=xgui.anchor }
|
||||
function xgui.chunkbox:Progress( datatype )
|
||||
self.value = self.value + 1
|
||||
self:SetFraction( self.value / self.max )
|
||||
self.Label:SetText( "Getting data: " .. datatype .. " - " .. string.format("%.2f", (self.value / self.max) * 100) .. "%" )
|
||||
if self.value == self.max then
|
||||
xgui.expectingdata = nil
|
||||
self.Label:SetText( "Waiting for clientside processing..." )
|
||||
xgui.queueFunctionCall( xgui.chunkbox.SetVisible, "chunkbox", xgui.chunkbox, false )
|
||||
RunConsoleCommand( "_xgui", "dataComplete" )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
------------------------
|
||||
--XGUI QueueFunctionCall
|
||||
------------------------
|
||||
--This is essentially a straight copy of Megiddo's queueFunctionCall; Since XGUI tends to use it quite a lot, I decided to seperate it to prevent delays in ULib's stuff
|
||||
--I also now get to add a method of flushing the queue based on a tag in the event that new data needs to be updated.
|
||||
local stack = {}
|
||||
local function onThink()
|
||||
|
||||
local num = #stack
|
||||
if num > 0 then
|
||||
for i=1,3 do --Run 3 lines per frame
|
||||
if stack[1] ~= nil then
|
||||
local b, e = pcall( stack[ 1 ].fn, unpack( stack[ 1 ], 1, stack[ 1 ].n ) )
|
||||
if not b then
|
||||
ErrorNoHalt( "XGUI queue error: " .. tostring( e ) .. "\n" )
|
||||
end
|
||||
end
|
||||
table.remove( stack, 1 ) -- Remove the first inserted item. This is FIFO
|
||||
end
|
||||
else
|
||||
hook.Remove( "Think", "XGUIQueueThink" )
|
||||
end
|
||||
end
|
||||
|
||||
function xgui.queueFunctionCall( fn, tag, ... )
|
||||
if type( fn ) ~= "function" then
|
||||
error( "queueFunctionCall received a bad function", 2 )
|
||||
return
|
||||
end
|
||||
|
||||
table.insert( stack, { fn=fn, tag=tag, n=select( "#", ... ), ... } )
|
||||
hook.Add( "Think", "XGUIQueueThink", onThink, HOOK_MONITOR_HIGH )
|
||||
end
|
||||
|
||||
function xgui.flushQueue( tag )
|
||||
local removeIndecies = {}
|
||||
for i, fncall in ipairs( stack ) do
|
||||
if fncall.tag == tag then
|
||||
table.insert( removeIndecies, i )
|
||||
end
|
||||
end
|
||||
for i=#removeIndecies,1,-1 do --Remove the queue functions backwards to prevent desynchronization of pairs
|
||||
table.remove( stack, removeIndecies[i] )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-------------------
|
||||
--ULIB XGUI helpers
|
||||
-------------------
|
||||
--Helper function to parse access tag for a particular argument
|
||||
function ulx.getTagArgNum( tag, argnum )
|
||||
return tag and ULib.splitArgs( tag, "<", ">" )[argnum]
|
||||
end
|
||||
|
||||
--Load control interpretations for ULib argument types
|
||||
function ULib.cmds.BaseArg.x_getcontrol( arg, argnum, parent )
|
||||
return xlib.makelabel{ label="Not Supported", parent=parent }
|
||||
end
|
||||
|
||||
function ULib.cmds.NumArg.x_getcontrol( arg, argnum, parent )
|
||||
local access, tag = LocalPlayer():query( arg.cmd )
|
||||
local restrictions = {}
|
||||
ULib.cmds.NumArg.processRestrictions( restrictions, arg, ulx.getTagArgNum( tag, argnum ) )
|
||||
|
||||
if table.HasValue( arg, ULib.cmds.allowTimeString ) then
|
||||
local min = restrictions.min or 0
|
||||
local max = restrictions.max or 10 * 60 * 24 * 365 --default slider max 10 years
|
||||
|
||||
local outPanel = xlib.makepanel{ h=40, parent=parent }
|
||||
xlib.makelabel{ x=5, y=3, label="Ban Length:", parent=outPanel }
|
||||
outPanel.interval = xlib.makecombobox{ x=90, w=75, parent=outPanel }
|
||||
outPanel.val = xlib.makeslider{ w=165, y=20, label="<--->", min=min, max=max, value=min, decimal=0, parent=outPanel }
|
||||
|
||||
local divisor = {}
|
||||
local sensiblemax = {}
|
||||
if min == 0 then outPanel.interval:AddChoice( "Permanent" ) table.insert( divisor, 1 ) table.insert( sensiblemax, 0 ) end
|
||||
if max >= 1 and min <= 60*24 then outPanel.interval:AddChoice( "Minutes" ) table.insert( divisor, 1 ) table.insert( sensiblemax, 60*24 ) end
|
||||
if max >= 60 and min <= 60*24*7 then outPanel.interval:AddChoice( "Hours" ) table.insert( divisor, 60 ) table.insert( sensiblemax, 24*7 ) end
|
||||
if max >= ( 60*24 ) and min <= 60*24*120 then outPanel.interval:AddChoice( "Days" ) table.insert( divisor, 60*24 ) table.insert( sensiblemax, 120 ) end
|
||||
if max >= ( 60*24*7 ) and min <= 60*24*7*52 then outPanel.interval:AddChoice( "Weeks" ) table.insert( divisor, 60*24*7 ) table.insert( sensiblemax, 52 ) end
|
||||
if max >= ( 60*24*365 ) then outPanel.interval:AddChoice( "Years" ) table.insert( divisor, 60*24*365 ) table.insert( sensiblemax, 10 ) end
|
||||
|
||||
outPanel.interval.OnSelect = function( self, index, value, data )
|
||||
outPanel.val:SetDisabled( value == "Permanent" )
|
||||
outPanel.val.maxvalue = math.min( max / divisor[index], sensiblemax[index] )
|
||||
outPanel.val.minvalue = math.max( min / divisor[index], 0 )
|
||||
outPanel.val:SetMax( outPanel.val.maxvalue )
|
||||
outPanel.val:SetMin( outPanel.val.minvalue )
|
||||
outPanel.val:SetValue( math.Clamp( tonumber( outPanel.val:GetValue() ), outPanel.val.minvalue, outPanel.val.maxvalue ) )
|
||||
end
|
||||
|
||||
function outPanel.val:ValueChanged( val )
|
||||
val = math.Clamp( tonumber( val ), self.minvalue or 0, self.maxvalue or 0 )
|
||||
self.Slider:SetSlideX( self.Scratch:GetFraction( val ) )
|
||||
if ( self.TextArea != vgui.GetKeyboardFocus() ) then
|
||||
self.TextArea:SetValue( self.Scratch:GetTextValue() )
|
||||
end
|
||||
self:OnValueChanged( val )
|
||||
end
|
||||
|
||||
if #outPanel.interval.Choices ~= 0 then
|
||||
outPanel.interval:ChooseOptionID( 1 )
|
||||
end
|
||||
|
||||
outPanel.GetValue = function( self )
|
||||
local val, char = self:GetRawValue()
|
||||
return val .. char
|
||||
end
|
||||
outPanel.GetRawValue = function( self )
|
||||
local char = string.lower( self.interval:GetValue():sub(1,1) )
|
||||
if char == "m" or char == "p" or tonumber( self.val:GetValue() ) == 0 then char = "" end
|
||||
return self.val:GetValue(), char
|
||||
end
|
||||
outPanel.GetMinutes = function( self )
|
||||
local btime, char = self:GetRawValue()
|
||||
if char == "h" then btime = btime * 60
|
||||
elseif char == "d" then btime = btime * 1440
|
||||
elseif char == "w" then btime = btime * 10080
|
||||
elseif char == "y" then btime = btime * 525600 end
|
||||
return btime
|
||||
end
|
||||
outPanel.TextArea = outPanel.val.TextArea
|
||||
return outPanel
|
||||
else
|
||||
local defvalue = arg.min
|
||||
if table.HasValue( arg, ULib.cmds.optional ) then defvalue = arg.default end
|
||||
if not defvalue then defvalue = 0 end --No default was set for this command, so we'll use 0.
|
||||
|
||||
local maxvalue = restrictions.max
|
||||
local minvalue = restrictions.min or 0
|
||||
if maxvalue == nil then
|
||||
if defvalue > 100 then
|
||||
maxvalue = defvalue
|
||||
else
|
||||
maxvalue = 100
|
||||
end
|
||||
end
|
||||
|
||||
local decimal = 0
|
||||
if not table.HasValue( arg, ULib.cmds.round ) then
|
||||
local minMaxDelta = maxvalue - minvalue
|
||||
if minMaxDelta < 5 then
|
||||
decimal = 2
|
||||
elseif minMaxDelta <= 10 then
|
||||
decimal = 1
|
||||
end
|
||||
end
|
||||
|
||||
local outPanel = xlib.makepanel{ h=35, parent=parent }
|
||||
xlib.makelabel{ label=arg.hint or "NumArg", parent=outPanel }
|
||||
outPanel.val = xlib.makeslider{ y=15, w=165, min=minvalue, max=maxvalue, value=defvalue, decimal=decimal, label="<--->", parent=outPanel }
|
||||
outPanel.GetValue = function( self ) return outPanel.val.GetValue( outPanel.val ) end
|
||||
outPanel.TextArea = outPanel.val.TextArea
|
||||
return outPanel
|
||||
end
|
||||
end
|
||||
|
||||
function ULib.cmds.NumArg.getTime( arg )
|
||||
if arg == nil or arg == "" then return nil, nil end
|
||||
|
||||
if arg == 0 or tonumber( arg ) == 0 then
|
||||
return "Permanent", 0
|
||||
end
|
||||
|
||||
local charPriority = { "y", "w", "d", "h" }
|
||||
local charMap = { "Years", "Weeks", "Days", "Hours" }
|
||||
local divisor = { 60 * 24 * 365, 60 * 24 * 7, 60 * 24, 60 }
|
||||
for i, v in ipairs( charPriority ) do
|
||||
if arg:find( v, 1, true ) then
|
||||
if not charMap[ i ] or not divisor [ i ] or not ULib.stringTimeToSeconds( arg ) then return nil, nil end
|
||||
local val = ULib.stringTimeToSeconds( arg ) / divisor[ i ]
|
||||
if val == 0 then return "Permanent", 0 end
|
||||
return charMap[ i ], val
|
||||
end
|
||||
end
|
||||
|
||||
return "Minutes", ULib.stringTimeToSeconds( arg )
|
||||
end
|
||||
|
||||
|
||||
function ULib.cmds.StringArg.x_getcontrol( arg, argnum, parent )
|
||||
local access, tag = LocalPlayer():query( arg.cmd )
|
||||
local restrictions = {}
|
||||
ULib.cmds.StringArg.processRestrictions( restrictions, arg, ulx.getTagArgNum( tag, argnum ) )
|
||||
|
||||
local is_restricted_to_completes = table.HasValue( arg, ULib.cmds.restrictToCompletes ) -- Program-level restriction (IE, ulx map)
|
||||
or restrictions.playerLevelRestriction -- The player's tag specifies only certain strings
|
||||
|
||||
if is_restricted_to_completes then
|
||||
return xlib.makecombobox{ text=arg.hint or "StringArg", choices=restrictions.restrictedCompletes, parent=parent }
|
||||
elseif restrictions.restrictedCompletes and table.Count( restrictions.restrictedCompletes ) > 0 then
|
||||
-- This is where there needs to be both a drop down AND an input box
|
||||
local outPanel = xlib.makecombobox{ text=arg.hint, choices=restrictions.restrictedCompletes, enableinput=true, selectall=true, parent=parent }
|
||||
outPanel.OnEnter = function( self )
|
||||
self:GetParent():OnEnter()
|
||||
end
|
||||
return outPanel
|
||||
else
|
||||
return xlib.maketextbox{ text=arg.hint or "StringArg", selectall=true, parent=parent }
|
||||
end
|
||||
end
|
||||
|
||||
function ULib.cmds.PlayerArg.x_getcontrol( arg, argnum, parent )
|
||||
local access, tag = LocalPlayer():query( arg.cmd )
|
||||
local restrictions = {}
|
||||
ULib.cmds.PlayerArg.processRestrictions( restrictions, LocalPlayer(), arg, ulx.getTagArgNum( tag, argnum ) )
|
||||
|
||||
local outPanel = xlib.makecombobox{ text=arg.hint, parent=parent }
|
||||
local targets = restrictions.restrictedTargets
|
||||
if targets == false then -- No one allowed
|
||||
targets = {}
|
||||
elseif targets == nil then -- Everyone allowed
|
||||
targets = player.GetAll()
|
||||
end
|
||||
|
||||
for _, ply in ipairs( targets ) do
|
||||
outPanel:AddChoice( ply:Nick() )
|
||||
end
|
||||
return outPanel
|
||||
end
|
||||
|
||||
function ULib.cmds.CallingPlayerArg.x_getcontrol( arg, argnum, parent )
|
||||
return xlib.makelabel{ label=arg.hint or "CallingPlayer", parent=parent }
|
||||
end
|
||||
|
||||
function ULib.cmds.BoolArg.x_getcontrol( arg, argnum, parent )
|
||||
local access, tag = LocalPlayer():query( arg.cmd )
|
||||
local restrictions = {}
|
||||
ULib.cmds.BoolArg.processRestrictions( restrictions, arg, ulx.getTagArgNum( tag, argnum ) )
|
||||
|
||||
local outPanel = xlib.makecheckbox{ label=arg.hint or "BoolArg", value=restrictions.restrictedTo, parent=parent }
|
||||
if restrictions.restrictedTo ~= nil then outPanel:SetDisabled( true ) end
|
||||
outPanel.GetValue = function( self )
|
||||
return self:GetChecked() and 1 or 0
|
||||
end
|
||||
return outPanel
|
||||
end
|
||||
--xgui_helpers -- by Stickly Man!
|
||||
--A set of generic functions to help with various XGUI-related things.
|
||||
|
||||
function xgui.load_helpers()
|
||||
--These handle keyboard focus for textboxes within XGUI.
|
||||
local function getKeyboardFocus( pnl )
|
||||
if pnl:HasParent( xgui.base ) then
|
||||
xgui.anchor:SetKeyboardInputEnabled( true )
|
||||
end
|
||||
if pnl.selectAll then
|
||||
pnl:SelectAllText()
|
||||
end
|
||||
end
|
||||
hook.Add( "OnTextEntryGetFocus", "XGUI_GetKeyboardFocus", getKeyboardFocus )
|
||||
|
||||
local function loseKeyboardFocus( pnl )
|
||||
if pnl:HasParent( xgui.base ) then
|
||||
xgui.anchor:SetKeyboardInputEnabled( false )
|
||||
end
|
||||
end
|
||||
hook.Add( "OnTextEntryLoseFocus", "XGUI_LoseKeyboardFocus", loseKeyboardFocus )
|
||||
|
||||
|
||||
---------------------------------
|
||||
--Code for creating the XGUI base
|
||||
---------------------------------
|
||||
function xgui.makeXGUIbase()
|
||||
xgui.anchor = xlib.makeXpanel{ w=600, h=420, x=ScrW()/2-300, y=ScrH()/2-270 }
|
||||
xgui.anchor:SetVisible( false )
|
||||
xgui.anchor:SetKeyboardInputEnabled( false )
|
||||
xgui.anchor.Paint = function( self, w, h ) hook.Call( "XLIBDoAnimation" ) end
|
||||
xgui.anchor:SetAlpha( 0 )
|
||||
|
||||
xgui.base = xlib.makepropertysheet{ x=0, y=0, w=600, h=400, parent=xgui.anchor, offloadparent=xgui.null }
|
||||
xgui.base.animOpen = function() --First 4 are fade animations, last (or invalid choice) is the default fade animation.
|
||||
xgui.settings.animIntype = tonumber( xgui.settings.animIntype )
|
||||
if xgui.settings.animIntype == 2 then
|
||||
xlib.addToAnimQueue( function() xgui.anchor:SetAlpha(255) end )
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=xgui.anchor, startx=xgui.x, starty=-490, endx=xgui.x, endy=xgui.y, setvisible=true } )
|
||||
elseif xgui.settings.animIntype == 3 then
|
||||
xlib.addToAnimQueue( function() xgui.anchor:SetAlpha(255) end )
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=xgui.anchor, startx=-610, starty=xgui.y, endx=xgui.x, endy=xgui.y, setvisible=true } )
|
||||
elseif xgui.settings.animIntype == 4 then
|
||||
xlib.addToAnimQueue( function() xgui.anchor:SetAlpha(255) end )
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=xgui.anchor, startx=xgui.x, starty=ScrH(), endx=xgui.x, endy=xgui.y, setvisible=true } )
|
||||
elseif xgui.settings.animIntype == 5 then
|
||||
xlib.addToAnimQueue( function() xgui.anchor:SetAlpha(255) end )
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=xgui.anchor, startx=ScrW(), starty=xgui.y, endx=xgui.x, endy=xgui.y, setvisible=true } )
|
||||
else
|
||||
xlib.addToAnimQueue( function() xgui.anchor:SetPos( xgui.x, xgui.y ) end )
|
||||
xlib.addToAnimQueue( "pnlFade", { panelIn=xgui.anchor } )
|
||||
end
|
||||
xlib.animQueue_start()
|
||||
end
|
||||
xgui.base.animClose = function()
|
||||
xgui.settings.animOuttype = tonumber( xgui.settings.animOuttype )
|
||||
if xgui.settings.animOuttype == 2 then
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=xgui.anchor, startx=xgui.x, starty=xgui.y, endx=xgui.x, endy=-490, setvisible=false } )
|
||||
xlib.addToAnimQueue( function() xgui.anchor:SetAlpha(0) end )
|
||||
elseif xgui.settings.animOuttype == 3 then
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=xgui.anchor, startx=xgui.x, starty=xgui.y, endx=-610, endy=xgui.y, setvisible=false } )
|
||||
xlib.addToAnimQueue( function() xgui.anchor:SetAlpha(0) end )
|
||||
elseif xgui.settings.animOuttype == 4 then
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=xgui.anchor, startx=xgui.x, starty=xgui.y, endx=xgui.x, endy=ScrH(), setvisible=false } )
|
||||
xlib.addToAnimQueue( function() xgui.anchor:SetAlpha(0) end )
|
||||
elseif xgui.settings.animOuttype == 5 then
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=xgui.anchor, startx=xgui.x, starty=xgui.y, endx=ScrW(), endy=xgui.y, setvisible=false } )
|
||||
xlib.addToAnimQueue( function() xgui.anchor:SetAlpha(0) end )
|
||||
else
|
||||
xlib.addToAnimQueue( function() xgui.anchor:SetPos( xgui.x, xgui.y ) end )
|
||||
xlib.addToAnimQueue( "pnlFade", { panelOut=xgui.anchor } )
|
||||
end
|
||||
xlib.animQueue_start()
|
||||
end
|
||||
|
||||
function xgui.SetPos( pos, xoff, yoff, ignoreanim ) --Sets the position of XGUI based on "pos", and checks to make sure that with whatever offset and pos combination, XGUI does not go off the screen.
|
||||
pos = tonumber( pos )
|
||||
xoff = tonumber( xoff )
|
||||
yoff = tonumber( yoff )
|
||||
if not xoff then xoff = 0 end
|
||||
if not yoff then yoff = 0 end
|
||||
if not pos then pos = 5 end
|
||||
if pos == 1 or pos == 4 or pos == 7 then --Left side of the screen
|
||||
if xoff < -10 then
|
||||
xoff = -10
|
||||
elseif xoff > ScrW()-610 then
|
||||
xoff = ScrW()-610
|
||||
end
|
||||
xgui.x = 10+xoff
|
||||
elseif pos == 3 or pos == 6 or pos == 9 then --Right side of the screen
|
||||
if xoff < -ScrW()+610 then
|
||||
xoff = -ScrW()+610
|
||||
elseif xoff > 10 then
|
||||
xoff = 10
|
||||
end
|
||||
xgui.x = ScrW()-610+xoff
|
||||
else --Center
|
||||
if xoff < -ScrW()/2+300 then
|
||||
xoff = -ScrW()/2+300
|
||||
elseif xoff > ScrW()/2-300 then
|
||||
xoff = ScrW()/2-300
|
||||
end
|
||||
xgui.x = ScrW()/2-300+xoff
|
||||
end
|
||||
|
||||
if pos == 1 or pos == 2 or pos == 3 then --Bottom of the screen
|
||||
if yoff < -ScrH()+430 then
|
||||
yoff = -ScrH()+430
|
||||
elseif yoff > 30 then
|
||||
yoff = 30
|
||||
end
|
||||
xgui.y = ScrH()-430+yoff
|
||||
elseif pos == 7 or pos == 8 or pos == 9 then --Top of the screen
|
||||
if yoff < -10 then
|
||||
yoff = -10
|
||||
elseif yoff > ScrH()-410 then
|
||||
yoff = ScrH()-410
|
||||
end
|
||||
xgui.y = yoff+10
|
||||
else --Center
|
||||
if yoff < -ScrH()/2+210 then
|
||||
yoff = -ScrH()/2+210
|
||||
elseif yoff > ScrH()/2-190 then
|
||||
yoff = ScrH()/2-190
|
||||
end
|
||||
xgui.y = ScrH()/2-210+yoff
|
||||
end
|
||||
if ignoreanim then
|
||||
xgui.anchor:SetPos( xgui.x, xgui.y )
|
||||
else
|
||||
local curx, cury = xgui.anchor:GetPos()
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=xgui.anchor, startx=curx, starty=cury, endx=xgui.x, endy=xgui.y } )
|
||||
xlib.animQueue_start()
|
||||
end
|
||||
end
|
||||
xgui.SetPos( xgui.settings.xguipos.pos, xgui.settings.xguipos.xoff, xgui.settings.xguipos.yoff )
|
||||
|
||||
function xgui.base:SetActiveTab( active, ignoreAnim )
|
||||
if ( self.m_pActiveTab == active ) then return end
|
||||
if ( self.m_pActiveTab ) then
|
||||
if not ignoreAnim then
|
||||
xlib.addToAnimQueue( "pnlFade", { panelOut=self.m_pActiveTab:GetPanel(), panelIn=active:GetPanel() } )
|
||||
else
|
||||
--Run this when module permissions have changed.
|
||||
xlib.addToAnimQueue( "pnlFade", { panelOut=nil, panelIn=active:GetPanel() }, 0 )
|
||||
end
|
||||
xlib.animQueue_start()
|
||||
end
|
||||
self.m_pActiveTab = active
|
||||
self:InvalidateLayout()
|
||||
end
|
||||
|
||||
--Progress bar
|
||||
xgui.chunkbox = xlib.makeprogressbar{ x=420, w=180, h=20, visible=false, skin=xgui.settings.skin, parent=xgui.anchor }
|
||||
function xgui.chunkbox:Progress( datatype )
|
||||
self.value = self.value + 1
|
||||
self:SetFraction( self.value / self.max )
|
||||
self.Label:SetText( "Getting data: " .. datatype .. " - " .. string.format("%.2f", (self.value / self.max) * 100) .. "%" )
|
||||
if self.value == self.max then
|
||||
xgui.expectingdata = nil
|
||||
self.Label:SetText( "Waiting for clientside processing..." )
|
||||
xgui.queueFunctionCall( xgui.chunkbox.SetVisible, "chunkbox", xgui.chunkbox, false )
|
||||
RunConsoleCommand( "_xgui", "dataComplete" )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
------------------------
|
||||
--XGUI QueueFunctionCall
|
||||
------------------------
|
||||
--This is essentially a straight copy of Megiddo's queueFunctionCall; Since XGUI tends to use it quite a lot, I decided to seperate it to prevent delays in ULib's stuff
|
||||
--I also now get to add a method of flushing the queue based on a tag in the event that new data needs to be updated.
|
||||
local stack = {}
|
||||
local function onThink()
|
||||
|
||||
local num = #stack
|
||||
if num > 0 then
|
||||
for i=1,3 do --Run 3 lines per frame
|
||||
if stack[1] ~= nil then
|
||||
local b, e = pcall( stack[ 1 ].fn, unpack( stack[ 1 ], 1, stack[ 1 ].n ) )
|
||||
if not b then
|
||||
ErrorNoHalt( "XGUI queue error: " .. tostring( e ) .. "\n" )
|
||||
end
|
||||
end
|
||||
table.remove( stack, 1 ) -- Remove the first inserted item. This is FIFO
|
||||
end
|
||||
else
|
||||
hook.Remove( "Think", "XGUIQueueThink" )
|
||||
end
|
||||
end
|
||||
|
||||
function xgui.queueFunctionCall( fn, tag, ... )
|
||||
if type( fn ) ~= "function" then
|
||||
error( "queueFunctionCall received a bad function", 2 )
|
||||
return
|
||||
end
|
||||
|
||||
table.insert( stack, { fn=fn, tag=tag, n=select( "#", ... ), ... } )
|
||||
hook.Add( "Think", "XGUIQueueThink", onThink, HOOK_MONITOR_HIGH )
|
||||
end
|
||||
|
||||
function xgui.flushQueue( tag )
|
||||
local removeIndecies = {}
|
||||
for i, fncall in ipairs( stack ) do
|
||||
if fncall.tag == tag then
|
||||
table.insert( removeIndecies, i )
|
||||
end
|
||||
end
|
||||
for i=#removeIndecies,1,-1 do --Remove the queue functions backwards to prevent desynchronization of pairs
|
||||
table.remove( stack, removeIndecies[i] )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-------------------
|
||||
--ULIB XGUI helpers
|
||||
-------------------
|
||||
--Helper function to parse access tag for a particular argument
|
||||
function ulx.getTagArgNum( tag, argnum )
|
||||
return tag and ULib.splitArgs( tag, "<", ">" )[argnum]
|
||||
end
|
||||
|
||||
--Load control interpretations for ULib argument types
|
||||
function ULib.cmds.BaseArg.x_getcontrol( arg, argnum, parent )
|
||||
return xlib.makelabel{ label="Not Supported", parent=parent }
|
||||
end
|
||||
|
||||
function ULib.cmds.NumArg.x_getcontrol( arg, argnum, parent )
|
||||
local access, tag = LocalPlayer():query( arg.cmd )
|
||||
local restrictions = {}
|
||||
ULib.cmds.NumArg.processRestrictions( restrictions, arg, ulx.getTagArgNum( tag, argnum ) )
|
||||
|
||||
if table.HasValue( arg, ULib.cmds.allowTimeString ) then
|
||||
local min = restrictions.min or 0
|
||||
local max = restrictions.max or 10 * 60 * 24 * 365 --default slider max 10 years
|
||||
|
||||
local outPanel = xlib.makepanel{ h=40, parent=parent }
|
||||
xlib.makelabel{ x=5, y=3, label="Ban Length:", parent=outPanel }
|
||||
outPanel.interval = xlib.makecombobox{ x=90, w=75, parent=outPanel }
|
||||
outPanel.val = xlib.makeslider{ w=165, y=20, label="<--->", min=min, max=max, value=min, decimal=0, parent=outPanel }
|
||||
|
||||
local divisor = {}
|
||||
local sensiblemax = {}
|
||||
if min == 0 then outPanel.interval:AddChoice( "Permanent" ) table.insert( divisor, 1 ) table.insert( sensiblemax, 0 ) end
|
||||
if max >= 1 and min <= 60*24 then outPanel.interval:AddChoice( "Minutes" ) table.insert( divisor, 1 ) table.insert( sensiblemax, 60*24 ) end
|
||||
if max >= 60 and min <= 60*24*7 then outPanel.interval:AddChoice( "Hours" ) table.insert( divisor, 60 ) table.insert( sensiblemax, 24*7 ) end
|
||||
if max >= ( 60*24 ) and min <= 60*24*120 then outPanel.interval:AddChoice( "Days" ) table.insert( divisor, 60*24 ) table.insert( sensiblemax, 120 ) end
|
||||
if max >= ( 60*24*7 ) and min <= 60*24*7*52 then outPanel.interval:AddChoice( "Weeks" ) table.insert( divisor, 60*24*7 ) table.insert( sensiblemax, 52 ) end
|
||||
if max >= ( 60*24*365 ) then outPanel.interval:AddChoice( "Years" ) table.insert( divisor, 60*24*365 ) table.insert( sensiblemax, 10 ) end
|
||||
|
||||
outPanel.interval.OnSelect = function( self, index, value, data )
|
||||
outPanel.val:SetDisabled( value == "Permanent" )
|
||||
outPanel.val.maxvalue = math.min( max / divisor[index], sensiblemax[index] )
|
||||
outPanel.val.minvalue = math.max( min / divisor[index], 0 )
|
||||
outPanel.val:SetMax( outPanel.val.maxvalue )
|
||||
outPanel.val:SetMin( outPanel.val.minvalue )
|
||||
outPanel.val:SetValue( math.Clamp( tonumber( outPanel.val:GetValue() ), outPanel.val.minvalue, outPanel.val.maxvalue ) )
|
||||
end
|
||||
|
||||
function outPanel.val:ValueChanged( val )
|
||||
val = math.Clamp( tonumber( val ), self.minvalue or 0, self.maxvalue or 0 )
|
||||
self.Slider:SetSlideX( self.Scratch:GetFraction( val ) )
|
||||
if ( self.TextArea != vgui.GetKeyboardFocus() ) then
|
||||
self.TextArea:SetValue( self.Scratch:GetTextValue() )
|
||||
end
|
||||
self:OnValueChanged( val )
|
||||
end
|
||||
|
||||
if #outPanel.interval.Choices ~= 0 then
|
||||
outPanel.interval:ChooseOptionID( 1 )
|
||||
end
|
||||
|
||||
outPanel.GetValue = function( self )
|
||||
local val, char = self:GetRawValue()
|
||||
return val .. char
|
||||
end
|
||||
outPanel.GetRawValue = function( self )
|
||||
local char = string.lower( self.interval:GetValue():sub(1,1) )
|
||||
if char == "m" or char == "p" or tonumber( self.val:GetValue() ) == 0 then char = "" end
|
||||
return self.val:GetValue(), char
|
||||
end
|
||||
outPanel.GetMinutes = function( self )
|
||||
local btime, char = self:GetRawValue()
|
||||
if char == "h" then btime = btime * 60
|
||||
elseif char == "d" then btime = btime * 1440
|
||||
elseif char == "w" then btime = btime * 10080
|
||||
elseif char == "y" then btime = btime * 525600 end
|
||||
return btime
|
||||
end
|
||||
outPanel.TextArea = outPanel.val.TextArea
|
||||
return outPanel
|
||||
else
|
||||
local defvalue = arg.min
|
||||
if table.HasValue( arg, ULib.cmds.optional ) then defvalue = arg.default end
|
||||
if not defvalue then defvalue = 0 end --No default was set for this command, so we'll use 0.
|
||||
|
||||
local maxvalue = restrictions.max
|
||||
local minvalue = restrictions.min or 0
|
||||
if maxvalue == nil then
|
||||
if defvalue > 100 then
|
||||
maxvalue = defvalue
|
||||
else
|
||||
maxvalue = 100
|
||||
end
|
||||
end
|
||||
|
||||
local decimal = 0
|
||||
if not table.HasValue( arg, ULib.cmds.round ) then
|
||||
local minMaxDelta = maxvalue - minvalue
|
||||
if minMaxDelta < 5 then
|
||||
decimal = 2
|
||||
elseif minMaxDelta <= 10 then
|
||||
decimal = 1
|
||||
end
|
||||
end
|
||||
|
||||
local outPanel = xlib.makepanel{ h=35, parent=parent }
|
||||
xlib.makelabel{ label=arg.hint or "NumArg", parent=outPanel }
|
||||
outPanel.val = xlib.makeslider{ y=15, w=165, min=minvalue, max=maxvalue, value=defvalue, decimal=decimal, label="<--->", parent=outPanel }
|
||||
outPanel.GetValue = function( self ) return outPanel.val.GetValue( outPanel.val ) end
|
||||
outPanel.TextArea = outPanel.val.TextArea
|
||||
return outPanel
|
||||
end
|
||||
end
|
||||
|
||||
function ULib.cmds.NumArg.getTime( arg )
|
||||
if arg == nil or arg == "" then return nil, nil end
|
||||
|
||||
if arg == 0 or tonumber( arg ) == 0 then
|
||||
return "Permanent", 0
|
||||
end
|
||||
|
||||
local charPriority = { "y", "w", "d", "h" }
|
||||
local charMap = { "Years", "Weeks", "Days", "Hours" }
|
||||
local divisor = { 60 * 24 * 365, 60 * 24 * 7, 60 * 24, 60 }
|
||||
for i, v in ipairs( charPriority ) do
|
||||
if arg:find( v, 1, true ) then
|
||||
if not charMap[ i ] or not divisor [ i ] or not ULib.stringTimeToSeconds( arg ) then return nil, nil end
|
||||
local val = ULib.stringTimeToSeconds( arg ) / divisor[ i ]
|
||||
if val == 0 then return "Permanent", 0 end
|
||||
return charMap[ i ], val
|
||||
end
|
||||
end
|
||||
|
||||
return "Minutes", ULib.stringTimeToSeconds( arg )
|
||||
end
|
||||
|
||||
|
||||
function ULib.cmds.StringArg.x_getcontrol( arg, argnum, parent )
|
||||
local access, tag = LocalPlayer():query( arg.cmd )
|
||||
local restrictions = {}
|
||||
ULib.cmds.StringArg.processRestrictions( restrictions, arg, ulx.getTagArgNum( tag, argnum ) )
|
||||
|
||||
local is_restricted_to_completes = table.HasValue( arg, ULib.cmds.restrictToCompletes ) -- Program-level restriction (IE, ulx map)
|
||||
or restrictions.playerLevelRestriction -- The player's tag specifies only certain strings
|
||||
|
||||
if is_restricted_to_completes then
|
||||
return xlib.makecombobox{ text=arg.hint or "StringArg", choices=restrictions.restrictedCompletes, parent=parent }
|
||||
elseif restrictions.restrictedCompletes and table.Count( restrictions.restrictedCompletes ) > 0 then
|
||||
-- This is where there needs to be both a drop down AND an input box
|
||||
local outPanel = xlib.makecombobox{ text=arg.hint, choices=restrictions.restrictedCompletes, enableinput=true, selectall=true, parent=parent }
|
||||
outPanel.OnEnter = function( self )
|
||||
self:GetParent():OnEnter()
|
||||
end
|
||||
return outPanel
|
||||
else
|
||||
return xlib.maketextbox{ text=arg.hint or "StringArg", selectall=true, parent=parent }
|
||||
end
|
||||
end
|
||||
|
||||
function ULib.cmds.PlayerArg.x_getcontrol( arg, argnum, parent )
|
||||
local access, tag = LocalPlayer():query( arg.cmd )
|
||||
local restrictions = {}
|
||||
ULib.cmds.PlayerArg.processRestrictions( restrictions, LocalPlayer(), arg, ulx.getTagArgNum( tag, argnum ) )
|
||||
|
||||
local outPanel = xlib.makecombobox{ text=arg.hint, parent=parent }
|
||||
local targets = restrictions.restrictedTargets
|
||||
if targets == false then -- No one allowed
|
||||
targets = {}
|
||||
elseif targets == nil then -- Everyone allowed
|
||||
targets = player.GetAll()
|
||||
end
|
||||
|
||||
for _, ply in ipairs( targets ) do
|
||||
outPanel:AddChoice( ply:Nick() )
|
||||
end
|
||||
return outPanel
|
||||
end
|
||||
|
||||
function ULib.cmds.CallingPlayerArg.x_getcontrol( arg, argnum, parent )
|
||||
return xlib.makelabel{ label=arg.hint or "CallingPlayer", parent=parent }
|
||||
end
|
||||
|
||||
function ULib.cmds.BoolArg.x_getcontrol( arg, argnum, parent )
|
||||
local access, tag = LocalPlayer():query( arg.cmd )
|
||||
local restrictions = {}
|
||||
ULib.cmds.BoolArg.processRestrictions( restrictions, arg, ulx.getTagArgNum( tag, argnum ) )
|
||||
|
||||
local outPanel = xlib.makecheckbox{ label=arg.hint or "BoolArg", value=restrictions.restrictedTo, parent=parent }
|
||||
if restrictions.restrictedTo ~= nil then outPanel:SetDisabled( true ) end
|
||||
outPanel.GetValue = function( self )
|
||||
return self:GetChecked() and 1 or 0
|
||||
end
|
||||
return outPanel
|
||||
end
|
||||
end
|
File diff suppressed because it is too large
Load Diff
@ -1,48 +1,48 @@
|
||||
local CATEGORY_NAME = "Menus"
|
||||
|
||||
if ULib.fileExists( "lua/ulx/modules/cl/motdmenu.lua" ) or ulx.motdmenu_exists then
|
||||
CreateConVar( "motdfile", "ulx_motd.txt" ) -- Garry likes to add and remove this cvar a lot, so it's here just in case he removes it again.
|
||||
local function sendMotd( ply, showMotd )
|
||||
if showMotd == "1" then -- Assume it's a file
|
||||
if ply.ulxHasMotd then return end -- This player already has the motd
|
||||
if not ULib.fileExists( GetConVarString( "motdfile" ) ) then return end -- Invalid
|
||||
local f = ULib.fileRead( GetConVarString( "motdfile" ) )
|
||||
|
||||
ULib.clientRPC( ply, "ulx.rcvMotd", false, f )
|
||||
|
||||
ply.ulxHasMotd = true
|
||||
|
||||
else -- Assume URL
|
||||
ULib.clientRPC( ply, "ulx.rcvMotd", true, showMotd )
|
||||
ply.ulxHasMotd = nil
|
||||
end
|
||||
end
|
||||
|
||||
local function showMotd( ply )
|
||||
local showMotd = GetConVarString( "ulx_showMotd" )
|
||||
if showMotd == "0" then return end
|
||||
if not ply:IsValid() then return end -- They left, doh!
|
||||
|
||||
sendMotd( ply, showMotd )
|
||||
ULib.clientRPC( ply, "ulx.showMotdMenu", ply:SteamID() ) -- Passing it because they may get it before LocalPlayer() is valid
|
||||
end
|
||||
hook.Add( "PlayerInitialSpawn", "showMotd", showMotd )
|
||||
|
||||
function ulx.motd( calling_ply )
|
||||
if not calling_ply:IsValid() then
|
||||
Msg( "You can't see the motd from the console.\n" )
|
||||
return
|
||||
end
|
||||
|
||||
if GetConVarString( "ulx_showMotd" ) == "0" then
|
||||
ULib.tsay( calling_ply, "The MOTD has been disabled on this server." )
|
||||
return
|
||||
end
|
||||
|
||||
showMotd( calling_ply )
|
||||
end
|
||||
local motdmenu = ulx.command( CATEGORY_NAME, "ulx motd", ulx.motd, "!motd" )
|
||||
motdmenu:defaultAccess( ULib.ACCESS_ALL )
|
||||
motdmenu:help( "Show the message of the day." )
|
||||
if SERVER then ulx.convar( "showMotd", "1", " <0/1/(url)> - Shows the motd to clients on startup. Can specify URL here.", ULib.ACCESS_ADMIN ) end
|
||||
end
|
||||
local CATEGORY_NAME = "Menus"
|
||||
|
||||
if ULib.fileExists( "lua/ulx/modules/cl/motdmenu.lua" ) or ulx.motdmenu_exists then
|
||||
CreateConVar( "motdfile", "ulx_motd.txt" ) -- Garry likes to add and remove this cvar a lot, so it's here just in case he removes it again.
|
||||
local function sendMotd( ply, showMotd )
|
||||
if showMotd == "1" then -- Assume it's a file
|
||||
if ply.ulxHasMotd then return end -- This player already has the motd
|
||||
if not ULib.fileExists( GetConVarString( "motdfile" ) ) then return end -- Invalid
|
||||
local f = ULib.fileRead( GetConVarString( "motdfile" ) )
|
||||
|
||||
ULib.clientRPC( ply, "ulx.rcvMotd", false, f )
|
||||
|
||||
ply.ulxHasMotd = true
|
||||
|
||||
else -- Assume URL
|
||||
ULib.clientRPC( ply, "ulx.rcvMotd", true, showMotd )
|
||||
ply.ulxHasMotd = nil
|
||||
end
|
||||
end
|
||||
|
||||
local function showMotd( ply )
|
||||
local showMotd = GetConVarString( "ulx_showMotd" )
|
||||
if showMotd == "0" then return end
|
||||
if not ply:IsValid() then return end -- They left, doh!
|
||||
|
||||
sendMotd( ply, showMotd )
|
||||
ULib.clientRPC( ply, "ulx.showMotdMenu", ply:SteamID() ) -- Passing it because they may get it before LocalPlayer() is valid
|
||||
end
|
||||
hook.Add( "PlayerInitialSpawn", "showMotd", showMotd )
|
||||
|
||||
function ulx.motd( calling_ply )
|
||||
if not calling_ply:IsValid() then
|
||||
Msg( "You can't see the motd from the console.\n" )
|
||||
return
|
||||
end
|
||||
|
||||
if GetConVarString( "ulx_showMotd" ) == "0" then
|
||||
ULib.tsay( calling_ply, "The MOTD has been disabled on this server." )
|
||||
return
|
||||
end
|
||||
|
||||
showMotd( calling_ply )
|
||||
end
|
||||
local motdmenu = ulx.command( CATEGORY_NAME, "ulx motd", ulx.motd, "!motd" )
|
||||
motdmenu:defaultAccess( ULib.ACCESS_ALL )
|
||||
motdmenu:help( "Show the message of the day." )
|
||||
if SERVER then ulx.convar( "showMotd", "1", " <0/1/(url)> - Shows the motd to clients on startup. Can specify URL here.", ULib.ACCESS_ADMIN ) end
|
||||
end
|
||||
|
@ -1,85 +1,85 @@
|
||||
local help = [[
|
||||
General User Management Concepts:
|
||||
User access is driven by ULib's Ulysses Control List (UCL). This list contains users and groups
|
||||
which in turn contains lists of allowed and denied accesses. The allow and deny lists contain
|
||||
access strings like "ulx slap" or "ulx phygunplayer" to show what a user and/or group does and does
|
||||
not have access to. If a user has "ulx slap" in their user allow list or in the allow list of one
|
||||
of the groups they belong to, they have access to slap. If a user has "ulx slap" in their user deny
|
||||
list they are DENIED the command, even if they have the command in one of their group's allow
|
||||
lists. In this way, deny takes precedence over allow.
|
||||
|
||||
ULib supports immunity by being able to specify what various users and groups are allowed to
|
||||
target. This is often used to make it so lower admins cannot target higher admins. EG, by default
|
||||
admins can't target superadmins, but superadmins can still target admins.
|
||||
|
||||
|
||||
More Advanced Concepts:
|
||||
Groups have inheritance. You can specify what group they inherit from in the addgroup command. If a
|
||||
user is in a group that has inheritance, UCL will check all groups connected in the inheritance
|
||||
chain. Note that groups do not support deny lists for the sake of simplicity. If you feel that a
|
||||
group needs to be denied something, you should split your groups up instead.
|
||||
|
||||
The "user" group applies to everyone who does not otherwise belong in a group. You can use
|
||||
groupallow on this group just like any other, just remember that everyone is being allowed access.
|
||||
|
||||
ULib supports an advanced, highly configurable permission system by using "access tags". Access
|
||||
tags specify what a user is allowed to pass as arguments to a command. For example, you can make it
|
||||
so that admins are only allowed to slay users with "killme" somewhere in their name, or you can
|
||||
give everyone access to the "ulx teleport" command, but only allow them to teleport themselves.
|
||||
|
||||
Examples of using access tags are given below in the userallow and groupallow commands. The format
|
||||
for access tags is as follows. Each argument that is passed to the command can be limited by the
|
||||
access tag. Each argument being limited must be listed in the same order as in the command,
|
||||
separated by spaces. If you don't want to limit an argument, use a star ("*"). EG, to limit "ulx
|
||||
slap" damage to 0 through 10, but still allow it to be used on anyone, use the tag "* 0:10".
|
||||
|
||||
User Management Commands:
|
||||
ulx adduser <user> <group> - Add the specified CONNECTED player to the specified group.
|
||||
The group MUST exist for this command to succeed. Use operator, admin, superadmin, or see ulx
|
||||
addgroup. You can only specify one group. See above for explanation on immunity.
|
||||
Ex 1. ulx adduser "Someguy" superadmin -- This will add the connected "Someguy" as a superadmin
|
||||
Ex 2. ulx adduser "Dood" monkey -- This will add the connected "Dood" to the group monkey
|
||||
on the condition that the group exists
|
||||
|
||||
ulx removeuser <user> - Remove the specified connected player from the permanent access list.
|
||||
Ex 1. ulx removeuser "Foo bar" -- This removes the user "Foo bar"
|
||||
|
||||
ulx userallow <user> <access> [<access tag>] - Puts the access on the USER'S ALLOW list, with
|
||||
optional access tag (see above)
|
||||
See above for explanation of allow list vs. deny list, as well as how access strings/tags work.
|
||||
Ex 1. ulx userallow "Pi" "ulx slap" -- This grants the user access to "ulx slap"
|
||||
Ex 2. ulx userallow "Pi" "ulx slap" "!%admin 0" -- This grants the user access to "ulx slap"
|
||||
-- but they can only slap users lower than an admin, and they can only slap for 0 damage
|
||||
|
||||
ulx userdeny <user> <access> [<revoke>] - Removes a player's access. If revoke is true, this simply
|
||||
removes the access string from the user's allow/deny lists instead of adding it to the user's
|
||||
deny list. See above for an explanation on the deny list.
|
||||
|
||||
ulx addgroup <group> [<inherits from>] - Creates a group, optionally inheriting from the specified
|
||||
group. See above for explanation on inheritance.
|
||||
|
||||
ulx removegroup <group> - Removes a group PERMANENTLY. Also removes the group from all connected
|
||||
users and all users who connect in the future. If a user has no group besides this, they will
|
||||
become guests. Please be VERY careful with this command!
|
||||
|
||||
ulx renamegroup <current group> <new group> - Renames a group
|
||||
|
||||
ulx setgroupcantarget <group> [<target string>] - Limits what users a group can target. Pass no
|
||||
argument to clear the restriction.
|
||||
Ex 1. ulx setgroupcantarget user !%admin - Guests cannot target admins or above
|
||||
Ex 2. ulx setgroupcantarget admin !^ - Admins cannot target themselves
|
||||
|
||||
ulx groupallow <group> <access> [<access tag>] - Puts the access on the group's allow list. See
|
||||
above on how access strings/tags work.
|
||||
|
||||
ulx groupdeny <group> <access> - Removes the group's access.
|
||||
|
||||
|
||||
]]
|
||||
|
||||
function ulx.showUserHelp()
|
||||
local lines = ULib.explode( "\n", help )
|
||||
for _, line in ipairs( lines ) do
|
||||
Msg( line .. "\n" )
|
||||
end
|
||||
end
|
||||
local help = [[
|
||||
General User Management Concepts:
|
||||
User access is driven by ULib's Ulysses Control List (UCL). This list contains users and groups
|
||||
which in turn contains lists of allowed and denied accesses. The allow and deny lists contain
|
||||
access strings like "ulx slap" or "ulx phygunplayer" to show what a user and/or group does and does
|
||||
not have access to. If a user has "ulx slap" in their user allow list or in the allow list of one
|
||||
of the groups they belong to, they have access to slap. If a user has "ulx slap" in their user deny
|
||||
list they are DENIED the command, even if they have the command in one of their group's allow
|
||||
lists. In this way, deny takes precedence over allow.
|
||||
|
||||
ULib supports immunity by being able to specify what various users and groups are allowed to
|
||||
target. This is often used to make it so lower admins cannot target higher admins. EG, by default
|
||||
admins can't target superadmins, but superadmins can still target admins.
|
||||
|
||||
|
||||
More Advanced Concepts:
|
||||
Groups have inheritance. You can specify what group they inherit from in the addgroup command. If a
|
||||
user is in a group that has inheritance, UCL will check all groups connected in the inheritance
|
||||
chain. Note that groups do not support deny lists for the sake of simplicity. If you feel that a
|
||||
group needs to be denied something, you should split your groups up instead.
|
||||
|
||||
The "user" group applies to everyone who does not otherwise belong in a group. You can use
|
||||
groupallow on this group just like any other, just remember that everyone is being allowed access.
|
||||
|
||||
ULib supports an advanced, highly configurable permission system by using "access tags". Access
|
||||
tags specify what a user is allowed to pass as arguments to a command. For example, you can make it
|
||||
so that admins are only allowed to slay users with "killme" somewhere in their name, or you can
|
||||
give everyone access to the "ulx teleport" command, but only allow them to teleport themselves.
|
||||
|
||||
Examples of using access tags are given below in the userallow and groupallow commands. The format
|
||||
for access tags is as follows. Each argument that is passed to the command can be limited by the
|
||||
access tag. Each argument being limited must be listed in the same order as in the command,
|
||||
separated by spaces. If you don't want to limit an argument, use a star ("*"). EG, to limit "ulx
|
||||
slap" damage to 0 through 10, but still allow it to be used on anyone, use the tag "* 0:10".
|
||||
|
||||
User Management Commands:
|
||||
ulx adduser <user> <group> - Add the specified CONNECTED player to the specified group.
|
||||
The group MUST exist for this command to succeed. Use operator, admin, superadmin, or see ulx
|
||||
addgroup. You can only specify one group. See above for explanation on immunity.
|
||||
Ex 1. ulx adduser "Someguy" superadmin -- This will add the connected "Someguy" as a superadmin
|
||||
Ex 2. ulx adduser "Dood" monkey -- This will add the connected "Dood" to the group monkey
|
||||
on the condition that the group exists
|
||||
|
||||
ulx removeuser <user> - Remove the specified connected player from the permanent access list.
|
||||
Ex 1. ulx removeuser "Foo bar" -- This removes the user "Foo bar"
|
||||
|
||||
ulx userallow <user> <access> [<access tag>] - Puts the access on the USER'S ALLOW list, with
|
||||
optional access tag (see above)
|
||||
See above for explanation of allow list vs. deny list, as well as how access strings/tags work.
|
||||
Ex 1. ulx userallow "Pi" "ulx slap" -- This grants the user access to "ulx slap"
|
||||
Ex 2. ulx userallow "Pi" "ulx slap" "!%admin 0" -- This grants the user access to "ulx slap"
|
||||
-- but they can only slap users lower than an admin, and they can only slap for 0 damage
|
||||
|
||||
ulx userdeny <user> <access> [<revoke>] - Removes a player's access. If revoke is true, this simply
|
||||
removes the access string from the user's allow/deny lists instead of adding it to the user's
|
||||
deny list. See above for an explanation on the deny list.
|
||||
|
||||
ulx addgroup <group> [<inherits from>] - Creates a group, optionally inheriting from the specified
|
||||
group. See above for explanation on inheritance.
|
||||
|
||||
ulx removegroup <group> - Removes a group PERMANENTLY. Also removes the group from all connected
|
||||
users and all users who connect in the future. If a user has no group besides this, they will
|
||||
become guests. Please be VERY careful with this command!
|
||||
|
||||
ulx renamegroup <current group> <new group> - Renames a group
|
||||
|
||||
ulx setgroupcantarget <group> [<target string>] - Limits what users a group can target. Pass no
|
||||
argument to clear the restriction.
|
||||
Ex 1. ulx setgroupcantarget user !%admin - Guests cannot target admins or above
|
||||
Ex 2. ulx setgroupcantarget admin !^ - Admins cannot target themselves
|
||||
|
||||
ulx groupallow <group> <access> [<access tag>] - Puts the access on the group's allow list. See
|
||||
above on how access strings/tags work.
|
||||
|
||||
ulx groupdeny <group> <access> - Removes the group's access.
|
||||
|
||||
|
||||
]]
|
||||
|
||||
function ulx.showUserHelp()
|
||||
local lines = ULib.explode( "\n", help )
|
||||
for _, line in ipairs( lines ) do
|
||||
Msg( line .. "\n" )
|
||||
end
|
||||
end
|
||||
|
@ -1,89 +1,89 @@
|
||||
ulx.convar( "rslotsMode", "0", " - Sets the slots mode. See config for more information.", ULib.ACCESS_ADMIN )
|
||||
ulx.convar( "rslots", "2", " - Sets the number of reserved slots, only applicable for modes 1 and 2.", ULib.ACCESS_ADMIN )
|
||||
ulx.convar( "rslotsVisible", "1", " - Sets whether slots are visible. See config for more information.", ULib.ACCESS_ADMIN )
|
||||
|
||||
local access = "ulx reservedslots" -- Access string needed for reserved slots
|
||||
ULib.ucl.registerAccess( access, ULib.ACCESS_ADMIN, "Access to reserved slots", "Other" ) -- Give admins access to reserved slots by default
|
||||
|
||||
function calcSlots( disconnect )
|
||||
local mode = GetConVarNumber( "ulx_rslotsMode" )
|
||||
if mode == 3 then return 1 end -- Only one slot on this mode
|
||||
|
||||
local slots = GetConVarNumber( "ulx_rslots" )
|
||||
if mode == 2 then return slots end
|
||||
|
||||
if mode == 1 then
|
||||
local admins = 0 -- Keep track of how many people with access we have
|
||||
|
||||
local players = player.GetAll()
|
||||
for _, player in ipairs( players ) do
|
||||
if player:IsConnected() and player:query( access ) then
|
||||
admins = admins + 1
|
||||
end
|
||||
end
|
||||
|
||||
if disconnect then admins = admins - 1 end -- Otherwise we're counting the disconnecting admin
|
||||
if admins < 0 then admins = 0 end -- Just to be safe!
|
||||
|
||||
local rslots = slots - admins
|
||||
if rslots < 0 then rslots = 0 end -- If we have more admins right now then slots for them, we don't want to return a negative number.
|
||||
return rslots
|
||||
end
|
||||
|
||||
return 0 -- We're actually having an error if we get here, but let's handle it gracefully
|
||||
end
|
||||
|
||||
local function updateSlots( ply, disconnect )
|
||||
local visible = ULib.toBool( GetConVarString( "ulx_rslotsVisible" ) )
|
||||
if not visible then -- Make sure our visible slots is up to date
|
||||
local slots = calcSlots( disconnect )
|
||||
local max = game.MaxPlayers()
|
||||
game.ConsoleCommand( "sv_visiblemaxplayers " .. max - slots .. "\n" )
|
||||
end
|
||||
end
|
||||
hook.Add( "PlayerDisconnected", "ulxSlotsDisconnect", function( ply ) updateSlots( ply, ply:query( access ) ) end )
|
||||
hook.Add( ulx.HOOK_ULXDONELOADING, "ULXUpdateSlots", updateSlots )
|
||||
|
||||
local function playerAccess( ply )
|
||||
local mode = GetConVarNumber( "ulx_rslotsMode" )
|
||||
if mode == 0 then return end -- Off!
|
||||
|
||||
local visible = ULib.toBool( GetConVarString( "ulx_rslotsVisible" ) )
|
||||
local slots = calcSlots()
|
||||
local cur = #player.GetAll()
|
||||
local max = game.MaxPlayers()
|
||||
|
||||
if ply:query( access ) then -- If they have access, handle this differently
|
||||
if not visible then -- Make sure our visible slots is up to date
|
||||
updateSlots()
|
||||
end
|
||||
|
||||
if mode == 3 and cur + slots > max then -- We've got some kicking to do!
|
||||
local shortestply
|
||||
local shortesttime = math.huge
|
||||
|
||||
local players = player.GetAll()
|
||||
for _, player in ipairs( players ) do
|
||||
if not ULib.ucl.query( player, access ) then
|
||||
if player:TimeConnected() < shortesttime then
|
||||
shortesttime = player:TimeConnected()
|
||||
shortestply = player
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not shortestply then -- We've got a server filled to the brim with admins? Odd but okay
|
||||
return
|
||||
end
|
||||
|
||||
ULib.kick( shortestply, "[ULX] Freeing slot. Sorry, you had the shortest connection time." )
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if cur + slots > max then
|
||||
ULib.queueFunctionCall( ULib.kick, ply, "[ULX] Reserved slot, sorry!" ) -- Wait a frame so all access hooks can be called properly.
|
||||
end
|
||||
end
|
||||
hook.Add( ULib.HOOK_UCLAUTH, "ULXReservedSlots", playerAccess, HOOK_MONITOR_LOW ) -- Run at the end of auth
|
||||
ulx.convar( "rslotsMode", "0", " - Sets the slots mode. See config for more information.", ULib.ACCESS_ADMIN )
|
||||
ulx.convar( "rslots", "2", " - Sets the number of reserved slots, only applicable for modes 1 and 2.", ULib.ACCESS_ADMIN )
|
||||
ulx.convar( "rslotsVisible", "1", " - Sets whether slots are visible. See config for more information.", ULib.ACCESS_ADMIN )
|
||||
|
||||
local access = "ulx reservedslots" -- Access string needed for reserved slots
|
||||
ULib.ucl.registerAccess( access, ULib.ACCESS_ADMIN, "Access to reserved slots", "Other" ) -- Give admins access to reserved slots by default
|
||||
|
||||
function calcSlots( disconnect )
|
||||
local mode = GetConVarNumber( "ulx_rslotsMode" )
|
||||
if mode == 3 then return 1 end -- Only one slot on this mode
|
||||
|
||||
local slots = GetConVarNumber( "ulx_rslots" )
|
||||
if mode == 2 then return slots end
|
||||
|
||||
if mode == 1 then
|
||||
local admins = 0 -- Keep track of how many people with access we have
|
||||
|
||||
local players = player.GetAll()
|
||||
for _, player in ipairs( players ) do
|
||||
if player:IsConnected() and player:query( access ) then
|
||||
admins = admins + 1
|
||||
end
|
||||
end
|
||||
|
||||
if disconnect then admins = admins - 1 end -- Otherwise we're counting the disconnecting admin
|
||||
if admins < 0 then admins = 0 end -- Just to be safe!
|
||||
|
||||
local rslots = slots - admins
|
||||
if rslots < 0 then rslots = 0 end -- If we have more admins right now then slots for them, we don't want to return a negative number.
|
||||
return rslots
|
||||
end
|
||||
|
||||
return 0 -- We're actually having an error if we get here, but let's handle it gracefully
|
||||
end
|
||||
|
||||
local function updateSlots( ply, disconnect )
|
||||
local visible = ULib.toBool( GetConVarString( "ulx_rslotsVisible" ) )
|
||||
if not visible then -- Make sure our visible slots is up to date
|
||||
local slots = calcSlots( disconnect )
|
||||
local max = game.MaxPlayers()
|
||||
game.ConsoleCommand( "sv_visiblemaxplayers " .. max - slots .. "\n" )
|
||||
end
|
||||
end
|
||||
hook.Add( "PlayerDisconnected", "ulxSlotsDisconnect", function( ply ) updateSlots( ply, ply:query( access ) ) end )
|
||||
hook.Add( ulx.HOOK_ULXDONELOADING, "ULXUpdateSlots", updateSlots )
|
||||
|
||||
local function playerAccess( ply )
|
||||
local mode = GetConVarNumber( "ulx_rslotsMode" )
|
||||
if mode == 0 then return end -- Off!
|
||||
|
||||
local visible = ULib.toBool( GetConVarString( "ulx_rslotsVisible" ) )
|
||||
local slots = calcSlots()
|
||||
local cur = #player.GetAll()
|
||||
local max = game.MaxPlayers()
|
||||
|
||||
if ply:query( access ) then -- If they have access, handle this differently
|
||||
if not visible then -- Make sure our visible slots is up to date
|
||||
updateSlots()
|
||||
end
|
||||
|
||||
if mode == 3 and cur + slots > max then -- We've got some kicking to do!
|
||||
local shortestply
|
||||
local shortesttime = math.huge
|
||||
|
||||
local players = player.GetAll()
|
||||
for _, player in ipairs( players ) do
|
||||
if not ULib.ucl.query( player, access ) then
|
||||
if player:TimeConnected() < shortesttime then
|
||||
shortesttime = player:TimeConnected()
|
||||
shortestply = player
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not shortestply then -- We've got a server filled to the brim with admins? Odd but okay
|
||||
return
|
||||
end
|
||||
|
||||
ULib.kick( shortestply, "[ULX] Freeing slot. Sorry, you had the shortest connection time." )
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if cur + slots > max then
|
||||
ULib.queueFunctionCall( ULib.kick, ply, "[ULX] Reserved slot, sorry!" ) -- Wait a frame so all access hooks can be called properly.
|
||||
end
|
||||
end
|
||||
hook.Add( ULib.HOOK_UCLAUTH, "ULXReservedSlots", playerAccess, HOOK_MONITOR_LOW ) -- Run at the end of auth
|
||||
|
@ -1,181 +1,181 @@
|
||||
------------------
|
||||
--Public votemap--
|
||||
------------------
|
||||
ulx.votemaps = ulx.votemaps or {}
|
||||
local specifiedMaps = {}
|
||||
|
||||
local function init()
|
||||
local mode = GetConVarNumber( "ulx_votemapMapmode" ) or 1
|
||||
if mode == 1 then -- Add all but specified
|
||||
local maps = file.Find( "maps/*.bsp", "GAME" )
|
||||
for _, map in ipairs( maps ) do
|
||||
map = map:sub( 1, -5 ) -- Take off .bsp
|
||||
if not specifiedMaps[ map ] then
|
||||
table.insert( ulx.votemaps, map )
|
||||
end
|
||||
end
|
||||
else
|
||||
for map, _ in pairs( specifiedMaps ) do
|
||||
if ULib.fileExists( "maps/" .. map .. ".bsp" ) then
|
||||
table.insert( ulx.votemaps, map )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Now, let's sort!
|
||||
table.sort( ulx.votemaps )
|
||||
end
|
||||
hook.Add( ulx.HOOK_ULXDONELOADING, "ULXInitConfigs", init ) -- Time for configs
|
||||
|
||||
local userMapvote = {} -- Indexed by player.
|
||||
local mapvotes = {} -- Indexed by map.
|
||||
ulx.timedVeto = nil
|
||||
|
||||
ulx.convar( "votemapEnabled", "1", _, ULib.ACCESS_ADMIN ) -- Enable/Disable the entire votemap command
|
||||
ulx.convar( "votemapMintime", "10", _, ULib.ACCESS_ADMIN ) -- Time after map change before votes count.
|
||||
ulx.convar( "votemapWaittime", "5", _, ULib.ACCESS_ADMIN ) -- Time before a user must wait before they can change their vote.
|
||||
ulx.convar( "votemapSuccessratio", "0.5", _, ULib.ACCESS_ADMIN ) -- Ratio of (votes for map)/(total players) needed to change map. (Rounds up)
|
||||
ulx.convar( "votemapMinvotes", "3", _, ULib.ACCESS_ADMIN ) -- Number of minimum votes needed to change map (Prevents llamas). This supercedes the above convar on small servers.
|
||||
ulx.convar( "votemapVetotime", "30", _, ULib.ACCESS_ADMIN ) -- Time in seconds an admin has after a successful votemap to veto the vote. Set to 0 to disable.
|
||||
ulx.convar( "votemapMapmode", "1", _, ULib.ACCESS_ADMIN ) -- 1 = Use all maps but what's specified below, 2 = Use only the maps specified below.
|
||||
|
||||
function ulx.votemapVeto( calling_ply )
|
||||
if not ulx.timedVeto then
|
||||
ULib.tsayError( calling_ply, "There's nothing to veto!", true )
|
||||
return
|
||||
end
|
||||
|
||||
timer.Remove( "ULXVotemap" )
|
||||
ulx.timedVeto = nil
|
||||
hook.Call( ulx.HOOK_VETO )
|
||||
ULib.tsay( _, "Votemap changelevel halted.", true )
|
||||
ulx.logServAct( calling_ply, "#A vetoed the votemap" )
|
||||
end
|
||||
-- The command is defined at the end of vote.lua
|
||||
|
||||
function ulx.votemapAddMap( map )
|
||||
specifiedMaps[ map ] = true
|
||||
end
|
||||
|
||||
function ulx.clearVotemaps()
|
||||
table.Empty( specifiedMaps )
|
||||
end
|
||||
|
||||
function ulx.votemap( calling_ply, map )
|
||||
if not ULib.toBool( GetConVarNumber( "ulx_votemapEnabled" ) ) then
|
||||
ULib.tsayError( calling_ply, "The votemap command has been disabled by a server admin.", true )
|
||||
return
|
||||
end
|
||||
|
||||
if not calling_ply:IsValid() then
|
||||
Msg( "You can't use votemap from the dedicated server console.\n" )
|
||||
return
|
||||
end
|
||||
|
||||
if ulx.timedVeto then
|
||||
ULib.tsayError( calling_ply, "You cannot vote right now, another map has already won and is pending approval.", true )
|
||||
return
|
||||
end
|
||||
|
||||
if not map or map == "" then
|
||||
ULib.tsay( calling_ply, "Map list printed to console", true )
|
||||
ULib.console( calling_ply, "Use \"votemap <id>\" to vote for a map. Map list:" )
|
||||
for id, map in ipairs( ulx.votemaps ) do
|
||||
ULib.console( calling_ply, " " .. id .. " -\t" .. map )
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local mintime = tonumber( GetConVarString( "ulx_votemapMintime" ) ) or 10
|
||||
if CurTime() < mintime * 60 then -- Minutes -> seconds
|
||||
ULib.tsayError( calling_ply, "Sorry, you must wait " .. mintime .. " minutes after a map change before you can vote for another map.", true )
|
||||
local timediff = mintime*60 - CurTime()
|
||||
ULib.tsayError( calling_ply, "That means you must wait " .. string.FormattedTime( math.fmod( timediff, 3600 ), (mintime < 60) and "%02i:%02i" or math.floor( timediff/3600 ) .. " hour(s) and %02i:%02i" ) .. " more minutes.", true )
|
||||
return
|
||||
end
|
||||
|
||||
if userMapvote[ calling_ply ] then
|
||||
local waittime = tonumber( GetConVarString( "ulx_votemapWaittime" ) ) or 5
|
||||
if CurTime() - userMapvote[ calling_ply ].time < waittime * 60 then -- Minutes -> seconds
|
||||
ULib.tsayError( calling_ply, "Sorry, you must wait " .. waittime .. " minutes before changing your vote.", true )
|
||||
local timediff = waittime*60 - (CurTime() - userMapvote[ calling_ply ].time)
|
||||
ULib.tsayError( calling_ply, "That means you must wait " .. string.FormattedTime( math.fmod( timediff, 3600 ), (waittime < 60) and "%02i:%02i" or math.floor( timediff/3600 ) .. " hour(s) and %02i:%02i" ) .. " more minutes.", true )
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local mapid
|
||||
if tonumber( map ) then
|
||||
mapid = tonumber( map )
|
||||
if not ulx.votemaps[ mapid ] then
|
||||
ULib.tsayError( calling_ply, "Invalid map id!", true )
|
||||
return
|
||||
end
|
||||
else
|
||||
if string.sub( map, -4 ) == ".bsp" then
|
||||
map = string.sub( map, 1, -5 ) -- Take off the .bsp
|
||||
end
|
||||
|
||||
mapid = ULib.findInTable( ulx.votemaps, map )
|
||||
if not mapid then
|
||||
ULib.tsayError( calling_ply, "Invalid map!", true )
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if userMapvote[ calling_ply ] then -- Take away from their previous vote
|
||||
mapvotes[ userMapvote[ calling_ply ].mapid ] = mapvotes[ userMapvote[ calling_ply ].mapid ] - 1
|
||||
end
|
||||
|
||||
userMapvote[ calling_ply ] = { mapid=mapid, time=CurTime() }
|
||||
mapvotes[ mapid ] = mapvotes[ mapid ] or 0
|
||||
mapvotes[ mapid ] = mapvotes[ mapid ] + 1
|
||||
|
||||
local minvotes = tonumber( GetConVarString( "ulx_votemapMinvotes" ) ) or 0
|
||||
local successratio = tonumber( GetConVarString( "ulx_votemapSuccessratio" ) ) or 0.5
|
||||
|
||||
local votes_needed = math.ceil( math.max( minvotes, successratio * #player.GetAll() ) ) -- Round up whatever the largest is.
|
||||
|
||||
-- TODO, color?
|
||||
ULib.tsay( _, string.format( "%s voted for %s (%i/%i). Say \"!votemap %i\" to vote for this map too.", calling_ply:Nick(), ulx.votemaps[ mapid ], mapvotes[ mapid ], votes_needed, mapid ), true )
|
||||
ulx.logString( string.format( "%s voted for %s (%i/%i)", calling_ply:Nick(), ulx.votemaps[ mapid ], mapvotes[ mapid ], votes_needed ) )
|
||||
|
||||
if mapvotes[ mapid ] >= votes_needed then
|
||||
local vetotime = tonumber( GetConVarString( "ulx_votemapVetotime" ) ) or 30
|
||||
|
||||
local admins = {}
|
||||
local players = player.GetAll()
|
||||
for _, player in ipairs( players ) do
|
||||
if player:IsConnected() then
|
||||
if ULib.ucl.query( player, "ulx veto" ) then
|
||||
table.insert( admins, player )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if #admins <= 0 or vetotime < 1 then
|
||||
ULib.tsay( _, "Vote for map " .. ulx.votemaps[ mapid ] .. " successful! Changing levels now.", true ) -- TODO, color?
|
||||
ulx.logString( "Votemap for " .. ulx.votemaps[ mapid ] .. " won." )
|
||||
game.ConsoleCommand( "changelevel " .. ulx.votemaps[ mapid ] .. "\n" )
|
||||
else
|
||||
ULib.tsay( _, "Vote for map " .. ulx.votemaps[ mapid ] .. " successful! Now pending admin approval. (" .. vetotime .. " seconds)", true ) -- TODO, color?
|
||||
for _, player in ipairs( admins ) do
|
||||
ULib.tsay( player, "To veto this vote, just say \"!veto\"", true ) -- TODO, color?
|
||||
end
|
||||
ulx.logString( "Votemap for " .. ulx.votemaps[ mapid ] .. " won. Pending admin veto." )
|
||||
ulx.timedVeto = true
|
||||
hook.Call( ulx.HOOK_VETO )
|
||||
timer.Create( "ULXVotemap", vetotime, 1, function() game.ConsoleCommand( "changelevel " .. ulx.votemaps[ mapid ] .. "\n" ) end )
|
||||
end
|
||||
end
|
||||
end
|
||||
-- This command is defined at the bottom of vote.lua
|
||||
|
||||
function ulx.votemap_disconnect( ply ) -- We use this to clear out old people's votes
|
||||
if userMapvote[ ply ] then -- Take away from their previous vote
|
||||
mapvotes[ userMapvote[ ply ].mapid ] = mapvotes[ userMapvote[ ply ].mapid ] - 1
|
||||
userMapvote[ ply ] = nil
|
||||
end
|
||||
end
|
||||
hook.Add( "PlayerDisconnected", "ULXVoteDisconnect", ulx.votemap_disconnect )
|
||||
------------------
|
||||
--Public votemap--
|
||||
------------------
|
||||
ulx.votemaps = ulx.votemaps or {}
|
||||
local specifiedMaps = {}
|
||||
|
||||
local function init()
|
||||
local mode = GetConVarNumber( "ulx_votemapMapmode" ) or 1
|
||||
if mode == 1 then -- Add all but specified
|
||||
local maps = file.Find( "maps/*.bsp", "GAME" )
|
||||
for _, map in ipairs( maps ) do
|
||||
map = map:sub( 1, -5 ) -- Take off .bsp
|
||||
if not specifiedMaps[ map ] then
|
||||
table.insert( ulx.votemaps, map )
|
||||
end
|
||||
end
|
||||
else
|
||||
for map, _ in pairs( specifiedMaps ) do
|
||||
if ULib.fileExists( "maps/" .. map .. ".bsp" ) then
|
||||
table.insert( ulx.votemaps, map )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Now, let's sort!
|
||||
table.sort( ulx.votemaps )
|
||||
end
|
||||
hook.Add( ulx.HOOK_ULXDONELOADING, "ULXInitConfigs", init ) -- Time for configs
|
||||
|
||||
local userMapvote = {} -- Indexed by player.
|
||||
local mapvotes = {} -- Indexed by map.
|
||||
ulx.timedVeto = nil
|
||||
|
||||
ulx.convar( "votemapEnabled", "1", _, ULib.ACCESS_ADMIN ) -- Enable/Disable the entire votemap command
|
||||
ulx.convar( "votemapMintime", "10", _, ULib.ACCESS_ADMIN ) -- Time after map change before votes count.
|
||||
ulx.convar( "votemapWaittime", "5", _, ULib.ACCESS_ADMIN ) -- Time before a user must wait before they can change their vote.
|
||||
ulx.convar( "votemapSuccessratio", "0.5", _, ULib.ACCESS_ADMIN ) -- Ratio of (votes for map)/(total players) needed to change map. (Rounds up)
|
||||
ulx.convar( "votemapMinvotes", "3", _, ULib.ACCESS_ADMIN ) -- Number of minimum votes needed to change map (Prevents llamas). This supercedes the above convar on small servers.
|
||||
ulx.convar( "votemapVetotime", "30", _, ULib.ACCESS_ADMIN ) -- Time in seconds an admin has after a successful votemap to veto the vote. Set to 0 to disable.
|
||||
ulx.convar( "votemapMapmode", "1", _, ULib.ACCESS_ADMIN ) -- 1 = Use all maps but what's specified below, 2 = Use only the maps specified below.
|
||||
|
||||
function ulx.votemapVeto( calling_ply )
|
||||
if not ulx.timedVeto then
|
||||
ULib.tsayError( calling_ply, "There's nothing to veto!", true )
|
||||
return
|
||||
end
|
||||
|
||||
timer.Remove( "ULXVotemap" )
|
||||
ulx.timedVeto = nil
|
||||
hook.Call( ulx.HOOK_VETO )
|
||||
ULib.tsay( _, "Votemap changelevel halted.", true )
|
||||
ulx.logServAct( calling_ply, "#A vetoed the votemap" )
|
||||
end
|
||||
-- The command is defined at the end of vote.lua
|
||||
|
||||
function ulx.votemapAddMap( map )
|
||||
specifiedMaps[ map ] = true
|
||||
end
|
||||
|
||||
function ulx.clearVotemaps()
|
||||
table.Empty( specifiedMaps )
|
||||
end
|
||||
|
||||
function ulx.votemap( calling_ply, map )
|
||||
if not ULib.toBool( GetConVarNumber( "ulx_votemapEnabled" ) ) then
|
||||
ULib.tsayError( calling_ply, "The votemap command has been disabled by a server admin.", true )
|
||||
return
|
||||
end
|
||||
|
||||
if not calling_ply:IsValid() then
|
||||
Msg( "You can't use votemap from the dedicated server console.\n" )
|
||||
return
|
||||
end
|
||||
|
||||
if ulx.timedVeto then
|
||||
ULib.tsayError( calling_ply, "You cannot vote right now, another map has already won and is pending approval.", true )
|
||||
return
|
||||
end
|
||||
|
||||
if not map or map == "" then
|
||||
ULib.tsay( calling_ply, "Map list printed to console", true )
|
||||
ULib.console( calling_ply, "Use \"votemap <id>\" to vote for a map. Map list:" )
|
||||
for id, map in ipairs( ulx.votemaps ) do
|
||||
ULib.console( calling_ply, " " .. id .. " -\t" .. map )
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local mintime = tonumber( GetConVarString( "ulx_votemapMintime" ) ) or 10
|
||||
if CurTime() < mintime * 60 then -- Minutes -> seconds
|
||||
ULib.tsayError( calling_ply, "Sorry, you must wait " .. mintime .. " minutes after a map change before you can vote for another map.", true )
|
||||
local timediff = mintime*60 - CurTime()
|
||||
ULib.tsayError( calling_ply, "That means you must wait " .. string.FormattedTime( math.fmod( timediff, 3600 ), (mintime < 60) and "%02i:%02i" or math.floor( timediff/3600 ) .. " hour(s) and %02i:%02i" ) .. " more minutes.", true )
|
||||
return
|
||||
end
|
||||
|
||||
if userMapvote[ calling_ply ] then
|
||||
local waittime = tonumber( GetConVarString( "ulx_votemapWaittime" ) ) or 5
|
||||
if CurTime() - userMapvote[ calling_ply ].time < waittime * 60 then -- Minutes -> seconds
|
||||
ULib.tsayError( calling_ply, "Sorry, you must wait " .. waittime .. " minutes before changing your vote.", true )
|
||||
local timediff = waittime*60 - (CurTime() - userMapvote[ calling_ply ].time)
|
||||
ULib.tsayError( calling_ply, "That means you must wait " .. string.FormattedTime( math.fmod( timediff, 3600 ), (waittime < 60) and "%02i:%02i" or math.floor( timediff/3600 ) .. " hour(s) and %02i:%02i" ) .. " more minutes.", true )
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local mapid
|
||||
if tonumber( map ) then
|
||||
mapid = tonumber( map )
|
||||
if not ulx.votemaps[ mapid ] then
|
||||
ULib.tsayError( calling_ply, "Invalid map id!", true )
|
||||
return
|
||||
end
|
||||
else
|
||||
if string.sub( map, -4 ) == ".bsp" then
|
||||
map = string.sub( map, 1, -5 ) -- Take off the .bsp
|
||||
end
|
||||
|
||||
mapid = ULib.findInTable( ulx.votemaps, map )
|
||||
if not mapid then
|
||||
ULib.tsayError( calling_ply, "Invalid map!", true )
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if userMapvote[ calling_ply ] then -- Take away from their previous vote
|
||||
mapvotes[ userMapvote[ calling_ply ].mapid ] = mapvotes[ userMapvote[ calling_ply ].mapid ] - 1
|
||||
end
|
||||
|
||||
userMapvote[ calling_ply ] = { mapid=mapid, time=CurTime() }
|
||||
mapvotes[ mapid ] = mapvotes[ mapid ] or 0
|
||||
mapvotes[ mapid ] = mapvotes[ mapid ] + 1
|
||||
|
||||
local minvotes = tonumber( GetConVarString( "ulx_votemapMinvotes" ) ) or 0
|
||||
local successratio = tonumber( GetConVarString( "ulx_votemapSuccessratio" ) ) or 0.5
|
||||
|
||||
local votes_needed = math.ceil( math.max( minvotes, successratio * #player.GetAll() ) ) -- Round up whatever the largest is.
|
||||
|
||||
-- TODO, color?
|
||||
ULib.tsay( _, string.format( "%s voted for %s (%i/%i). Say \"!votemap %i\" to vote for this map too.", calling_ply:Nick(), ulx.votemaps[ mapid ], mapvotes[ mapid ], votes_needed, mapid ), true )
|
||||
ulx.logString( string.format( "%s voted for %s (%i/%i)", calling_ply:Nick(), ulx.votemaps[ mapid ], mapvotes[ mapid ], votes_needed ) )
|
||||
|
||||
if mapvotes[ mapid ] >= votes_needed then
|
||||
local vetotime = tonumber( GetConVarString( "ulx_votemapVetotime" ) ) or 30
|
||||
|
||||
local admins = {}
|
||||
local players = player.GetAll()
|
||||
for _, player in ipairs( players ) do
|
||||
if player:IsConnected() then
|
||||
if ULib.ucl.query( player, "ulx veto" ) then
|
||||
table.insert( admins, player )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if #admins <= 0 or vetotime < 1 then
|
||||
ULib.tsay( _, "Vote for map " .. ulx.votemaps[ mapid ] .. " successful! Changing levels now.", true ) -- TODO, color?
|
||||
ulx.logString( "Votemap for " .. ulx.votemaps[ mapid ] .. " won." )
|
||||
game.ConsoleCommand( "changelevel " .. ulx.votemaps[ mapid ] .. "\n" )
|
||||
else
|
||||
ULib.tsay( _, "Vote for map " .. ulx.votemaps[ mapid ] .. " successful! Now pending admin approval. (" .. vetotime .. " seconds)", true ) -- TODO, color?
|
||||
for _, player in ipairs( admins ) do
|
||||
ULib.tsay( player, "To veto this vote, just say \"!veto\"", true ) -- TODO, color?
|
||||
end
|
||||
ulx.logString( "Votemap for " .. ulx.votemaps[ mapid ] .. " won. Pending admin veto." )
|
||||
ulx.timedVeto = true
|
||||
hook.Call( ulx.HOOK_VETO )
|
||||
timer.Create( "ULXVotemap", vetotime, 1, function() game.ConsoleCommand( "changelevel " .. ulx.votemaps[ mapid ] .. "\n" ) end )
|
||||
end
|
||||
end
|
||||
end
|
||||
-- This command is defined at the bottom of vote.lua
|
||||
|
||||
function ulx.votemap_disconnect( ply ) -- We use this to clear out old people's votes
|
||||
if userMapvote[ ply ] then -- Take away from their previous vote
|
||||
mapvotes[ userMapvote[ ply ].mapid ] = mapvotes[ userMapvote[ ply ].mapid ] - 1
|
||||
userMapvote[ ply ] = nil
|
||||
end
|
||||
end
|
||||
hook.Add( "PlayerDisconnected", "ULXVoteDisconnect", ulx.votemap_disconnect )
|
||||
|
@ -1,302 +1,302 @@
|
||||
--Server stuff for the GUI for ULX --by Stickly Man!
|
||||
|
||||
xgui = xgui or {}
|
||||
xgui.svmodules = {}
|
||||
function xgui.addSVModule( name, initFunc, postinitFunc )
|
||||
local found = false
|
||||
for i, svmodule in pairs( xgui.svmodules ) do
|
||||
if svmodule.name == name then
|
||||
table.remove( xgui.svmodules, i )
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
table.insert( xgui.svmodules, { name=name, init=initFunc, postinit=postinitFunc } )
|
||||
if found then -- Autorefresh
|
||||
initFunc()
|
||||
postinitFunc()
|
||||
end
|
||||
end
|
||||
|
||||
Msg( "///////////////////////////////\n" )
|
||||
Msg( "// ULX GUI -- by Stickly Man //\n" )
|
||||
Msg( "///////////////////////////////\n" )
|
||||
Msg( "// Adding Main Modules.. //\n" )
|
||||
for _, file in ipairs( file.Find( "ulx/xgui/*.lua", "LUA" ) ) do
|
||||
AddCSLuaFile( "ulx/xgui/" .. file )
|
||||
Msg( "// " .. file .. string.rep( " ", 25 - file:len() ) .. "//\n" )
|
||||
end
|
||||
Msg( "// Adding Setting Modules.. //\n" )
|
||||
for _, file in ipairs( file.Find( "ulx/xgui/settings/*.lua", "LUA" ) ) do
|
||||
AddCSLuaFile( "ulx/xgui/settings/" .. file )
|
||||
Msg( "// " .. file .. string.rep( " ", 25 - file:len() ) .. "//\n" )
|
||||
end
|
||||
Msg( "// Adding Gamemode Modules.. //\n" )
|
||||
for _, file in ipairs( file.Find( "ulx/xgui/gamemodes/*.lua", "LUA" ) ) do
|
||||
AddCSLuaFile( "ulx/xgui/gamemodes/" .. file )
|
||||
Msg( "// " .. file .. string.rep( " ", 25 - file:len() ) .. "//\n" )
|
||||
end
|
||||
Msg( "// Loading Server Modules.. //\n" )
|
||||
for _, file in ipairs( file.Find( "ulx/xgui/server/*.lua", "LUA" ) ) do
|
||||
include( "ulx/xgui/server/" .. file )
|
||||
Msg( "// " .. file .. string.rep( " ", 25 - file:len() ) .. "//\n" )
|
||||
end
|
||||
Msg( "// XGUI modules added! //\n" )
|
||||
Msg( "///////////////////////////////\n" )
|
||||
|
||||
function xgui.init()
|
||||
local function xgui_chatCommand( ply, func, args )
|
||||
if ply:IsValid() then
|
||||
ULib.clientRPC( ply, "xgui.toggle", args )
|
||||
end
|
||||
end
|
||||
ULib.addSayCommand( "!xgui", xgui_chatCommand )
|
||||
ULib.addSayCommand( "!menu", xgui_chatCommand )
|
||||
|
||||
--XGUI command stuff
|
||||
xgui.cmds = {}
|
||||
function xgui.addCmd( name, func )
|
||||
xgui.cmds[name] = func
|
||||
end
|
||||
function xgui.cmd( ply, cmd, args )
|
||||
local name=args[1]
|
||||
table.remove( args, 1 )
|
||||
if xgui.cmds[name] then
|
||||
xgui.cmds[name]( ply, args )
|
||||
else
|
||||
ULib.tsay( ply, "XGUI: Command " .. ( name or "<none>" ) .. " not recognized!" )
|
||||
end
|
||||
end
|
||||
concommand.Add( "_xgui", xgui.cmd )
|
||||
|
||||
|
||||
-----------------
|
||||
--XGUI data stuff
|
||||
-----------------
|
||||
xgui.dataTypes = {}
|
||||
xgui.activeUsers = {} --Set up a table to list users who are actively transferring data
|
||||
xgui.readyPlayers = {} --Set up a table to store users who are ready to receive data.
|
||||
function xgui.addDataType( name, retrievalFunc, access, maxChunkSize, priority )
|
||||
xgui.dataTypes[name] = { getData=retrievalFunc, access=access, maxchunk=maxChunkSize }
|
||||
table.insert( xgui.dataTypes, { name=name, priority=priority or 0 } )
|
||||
table.sort( xgui.dataTypes, function(a,b) return a.priority < b.priority end )
|
||||
end
|
||||
|
||||
function xgui.getdata( ply, args )
|
||||
xgui.sendDataTable( ply, args )
|
||||
end
|
||||
xgui.addCmd( "getdata", xgui.getdata )
|
||||
|
||||
--Let the server know when players are/aren't ready to receive data.
|
||||
function xgui.getInstalled( ply )
|
||||
ULib.clientRPC( ply, "xgui.getInstalled" )
|
||||
xgui.readyPlayers[ply:UniqueID()] = 1
|
||||
end
|
||||
xgui.addCmd( "getInstalled", xgui.getInstalled )
|
||||
|
||||
function xgui.onDisconnect( ply )
|
||||
xgui.activeUsers[ply:UniqueID()] = nil
|
||||
xgui.readyPlayers[ply:UniqueID()] = nil
|
||||
end
|
||||
hook.Add( "PlayerDisconnected", "xgui_ply_disconnect", xgui.onDisconnect )
|
||||
|
||||
function xgui.refreshdata( ply, existingDatas )
|
||||
local t = {}
|
||||
if #existingDatas ~= 0 then
|
||||
for _, data in ipairs( xgui.dataTypes ) do
|
||||
--Only refresh data that the user says they don't have, and refresh datatypes they do not have access to
|
||||
if not table.HasValue( existingDatas, data.name ) or not ULib.ucl.query( ply, xgui.dataTypes[data.name].access ) then
|
||||
table.insert( t, data.name )
|
||||
end
|
||||
end
|
||||
if #t == 0 then return end --If no updates were needed, then just end the function
|
||||
end
|
||||
xgui.sendDataTable( ply, t )
|
||||
end
|
||||
xgui.addCmd( "refreshdata", xgui.refreshdata )
|
||||
|
||||
local function plyToTable( plys ) --If plys is empty, then return the full playerlist.
|
||||
if type( plys ) == "Player" then
|
||||
plys = { plys }
|
||||
elseif #plys == 0 then
|
||||
for _, v in pairs( player.GetAll() ) do
|
||||
table.insert( plys, v )
|
||||
end
|
||||
end
|
||||
return plys
|
||||
end
|
||||
|
||||
--Send an entire table of data to the client(s)
|
||||
function xgui.sendDataTable( plys, datatypes, forceSend )
|
||||
if type( datatypes ) ~= "table" then
|
||||
datatypes = { datatypes }
|
||||
elseif #datatypes == 0 then
|
||||
for _, k in ipairs( xgui.dataTypes ) do
|
||||
table.insert( datatypes, k.name )
|
||||
end
|
||||
end
|
||||
|
||||
plys = plyToTable( plys )
|
||||
|
||||
for k, ply in pairs( plys ) do
|
||||
if not xgui.readyPlayers[ply:UniqueID()] then return end --Ignore requests to players who are not ready, they'll get the data as soon as they can.
|
||||
|
||||
if xgui.activeUsers[ply:UniqueID()] and not forceSend then --If data is currently being sent to the client
|
||||
for _, dtype in ipairs( datatypes ) do
|
||||
local exists = false
|
||||
for _,existingArg in ipairs(xgui.activeUsers[ply:UniqueID()].tables) do
|
||||
if dtype == existingArg then exists=true break end
|
||||
end
|
||||
if not exists then table.insert( xgui.activeUsers[ply:UniqueID()].tables, dtype ) end
|
||||
--Clear any events relating to this data type, since those changes will be reflected whenever the new table is sent.
|
||||
for i=#xgui.activeUsers[ply:UniqueID()].events,1,-1 do
|
||||
if xgui.activeUsers[ply:UniqueID()].events[i][2] == dtype then
|
||||
table.remove( xgui.activeUsers[ply:UniqueID()].events, i )
|
||||
end
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local chunks = {}
|
||||
for _, dtype in ipairs( datatypes ) do
|
||||
if xgui.dataTypes[dtype] then
|
||||
local data = xgui.dataTypes[dtype]
|
||||
if ULib.ucl.query( ply, data.access ) then
|
||||
local t = data.getData()
|
||||
local size = data.maxchunk or 0 --Split the table into "chunks" of per-datatype specified size to even out data flow. 0 to disable
|
||||
if t and table.Count( t ) > size and size != 0 then
|
||||
table.insert( chunks, { 5, dtype } ) --Signify beginning of split chunks
|
||||
local c = 1
|
||||
local part = {}
|
||||
for key, data in pairs( t ) do
|
||||
part[key] = data
|
||||
c = c + 1
|
||||
if c > size then
|
||||
table.insert( chunks, { 1, dtype, part } )
|
||||
part = {}
|
||||
c = 1
|
||||
end
|
||||
end
|
||||
table.insert( chunks, { 1, dtype, part } )
|
||||
table.insert( chunks, { 6, dtype } ) --Signify end of split chunks
|
||||
else
|
||||
table.insert( chunks, { 1, dtype, data.getData() } )
|
||||
end
|
||||
else
|
||||
table.insert( chunks, { 0, dtype } )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if #chunks ~= 0 then
|
||||
xgui.sendChunks( ply, chunks )
|
||||
else
|
||||
xgui.chunksFinished( ply )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Send a portion of table data to the client(s). The table "data" gets table.Merge'd with the existing table on the client.
|
||||
function xgui.addData( plys, dtype, data )
|
||||
xgui.sendDataEvent( plys, 2, dtype, data )
|
||||
end
|
||||
|
||||
--(Same as add, you can call them differently in your code if you need to be able to determine if one is added vs. updated)
|
||||
function xgui.updateData( plys, dtype, data )
|
||||
xgui.sendDataEvent( plys, 3, dtype, data )
|
||||
end
|
||||
|
||||
--Removes a single key from the table -- The table "data" should be structured that it contains the set of tables to a single key which will be removed. (i.e. data = {base={subtable1="key"}} )
|
||||
--It can also remove multiple values. Here are a few examples:
|
||||
--xgui.removeData( {}, "adverts", {[2]={[1]={"rpt"} } } ) --This would remove the repeat time of the first advert in the second advert group.
|
||||
--xgui.removeData( {}, "votemaps", {3, 3, 3, 3} ) --This will remove votemaps numbered 3-6 in xgui.data.votemaps. (It uses table.remove, but you can alternatively do {6,5,4,3} to produce the same effect)
|
||||
function xgui.removeData( plys, dtype, data )
|
||||
xgui.sendDataEvent( plys, 4, dtype, data )
|
||||
end
|
||||
|
||||
function xgui.sendDataEvent( plys, evtype, dtype, entry )
|
||||
plys = plyToTable( plys )
|
||||
for k, ply in pairs( plys ) do
|
||||
if xgui.activeUsers[ply:UniqueID()] then
|
||||
table.insert( xgui.activeUsers[ply:UniqueID()].events, { evtype, dtype, entry } )
|
||||
return
|
||||
end
|
||||
|
||||
local chunks = {}
|
||||
table.insert( chunks, { evtype, dtype, entry } )
|
||||
xgui.sendChunks( ply, chunks )
|
||||
end
|
||||
end
|
||||
|
||||
function xgui.sendChunks( ply, chunks )
|
||||
ULib.clientRPC( ply, "xgui.expectChunks", #chunks )
|
||||
if not xgui.activeUsers[ply:UniqueID()] then xgui.activeUsers[ply:UniqueID()] = { tables={}, events={} } end
|
||||
for _, chunk in ipairs( chunks ) do
|
||||
ULib.queueFunctionCall( ULib.clientRPC, ply, "xgui.getChunk", chunk[1], chunk[2], chunk[3] )
|
||||
end
|
||||
end
|
||||
|
||||
function xgui.chunksFinished( ply )
|
||||
if xgui.activeUsers[ply:UniqueID()] then
|
||||
if #xgui.activeUsers[ply:UniqueID()].tables > 0 then --Data tables have been requested while the player was transferring data
|
||||
xgui.sendDataTable( ply, xgui.activeUsers[ply:UniqueID()].tables, true )
|
||||
xgui.activeUsers[ply:UniqueID()].tables = {}
|
||||
elseif #xgui.activeUsers[ply:UniqueID()].events > 0 then --No data tables are needed, and events have occurred while the player was transferring data
|
||||
local chunks = {}
|
||||
for _,v in ipairs( xgui.activeUsers[ply:UniqueID()].events ) do
|
||||
table.insert( chunks, v )
|
||||
end
|
||||
xgui.sendChunks( ply, chunks )
|
||||
xgui.activeUsers[ply:UniqueID()].events = {}
|
||||
else --Client is up-to-date!
|
||||
xgui.activeUsers[ply:UniqueID()] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "dataComplete", xgui.chunksFinished )
|
||||
|
||||
------------
|
||||
--Misc Stuff
|
||||
------------
|
||||
function xgui.getCommentHeader( data, comment_char )
|
||||
comment_char = comment_char or ";"
|
||||
local lines = ULib.explode( "\n", data )
|
||||
local end_comment_line = 0
|
||||
for _, line in ipairs( lines ) do
|
||||
local trimmed = line:Trim()
|
||||
if trimmed == "" or trimmed:sub( 1, 1 ) == comment_char then
|
||||
end_comment_line = end_comment_line + 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local comment = table.concat( lines, "\n", 1, end_comment_line )
|
||||
if comment ~= "" then comment = comment .. "\n" end
|
||||
return comment
|
||||
end
|
||||
|
||||
--Initialize the server modules!
|
||||
for _, v in ipairs( xgui.svmodules ) do v.init() end
|
||||
|
||||
ulx.addToHelpManually( "Menus", "xgui", "<show, hide, toggle> - Opens and/or closes XGUI. (say: !xgui, !menu) (alias: ulx menu)" )
|
||||
end
|
||||
|
||||
--Init the code when the server is ready
|
||||
hook.Add( "Initialize", "XGUI_InitServer", xgui.init, HOOK_HIGH )
|
||||
|
||||
--Call the modules postinit function when ULX is done loading. Should be called well after the Initialize hook.
|
||||
function xgui.postInit()
|
||||
for _, v in ipairs( xgui.svmodules ) do if v.postinit then v.postinit() end end
|
||||
|
||||
--Fix any users who requested data before the server was ready
|
||||
for _, ply in pairs( player.GetAll() ) do
|
||||
for UID, data in pairs( xgui.activeUsers ) do
|
||||
if ply:UniqueID() == UID then
|
||||
ULib.clientRPC( ply, "xgui.getChunk", -1, "Initializing..." )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
hook.Add( ulx.HOOK_ULXDONELOADING, "XGUI_PostInitServer", xgui.postInit, HOOK_MONITOR_LOW )
|
||||
--Server stuff for the GUI for ULX --by Stickly Man!
|
||||
|
||||
xgui = xgui or {}
|
||||
xgui.svmodules = {}
|
||||
function xgui.addSVModule( name, initFunc, postinitFunc )
|
||||
local found = false
|
||||
for i, svmodule in pairs( xgui.svmodules ) do
|
||||
if svmodule.name == name then
|
||||
table.remove( xgui.svmodules, i )
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
table.insert( xgui.svmodules, { name=name, init=initFunc, postinit=postinitFunc } )
|
||||
if found then -- Autorefresh
|
||||
initFunc()
|
||||
postinitFunc()
|
||||
end
|
||||
end
|
||||
|
||||
Msg( "///////////////////////////////\n" )
|
||||
Msg( "// ULX GUI -- by Stickly Man //\n" )
|
||||
Msg( "///////////////////////////////\n" )
|
||||
Msg( "// Adding Main Modules.. //\n" )
|
||||
for _, file in ipairs( file.Find( "ulx/xgui/*.lua", "LUA" ) ) do
|
||||
AddCSLuaFile( "ulx/xgui/" .. file )
|
||||
Msg( "// " .. file .. string.rep( " ", 25 - file:len() ) .. "//\n" )
|
||||
end
|
||||
Msg( "// Adding Setting Modules.. //\n" )
|
||||
for _, file in ipairs( file.Find( "ulx/xgui/settings/*.lua", "LUA" ) ) do
|
||||
AddCSLuaFile( "ulx/xgui/settings/" .. file )
|
||||
Msg( "// " .. file .. string.rep( " ", 25 - file:len() ) .. "//\n" )
|
||||
end
|
||||
Msg( "// Adding Gamemode Modules.. //\n" )
|
||||
for _, file in ipairs( file.Find( "ulx/xgui/gamemodes/*.lua", "LUA" ) ) do
|
||||
AddCSLuaFile( "ulx/xgui/gamemodes/" .. file )
|
||||
Msg( "// " .. file .. string.rep( " ", 25 - file:len() ) .. "//\n" )
|
||||
end
|
||||
Msg( "// Loading Server Modules.. //\n" )
|
||||
for _, file in ipairs( file.Find( "ulx/xgui/server/*.lua", "LUA" ) ) do
|
||||
include( "ulx/xgui/server/" .. file )
|
||||
Msg( "// " .. file .. string.rep( " ", 25 - file:len() ) .. "//\n" )
|
||||
end
|
||||
Msg( "// XGUI modules added! //\n" )
|
||||
Msg( "///////////////////////////////\n" )
|
||||
|
||||
function xgui.init()
|
||||
local function xgui_chatCommand( ply, func, args )
|
||||
if ply:IsValid() then
|
||||
ULib.clientRPC( ply, "xgui.toggle", args )
|
||||
end
|
||||
end
|
||||
ULib.addSayCommand( "!xgui", xgui_chatCommand )
|
||||
ULib.addSayCommand( "!menu", xgui_chatCommand )
|
||||
|
||||
--XGUI command stuff
|
||||
xgui.cmds = {}
|
||||
function xgui.addCmd( name, func )
|
||||
xgui.cmds[name] = func
|
||||
end
|
||||
function xgui.cmd( ply, cmd, args )
|
||||
local name=args[1]
|
||||
table.remove( args, 1 )
|
||||
if xgui.cmds[name] then
|
||||
xgui.cmds[name]( ply, args )
|
||||
else
|
||||
ULib.tsay( ply, "XGUI: Command " .. ( name or "<none>" ) .. " not recognized!" )
|
||||
end
|
||||
end
|
||||
concommand.Add( "_xgui", xgui.cmd )
|
||||
|
||||
|
||||
-----------------
|
||||
--XGUI data stuff
|
||||
-----------------
|
||||
xgui.dataTypes = {}
|
||||
xgui.activeUsers = {} --Set up a table to list users who are actively transferring data
|
||||
xgui.readyPlayers = {} --Set up a table to store users who are ready to receive data.
|
||||
function xgui.addDataType( name, retrievalFunc, access, maxChunkSize, priority )
|
||||
xgui.dataTypes[name] = { getData=retrievalFunc, access=access, maxchunk=maxChunkSize }
|
||||
table.insert( xgui.dataTypes, { name=name, priority=priority or 0 } )
|
||||
table.sort( xgui.dataTypes, function(a,b) return a.priority < b.priority end )
|
||||
end
|
||||
|
||||
function xgui.getdata( ply, args )
|
||||
xgui.sendDataTable( ply, args )
|
||||
end
|
||||
xgui.addCmd( "getdata", xgui.getdata )
|
||||
|
||||
--Let the server know when players are/aren't ready to receive data.
|
||||
function xgui.getInstalled( ply )
|
||||
ULib.clientRPC( ply, "xgui.getInstalled" )
|
||||
xgui.readyPlayers[ply:UniqueID()] = 1
|
||||
end
|
||||
xgui.addCmd( "getInstalled", xgui.getInstalled )
|
||||
|
||||
function xgui.onDisconnect( ply )
|
||||
xgui.activeUsers[ply:UniqueID()] = nil
|
||||
xgui.readyPlayers[ply:UniqueID()] = nil
|
||||
end
|
||||
hook.Add( "PlayerDisconnected", "xgui_ply_disconnect", xgui.onDisconnect )
|
||||
|
||||
function xgui.refreshdata( ply, existingDatas )
|
||||
local t = {}
|
||||
if #existingDatas ~= 0 then
|
||||
for _, data in ipairs( xgui.dataTypes ) do
|
||||
--Only refresh data that the user says they don't have, and refresh datatypes they do not have access to
|
||||
if not table.HasValue( existingDatas, data.name ) or not ULib.ucl.query( ply, xgui.dataTypes[data.name].access ) then
|
||||
table.insert( t, data.name )
|
||||
end
|
||||
end
|
||||
if #t == 0 then return end --If no updates were needed, then just end the function
|
||||
end
|
||||
xgui.sendDataTable( ply, t )
|
||||
end
|
||||
xgui.addCmd( "refreshdata", xgui.refreshdata )
|
||||
|
||||
local function plyToTable( plys ) --If plys is empty, then return the full playerlist.
|
||||
if type( plys ) == "Player" then
|
||||
plys = { plys }
|
||||
elseif #plys == 0 then
|
||||
for _, v in pairs( player.GetAll() ) do
|
||||
table.insert( plys, v )
|
||||
end
|
||||
end
|
||||
return plys
|
||||
end
|
||||
|
||||
--Send an entire table of data to the client(s)
|
||||
function xgui.sendDataTable( plys, datatypes, forceSend )
|
||||
if type( datatypes ) ~= "table" then
|
||||
datatypes = { datatypes }
|
||||
elseif #datatypes == 0 then
|
||||
for _, k in ipairs( xgui.dataTypes ) do
|
||||
table.insert( datatypes, k.name )
|
||||
end
|
||||
end
|
||||
|
||||
plys = plyToTable( plys )
|
||||
|
||||
for k, ply in pairs( plys ) do
|
||||
if not xgui.readyPlayers[ply:UniqueID()] then return end --Ignore requests to players who are not ready, they'll get the data as soon as they can.
|
||||
|
||||
if xgui.activeUsers[ply:UniqueID()] and not forceSend then --If data is currently being sent to the client
|
||||
for _, dtype in ipairs( datatypes ) do
|
||||
local exists = false
|
||||
for _,existingArg in ipairs(xgui.activeUsers[ply:UniqueID()].tables) do
|
||||
if dtype == existingArg then exists=true break end
|
||||
end
|
||||
if not exists then table.insert( xgui.activeUsers[ply:UniqueID()].tables, dtype ) end
|
||||
--Clear any events relating to this data type, since those changes will be reflected whenever the new table is sent.
|
||||
for i=#xgui.activeUsers[ply:UniqueID()].events,1,-1 do
|
||||
if xgui.activeUsers[ply:UniqueID()].events[i][2] == dtype then
|
||||
table.remove( xgui.activeUsers[ply:UniqueID()].events, i )
|
||||
end
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local chunks = {}
|
||||
for _, dtype in ipairs( datatypes ) do
|
||||
if xgui.dataTypes[dtype] then
|
||||
local data = xgui.dataTypes[dtype]
|
||||
if ULib.ucl.query( ply, data.access ) then
|
||||
local t = data.getData()
|
||||
local size = data.maxchunk or 0 --Split the table into "chunks" of per-datatype specified size to even out data flow. 0 to disable
|
||||
if t and table.Count( t ) > size and size != 0 then
|
||||
table.insert( chunks, { 5, dtype } ) --Signify beginning of split chunks
|
||||
local c = 1
|
||||
local part = {}
|
||||
for key, data in pairs( t ) do
|
||||
part[key] = data
|
||||
c = c + 1
|
||||
if c > size then
|
||||
table.insert( chunks, { 1, dtype, part } )
|
||||
part = {}
|
||||
c = 1
|
||||
end
|
||||
end
|
||||
table.insert( chunks, { 1, dtype, part } )
|
||||
table.insert( chunks, { 6, dtype } ) --Signify end of split chunks
|
||||
else
|
||||
table.insert( chunks, { 1, dtype, data.getData() } )
|
||||
end
|
||||
else
|
||||
table.insert( chunks, { 0, dtype } )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if #chunks ~= 0 then
|
||||
xgui.sendChunks( ply, chunks )
|
||||
else
|
||||
xgui.chunksFinished( ply )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Send a portion of table data to the client(s). The table "data" gets table.Merge'd with the existing table on the client.
|
||||
function xgui.addData( plys, dtype, data )
|
||||
xgui.sendDataEvent( plys, 2, dtype, data )
|
||||
end
|
||||
|
||||
--(Same as add, you can call them differently in your code if you need to be able to determine if one is added vs. updated)
|
||||
function xgui.updateData( plys, dtype, data )
|
||||
xgui.sendDataEvent( plys, 3, dtype, data )
|
||||
end
|
||||
|
||||
--Removes a single key from the table -- The table "data" should be structured that it contains the set of tables to a single key which will be removed. (i.e. data = {base={subtable1="key"}} )
|
||||
--It can also remove multiple values. Here are a few examples:
|
||||
--xgui.removeData( {}, "adverts", {[2]={[1]={"rpt"} } } ) --This would remove the repeat time of the first advert in the second advert group.
|
||||
--xgui.removeData( {}, "votemaps", {3, 3, 3, 3} ) --This will remove votemaps numbered 3-6 in xgui.data.votemaps. (It uses table.remove, but you can alternatively do {6,5,4,3} to produce the same effect)
|
||||
function xgui.removeData( plys, dtype, data )
|
||||
xgui.sendDataEvent( plys, 4, dtype, data )
|
||||
end
|
||||
|
||||
function xgui.sendDataEvent( plys, evtype, dtype, entry )
|
||||
plys = plyToTable( plys )
|
||||
for k, ply in pairs( plys ) do
|
||||
if xgui.activeUsers[ply:UniqueID()] then
|
||||
table.insert( xgui.activeUsers[ply:UniqueID()].events, { evtype, dtype, entry } )
|
||||
return
|
||||
end
|
||||
|
||||
local chunks = {}
|
||||
table.insert( chunks, { evtype, dtype, entry } )
|
||||
xgui.sendChunks( ply, chunks )
|
||||
end
|
||||
end
|
||||
|
||||
function xgui.sendChunks( ply, chunks )
|
||||
ULib.clientRPC( ply, "xgui.expectChunks", #chunks )
|
||||
if not xgui.activeUsers[ply:UniqueID()] then xgui.activeUsers[ply:UniqueID()] = { tables={}, events={} } end
|
||||
for _, chunk in ipairs( chunks ) do
|
||||
ULib.queueFunctionCall( ULib.clientRPC, ply, "xgui.getChunk", chunk[1], chunk[2], chunk[3] )
|
||||
end
|
||||
end
|
||||
|
||||
function xgui.chunksFinished( ply )
|
||||
if xgui.activeUsers[ply:UniqueID()] then
|
||||
if #xgui.activeUsers[ply:UniqueID()].tables > 0 then --Data tables have been requested while the player was transferring data
|
||||
xgui.sendDataTable( ply, xgui.activeUsers[ply:UniqueID()].tables, true )
|
||||
xgui.activeUsers[ply:UniqueID()].tables = {}
|
||||
elseif #xgui.activeUsers[ply:UniqueID()].events > 0 then --No data tables are needed, and events have occurred while the player was transferring data
|
||||
local chunks = {}
|
||||
for _,v in ipairs( xgui.activeUsers[ply:UniqueID()].events ) do
|
||||
table.insert( chunks, v )
|
||||
end
|
||||
xgui.sendChunks( ply, chunks )
|
||||
xgui.activeUsers[ply:UniqueID()].events = {}
|
||||
else --Client is up-to-date!
|
||||
xgui.activeUsers[ply:UniqueID()] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "dataComplete", xgui.chunksFinished )
|
||||
|
||||
------------
|
||||
--Misc Stuff
|
||||
------------
|
||||
function xgui.getCommentHeader( data, comment_char )
|
||||
comment_char = comment_char or ";"
|
||||
local lines = ULib.explode( "\n", data )
|
||||
local end_comment_line = 0
|
||||
for _, line in ipairs( lines ) do
|
||||
local trimmed = line:Trim()
|
||||
if trimmed == "" or trimmed:sub( 1, 1 ) == comment_char then
|
||||
end_comment_line = end_comment_line + 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local comment = table.concat( lines, "\n", 1, end_comment_line )
|
||||
if comment ~= "" then comment = comment .. "\n" end
|
||||
return comment
|
||||
end
|
||||
|
||||
--Initialize the server modules!
|
||||
for _, v in ipairs( xgui.svmodules ) do v.init() end
|
||||
|
||||
ulx.addToHelpManually( "Menus", "xgui", "<show, hide, toggle> - Opens and/or closes XGUI. (say: !xgui, !menu) (alias: ulx menu)" )
|
||||
end
|
||||
|
||||
--Init the code when the server is ready
|
||||
hook.Add( "Initialize", "XGUI_InitServer", xgui.init, HOOK_HIGH )
|
||||
|
||||
--Call the modules postinit function when ULX is done loading. Should be called well after the Initialize hook.
|
||||
function xgui.postInit()
|
||||
for _, v in ipairs( xgui.svmodules ) do if v.postinit then v.postinit() end end
|
||||
|
||||
--Fix any users who requested data before the server was ready
|
||||
for _, ply in pairs( player.GetAll() ) do
|
||||
for UID, data in pairs( xgui.activeUsers ) do
|
||||
if ply:UniqueID() == UID then
|
||||
ULib.clientRPC( ply, "xgui.getChunk", -1, "Initializing..." )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
hook.Add( ulx.HOOK_ULXDONELOADING, "XGUI_PostInitServer", xgui.postInit, HOOK_MONITOR_LOW )
|
||||
|
@ -1,15 +1,15 @@
|
||||
ulx.LOW_ARGS = "You did not specify enough arguments for this command. Type 'ulx help' in console for help."
|
||||
|
||||
ulx.version = 3.70 -- Current release version. Don't access directly, use ulx.getVersion instead. (SVN checks)
|
||||
ulx.release = false -- Is this the release?
|
||||
|
||||
ulx.ID_ORIGINAL = 1
|
||||
ulx.ID_PLAYER_HELP = 2
|
||||
ulx.ID_HELP = 3
|
||||
|
||||
ulx.ID_MMAIN = 1
|
||||
ulx.ID_MCLIENT = 2
|
||||
ulx.ID_MADMIN = 3
|
||||
|
||||
ulx.HOOK_ULXDONELOADING = "ULXLoaded"
|
||||
ulx.HOOK_VETO = "ULXVetoChanged"
|
||||
ulx.LOW_ARGS = "You did not specify enough arguments for this command. Type 'ulx help' in console for help."
|
||||
|
||||
ulx.version = 3.70 -- Current release version. Don't access directly, use ulx.getVersion instead. (SVN checks)
|
||||
ulx.release = false -- Is this the release?
|
||||
|
||||
ulx.ID_ORIGINAL = 1
|
||||
ulx.ID_PLAYER_HELP = 2
|
||||
ulx.ID_HELP = 3
|
||||
|
||||
ulx.ID_MMAIN = 1
|
||||
ulx.ID_MCLIENT = 2
|
||||
ulx.ID_MADMIN = 3
|
||||
|
||||
ulx.HOOK_ULXDONELOADING = "ULXLoaded"
|
||||
ulx.HOOK_VETO = "ULXVetoChanged"
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,394 +1,394 @@
|
||||
--Commands module (formerly players module) v2 for ULX GUI -- by Stickly Man!
|
||||
--Handles all user-executable commands, such as kick, slay, ban, etc.
|
||||
|
||||
local cmds = xlib.makepanel{ parent=xgui.null }
|
||||
cmds.selcmd = nil
|
||||
cmds.mask = xlib.makepanel{ x=160, y=30, w=425, h=330, parent=cmds }
|
||||
cmds.argslist = xlib.makelistlayout{ w=165, h=330, parent=cmds.mask }
|
||||
cmds.argslist.secondaryPos = nil
|
||||
|
||||
cmds.argslist.scroll:SetVisible( false )
|
||||
|
||||
function cmds.argslist:Open( cmd, secondary )
|
||||
if secondary then
|
||||
if cmds.plist.open then
|
||||
cmds.plist:Close()
|
||||
elseif self.open then
|
||||
self:Close()
|
||||
end
|
||||
end
|
||||
self:openAnim( cmd, secondary )
|
||||
self.open = true
|
||||
end
|
||||
function cmds.argslist:Close()
|
||||
self:closeAnim( self.secondaryPos )
|
||||
self.open = false
|
||||
end
|
||||
cmds.plist = xlib.makelistview{ w=250, h=330, multiselect=true, parent=cmds.mask }
|
||||
function cmds.plist:Open( arg )
|
||||
if cmds.argslist.secondaryPos == true then cmds.argslist:Close()
|
||||
elseif self.open then self:Close() end
|
||||
self:openAnim( arg )
|
||||
--Determine if the arguments should be visible after changing (If a valid player will be selected)
|
||||
local targets = cmds.calculateValidPlayers( arg )
|
||||
local playerWillBeSelected = false
|
||||
for _, line in ipairs( cmds.plist:GetSelected() ) do
|
||||
if table.HasValue( targets, line.ply ) then
|
||||
playerWillBeSelected = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if playerWillBeSelected then
|
||||
cmds.argslist:Open( ULib.cmds.translatedCmds[arg.cmd], false )
|
||||
end
|
||||
self.open = true
|
||||
end
|
||||
function cmds.plist:Close()
|
||||
if cmds.argslist.open then cmds.argslist:Close() end
|
||||
self:closeAnim()
|
||||
self.open = false
|
||||
end
|
||||
cmds.plist.DoDoubleClick = function()
|
||||
cmds.runCmd( cmds.selcmd )
|
||||
end
|
||||
cmds.plist:SetVisible( false )
|
||||
cmds.plist:AddColumn( "Name" )
|
||||
cmds.plist:AddColumn( "Group" )
|
||||
|
||||
cmds.cmds = xlib.makelistlayout{ x=5, y=30, w=150, h=330, parent=cmds, padding=1, spacing=1 }
|
||||
cmds.setselected = function( selcat, LineID )
|
||||
if selcat.Lines[LineID]:GetColumnText(2) == cmds.selcmd then
|
||||
selcat:ClearSelection()
|
||||
if cmds.plist.open then cmds.plist:Close() else cmds.argslist:Close() end
|
||||
xlib.animQueue_start()
|
||||
cmds.selcmd = nil
|
||||
return
|
||||
end
|
||||
|
||||
for _, cat in pairs( cmds.cmd_contents ) do
|
||||
if cat ~= selcat then
|
||||
cat:ClearSelection()
|
||||
end
|
||||
end
|
||||
cmds.selcmd = selcat.Lines[LineID]:GetColumnText(2)
|
||||
|
||||
if cmds.permissionChanged then cmds.refreshPlist() return end
|
||||
|
||||
if xlib.animRunning then xlib.animQueue_forceStop() end
|
||||
|
||||
local cmd = ULib.cmds.translatedCmds[cmds.selcmd]
|
||||
if cmd.args[2] and ( cmd.args[2].type == ULib.cmds.PlayersArg or cmd.args[2].type == ULib.cmds.PlayerArg ) then
|
||||
cmds.plist:Open( cmd.args[2] )
|
||||
else
|
||||
cmds.argslist:Open( cmd, true )
|
||||
end
|
||||
xlib.animQueue_start()
|
||||
end
|
||||
|
||||
function cmds.refreshPlist( arg )
|
||||
if not arg then arg = ULib.cmds.translatedCmds[cmds.selcmd].args[2] end
|
||||
if not arg or ( arg.type ~= ULib.cmds.PlayersArg and arg.type ~= ULib.cmds.PlayerArg ) then return end
|
||||
|
||||
local lastplys = {}
|
||||
for k, Line in pairs( cmds.plist.Lines ) do
|
||||
if ( Line:IsLineSelected() ) then table.insert( lastplys, Line:GetColumnText(1) ) end
|
||||
end
|
||||
|
||||
local targets = cmds.calculateValidPlayers( arg )
|
||||
|
||||
cmds.plist:Clear()
|
||||
cmds.plist:SetMultiSelect( arg.type == ULib.cmds.PlayersArg )
|
||||
for _, ply in ipairs( targets ) do
|
||||
local line = cmds.plist:AddLine( ply:Nick(), ply:GetUserGroup() )
|
||||
line.ply = ply
|
||||
line.OnSelect = function()
|
||||
if cmds.permissionChanged then return end
|
||||
|
||||
if not xlib.animRunning and not cmds.argslist.open then
|
||||
cmds.argslist:Open( ULib.cmds.translatedCmds[cmds.selcmd], false )
|
||||
xlib.animQueue_start( )
|
||||
else
|
||||
if not cmds.clickedFlag then --Prevent this from happening multiple times.
|
||||
cmds.clickedFlag = true
|
||||
xlib.addToAnimQueue( function() if not cmds.argslist.open then
|
||||
cmds.argslist:Open( ULib.cmds.translatedCmds[cmds.selcmd], false ) end
|
||||
cmds.clickedFlag = nil end )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Select previously selected Lines
|
||||
if table.HasValue( lastplys, ply:Nick() ) then
|
||||
cmds.plist:SelectItem( line )
|
||||
end
|
||||
end
|
||||
--Select only the first item if multiselect is disabled.
|
||||
if not cmds.plist:GetMultiSelect() then
|
||||
local firstSelected = cmds.plist:GetSelected()[1]
|
||||
cmds.plist:ClearSelection()
|
||||
cmds.plist:SelectItem( firstSelected )
|
||||
end
|
||||
|
||||
if not cmds.plist:GetSelectedLine() then
|
||||
if not xlib.animRunning then
|
||||
if cmds.argslist.open then
|
||||
cmds.argslist:Close()
|
||||
xlib.animQueue_start()
|
||||
end
|
||||
else
|
||||
if cmds.permissionChanged then
|
||||
xlib.addToAnimQueue( function() if cmds.argslist.open and cmds.plist.open then cmds.argslist:Close() end end )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function cmds.calculateValidPlayers( arg )
|
||||
if not arg then arg = ULib.cmds.translatedCmds[cmds.selcmd].args[2] end
|
||||
|
||||
local access, tag = LocalPlayer():query( arg.cmd )
|
||||
local restrictions = {}
|
||||
ULib.cmds.PlayerArg.processRestrictions( restrictions, LocalPlayer(), arg, ulx.getTagArgNum( tag, 1 ) )
|
||||
|
||||
local targets = restrictions.restrictedTargets
|
||||
if targets == false then -- No one allowed
|
||||
targets = {}
|
||||
elseif targets == nil then -- Everyone allowed
|
||||
targets = player.GetAll()
|
||||
end
|
||||
return targets
|
||||
end
|
||||
|
||||
function cmds.buildArgsList( cmd )
|
||||
cmds.argslist:Clear()
|
||||
cmds.curargs = {}
|
||||
local argnum = 0
|
||||
local zpos = 0
|
||||
local expectingplayers = cmd.args[2] and ( ( cmd.args[2].type == ULib.cmds.PlayersArg ) or ( cmd.args[2].type == ULib.cmds.PlayerArg ) ) or false
|
||||
for _, arg in ipairs( cmd.args ) do
|
||||
if not arg.type.invisible then
|
||||
argnum = argnum + 1
|
||||
if not ( argnum == 1 and expectingplayers ) then
|
||||
if arg.invisible ~= true then
|
||||
local curitem = arg
|
||||
if curitem.repeat_min then --This command repeats!
|
||||
local panel = xlib.makepanel{ h=20, parent=cmds.argslist }
|
||||
local choices = {}
|
||||
panel.argnum = argnum
|
||||
panel.xguiIgnore = true
|
||||
panel.arg = curitem
|
||||
panel.addbutton = xlib.makebutton{ label="Add", w=83, parent=panel }
|
||||
panel.addbutton.DoClick = function( self )
|
||||
local parent = self:GetParent()
|
||||
local ctrl = parent.arg.type.x_getcontrol( parent.arg, parent.argnum, cmds.argslist )
|
||||
cmds.argslist:Add( ctrl )
|
||||
ctrl:MoveToAfter( choices[#choices] )
|
||||
table.insert( choices, ctrl )
|
||||
table.insert( cmds.curargs, ctrl )
|
||||
panel.removebutton:SetDisabled( false )
|
||||
if parent.arg.repeat_max and #choices >= parent.arg.repeat_max then self:SetDisabled( true ) end
|
||||
end
|
||||
panel.removebutton = xlib.makebutton{ label="Remove", x=83, w=82, disabled=true, parent=panel }
|
||||
panel.removebutton.DoClick = function( self )
|
||||
local parent = self:GetParent()
|
||||
local ctrl = choices[#choices]
|
||||
ctrl:Remove()
|
||||
table.remove( choices )
|
||||
table.remove( cmds.curargs )
|
||||
panel.addbutton:SetDisabled( false )
|
||||
if #choices <= parent.arg.repeat_min then self:SetDisabled( true ) end
|
||||
end
|
||||
cmds.argslist:Add( panel )
|
||||
panel:SetZPos( zpos )
|
||||
zpos = zpos + 1
|
||||
for i=1,curitem.repeat_min do
|
||||
local ctrl = arg.type.x_getcontrol( arg, argnum, cmds.argslist )
|
||||
cmds.argslist:Add( ctrl )
|
||||
ctrl:SetZPos( zpos )
|
||||
zpos = zpos + 1
|
||||
table.insert( choices, ctrl )
|
||||
table.insert( cmds.curargs, ctrl )
|
||||
end
|
||||
else
|
||||
local panel = arg.type.x_getcontrol( arg, argnum, cmds.argslist )
|
||||
table.insert( cmds.curargs, panel )
|
||||
if curitem.type == ULib.cmds.NumArg then
|
||||
panel.TextArea.OnEnter = function( self )
|
||||
cmds.runCmd( cmd.cmd )
|
||||
end
|
||||
elseif curitem.type == ULib.cmds.StringArg then
|
||||
panel.OnEnter = function( self )
|
||||
cmds.runCmd( cmd.cmd )
|
||||
end
|
||||
end
|
||||
cmds.argslist:Add( panel )
|
||||
panel:SetZPos( zpos )
|
||||
zpos = zpos + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if LocalPlayer():query( cmd.cmd ) then
|
||||
local panel = xlib.makebutton{ label=cmd.cmd, parent=cmds.argslist }
|
||||
panel.xguiIgnore = true
|
||||
panel.DoClick = function()
|
||||
cmds.runCmd( cmd.cmd )
|
||||
end
|
||||
cmds.argslist:Add( panel )
|
||||
panel:SetZPos( zpos )
|
||||
zpos = zpos + 1
|
||||
end
|
||||
if cmd.opposite and LocalPlayer():query( cmd.opposite ) then
|
||||
local panel = xlib.makebutton{ label=cmd.opposite, parent=cmds.argslist }
|
||||
panel.DoClick = function()
|
||||
cmds.runCmd( cmd.opposite )
|
||||
end
|
||||
panel.xguiIgnore = true
|
||||
cmds.argslist:Add( panel )
|
||||
panel:SetZPos( zpos )
|
||||
zpos = zpos + 1
|
||||
end
|
||||
if cmd.helpStr then --If the command has a string for help
|
||||
local panel = xlib.makelabel{ w=160, label=cmd.helpStr, wordwrap=true, parent=cmds.argslist }
|
||||
panel.xguiIgnore = true
|
||||
cmds.argslist:Add( panel )
|
||||
panel:SetZPos( zpos )
|
||||
zpos = zpos + 1
|
||||
end
|
||||
end
|
||||
|
||||
function cmds.runCmd( cmd )
|
||||
local cmd = string.Explode( " ", cmd )
|
||||
if cmds.plist:IsVisible() then
|
||||
local plys = {}
|
||||
for _, line in ipairs( cmds.plist:GetSelected() ) do
|
||||
table.insert( plys, "$" .. ULib.getUniqueIDForPlayer( line.ply ) )
|
||||
table.insert( plys, "," )
|
||||
end
|
||||
table.remove( plys ) --Removes the final comma
|
||||
table.insert( cmd, table.concat( plys ) )
|
||||
end
|
||||
|
||||
for _, arg in ipairs( cmds.curargs ) do
|
||||
if not arg.xguiIgnore then
|
||||
table.insert( cmd, arg:GetValue() )
|
||||
end
|
||||
end
|
||||
RunConsoleCommand( unpack( cmd ) )
|
||||
end
|
||||
|
||||
function cmds.playerNameChanged( ply, old, new )
|
||||
for i, line in ipairs( cmds.plist.Lines ) do
|
||||
if line:GetColumnText(1) == old then
|
||||
line:SetColumnText( 1, new )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
cmds.refresh = function( permissionChanged )
|
||||
local lastcmd = cmds.selcmd
|
||||
cmds.cmds:Clear()
|
||||
cmds.cmd_contents = {}
|
||||
cmds.expandedcat = nil
|
||||
cmds.selcmd = nil
|
||||
cmds.permissionChanged = true
|
||||
|
||||
local newcategories = {}
|
||||
local sortcategories = {}
|
||||
local matchedCmdFound = false
|
||||
for cmd, data in pairs( ULib.cmds.translatedCmds ) do
|
||||
local opposite = data.opposite or ""
|
||||
if opposite ~= cmd and ( LocalPlayer():query( data.cmd ) or LocalPlayer():query( opposite ) ) then
|
||||
local catname = data.category
|
||||
if catname == nil or catname == "" then catname = "_Uncategorized" end
|
||||
if not cmds.cmd_contents[catname] then
|
||||
--Make a new category
|
||||
cmds.cmd_contents[catname] = xlib.makelistview{ headerheight=0, multiselect=false, h=136 }
|
||||
cmds.cmd_contents[catname].OnRowSelected = function( self, LineID ) cmds.setselected( self, LineID ) end
|
||||
cmds.cmd_contents[catname]:AddColumn( "" )
|
||||
local cat = xlib.makecat{ label=catname, contents=cmds.cmd_contents[catname], expanded=false, parent=xgui.null }
|
||||
function cat.Header:OnMousePressed( mcode )
|
||||
if ( mcode == MOUSE_LEFT ) then
|
||||
self:GetParent():Toggle()
|
||||
if cmds.expandedcat then
|
||||
if cmds.expandedcat ~= self:GetParent() then
|
||||
cmds.expandedcat:Toggle()
|
||||
else
|
||||
cmds.expandedcat = nil
|
||||
return
|
||||
end
|
||||
end
|
||||
cmds.expandedcat = self:GetParent()
|
||||
return
|
||||
end
|
||||
return self:GetParent():OnMousePressed( mcode )
|
||||
end
|
||||
newcategories[catname] = cat
|
||||
table.insert( sortcategories, catname )
|
||||
end
|
||||
local line = cmds.cmd_contents[catname]:AddLine( string.gsub( data.cmd, "ulx ", "" ), data.cmd )
|
||||
if data.cmd == lastcmd then
|
||||
cmds.cmd_contents[catname]:SelectItem( line )
|
||||
cmds.expandedcat = cmds.cmd_contents[catname]:GetParent()
|
||||
cmds.expandedcat:SetExpanded( true )
|
||||
matchedCmdFound = true
|
||||
end
|
||||
end
|
||||
end
|
||||
if not matchedCmdFound then
|
||||
if cmds.plist.open then
|
||||
cmds.plist:Close()
|
||||
xlib.animQueue_start()
|
||||
elseif cmds.argslist.open then
|
||||
cmds.argslist:Close()
|
||||
xlib.animQueue_start()
|
||||
end
|
||||
end
|
||||
|
||||
table.sort( sortcategories )
|
||||
for _, catname in ipairs( sortcategories ) do
|
||||
local cat = newcategories[catname]
|
||||
cmds.cmds:Add( cat )
|
||||
cat.Contents:SortByColumn( 1 )
|
||||
cat.Contents:SetHeight( 17*#cat.Contents:GetLines() )
|
||||
end
|
||||
cmds.permissionChanged = nil
|
||||
end
|
||||
|
||||
--------------
|
||||
--ANIMATIONS--
|
||||
--------------
|
||||
function cmds.plist:openAnim( arg )
|
||||
xlib.addToAnimQueue( cmds.refreshPlist, arg )
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=self, startx=-250, starty=0, endx=0, endy=0, setvisible=true } )
|
||||
end
|
||||
|
||||
function cmds.plist:closeAnim()
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=self, startx=0, starty=0, endx=-250, endy=0, setvisible=false } )
|
||||
end
|
||||
|
||||
function cmds.argslist:openAnim( cmd, secondary )
|
||||
xlib.addToAnimQueue( function() cmds.argslist.secondaryPos = secondary end )
|
||||
xlib.addToAnimQueue( cmds.buildArgsList, cmd )
|
||||
if secondary then
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=self.scroll, startx=-170, starty=0, endx=0, endy=0, setvisible=true } )
|
||||
else
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=self.scroll, startx=80, starty=0, endx=255, endy=0, setvisible=true } )
|
||||
end
|
||||
end
|
||||
|
||||
function cmds.argslist:closeAnim( secondary )
|
||||
if secondary then
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=self.scroll, startx=0, starty=0, endx=-170, endy=0, setvisible=false } )
|
||||
else
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=self.scroll, startx=255, starty=0, endx=80, endy=0, setvisible=false } )
|
||||
end
|
||||
xlib.addToAnimQueue( function() cmds.argslist.secondaryPos = nil end )
|
||||
end
|
||||
--------------
|
||||
|
||||
cmds.refresh()
|
||||
hook.Add( "UCLChanged", "xgui_RefreshPlayerCmds", cmds.refresh )
|
||||
hook.Add( "ULibPlayerNameChanged", "xgui_plyUpdateCmds", cmds.playerNameChanged )
|
||||
--Commands module (formerly players module) v2 for ULX GUI -- by Stickly Man!
|
||||
--Handles all user-executable commands, such as kick, slay, ban, etc.
|
||||
|
||||
local cmds = xlib.makepanel{ parent=xgui.null }
|
||||
cmds.selcmd = nil
|
||||
cmds.mask = xlib.makepanel{ x=160, y=30, w=425, h=330, parent=cmds }
|
||||
cmds.argslist = xlib.makelistlayout{ w=165, h=330, parent=cmds.mask }
|
||||
cmds.argslist.secondaryPos = nil
|
||||
|
||||
cmds.argslist.scroll:SetVisible( false )
|
||||
|
||||
function cmds.argslist:Open( cmd, secondary )
|
||||
if secondary then
|
||||
if cmds.plist.open then
|
||||
cmds.plist:Close()
|
||||
elseif self.open then
|
||||
self:Close()
|
||||
end
|
||||
end
|
||||
self:openAnim( cmd, secondary )
|
||||
self.open = true
|
||||
end
|
||||
function cmds.argslist:Close()
|
||||
self:closeAnim( self.secondaryPos )
|
||||
self.open = false
|
||||
end
|
||||
cmds.plist = xlib.makelistview{ w=250, h=330, multiselect=true, parent=cmds.mask }
|
||||
function cmds.plist:Open( arg )
|
||||
if cmds.argslist.secondaryPos == true then cmds.argslist:Close()
|
||||
elseif self.open then self:Close() end
|
||||
self:openAnim( arg )
|
||||
--Determine if the arguments should be visible after changing (If a valid player will be selected)
|
||||
local targets = cmds.calculateValidPlayers( arg )
|
||||
local playerWillBeSelected = false
|
||||
for _, line in ipairs( cmds.plist:GetSelected() ) do
|
||||
if table.HasValue( targets, line.ply ) then
|
||||
playerWillBeSelected = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if playerWillBeSelected then
|
||||
cmds.argslist:Open( ULib.cmds.translatedCmds[arg.cmd], false )
|
||||
end
|
||||
self.open = true
|
||||
end
|
||||
function cmds.plist:Close()
|
||||
if cmds.argslist.open then cmds.argslist:Close() end
|
||||
self:closeAnim()
|
||||
self.open = false
|
||||
end
|
||||
cmds.plist.DoDoubleClick = function()
|
||||
cmds.runCmd( cmds.selcmd )
|
||||
end
|
||||
cmds.plist:SetVisible( false )
|
||||
cmds.plist:AddColumn( "Name" )
|
||||
cmds.plist:AddColumn( "Group" )
|
||||
|
||||
cmds.cmds = xlib.makelistlayout{ x=5, y=30, w=150, h=330, parent=cmds, padding=1, spacing=1 }
|
||||
cmds.setselected = function( selcat, LineID )
|
||||
if selcat.Lines[LineID]:GetColumnText(2) == cmds.selcmd then
|
||||
selcat:ClearSelection()
|
||||
if cmds.plist.open then cmds.plist:Close() else cmds.argslist:Close() end
|
||||
xlib.animQueue_start()
|
||||
cmds.selcmd = nil
|
||||
return
|
||||
end
|
||||
|
||||
for _, cat in pairs( cmds.cmd_contents ) do
|
||||
if cat ~= selcat then
|
||||
cat:ClearSelection()
|
||||
end
|
||||
end
|
||||
cmds.selcmd = selcat.Lines[LineID]:GetColumnText(2)
|
||||
|
||||
if cmds.permissionChanged then cmds.refreshPlist() return end
|
||||
|
||||
if xlib.animRunning then xlib.animQueue_forceStop() end
|
||||
|
||||
local cmd = ULib.cmds.translatedCmds[cmds.selcmd]
|
||||
if cmd.args[2] and ( cmd.args[2].type == ULib.cmds.PlayersArg or cmd.args[2].type == ULib.cmds.PlayerArg ) then
|
||||
cmds.plist:Open( cmd.args[2] )
|
||||
else
|
||||
cmds.argslist:Open( cmd, true )
|
||||
end
|
||||
xlib.animQueue_start()
|
||||
end
|
||||
|
||||
function cmds.refreshPlist( arg )
|
||||
if not arg then arg = ULib.cmds.translatedCmds[cmds.selcmd].args[2] end
|
||||
if not arg or ( arg.type ~= ULib.cmds.PlayersArg and arg.type ~= ULib.cmds.PlayerArg ) then return end
|
||||
|
||||
local lastplys = {}
|
||||
for k, Line in pairs( cmds.plist.Lines ) do
|
||||
if ( Line:IsLineSelected() ) then table.insert( lastplys, Line:GetColumnText(1) ) end
|
||||
end
|
||||
|
||||
local targets = cmds.calculateValidPlayers( arg )
|
||||
|
||||
cmds.plist:Clear()
|
||||
cmds.plist:SetMultiSelect( arg.type == ULib.cmds.PlayersArg )
|
||||
for _, ply in ipairs( targets ) do
|
||||
local line = cmds.plist:AddLine( ply:Nick(), ply:GetUserGroup() )
|
||||
line.ply = ply
|
||||
line.OnSelect = function()
|
||||
if cmds.permissionChanged then return end
|
||||
|
||||
if not xlib.animRunning and not cmds.argslist.open then
|
||||
cmds.argslist:Open( ULib.cmds.translatedCmds[cmds.selcmd], false )
|
||||
xlib.animQueue_start( )
|
||||
else
|
||||
if not cmds.clickedFlag then --Prevent this from happening multiple times.
|
||||
cmds.clickedFlag = true
|
||||
xlib.addToAnimQueue( function() if not cmds.argslist.open then
|
||||
cmds.argslist:Open( ULib.cmds.translatedCmds[cmds.selcmd], false ) end
|
||||
cmds.clickedFlag = nil end )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Select previously selected Lines
|
||||
if table.HasValue( lastplys, ply:Nick() ) then
|
||||
cmds.plist:SelectItem( line )
|
||||
end
|
||||
end
|
||||
--Select only the first item if multiselect is disabled.
|
||||
if not cmds.plist:GetMultiSelect() then
|
||||
local firstSelected = cmds.plist:GetSelected()[1]
|
||||
cmds.plist:ClearSelection()
|
||||
cmds.plist:SelectItem( firstSelected )
|
||||
end
|
||||
|
||||
if not cmds.plist:GetSelectedLine() then
|
||||
if not xlib.animRunning then
|
||||
if cmds.argslist.open then
|
||||
cmds.argslist:Close()
|
||||
xlib.animQueue_start()
|
||||
end
|
||||
else
|
||||
if cmds.permissionChanged then
|
||||
xlib.addToAnimQueue( function() if cmds.argslist.open and cmds.plist.open then cmds.argslist:Close() end end )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function cmds.calculateValidPlayers( arg )
|
||||
if not arg then arg = ULib.cmds.translatedCmds[cmds.selcmd].args[2] end
|
||||
|
||||
local access, tag = LocalPlayer():query( arg.cmd )
|
||||
local restrictions = {}
|
||||
ULib.cmds.PlayerArg.processRestrictions( restrictions, LocalPlayer(), arg, ulx.getTagArgNum( tag, 1 ) )
|
||||
|
||||
local targets = restrictions.restrictedTargets
|
||||
if targets == false then -- No one allowed
|
||||
targets = {}
|
||||
elseif targets == nil then -- Everyone allowed
|
||||
targets = player.GetAll()
|
||||
end
|
||||
return targets
|
||||
end
|
||||
|
||||
function cmds.buildArgsList( cmd )
|
||||
cmds.argslist:Clear()
|
||||
cmds.curargs = {}
|
||||
local argnum = 0
|
||||
local zpos = 0
|
||||
local expectingplayers = cmd.args[2] and ( ( cmd.args[2].type == ULib.cmds.PlayersArg ) or ( cmd.args[2].type == ULib.cmds.PlayerArg ) ) or false
|
||||
for _, arg in ipairs( cmd.args ) do
|
||||
if not arg.type.invisible then
|
||||
argnum = argnum + 1
|
||||
if not ( argnum == 1 and expectingplayers ) then
|
||||
if arg.invisible ~= true then
|
||||
local curitem = arg
|
||||
if curitem.repeat_min then --This command repeats!
|
||||
local panel = xlib.makepanel{ h=20, parent=cmds.argslist }
|
||||
local choices = {}
|
||||
panel.argnum = argnum
|
||||
panel.xguiIgnore = true
|
||||
panel.arg = curitem
|
||||
panel.addbutton = xlib.makebutton{ label="Add", w=83, parent=panel }
|
||||
panel.addbutton.DoClick = function( self )
|
||||
local parent = self:GetParent()
|
||||
local ctrl = parent.arg.type.x_getcontrol( parent.arg, parent.argnum, cmds.argslist )
|
||||
cmds.argslist:Add( ctrl )
|
||||
ctrl:MoveToAfter( choices[#choices] )
|
||||
table.insert( choices, ctrl )
|
||||
table.insert( cmds.curargs, ctrl )
|
||||
panel.removebutton:SetDisabled( false )
|
||||
if parent.arg.repeat_max and #choices >= parent.arg.repeat_max then self:SetDisabled( true ) end
|
||||
end
|
||||
panel.removebutton = xlib.makebutton{ label="Remove", x=83, w=82, disabled=true, parent=panel }
|
||||
panel.removebutton.DoClick = function( self )
|
||||
local parent = self:GetParent()
|
||||
local ctrl = choices[#choices]
|
||||
ctrl:Remove()
|
||||
table.remove( choices )
|
||||
table.remove( cmds.curargs )
|
||||
panel.addbutton:SetDisabled( false )
|
||||
if #choices <= parent.arg.repeat_min then self:SetDisabled( true ) end
|
||||
end
|
||||
cmds.argslist:Add( panel )
|
||||
panel:SetZPos( zpos )
|
||||
zpos = zpos + 1
|
||||
for i=1,curitem.repeat_min do
|
||||
local ctrl = arg.type.x_getcontrol( arg, argnum, cmds.argslist )
|
||||
cmds.argslist:Add( ctrl )
|
||||
ctrl:SetZPos( zpos )
|
||||
zpos = zpos + 1
|
||||
table.insert( choices, ctrl )
|
||||
table.insert( cmds.curargs, ctrl )
|
||||
end
|
||||
else
|
||||
local panel = arg.type.x_getcontrol( arg, argnum, cmds.argslist )
|
||||
table.insert( cmds.curargs, panel )
|
||||
if curitem.type == ULib.cmds.NumArg then
|
||||
panel.TextArea.OnEnter = function( self )
|
||||
cmds.runCmd( cmd.cmd )
|
||||
end
|
||||
elseif curitem.type == ULib.cmds.StringArg then
|
||||
panel.OnEnter = function( self )
|
||||
cmds.runCmd( cmd.cmd )
|
||||
end
|
||||
end
|
||||
cmds.argslist:Add( panel )
|
||||
panel:SetZPos( zpos )
|
||||
zpos = zpos + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if LocalPlayer():query( cmd.cmd ) then
|
||||
local panel = xlib.makebutton{ label=cmd.cmd, parent=cmds.argslist }
|
||||
panel.xguiIgnore = true
|
||||
panel.DoClick = function()
|
||||
cmds.runCmd( cmd.cmd )
|
||||
end
|
||||
cmds.argslist:Add( panel )
|
||||
panel:SetZPos( zpos )
|
||||
zpos = zpos + 1
|
||||
end
|
||||
if cmd.opposite and LocalPlayer():query( cmd.opposite ) then
|
||||
local panel = xlib.makebutton{ label=cmd.opposite, parent=cmds.argslist }
|
||||
panel.DoClick = function()
|
||||
cmds.runCmd( cmd.opposite )
|
||||
end
|
||||
panel.xguiIgnore = true
|
||||
cmds.argslist:Add( panel )
|
||||
panel:SetZPos( zpos )
|
||||
zpos = zpos + 1
|
||||
end
|
||||
if cmd.helpStr then --If the command has a string for help
|
||||
local panel = xlib.makelabel{ w=160, label=cmd.helpStr, wordwrap=true, parent=cmds.argslist }
|
||||
panel.xguiIgnore = true
|
||||
cmds.argslist:Add( panel )
|
||||
panel:SetZPos( zpos )
|
||||
zpos = zpos + 1
|
||||
end
|
||||
end
|
||||
|
||||
function cmds.runCmd( cmd )
|
||||
local cmd = string.Explode( " ", cmd )
|
||||
if cmds.plist:IsVisible() then
|
||||
local plys = {}
|
||||
for _, line in ipairs( cmds.plist:GetSelected() ) do
|
||||
table.insert( plys, "$" .. ULib.getUniqueIDForPlayer( line.ply ) )
|
||||
table.insert( plys, "," )
|
||||
end
|
||||
table.remove( plys ) --Removes the final comma
|
||||
table.insert( cmd, table.concat( plys ) )
|
||||
end
|
||||
|
||||
for _, arg in ipairs( cmds.curargs ) do
|
||||
if not arg.xguiIgnore then
|
||||
table.insert( cmd, arg:GetValue() )
|
||||
end
|
||||
end
|
||||
RunConsoleCommand( unpack( cmd ) )
|
||||
end
|
||||
|
||||
function cmds.playerNameChanged( ply, old, new )
|
||||
for i, line in ipairs( cmds.plist.Lines ) do
|
||||
if line:GetColumnText(1) == old then
|
||||
line:SetColumnText( 1, new )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
cmds.refresh = function( permissionChanged )
|
||||
local lastcmd = cmds.selcmd
|
||||
cmds.cmds:Clear()
|
||||
cmds.cmd_contents = {}
|
||||
cmds.expandedcat = nil
|
||||
cmds.selcmd = nil
|
||||
cmds.permissionChanged = true
|
||||
|
||||
local newcategories = {}
|
||||
local sortcategories = {}
|
||||
local matchedCmdFound = false
|
||||
for cmd, data in pairs( ULib.cmds.translatedCmds ) do
|
||||
local opposite = data.opposite or ""
|
||||
if opposite ~= cmd and ( LocalPlayer():query( data.cmd ) or LocalPlayer():query( opposite ) ) then
|
||||
local catname = data.category
|
||||
if catname == nil or catname == "" then catname = "_Uncategorized" end
|
||||
if not cmds.cmd_contents[catname] then
|
||||
--Make a new category
|
||||
cmds.cmd_contents[catname] = xlib.makelistview{ headerheight=0, multiselect=false, h=136 }
|
||||
cmds.cmd_contents[catname].OnRowSelected = function( self, LineID ) cmds.setselected( self, LineID ) end
|
||||
cmds.cmd_contents[catname]:AddColumn( "" )
|
||||
local cat = xlib.makecat{ label=catname, contents=cmds.cmd_contents[catname], expanded=false, parent=xgui.null }
|
||||
function cat.Header:OnMousePressed( mcode )
|
||||
if ( mcode == MOUSE_LEFT ) then
|
||||
self:GetParent():Toggle()
|
||||
if cmds.expandedcat then
|
||||
if cmds.expandedcat ~= self:GetParent() then
|
||||
cmds.expandedcat:Toggle()
|
||||
else
|
||||
cmds.expandedcat = nil
|
||||
return
|
||||
end
|
||||
end
|
||||
cmds.expandedcat = self:GetParent()
|
||||
return
|
||||
end
|
||||
return self:GetParent():OnMousePressed( mcode )
|
||||
end
|
||||
newcategories[catname] = cat
|
||||
table.insert( sortcategories, catname )
|
||||
end
|
||||
local line = cmds.cmd_contents[catname]:AddLine( string.gsub( data.cmd, "ulx ", "" ), data.cmd )
|
||||
if data.cmd == lastcmd then
|
||||
cmds.cmd_contents[catname]:SelectItem( line )
|
||||
cmds.expandedcat = cmds.cmd_contents[catname]:GetParent()
|
||||
cmds.expandedcat:SetExpanded( true )
|
||||
matchedCmdFound = true
|
||||
end
|
||||
end
|
||||
end
|
||||
if not matchedCmdFound then
|
||||
if cmds.plist.open then
|
||||
cmds.plist:Close()
|
||||
xlib.animQueue_start()
|
||||
elseif cmds.argslist.open then
|
||||
cmds.argslist:Close()
|
||||
xlib.animQueue_start()
|
||||
end
|
||||
end
|
||||
|
||||
table.sort( sortcategories )
|
||||
for _, catname in ipairs( sortcategories ) do
|
||||
local cat = newcategories[catname]
|
||||
cmds.cmds:Add( cat )
|
||||
cat.Contents:SortByColumn( 1 )
|
||||
cat.Contents:SetHeight( 17*#cat.Contents:GetLines() )
|
||||
end
|
||||
cmds.permissionChanged = nil
|
||||
end
|
||||
|
||||
--------------
|
||||
--ANIMATIONS--
|
||||
--------------
|
||||
function cmds.plist:openAnim( arg )
|
||||
xlib.addToAnimQueue( cmds.refreshPlist, arg )
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=self, startx=-250, starty=0, endx=0, endy=0, setvisible=true } )
|
||||
end
|
||||
|
||||
function cmds.plist:closeAnim()
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=self, startx=0, starty=0, endx=-250, endy=0, setvisible=false } )
|
||||
end
|
||||
|
||||
function cmds.argslist:openAnim( cmd, secondary )
|
||||
xlib.addToAnimQueue( function() cmds.argslist.secondaryPos = secondary end )
|
||||
xlib.addToAnimQueue( cmds.buildArgsList, cmd )
|
||||
if secondary then
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=self.scroll, startx=-170, starty=0, endx=0, endy=0, setvisible=true } )
|
||||
else
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=self.scroll, startx=80, starty=0, endx=255, endy=0, setvisible=true } )
|
||||
end
|
||||
end
|
||||
|
||||
function cmds.argslist:closeAnim( secondary )
|
||||
if secondary then
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=self.scroll, startx=0, starty=0, endx=-170, endy=0, setvisible=false } )
|
||||
else
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=self.scroll, startx=255, starty=0, endx=80, endy=0, setvisible=false } )
|
||||
end
|
||||
xlib.addToAnimQueue( function() cmds.argslist.secondaryPos = nil end )
|
||||
end
|
||||
--------------
|
||||
|
||||
cmds.refresh()
|
||||
hook.Add( "UCLChanged", "xgui_RefreshPlayerCmds", cmds.refresh )
|
||||
hook.Add( "ULibPlayerNameChanged", "xgui_plyUpdateCmds", cmds.playerNameChanged )
|
||||
xgui.addModule( "Cmds", cmds, "icon16/user_gray.png" )
|
@ -1,39 +1,39 @@
|
||||
--Sandbox settings module for ULX GUI -- by Stickly Man!
|
||||
--Defines sbox cvar limits and sandbox specific settings for the sandbox gamemode.
|
||||
|
||||
xgui.prepareDataType( "sboxlimits" )
|
||||
local sbox_settings = xlib.makepanel{ parent=xgui.null }
|
||||
|
||||
xlib.makecheckbox{ x=10, y=10, label="Enable Noclip", repconvar="rep_sbox_noclip", parent=sbox_settings }
|
||||
xlib.makecheckbox{ x=10, y=30, label="Enable Godmode", repconvar="rep_sbox_godmode", parent=sbox_settings }
|
||||
xlib.makecheckbox{ x=10, y=50, label="Enable PvP Damage", repconvar="rep_sbox_playershurtplayers", parent=sbox_settings }
|
||||
xlib.makecheckbox{ x=10, y=70, label="Spawn With Weapons", repconvar="rep_sbox_weapons", parent=sbox_settings }
|
||||
xlib.makecheckbox{ x=10, y=90, label="Limited Physgun", repconvar="rep_physgun_limited", parent=sbox_settings }
|
||||
|
||||
xlib.makecheckbox{ x=10, y=130, label="Persist Props", repconvar="rep_sbox_persist", parent=sbox_settings }
|
||||
xlib.makecheckbox{ x=10, y=150, label="Bone Manip. Misc", repconvar="rep_sbox_bonemanip_misc", parent=sbox_settings }
|
||||
xlib.makecheckbox{ x=10, y=170, label="Bone Manip. NPC", repconvar="rep_sbox_bonemanip_npc", parent=sbox_settings }
|
||||
xlib.makecheckbox{ x=10, y=190, label="Bone Manip. Player", repconvar="rep_sbox_bonemanip_player", parent=sbox_settings }
|
||||
|
||||
xlib.makelabel{ x=5, y=247, w=140, wordwrap=true, label="NOTE: The non-ulx cvars configurable in XGUI are provided for easy access only and DO NOT SAVE when the server is shut down or crashes.", parent=sbox_settings }
|
||||
sbox_settings.plist = xlib.makelistlayout{ x=140, y=5, h=322, w=440, spacing=1, padding=2, parent=sbox_settings }
|
||||
|
||||
function sbox_settings.processLimits()
|
||||
sbox_settings.plist:Clear()
|
||||
for g, limits in ipairs( xgui.data.sboxlimits ) do
|
||||
if #limits > 0 then
|
||||
local panel = xlib.makepanel{ h=5+math.ceil( #limits/2 )*25 }
|
||||
local i=0
|
||||
for _, cvar in ipairs( limits ) do
|
||||
local cvardata = string.Explode( " ", cvar ) --Split the cvarname and max slider value number
|
||||
xgui.queueFunctionCall( xlib.makeslider, "sboxlimits", { x=10+(i%2*205), y=5+math.floor(i/2)*25, w=200, label="Max " .. cvardata[1]:sub(9), min=0, max=cvardata[2], repconvar="rep_"..cvardata[1], parent=panel, fixclip=true } )
|
||||
i = i + 1
|
||||
end
|
||||
sbox_settings.plist:Add( xlib.makecat{ label=limits.title .. " (" .. #limits .. " limit" .. ((#limits > 1) and "s" or "") .. ")", contents=panel, expanded=( g==1 ) } )
|
||||
end
|
||||
end
|
||||
end
|
||||
sbox_settings.processLimits()
|
||||
|
||||
xgui.hookEvent( "sboxlimits", "process", sbox_settings.processLimits, "sandboxProcessLimits" )
|
||||
xgui.addSettingModule( "Sandbox", sbox_settings, "icon16/box.png", "xgui_gmsettings" )
|
||||
--Sandbox settings module for ULX GUI -- by Stickly Man!
|
||||
--Defines sbox cvar limits and sandbox specific settings for the sandbox gamemode.
|
||||
|
||||
xgui.prepareDataType( "sboxlimits" )
|
||||
local sbox_settings = xlib.makepanel{ parent=xgui.null }
|
||||
|
||||
xlib.makecheckbox{ x=10, y=10, label="Enable Noclip", repconvar="rep_sbox_noclip", parent=sbox_settings }
|
||||
xlib.makecheckbox{ x=10, y=30, label="Enable Godmode", repconvar="rep_sbox_godmode", parent=sbox_settings }
|
||||
xlib.makecheckbox{ x=10, y=50, label="Enable PvP Damage", repconvar="rep_sbox_playershurtplayers", parent=sbox_settings }
|
||||
xlib.makecheckbox{ x=10, y=70, label="Spawn With Weapons", repconvar="rep_sbox_weapons", parent=sbox_settings }
|
||||
xlib.makecheckbox{ x=10, y=90, label="Limited Physgun", repconvar="rep_physgun_limited", parent=sbox_settings }
|
||||
|
||||
xlib.makecheckbox{ x=10, y=130, label="Persist Props", repconvar="rep_sbox_persist", parent=sbox_settings }
|
||||
xlib.makecheckbox{ x=10, y=150, label="Bone Manip. Misc", repconvar="rep_sbox_bonemanip_misc", parent=sbox_settings }
|
||||
xlib.makecheckbox{ x=10, y=170, label="Bone Manip. NPC", repconvar="rep_sbox_bonemanip_npc", parent=sbox_settings }
|
||||
xlib.makecheckbox{ x=10, y=190, label="Bone Manip. Player", repconvar="rep_sbox_bonemanip_player", parent=sbox_settings }
|
||||
|
||||
xlib.makelabel{ x=5, y=247, w=140, wordwrap=true, label="NOTE: The non-ulx cvars configurable in XGUI are provided for easy access only and DO NOT SAVE when the server is shut down or crashes.", parent=sbox_settings }
|
||||
sbox_settings.plist = xlib.makelistlayout{ x=140, y=5, h=322, w=440, spacing=1, padding=2, parent=sbox_settings }
|
||||
|
||||
function sbox_settings.processLimits()
|
||||
sbox_settings.plist:Clear()
|
||||
for g, limits in ipairs( xgui.data.sboxlimits ) do
|
||||
if #limits > 0 then
|
||||
local panel = xlib.makepanel{ h=5+math.ceil( #limits/2 )*25 }
|
||||
local i=0
|
||||
for _, cvar in ipairs( limits ) do
|
||||
local cvardata = string.Explode( " ", cvar ) --Split the cvarname and max slider value number
|
||||
xgui.queueFunctionCall( xlib.makeslider, "sboxlimits", { x=10+(i%2*205), y=5+math.floor(i/2)*25, w=200, label="Max " .. cvardata[1]:sub(9), min=0, max=cvardata[2], repconvar="rep_"..cvardata[1], parent=panel, fixclip=true } )
|
||||
i = i + 1
|
||||
end
|
||||
sbox_settings.plist:Add( xlib.makecat{ label=limits.title .. " (" .. #limits .. " limit" .. ((#limits > 1) and "s" or "") .. ")", contents=panel, expanded=( g==1 ) } )
|
||||
end
|
||||
end
|
||||
end
|
||||
sbox_settings.processLimits()
|
||||
|
||||
xgui.hookEvent( "sboxlimits", "process", sbox_settings.processLimits, "sandboxProcessLimits" )
|
||||
xgui.addSettingModule( "Sandbox", sbox_settings, "icon16/box.png", "xgui_gmsettings" )
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,176 +1,176 @@
|
||||
--Maps module for ULX GUI -- by Stickly Man!
|
||||
--Lists maps on server, allows for map voting, changing levels, etc. All players may access this menu.
|
||||
|
||||
ulx.votemaps = ulx.votemaps or {}
|
||||
xgui.prepareDataType( "votemaps", ulx.votemaps )
|
||||
local maps = xlib.makepanel{ parent=xgui.null }
|
||||
|
||||
maps.maplabel = xlib.makelabel{ x=10, y=13, label="Server Votemaps: (Votemaps are highlighted)", parent=maps }
|
||||
xlib.makelabel{ x=10, y=343, label="Gamemode:", parent=maps }
|
||||
maps.curmap = xlib.makelabel{ x=187, y=223, w=192, label="No Map Selected", parent=maps }
|
||||
|
||||
maps.list = xlib.makelistview{ x=5, y=30, w=175, h=310, multiselect=true, parent=maps, headerheight=0 } --Remember to enable/disable multiselect based on admin status?
|
||||
maps.list:AddColumn( "Map Name" )
|
||||
maps.list.OnRowSelected = function( self, LineID, Line )
|
||||
if ( ULib.fileExists( "maps/thumb/" .. maps.list:GetSelected()[1]:GetColumnText(1) .. ".png" ) ) then
|
||||
maps.disp:SetMaterial( Material( "maps/thumb/" .. maps.list:GetSelected()[1]:GetColumnText(1) .. ".png" ) )
|
||||
else
|
||||
maps.disp:SetMaterial( Material( "maps/thumb/noicon.png" ) )
|
||||
end
|
||||
maps.curmap:SetText( Line:GetColumnText(1) )
|
||||
maps.updateButtonStates()
|
||||
end
|
||||
|
||||
maps.disp = vgui.Create( "DImage", maps )
|
||||
maps.disp:SetPos( 185, 30 )
|
||||
maps.disp:SetMaterial( Material( "maps/thumb/noicon.png" ) )
|
||||
maps.disp:SetSize( 192, 192 )
|
||||
|
||||
maps.gamemode = xlib.makecombobox{ x=70, y=340, w=110, h=20, text="<default>", parent=maps }
|
||||
|
||||
maps.vote = xlib.makebutton{ x=185, y=245, w=192, h=20, label="Vote to play this map!", parent=maps }
|
||||
maps.vote.DoClick = function()
|
||||
if maps.curmap:GetValue() ~= "No Map Selected" then
|
||||
RunConsoleCommand( "ulx", "votemap", maps.curmap:GetValue() )
|
||||
end
|
||||
end
|
||||
|
||||
maps.svote = xlib.makebutton{ x=185, y=270, w=192, h=20, label="Server-wide vote of selected map(s)", parent=maps }
|
||||
maps.svote.DoClick = function()
|
||||
if maps.curmap:GetValue() ~= "No Map Selected" then
|
||||
local votemaps = {}
|
||||
for k, v in ipairs( maps.list:GetSelected() ) do
|
||||
table.insert( votemaps, maps.list:GetSelected()[k]:GetColumnText(1))
|
||||
end
|
||||
RunConsoleCommand( "ulx", "votemap2", unpack( votemaps ) )
|
||||
end
|
||||
end
|
||||
|
||||
maps.changemap = xlib.makebutton{ x=185, y=295, w=192, h=20, disabled=true, label="Force changelevel to this map", parent=maps }
|
||||
maps.changemap.DoClick = function()
|
||||
if maps.curmap:GetValue() ~= "No Map Selected" then
|
||||
Derma_Query( "Are you sure you would like to change the level to \"" .. maps.curmap:GetValue() .. "\"?", "XGUI WARNING",
|
||||
"Change Level", function()
|
||||
RunConsoleCommand( "ulx", "map", maps.curmap:GetValue(), ( maps.gamemode:GetValue() ~= "<default>" ) and maps.gamemode:GetValue() or nil ) end,
|
||||
"Cancel", function() end )
|
||||
end
|
||||
end
|
||||
|
||||
maps.vetomap = xlib.makebutton{ x=185, y=320, w=192, label="Veto a map vote", parent=maps }
|
||||
maps.vetomap.DoClick = function()
|
||||
RunConsoleCommand( "ulx", "veto" )
|
||||
end
|
||||
|
||||
maps.nextLevelLabel = xlib.makelabel{ x=382, y=13, label="Nextlevel (cvar)", parent=maps }
|
||||
maps.nextlevel = xlib.makecombobox{ x=382, y=30, w=180, h=20, repconvar="rep_nextlevel", convarblanklabel="<not specified>", parent=maps }
|
||||
|
||||
function maps.addMaptoList( mapname, lastselected )
|
||||
local line = maps.list:AddLine( mapname )
|
||||
if table.HasValue( lastselected, mapname ) then
|
||||
maps.list:SelectItem( line )
|
||||
end
|
||||
line.isNotVotemap = nil
|
||||
if not table.HasValue( ulx.votemaps, mapname ) then
|
||||
line:SetAlpha( 128 )
|
||||
line.isNotVotemap = true
|
||||
end
|
||||
end
|
||||
|
||||
function maps.updateVoteMaps()
|
||||
local lastselected = {}
|
||||
for k, Line in pairs( maps.list.Lines ) do
|
||||
if ( Line:IsLineSelected() ) then table.insert( lastselected, Line:GetColumnText(1) ) end
|
||||
end
|
||||
|
||||
maps.list:Clear()
|
||||
maps.nextlevel:Clear()
|
||||
|
||||
if LocalPlayer():query( "ulx map" ) then --Show all maps for admins who have access to change the level
|
||||
maps.maplabel:SetText( "Server Maps (Votemaps are highlighted)" )
|
||||
maps.nextlevel:AddChoice( "<not specified>" )
|
||||
maps.nextlevel.ConVarUpdated( "nextlevel", "rep_nextlevel", nil, nil, GetConVar( "rep_nextlevel" ):GetString() )
|
||||
maps.nextLevelLabel:SetAlpha(255);
|
||||
maps.nextlevel:SetDisabled( false )
|
||||
for _,v in ipairs( ulx.maps ) do
|
||||
maps.addMaptoList( v, lastselected )
|
||||
maps.nextlevel:AddChoice( v )
|
||||
end
|
||||
else
|
||||
maps.maplabel:SetText( "Server Votemaps" )
|
||||
maps.nextLevelLabel:SetAlpha(0);
|
||||
maps.nextlevel:SetDisabled( true )
|
||||
maps.nextlevel:SetAlpha(0);
|
||||
for _,v in ipairs( ulx.votemaps ) do --Show the list of votemaps for users without access to "ulx map"
|
||||
maps.addMaptoList( v, lastselected )
|
||||
end
|
||||
end
|
||||
if not maps.accessVotemap2 then --Only select the first map if they don't have access to votemap2
|
||||
local l = maps.list:GetSelected()[1]
|
||||
maps.list:ClearSelection()
|
||||
maps.list:SelectItem( l )
|
||||
end
|
||||
maps.updateButtonStates()
|
||||
|
||||
ULib.cmds.translatedCmds["ulx votemap"].args[2].completes = xgui.data.votemaps --Set concommand completes for the ulx votemap command. (Used by XGUI in the cmds tab)
|
||||
end
|
||||
|
||||
function maps.updateGamemodes()
|
||||
local lastselected = maps.gamemode:GetValue()
|
||||
maps.gamemode:Clear()
|
||||
maps.gamemode:SetText( lastselected )
|
||||
maps.gamemode:AddChoice( "<default>" )
|
||||
|
||||
-- Get allowed gamemodes
|
||||
local access, tag = LocalPlayer():query( "ulx map" )
|
||||
local restrictions = {}
|
||||
ULib.cmds.StringArg.processRestrictions( restrictions, ULib.cmds.translatedCmds['ulx map'].args[3], ulx.getTagArgNum( tag, 2 ) )
|
||||
|
||||
for _, v in ipairs( restrictions.restrictedCompletes ) do
|
||||
maps.gamemode:AddChoice( v )
|
||||
end
|
||||
end
|
||||
|
||||
function maps.updatePermissions()
|
||||
maps.vetomap:SetDisabled( true )
|
||||
RunConsoleCommand( "xgui", "getVetoState" ) --Get the proper enabled/disabled state of the veto button.
|
||||
maps.accessVotemap = ( GetConVarNumber( "ulx_votemapEnabled" ) == 1 )
|
||||
maps.accessVotemap2 = LocalPlayer():query( "ulx votemap2" )
|
||||
maps.accessMap = LocalPlayer():query( "ulx map" )
|
||||
maps.updateGamemodes()
|
||||
maps.updateVoteMaps()
|
||||
maps.updateButtonStates()
|
||||
end
|
||||
|
||||
function xgui.updateVetoButton( value )
|
||||
maps.vetomap:SetDisabled( not value )
|
||||
end
|
||||
|
||||
function maps.updateButtonStates()
|
||||
maps.gamemode:SetDisabled( not maps.accessMap )
|
||||
maps.list:SetMultiSelect( maps.accessVotemap2 )
|
||||
if maps.list:GetSelectedLine() then
|
||||
maps.vote:SetDisabled( maps.list:GetSelected()[1].isNotVotemap or not maps.accessVotemap )
|
||||
maps.svote:SetDisabled( not maps.accessVotemap2 )
|
||||
maps.changemap:SetDisabled( not maps.accessMap )
|
||||
else --No lines are selected
|
||||
maps.vote:SetDisabled( true )
|
||||
maps.svote:SetDisabled( true )
|
||||
maps.changemap:SetDisabled( true )
|
||||
maps.curmap:SetText( "No Map Selected" )
|
||||
maps.disp:SetMaterial( Material( "maps/thumb/noicon.png" ) )
|
||||
end
|
||||
end
|
||||
maps.updateVoteMaps() -- For autorefresh
|
||||
|
||||
--Enable/Disable the votemap button when ulx_votemapEnabled changes
|
||||
function maps.ConVarUpdated( sv_cvar, cl_cvar, ply, old_val, new_val )
|
||||
if cl_cvar == "ulx_votemapenabled" then
|
||||
maps.accessVotemap = ( tonumber( new_val ) == 1 )
|
||||
maps.updateButtonStates()
|
||||
end
|
||||
end
|
||||
hook.Add( "ULibReplicatedCvarChanged", "XGUI_mapsUpdateVotemapEnabled", maps.ConVarUpdated )
|
||||
|
||||
xgui.hookEvent( "onProcessModules", nil, maps.updatePermissions, "mapsUpdatePermissions" )
|
||||
xgui.hookEvent( "votemaps", "process", maps.updateVoteMaps, "mapsUpdateVotemaps" )
|
||||
xgui.addModule( "Maps", maps, "icon16/map.png" )
|
||||
--Maps module for ULX GUI -- by Stickly Man!
|
||||
--Lists maps on server, allows for map voting, changing levels, etc. All players may access this menu.
|
||||
|
||||
ulx.votemaps = ulx.votemaps or {}
|
||||
xgui.prepareDataType( "votemaps", ulx.votemaps )
|
||||
local maps = xlib.makepanel{ parent=xgui.null }
|
||||
|
||||
maps.maplabel = xlib.makelabel{ x=10, y=13, label="Server Votemaps: (Votemaps are highlighted)", parent=maps }
|
||||
xlib.makelabel{ x=10, y=343, label="Gamemode:", parent=maps }
|
||||
maps.curmap = xlib.makelabel{ x=187, y=223, w=192, label="No Map Selected", parent=maps }
|
||||
|
||||
maps.list = xlib.makelistview{ x=5, y=30, w=175, h=310, multiselect=true, parent=maps, headerheight=0 } --Remember to enable/disable multiselect based on admin status?
|
||||
maps.list:AddColumn( "Map Name" )
|
||||
maps.list.OnRowSelected = function( self, LineID, Line )
|
||||
if ( ULib.fileExists( "maps/thumb/" .. maps.list:GetSelected()[1]:GetColumnText(1) .. ".png" ) ) then
|
||||
maps.disp:SetMaterial( Material( "maps/thumb/" .. maps.list:GetSelected()[1]:GetColumnText(1) .. ".png" ) )
|
||||
else
|
||||
maps.disp:SetMaterial( Material( "maps/thumb/noicon.png" ) )
|
||||
end
|
||||
maps.curmap:SetText( Line:GetColumnText(1) )
|
||||
maps.updateButtonStates()
|
||||
end
|
||||
|
||||
maps.disp = vgui.Create( "DImage", maps )
|
||||
maps.disp:SetPos( 185, 30 )
|
||||
maps.disp:SetMaterial( Material( "maps/thumb/noicon.png" ) )
|
||||
maps.disp:SetSize( 192, 192 )
|
||||
|
||||
maps.gamemode = xlib.makecombobox{ x=70, y=340, w=110, h=20, text="<default>", parent=maps }
|
||||
|
||||
maps.vote = xlib.makebutton{ x=185, y=245, w=192, h=20, label="Vote to play this map!", parent=maps }
|
||||
maps.vote.DoClick = function()
|
||||
if maps.curmap:GetValue() ~= "No Map Selected" then
|
||||
RunConsoleCommand( "ulx", "votemap", maps.curmap:GetValue() )
|
||||
end
|
||||
end
|
||||
|
||||
maps.svote = xlib.makebutton{ x=185, y=270, w=192, h=20, label="Server-wide vote of selected map(s)", parent=maps }
|
||||
maps.svote.DoClick = function()
|
||||
if maps.curmap:GetValue() ~= "No Map Selected" then
|
||||
local votemaps = {}
|
||||
for k, v in ipairs( maps.list:GetSelected() ) do
|
||||
table.insert( votemaps, maps.list:GetSelected()[k]:GetColumnText(1))
|
||||
end
|
||||
RunConsoleCommand( "ulx", "votemap2", unpack( votemaps ) )
|
||||
end
|
||||
end
|
||||
|
||||
maps.changemap = xlib.makebutton{ x=185, y=295, w=192, h=20, disabled=true, label="Force changelevel to this map", parent=maps }
|
||||
maps.changemap.DoClick = function()
|
||||
if maps.curmap:GetValue() ~= "No Map Selected" then
|
||||
Derma_Query( "Are you sure you would like to change the level to \"" .. maps.curmap:GetValue() .. "\"?", "XGUI WARNING",
|
||||
"Change Level", function()
|
||||
RunConsoleCommand( "ulx", "map", maps.curmap:GetValue(), ( maps.gamemode:GetValue() ~= "<default>" ) and maps.gamemode:GetValue() or nil ) end,
|
||||
"Cancel", function() end )
|
||||
end
|
||||
end
|
||||
|
||||
maps.vetomap = xlib.makebutton{ x=185, y=320, w=192, label="Veto a map vote", parent=maps }
|
||||
maps.vetomap.DoClick = function()
|
||||
RunConsoleCommand( "ulx", "veto" )
|
||||
end
|
||||
|
||||
maps.nextLevelLabel = xlib.makelabel{ x=382, y=13, label="Nextlevel (cvar)", parent=maps }
|
||||
maps.nextlevel = xlib.makecombobox{ x=382, y=30, w=180, h=20, repconvar="rep_nextlevel", convarblanklabel="<not specified>", parent=maps }
|
||||
|
||||
function maps.addMaptoList( mapname, lastselected )
|
||||
local line = maps.list:AddLine( mapname )
|
||||
if table.HasValue( lastselected, mapname ) then
|
||||
maps.list:SelectItem( line )
|
||||
end
|
||||
line.isNotVotemap = nil
|
||||
if not table.HasValue( ulx.votemaps, mapname ) then
|
||||
line:SetAlpha( 128 )
|
||||
line.isNotVotemap = true
|
||||
end
|
||||
end
|
||||
|
||||
function maps.updateVoteMaps()
|
||||
local lastselected = {}
|
||||
for k, Line in pairs( maps.list.Lines ) do
|
||||
if ( Line:IsLineSelected() ) then table.insert( lastselected, Line:GetColumnText(1) ) end
|
||||
end
|
||||
|
||||
maps.list:Clear()
|
||||
maps.nextlevel:Clear()
|
||||
|
||||
if LocalPlayer():query( "ulx map" ) then --Show all maps for admins who have access to change the level
|
||||
maps.maplabel:SetText( "Server Maps (Votemaps are highlighted)" )
|
||||
maps.nextlevel:AddChoice( "<not specified>" )
|
||||
maps.nextlevel.ConVarUpdated( "nextlevel", "rep_nextlevel", nil, nil, GetConVar( "rep_nextlevel" ):GetString() )
|
||||
maps.nextLevelLabel:SetAlpha(255);
|
||||
maps.nextlevel:SetDisabled( false )
|
||||
for _,v in ipairs( ulx.maps ) do
|
||||
maps.addMaptoList( v, lastselected )
|
||||
maps.nextlevel:AddChoice( v )
|
||||
end
|
||||
else
|
||||
maps.maplabel:SetText( "Server Votemaps" )
|
||||
maps.nextLevelLabel:SetAlpha(0);
|
||||
maps.nextlevel:SetDisabled( true )
|
||||
maps.nextlevel:SetAlpha(0);
|
||||
for _,v in ipairs( ulx.votemaps ) do --Show the list of votemaps for users without access to "ulx map"
|
||||
maps.addMaptoList( v, lastselected )
|
||||
end
|
||||
end
|
||||
if not maps.accessVotemap2 then --Only select the first map if they don't have access to votemap2
|
||||
local l = maps.list:GetSelected()[1]
|
||||
maps.list:ClearSelection()
|
||||
maps.list:SelectItem( l )
|
||||
end
|
||||
maps.updateButtonStates()
|
||||
|
||||
ULib.cmds.translatedCmds["ulx votemap"].args[2].completes = xgui.data.votemaps --Set concommand completes for the ulx votemap command. (Used by XGUI in the cmds tab)
|
||||
end
|
||||
|
||||
function maps.updateGamemodes()
|
||||
local lastselected = maps.gamemode:GetValue()
|
||||
maps.gamemode:Clear()
|
||||
maps.gamemode:SetText( lastselected )
|
||||
maps.gamemode:AddChoice( "<default>" )
|
||||
|
||||
-- Get allowed gamemodes
|
||||
local access, tag = LocalPlayer():query( "ulx map" )
|
||||
local restrictions = {}
|
||||
ULib.cmds.StringArg.processRestrictions( restrictions, ULib.cmds.translatedCmds['ulx map'].args[3], ulx.getTagArgNum( tag, 2 ) )
|
||||
|
||||
for _, v in ipairs( restrictions.restrictedCompletes ) do
|
||||
maps.gamemode:AddChoice( v )
|
||||
end
|
||||
end
|
||||
|
||||
function maps.updatePermissions()
|
||||
maps.vetomap:SetDisabled( true )
|
||||
RunConsoleCommand( "xgui", "getVetoState" ) --Get the proper enabled/disabled state of the veto button.
|
||||
maps.accessVotemap = ( GetConVarNumber( "ulx_votemapEnabled" ) == 1 )
|
||||
maps.accessVotemap2 = LocalPlayer():query( "ulx votemap2" )
|
||||
maps.accessMap = LocalPlayer():query( "ulx map" )
|
||||
maps.updateGamemodes()
|
||||
maps.updateVoteMaps()
|
||||
maps.updateButtonStates()
|
||||
end
|
||||
|
||||
function xgui.updateVetoButton( value )
|
||||
maps.vetomap:SetDisabled( not value )
|
||||
end
|
||||
|
||||
function maps.updateButtonStates()
|
||||
maps.gamemode:SetDisabled( not maps.accessMap )
|
||||
maps.list:SetMultiSelect( maps.accessVotemap2 )
|
||||
if maps.list:GetSelectedLine() then
|
||||
maps.vote:SetDisabled( maps.list:GetSelected()[1].isNotVotemap or not maps.accessVotemap )
|
||||
maps.svote:SetDisabled( not maps.accessVotemap2 )
|
||||
maps.changemap:SetDisabled( not maps.accessMap )
|
||||
else --No lines are selected
|
||||
maps.vote:SetDisabled( true )
|
||||
maps.svote:SetDisabled( true )
|
||||
maps.changemap:SetDisabled( true )
|
||||
maps.curmap:SetText( "No Map Selected" )
|
||||
maps.disp:SetMaterial( Material( "maps/thumb/noicon.png" ) )
|
||||
end
|
||||
end
|
||||
maps.updateVoteMaps() -- For autorefresh
|
||||
|
||||
--Enable/Disable the votemap button when ulx_votemapEnabled changes
|
||||
function maps.ConVarUpdated( sv_cvar, cl_cvar, ply, old_val, new_val )
|
||||
if cl_cvar == "ulx_votemapenabled" then
|
||||
maps.accessVotemap = ( tonumber( new_val ) == 1 )
|
||||
maps.updateButtonStates()
|
||||
end
|
||||
end
|
||||
hook.Add( "ULibReplicatedCvarChanged", "XGUI_mapsUpdateVotemapEnabled", maps.ConVarUpdated )
|
||||
|
||||
xgui.hookEvent( "onProcessModules", nil, maps.updatePermissions, "mapsUpdatePermissions" )
|
||||
xgui.hookEvent( "votemaps", "process", maps.updateVoteMaps, "mapsUpdateVotemaps" )
|
||||
xgui.addModule( "Maps", maps, "icon16/map.png" )
|
||||
|
@ -1,281 +1,281 @@
|
||||
--sv_bans -- by Stickly Man!
|
||||
--Server-side code related to the bans menu.
|
||||
|
||||
local bans={}
|
||||
function bans.init()
|
||||
ULib.ucl.registerAccess( "xgui_managebans", "superadmin", "Allows addition, removal, and viewing of bans in XGUI.", "XGUI" )
|
||||
|
||||
xgui.addDataType( "bans", function() return { count=table.Count( ULib.bans ) } end, "xgui_managebans", 30, 20 )
|
||||
|
||||
--Chat commands
|
||||
local function xgui_banWindowChat( ply, func, args, doFreeze )
|
||||
if doFreeze ~= true then doFreeze = false end
|
||||
if args[1] and args[1] ~= "" then
|
||||
local target = ULib.getUser( args[1] )
|
||||
if target then
|
||||
ULib.clientRPC( ply, "xgui.ShowBanWindow", target, target:SteamID(), doFreeze )
|
||||
end
|
||||
else
|
||||
ULib.clientRPC( ply, "xgui.ShowBanWindow" )
|
||||
end
|
||||
end
|
||||
ULib.addSayCommand( "!xban", xgui_banWindowChat, "ulx ban" )
|
||||
|
||||
local function xgui_banWindowChatFreeze( ply, func, args )
|
||||
xgui_banWindowChat( ply, func, args, true )
|
||||
end
|
||||
ULib.addSayCommand( "!fban", xgui_banWindowChatFreeze, "ulx ban" )
|
||||
|
||||
--XGUI commands
|
||||
function bans.updateBan( ply, args )
|
||||
local access, accessTag = ULib.ucl.query( ply, "ulx ban" )
|
||||
if not access then
|
||||
ULib.tsayError( ply, "Error editing ban: You must have access to ulx ban, " .. ply:Nick() .. "!", true )
|
||||
return
|
||||
end
|
||||
|
||||
local steamID = args[1]
|
||||
local bantime = tonumber( args[2] )
|
||||
local reason = args[3]
|
||||
local name = args[4]
|
||||
|
||||
|
||||
-- Check restrictions
|
||||
local cmd = ULib.cmds.translatedCmds[ "ulx ban" ]
|
||||
local accessPieces = {}
|
||||
if accessTag then
|
||||
accessPieces = ULib.splitArgs( accessTag, "<", ">" )
|
||||
end
|
||||
|
||||
-- Ban length
|
||||
local argInfo = cmd.args[3]
|
||||
local success, err = argInfo.type:parseAndValidate( ply, bantime, argInfo, accessPieces[2] )
|
||||
if not success then
|
||||
ULib.tsayError( ply, "Error editing ban: " .. err, true )
|
||||
return
|
||||
end
|
||||
|
||||
-- Reason
|
||||
local argInfo = cmd.args[4]
|
||||
local success, err = argInfo.type:parseAndValidate( ply, reason, argInfo, accessPieces[3] )
|
||||
if not success then
|
||||
ULib.tsayError( ply, "Error editing ban: You did not specify a valid reason, " .. ply:Nick() .. "!", true )
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
if not ULib.bans[steamID] then
|
||||
ULib.addBan( steamID, bantime, reason, name, ply )
|
||||
return
|
||||
end
|
||||
|
||||
if name == "" then
|
||||
name = nil
|
||||
ULib.bans[steamID].name = nil
|
||||
end
|
||||
|
||||
if bantime ~= 0 then
|
||||
if (ULib.bans[steamID].time + bantime*60) <= os.time() then --New ban time makes the ban expired
|
||||
ULib.unban( steamID, ply )
|
||||
return
|
||||
end
|
||||
bantime = bantime - (os.time() - ULib.bans[steamID].time)/60
|
||||
end
|
||||
ULib.addBan( steamID, bantime, reason, name, ply )
|
||||
end
|
||||
xgui.addCmd( "updateBan", bans.updateBan )
|
||||
|
||||
--Misc functions
|
||||
function bans.processBans()
|
||||
bans.clearSortCache()
|
||||
xgui.sendDataTable( {}, "bans" ) --Only sends the ban count, and triggers the client to clear their cache.
|
||||
end
|
||||
|
||||
function bans.clearSortCache()
|
||||
xgui.bansbyid = {}
|
||||
xgui.bansbyname = {}
|
||||
xgui.bansbyadmin = {}
|
||||
xgui.bansbyreason = {}
|
||||
xgui.bansbydate = {}
|
||||
xgui.bansbyunban = {}
|
||||
xgui.bansbybanlength = {}
|
||||
end
|
||||
|
||||
function bans.getSortTable( sortType )
|
||||
-- Retrieve the sorted table of bans. If type hasn't been sorted, then sort and cache.
|
||||
if sortType == 1 then
|
||||
-- Bans by Name
|
||||
if next( xgui.bansbyname ) == nil then
|
||||
for k, v in pairs( ULib.bans ) do
|
||||
table.insert( xgui.bansbyname, { k, v.name and string.upper( v.name ) or nil } )
|
||||
end
|
||||
table.sort( xgui.bansbyname, function( a, b ) return (a[2] or "\255" .. a[1]) < (b[2] or "\255" .. b[1]) end )
|
||||
end
|
||||
return xgui.bansbyname
|
||||
|
||||
elseif sortType == 2 then
|
||||
-- Bans by SteamID
|
||||
if next( xgui.bansbyid ) == nil then
|
||||
for k, v in pairs( ULib.bans ) do
|
||||
table.insert( xgui.bansbyid, { k } )
|
||||
end
|
||||
table.sort( xgui.bansbyid, function( a, b ) return a[1] < b[1] end )
|
||||
end
|
||||
return xgui.bansbyid
|
||||
|
||||
elseif sortType == 3 then
|
||||
-- Bans by Admin
|
||||
if next( xgui.bansbyadmin ) == nil then
|
||||
for k, v in pairs( ULib.bans ) do
|
||||
table.insert( xgui.bansbyadmin, { k, v.admin or "" } )
|
||||
end
|
||||
table.sort( xgui.bansbyadmin, function( a, b ) return a[2] < b[2] end )
|
||||
end
|
||||
return xgui.bansbyadmin
|
||||
|
||||
elseif sortType == 4 then
|
||||
-- Bans by Reason
|
||||
if next( xgui.bansbyreason ) == nil then
|
||||
for k, v in pairs( ULib.bans ) do
|
||||
table.insert( xgui.bansbyreason, { k, v.reason or "" } )
|
||||
end
|
||||
table.sort( xgui.bansbyreason, function( a, b ) return a[2] < b[2] end )
|
||||
end
|
||||
return xgui.bansbyreason
|
||||
|
||||
elseif sortType == 5 then
|
||||
-- Bans by Unban Date
|
||||
if next( xgui.bansbyunban ) == nil then
|
||||
for k, v in pairs( ULib.bans ) do
|
||||
table.insert( xgui.bansbyunban, { k, tonumber(v.unban) or 0 } )
|
||||
end
|
||||
table.sort( xgui.bansbyunban, function( a, b ) return a[2] < b[2] end )
|
||||
end
|
||||
return xgui.bansbyunban
|
||||
|
||||
elseif sortType == 6 then
|
||||
-- Bans by Ban Length
|
||||
if next( xgui.bansbybanlength ) == nil then
|
||||
for k, v in pairs( ULib.bans ) do
|
||||
table.insert( xgui.bansbybanlength, { k, (tonumber(v.unban) ~= 0) and (v.unban - v.time) or nil } )
|
||||
end
|
||||
table.sort( xgui.bansbybanlength, function( a, b ) return (a[2] or math.huge) < (b[2] or math.huge) end )
|
||||
end
|
||||
return xgui.bansbybanlength
|
||||
|
||||
else
|
||||
if next( xgui.bansbydate ) == nil then
|
||||
for k, v in pairs( ULib.bans ) do
|
||||
table.insert( xgui.bansbydate, { k, v.time or 0 } )
|
||||
end
|
||||
table.sort( xgui.bansbydate, function( a, b ) return tonumber( a[2] ) > tonumber( b[2] ) end )
|
||||
end
|
||||
return xgui.bansbydate
|
||||
end
|
||||
end
|
||||
|
||||
function bans.sendBansToUser( ply, args )
|
||||
if not ply then return end
|
||||
|
||||
if not ULib.ucl.query( ply, "xgui_managebans" ) then return end
|
||||
|
||||
--local perfTimer = os.clock() --Debug
|
||||
|
||||
-- Default params
|
||||
sortType = tonumber( args[1] ) or 0
|
||||
filterString = args[2] ~= "" and string.lower( args[2] ) or nil
|
||||
filterPermaBan = args[3] and tonumber( args[3] ) or 0
|
||||
filterIncomplete = args[4] and tonumber( args[4] ) or 0
|
||||
page = tonumber( args[5] ) or 1
|
||||
ascending = tonumber( args[6] ) == 1 or false
|
||||
|
||||
-- Get cached sort table to use to reference the real data.
|
||||
sortTable = bans.getSortTable( sortType )
|
||||
|
||||
local bansToSend = {}
|
||||
|
||||
-- Handle ascending or descending
|
||||
local startValue = ascending and #sortTable or 1
|
||||
local endValue = ascending and 1 or #sortTable
|
||||
local firstEntry = (page - 1) * 17
|
||||
local currentEntry = 0
|
||||
|
||||
local noFilter = ( filterPermaBan == 0 and filterIncomplete == 0 and filterString == nil )
|
||||
|
||||
for i = startValue, endValue, ascending and -1 or 1 do
|
||||
local steamID = sortTable[i][1]
|
||||
local bandata = ULib.bans[steamID]
|
||||
|
||||
-- Handle filters. This is confusing, but essentially 0 means skip check, 1 means restrict if condition IS true, 2+ means restrict if condition IS NOT true.
|
||||
if not ( filterPermaBan > 0 and ( ( tonumber( bandata.unban ) == 0 ) == ( filterPermaBan == 1 ) ) ) then
|
||||
if not ( filterIncomplete > 0 and ( ( bandata.time == nil ) == ( filterIncomplete == 1 ) ) ) then
|
||||
|
||||
-- Handle string filter
|
||||
if not ( filterString and
|
||||
not ( steamID and string.find( string.lower( steamID ), filterString ) or
|
||||
bandata.name and string.find( string.lower( bandata.name ), filterString ) or
|
||||
bandata.reason and string.find( string.lower( bandata.reason ), filterString ) or
|
||||
bandata.admin and string.find( string.lower( bandata.admin ), filterString ) or
|
||||
bandata.modified_admin and string.find( string.lower( bandata.modified_admin ), filterString ) )) then
|
||||
|
||||
--We found a valid one! .. Now for the pagination.
|
||||
if #bansToSend < 17 and currentEntry >= firstEntry then
|
||||
table.insert( bansToSend, bandata )
|
||||
bansToSend[#bansToSend].steamID = steamID
|
||||
if noFilter and #bansToSend >= 17 then break end -- If there is a filter, then don't stop the loop so we can get a "result" count.
|
||||
end
|
||||
currentEntry = currentEntry + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if not noFilter then bansToSend.count = currentEntry end
|
||||
|
||||
--print( "XGUI: Ban request took " .. os.clock() - perfTimer ) --Debug
|
||||
|
||||
-- Send bans to client via custom handling.
|
||||
xgui.sendDataEvent( ply, 7, "bans", bansToSend )
|
||||
end
|
||||
xgui.addCmd( "getbans", bans.sendBansToUser )
|
||||
|
||||
--Hijack the addBan function to update XGUI's ban info.
|
||||
local banfunc = ULib.addBan
|
||||
ULib.addBan = function( steamid, time, reason, name, admin )
|
||||
banfunc( steamid, time, reason, name, admin )
|
||||
bans.processBans()
|
||||
bans.unbanTimer()
|
||||
end
|
||||
|
||||
--Hijack the unBan function to update XGUI's ban info.
|
||||
local unbanfunc = ULib.unban
|
||||
ULib.unban = function( steamid, admin )
|
||||
unbanfunc( steamid, admin )
|
||||
bans.processBans()
|
||||
if timer.Exists( "xgui_unban" .. steamid ) then
|
||||
timer.Remove( "xgui_unban" .. steamid )
|
||||
end
|
||||
end
|
||||
|
||||
--Create timers that will automatically perform an unban when a users ban runs out. Polls hourly.
|
||||
function bans.unbanTimer()
|
||||
timer.Create( "xgui_unbanTimer", 3600, 0, bans.unbanTimer )
|
||||
for ID, data in pairs( ULib.bans ) do
|
||||
if tonumber( data.unban ) ~= 0 then
|
||||
if tonumber( data.unban ) - os.time() <= 3600 then
|
||||
timer.Remove( "xgui_unban" .. ID )
|
||||
timer.Create( "xgui_unban" .. ID, tonumber( data.unban ) - os.time(), 1, function() ULib.unban( ID ) end )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
ulx.addToHelpManually( "Menus", "xgui fban", "<player> - Opens the add ban window, freezes the specified player, and fills out the Name/SteamID automatically. (say: !fban)" )
|
||||
ulx.addToHelpManually( "Menus", "xgui xban", "<player> - Opens the add ban window and fills out Name/SteamID automatically if a player was specified. (say: !xban)" )
|
||||
end
|
||||
|
||||
function bans.postinit()
|
||||
bans.processBans()
|
||||
bans.unbanTimer()
|
||||
end
|
||||
|
||||
--sv_bans -- by Stickly Man!
|
||||
--Server-side code related to the bans menu.
|
||||
|
||||
local bans={}
|
||||
function bans.init()
|
||||
ULib.ucl.registerAccess( "xgui_managebans", "superadmin", "Allows addition, removal, and viewing of bans in XGUI.", "XGUI" )
|
||||
|
||||
xgui.addDataType( "bans", function() return { count=table.Count( ULib.bans ) } end, "xgui_managebans", 30, 20 )
|
||||
|
||||
--Chat commands
|
||||
local function xgui_banWindowChat( ply, func, args, doFreeze )
|
||||
if doFreeze ~= true then doFreeze = false end
|
||||
if args[1] and args[1] ~= "" then
|
||||
local target = ULib.getUser( args[1] )
|
||||
if target then
|
||||
ULib.clientRPC( ply, "xgui.ShowBanWindow", target, target:SteamID(), doFreeze )
|
||||
end
|
||||
else
|
||||
ULib.clientRPC( ply, "xgui.ShowBanWindow" )
|
||||
end
|
||||
end
|
||||
ULib.addSayCommand( "!xban", xgui_banWindowChat, "ulx ban" )
|
||||
|
||||
local function xgui_banWindowChatFreeze( ply, func, args )
|
||||
xgui_banWindowChat( ply, func, args, true )
|
||||
end
|
||||
ULib.addSayCommand( "!fban", xgui_banWindowChatFreeze, "ulx ban" )
|
||||
|
||||
--XGUI commands
|
||||
function bans.updateBan( ply, args )
|
||||
local access, accessTag = ULib.ucl.query( ply, "ulx ban" )
|
||||
if not access then
|
||||
ULib.tsayError( ply, "Error editing ban: You must have access to ulx ban, " .. ply:Nick() .. "!", true )
|
||||
return
|
||||
end
|
||||
|
||||
local steamID = args[1]
|
||||
local bantime = tonumber( args[2] )
|
||||
local reason = args[3]
|
||||
local name = args[4]
|
||||
|
||||
|
||||
-- Check restrictions
|
||||
local cmd = ULib.cmds.translatedCmds[ "ulx ban" ]
|
||||
local accessPieces = {}
|
||||
if accessTag then
|
||||
accessPieces = ULib.splitArgs( accessTag, "<", ">" )
|
||||
end
|
||||
|
||||
-- Ban length
|
||||
local argInfo = cmd.args[3]
|
||||
local success, err = argInfo.type:parseAndValidate( ply, bantime, argInfo, accessPieces[2] )
|
||||
if not success then
|
||||
ULib.tsayError( ply, "Error editing ban: " .. err, true )
|
||||
return
|
||||
end
|
||||
|
||||
-- Reason
|
||||
local argInfo = cmd.args[4]
|
||||
local success, err = argInfo.type:parseAndValidate( ply, reason, argInfo, accessPieces[3] )
|
||||
if not success then
|
||||
ULib.tsayError( ply, "Error editing ban: You did not specify a valid reason, " .. ply:Nick() .. "!", true )
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
if not ULib.bans[steamID] then
|
||||
ULib.addBan( steamID, bantime, reason, name, ply )
|
||||
return
|
||||
end
|
||||
|
||||
if name == "" then
|
||||
name = nil
|
||||
ULib.bans[steamID].name = nil
|
||||
end
|
||||
|
||||
if bantime ~= 0 then
|
||||
if (ULib.bans[steamID].time + bantime*60) <= os.time() then --New ban time makes the ban expired
|
||||
ULib.unban( steamID, ply )
|
||||
return
|
||||
end
|
||||
bantime = bantime - (os.time() - ULib.bans[steamID].time)/60
|
||||
end
|
||||
ULib.addBan( steamID, bantime, reason, name, ply )
|
||||
end
|
||||
xgui.addCmd( "updateBan", bans.updateBan )
|
||||
|
||||
--Misc functions
|
||||
function bans.processBans()
|
||||
bans.clearSortCache()
|
||||
xgui.sendDataTable( {}, "bans" ) --Only sends the ban count, and triggers the client to clear their cache.
|
||||
end
|
||||
|
||||
function bans.clearSortCache()
|
||||
xgui.bansbyid = {}
|
||||
xgui.bansbyname = {}
|
||||
xgui.bansbyadmin = {}
|
||||
xgui.bansbyreason = {}
|
||||
xgui.bansbydate = {}
|
||||
xgui.bansbyunban = {}
|
||||
xgui.bansbybanlength = {}
|
||||
end
|
||||
|
||||
function bans.getSortTable( sortType )
|
||||
-- Retrieve the sorted table of bans. If type hasn't been sorted, then sort and cache.
|
||||
if sortType == 1 then
|
||||
-- Bans by Name
|
||||
if next( xgui.bansbyname ) == nil then
|
||||
for k, v in pairs( ULib.bans ) do
|
||||
table.insert( xgui.bansbyname, { k, v.name and string.upper( v.name ) or nil } )
|
||||
end
|
||||
table.sort( xgui.bansbyname, function( a, b ) return (a[2] or "\255" .. a[1]) < (b[2] or "\255" .. b[1]) end )
|
||||
end
|
||||
return xgui.bansbyname
|
||||
|
||||
elseif sortType == 2 then
|
||||
-- Bans by SteamID
|
||||
if next( xgui.bansbyid ) == nil then
|
||||
for k, v in pairs( ULib.bans ) do
|
||||
table.insert( xgui.bansbyid, { k } )
|
||||
end
|
||||
table.sort( xgui.bansbyid, function( a, b ) return a[1] < b[1] end )
|
||||
end
|
||||
return xgui.bansbyid
|
||||
|
||||
elseif sortType == 3 then
|
||||
-- Bans by Admin
|
||||
if next( xgui.bansbyadmin ) == nil then
|
||||
for k, v in pairs( ULib.bans ) do
|
||||
table.insert( xgui.bansbyadmin, { k, v.admin or "" } )
|
||||
end
|
||||
table.sort( xgui.bansbyadmin, function( a, b ) return a[2] < b[2] end )
|
||||
end
|
||||
return xgui.bansbyadmin
|
||||
|
||||
elseif sortType == 4 then
|
||||
-- Bans by Reason
|
||||
if next( xgui.bansbyreason ) == nil then
|
||||
for k, v in pairs( ULib.bans ) do
|
||||
table.insert( xgui.bansbyreason, { k, v.reason or "" } )
|
||||
end
|
||||
table.sort( xgui.bansbyreason, function( a, b ) return a[2] < b[2] end )
|
||||
end
|
||||
return xgui.bansbyreason
|
||||
|
||||
elseif sortType == 5 then
|
||||
-- Bans by Unban Date
|
||||
if next( xgui.bansbyunban ) == nil then
|
||||
for k, v in pairs( ULib.bans ) do
|
||||
table.insert( xgui.bansbyunban, { k, tonumber(v.unban) or 0 } )
|
||||
end
|
||||
table.sort( xgui.bansbyunban, function( a, b ) return a[2] < b[2] end )
|
||||
end
|
||||
return xgui.bansbyunban
|
||||
|
||||
elseif sortType == 6 then
|
||||
-- Bans by Ban Length
|
||||
if next( xgui.bansbybanlength ) == nil then
|
||||
for k, v in pairs( ULib.bans ) do
|
||||
table.insert( xgui.bansbybanlength, { k, (tonumber(v.unban) ~= 0) and (v.unban - v.time) or nil } )
|
||||
end
|
||||
table.sort( xgui.bansbybanlength, function( a, b ) return (a[2] or math.huge) < (b[2] or math.huge) end )
|
||||
end
|
||||
return xgui.bansbybanlength
|
||||
|
||||
else
|
||||
if next( xgui.bansbydate ) == nil then
|
||||
for k, v in pairs( ULib.bans ) do
|
||||
table.insert( xgui.bansbydate, { k, v.time or 0 } )
|
||||
end
|
||||
table.sort( xgui.bansbydate, function( a, b ) return tonumber( a[2] ) > tonumber( b[2] ) end )
|
||||
end
|
||||
return xgui.bansbydate
|
||||
end
|
||||
end
|
||||
|
||||
function bans.sendBansToUser( ply, args )
|
||||
if not ply then return end
|
||||
|
||||
if not ULib.ucl.query( ply, "xgui_managebans" ) then return end
|
||||
|
||||
--local perfTimer = os.clock() --Debug
|
||||
|
||||
-- Default params
|
||||
sortType = tonumber( args[1] ) or 0
|
||||
filterString = args[2] ~= "" and string.lower( args[2] ) or nil
|
||||
filterPermaBan = args[3] and tonumber( args[3] ) or 0
|
||||
filterIncomplete = args[4] and tonumber( args[4] ) or 0
|
||||
page = tonumber( args[5] ) or 1
|
||||
ascending = tonumber( args[6] ) == 1 or false
|
||||
|
||||
-- Get cached sort table to use to reference the real data.
|
||||
sortTable = bans.getSortTable( sortType )
|
||||
|
||||
local bansToSend = {}
|
||||
|
||||
-- Handle ascending or descending
|
||||
local startValue = ascending and #sortTable or 1
|
||||
local endValue = ascending and 1 or #sortTable
|
||||
local firstEntry = (page - 1) * 17
|
||||
local currentEntry = 0
|
||||
|
||||
local noFilter = ( filterPermaBan == 0 and filterIncomplete == 0 and filterString == nil )
|
||||
|
||||
for i = startValue, endValue, ascending and -1 or 1 do
|
||||
local steamID = sortTable[i][1]
|
||||
local bandata = ULib.bans[steamID]
|
||||
|
||||
-- Handle filters. This is confusing, but essentially 0 means skip check, 1 means restrict if condition IS true, 2+ means restrict if condition IS NOT true.
|
||||
if not ( filterPermaBan > 0 and ( ( tonumber( bandata.unban ) == 0 ) == ( filterPermaBan == 1 ) ) ) then
|
||||
if not ( filterIncomplete > 0 and ( ( bandata.time == nil ) == ( filterIncomplete == 1 ) ) ) then
|
||||
|
||||
-- Handle string filter
|
||||
if not ( filterString and
|
||||
not ( steamID and string.find( string.lower( steamID ), filterString ) or
|
||||
bandata.name and string.find( string.lower( bandata.name ), filterString ) or
|
||||
bandata.reason and string.find( string.lower( bandata.reason ), filterString ) or
|
||||
bandata.admin and string.find( string.lower( bandata.admin ), filterString ) or
|
||||
bandata.modified_admin and string.find( string.lower( bandata.modified_admin ), filterString ) )) then
|
||||
|
||||
--We found a valid one! .. Now for the pagination.
|
||||
if #bansToSend < 17 and currentEntry >= firstEntry then
|
||||
table.insert( bansToSend, bandata )
|
||||
bansToSend[#bansToSend].steamID = steamID
|
||||
if noFilter and #bansToSend >= 17 then break end -- If there is a filter, then don't stop the loop so we can get a "result" count.
|
||||
end
|
||||
currentEntry = currentEntry + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if not noFilter then bansToSend.count = currentEntry end
|
||||
|
||||
--print( "XGUI: Ban request took " .. os.clock() - perfTimer ) --Debug
|
||||
|
||||
-- Send bans to client via custom handling.
|
||||
xgui.sendDataEvent( ply, 7, "bans", bansToSend )
|
||||
end
|
||||
xgui.addCmd( "getbans", bans.sendBansToUser )
|
||||
|
||||
--Hijack the addBan function to update XGUI's ban info.
|
||||
local banfunc = ULib.addBan
|
||||
ULib.addBan = function( steamid, time, reason, name, admin )
|
||||
banfunc( steamid, time, reason, name, admin )
|
||||
bans.processBans()
|
||||
bans.unbanTimer()
|
||||
end
|
||||
|
||||
--Hijack the unBan function to update XGUI's ban info.
|
||||
local unbanfunc = ULib.unban
|
||||
ULib.unban = function( steamid, admin )
|
||||
unbanfunc( steamid, admin )
|
||||
bans.processBans()
|
||||
if timer.Exists( "xgui_unban" .. steamid ) then
|
||||
timer.Remove( "xgui_unban" .. steamid )
|
||||
end
|
||||
end
|
||||
|
||||
--Create timers that will automatically perform an unban when a users ban runs out. Polls hourly.
|
||||
function bans.unbanTimer()
|
||||
timer.Create( "xgui_unbanTimer", 3600, 0, bans.unbanTimer )
|
||||
for ID, data in pairs( ULib.bans ) do
|
||||
if tonumber( data.unban ) ~= 0 then
|
||||
if tonumber( data.unban ) - os.time() <= 3600 then
|
||||
timer.Remove( "xgui_unban" .. ID )
|
||||
timer.Create( "xgui_unban" .. ID, tonumber( data.unban ) - os.time(), 1, function() ULib.unban( ID ) end )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
ulx.addToHelpManually( "Menus", "xgui fban", "<player> - Opens the add ban window, freezes the specified player, and fills out the Name/SteamID automatically. (say: !fban)" )
|
||||
ulx.addToHelpManually( "Menus", "xgui xban", "<player> - Opens the add ban window and fills out Name/SteamID automatically if a player was specified. (say: !xban)" )
|
||||
end
|
||||
|
||||
function bans.postinit()
|
||||
bans.processBans()
|
||||
bans.unbanTimer()
|
||||
end
|
||||
|
||||
xgui.addSVModule( "bans", bans.init, bans.postinit )
|
@ -1,340 +1,340 @@
|
||||
--sv_groups -- by Stickly Man!
|
||||
--Server-side code related to the groups menu.
|
||||
|
||||
local groups = {}
|
||||
function groups.init()
|
||||
ULib.ucl.registerAccess( "xgui_managegroups", "superadmin", "Allows managing of groups, users, and access strings via the groups tab in XGUI.", "XGUI" )
|
||||
|
||||
xgui.addDataType( "playermodels", player_manager.AllValidModels, "xgui_managegroups", 0, 10 )
|
||||
xgui.addDataType( "teams", function() return xgui.teams end, "xgui_managegroups", 0, -20 )
|
||||
xgui.addDataType( "accesses", function() return xgui.accesses end, "xgui_managegroups", 0, 5 )
|
||||
xgui.addDataType( "users", function()
|
||||
local temp = groups.garryUsers
|
||||
table.Merge( temp, ULib.ucl.users )
|
||||
return temp
|
||||
end, "xgui_managegroups", 20, -10 )
|
||||
|
||||
function groups.setInheritance( ply, args )
|
||||
if ULib.ucl.query( ply, "ulx addgroup" ) then
|
||||
--Check for cycles
|
||||
local group = ULib.ucl.groupInheritsFrom( args[2] )
|
||||
while group do
|
||||
if group == args[1] or args[1] == args[2] then
|
||||
ULib.clientRPC( ply, "Derma_Message", "Cannot set inheritance! You cannot inherit from something you're inheriting to!", "XGUI NOTICE" )
|
||||
return
|
||||
end
|
||||
group = ULib.ucl.groupInheritsFrom( group )
|
||||
end
|
||||
ULib.ucl.setGroupInheritance( args[1], args[2] )
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "setinheritance", groups.setInheritance )
|
||||
|
||||
function xgui.playerExistsByID( id )
|
||||
for k, v in pairs( player.GetAll() ) do
|
||||
if v:SteamID() == id or v:UniqueID() == id or ULib.splitPort( v:IPAddress() ) == id then
|
||||
return v
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--Override adduser to (re)send the new user info to the players.
|
||||
local tempfuncadd = ULib.ucl.addUser
|
||||
ULib.ucl.addUser = function( id, allows, denies, group )
|
||||
local affectedply = xgui.playerExistsByID( id )
|
||||
if affectedply then groups.resetAllPlayerValues( affectedply ) end
|
||||
tempfuncadd( id, allows, denies, group )
|
||||
local temp = {}
|
||||
temp[id] = ULib.ucl.users[id]
|
||||
xgui.updateData( {}, "users", temp )
|
||||
end
|
||||
|
||||
--Override removeuser to resend the users table to the players.
|
||||
local tempfuncremove = ULib.ucl.removeUser
|
||||
ULib.ucl.removeUser = function( id )
|
||||
xgui.removeData( {}, "users", { id } )
|
||||
local affectedply = xgui.playerExistsByID( id )
|
||||
if affectedply then groups.resetAllPlayerValues( affectedply ) end
|
||||
tempfuncremove( id )
|
||||
end
|
||||
|
||||
---------------------------
|
||||
--UTeam Integration Stuff--
|
||||
---------------------------
|
||||
function groups.createTeam( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_managegroups" ) then
|
||||
--Check and make sure the team doesn't exist first
|
||||
local exists = false
|
||||
for i, v in ipairs( xgui.teams ) do
|
||||
if v.name == args[1] then
|
||||
exists = true
|
||||
end
|
||||
end
|
||||
if not exists then
|
||||
local team = {}
|
||||
team.name = args[1]
|
||||
team.color = Color( args[2], args[3], args[4], 255 )
|
||||
team.order = #xgui.teams+1
|
||||
team.groups = {}
|
||||
table.insert( xgui.teams, team )
|
||||
groups.refreshTeams()
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "createTeam", groups.createTeam )
|
||||
|
||||
function groups.removeTeam( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_managegroups" ) then
|
||||
for i, v in ipairs( xgui.teams ) do
|
||||
if v.name == args[1] then
|
||||
for _,group in ipairs( v.groups ) do --Unassign groups in team being deleted
|
||||
groups.doChangeGroupTeam( group, "" )
|
||||
end
|
||||
table.remove( xgui.teams, i )
|
||||
groups.setTeamsOrder()
|
||||
groups.refreshTeams()
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "removeTeam", groups.removeTeam )
|
||||
|
||||
function groups.changeGroupTeam( ply, args, norefresh )
|
||||
if ULib.ucl.query( ply, "xgui_managegroups" ) then
|
||||
groups.doChangeGroupTeam( args[1], args[2], norefresh )
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "changeGroupTeam", groups.changeGroupTeam )
|
||||
|
||||
function groups.doChangeGroupTeam( group, newteam, norefresh )
|
||||
local resettable = {}
|
||||
for _,teamdata in ipairs( xgui.teams ) do
|
||||
for i,groupname in ipairs( teamdata.groups ) do
|
||||
if group == groupname then --Found the previous team the group belonged to, remove it now!
|
||||
table.remove( teamdata.groups, i )
|
||||
--Grab old modifier info while we're here
|
||||
for modifier, _ in pairs( teamdata ) do
|
||||
if modifier ~= "order" and modifier ~= "index" and modifier ~= "groups" and modifier ~= "name" and modifier ~= "color" then
|
||||
table.insert( resettable, modifier )
|
||||
end
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
if teamdata.name == newteam then --If the team requested was found, then add it to the new team.
|
||||
table.insert( teamdata.groups, group )
|
||||
end
|
||||
end
|
||||
--Reset modifiers for affected players, then let UTeam set the new modifiers
|
||||
groups.resetTeamValue( group, resettable, newteam=="" ) --Let the function know if the new team is unassigned
|
||||
if not norefresh then groups.refreshTeams() end
|
||||
end
|
||||
|
||||
--UTeam Parameters: If values are a table, then it specifies default, min, then max. Otherwise it just specifies a min.
|
||||
--Note that the min/max values here are ABSOLUTE values, meaning values outside of this range will probably cause undesirable results.
|
||||
xgui.teamDefaults = {
|
||||
armor = { 0, 0, 255 },
|
||||
--crouchedWalkSpeed = 0.6, --Pointless setting?
|
||||
deaths = { 0, -2048, 2047 },
|
||||
duckSpeed = 0.3,
|
||||
frags = { 0, -2048, 2047 },
|
||||
gravity = 1,
|
||||
health = { 100, 1, 2.14748e+009 },
|
||||
jumpPower = 200,
|
||||
maxHealth = 100,
|
||||
--maxSpeed = 250, --Pointless setting?
|
||||
model = "scientist",
|
||||
runSpeed = { 500, 1, nil },
|
||||
stepSize = { 18, 0, 512 },
|
||||
unDuckSpeed = 0.2,
|
||||
walkSpeed = { 250, 1, nil } }
|
||||
|
||||
function groups.updateTeamValue( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_managegroups" ) then
|
||||
local modifier = args[2]
|
||||
local value = tonumber( args[3] ) or args[3] --If args[3] is a number, set value as a number.
|
||||
for k, v in ipairs( xgui.teams ) do
|
||||
if v.name == args[1] then
|
||||
if modifier == "color" then
|
||||
v.color = { r=tonumber(args[3]), g=tonumber(args[4]), b=tonumber(args[5]), a=255 }
|
||||
else
|
||||
if value ~= "" then
|
||||
--Check for out-of-bound values!
|
||||
local def = xgui.teamDefaults[modifier]
|
||||
if type(def) == "table" then
|
||||
if def[2] and value < def[2] then value = def[2] end
|
||||
if def[3] and value > def[3] then value = def[3] end
|
||||
end
|
||||
v[modifier] = value
|
||||
else
|
||||
v[modifier] = nil
|
||||
--Set the players back to the original value
|
||||
for _, group in ipairs( v.groups ) do
|
||||
groups.resetTeamValue( group, { args[2] } )
|
||||
end
|
||||
end
|
||||
end
|
||||
--Check for order updates, only refresh the teams when args[4] flag is set to prevent multiple data sendings
|
||||
if v[modifier] ~= "order" or args[4] == "true" then
|
||||
groups.refreshTeams()
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "updateTeamValue", groups.updateTeamValue )
|
||||
|
||||
function groups.refreshTeams()
|
||||
if not ULib.isSandbox() then return end --Do not perform any of the following code if UTeam is disabled.
|
||||
|
||||
ulx.teams = table.Copy( xgui.teams )
|
||||
ulx.saveTeams() --Let ULX reprocess the teams (Empty/new teams would be lost here)
|
||||
ulx.refreshTeams()
|
||||
table.sort( xgui.teams, function(a, b) return a.order < b.order end ) --Sort table by order.
|
||||
|
||||
xgui.sendDataTable( {}, "teams" )
|
||||
hook.Call( ULib.HOOK_UCLCHANGED )
|
||||
|
||||
--Save any teams that don't have a group assigned to it to a special file. (They'll be removed on changelevel if we don't)
|
||||
local emptyteams = {}
|
||||
for _, teamdata in ipairs( xgui.teams ) do
|
||||
if #teamdata.groups == 0 then
|
||||
table.insert( emptyteams, teamdata )
|
||||
end
|
||||
end
|
||||
if #emptyteams > 0 then
|
||||
local output = "//This file stores teams that do not have any groups assigned to it (Since ULX would discard them). Do not edit this file!\n"
|
||||
output = output .. ULib.makeKeyValues( emptyteams )
|
||||
ULib.fileWrite( "data/ulx/empty_teams.txt", output )
|
||||
else
|
||||
if ULib.fileExists( "data/ulx/empty_teams.txt" ) then
|
||||
ULib.fileDelete( "data/ulx/empty_teams.txt" )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function groups.resetPlayerValue( ply, values )
|
||||
for _, modifier in ipairs( values ) do
|
||||
--Code from UTeam
|
||||
local defaultvalue = xgui.teamDefaults[modifier]
|
||||
if type( defaultvalue ) == "table" then defaultvalue = xgui.teamDefaults[modifier][1] end
|
||||
ply[ "Set" .. modifier:sub( 1, 1 ):upper() .. modifier:sub( 2 ) ]( ply, defaultvalue )
|
||||
end
|
||||
end
|
||||
|
||||
--This function will locate all players affected by team modifier(s) being unset (or team being changed)
|
||||
--and will reset any related modifiers to their defaults.
|
||||
function groups.resetTeamValue( group, values, teamIsUnassigned )
|
||||
for _, ply in ipairs( player.GetAll() ) do
|
||||
if ply:GetUserGroup() == group then
|
||||
groups.resetPlayerValue( ply, values )
|
||||
if teamIsUnassigned then ply:SetTeam(1001) end --Force the player to the unassigned team
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Remove all UTeam values from a player (used when they change teams)
|
||||
function groups.resetAllPlayerValues( ply )
|
||||
for _, team in ipairs( ulx.teams ) do --Loop through each team
|
||||
for _, group in ipairs( team.groups ) do --Loop through each group per team
|
||||
if group == ply:GetUserGroup() then --Have we found our team associated with this players group?
|
||||
local resettable = {}
|
||||
for modifier, _ in pairs( team ) do --Good! Now go reset the UTeam params based on the current team.
|
||||
if modifier ~= "order" and modifier ~= "index" and modifier ~= "groups" and modifier ~= "name" and modifier ~= "color" then
|
||||
table.insert( resettable, modifier )
|
||||
end
|
||||
end
|
||||
groups.resetPlayerValue( ply, resettable )
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Check and make sure the teams have a specified order
|
||||
function groups.setTeamsOrder()
|
||||
for i, v in ipairs( xgui.teams ) do
|
||||
v.order = i --Assign based on their index, which should be in order set by the file
|
||||
end
|
||||
end
|
||||
|
||||
--Hijack the renameGroup and removeGroup ULib functions to properly update team information when these are called.
|
||||
local tempfunc = ULib.ucl.renameGroup
|
||||
ULib.ucl.renameGroup = function( orig, new )
|
||||
for _, teamdata in ipairs( xgui.teams ) do
|
||||
for i, groupname in ipairs( teamdata.groups ) do
|
||||
if groupname == orig then
|
||||
teamdata.groups[i] = new
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
tempfunc( orig, new )
|
||||
groups.refreshTeams()
|
||||
end
|
||||
|
||||
local otherfunc = ULib.ucl.removeGroup
|
||||
ULib.ucl.removeGroup = function( name )
|
||||
groups.doChangeGroupTeam( name, "", true )
|
||||
otherfunc( name )
|
||||
groups.refreshTeams()
|
||||
xgui.sendDataTable( {}, "users" ) --Resend user information in case users were bumped to another group.
|
||||
end
|
||||
end
|
||||
|
||||
function groups.postinit()
|
||||
--Get user information from Garry's users.txt
|
||||
groups.garryUsers = {}
|
||||
if ULib.fileExists( "settings/users.txt" ) then
|
||||
for group, users in pairs ( util.KeyValuesToTable( ULib.fileRead( "settings/users.txt", true ) ) ) do
|
||||
for user, steamID in pairs( users ) do
|
||||
groups.garryUsers[steamID] = { name=user, group=group }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Combine access data into one table.
|
||||
xgui.accesses = {}
|
||||
for k, v in pairs( ULib.ucl.accessStrings ) do
|
||||
xgui.accesses[k] = {}
|
||||
xgui.accesses[k].hStr = v
|
||||
end
|
||||
for k, v in pairs( ULib.ucl.accessCategories ) do
|
||||
xgui.accesses[k].cat = v
|
||||
end
|
||||
|
||||
---------------------------
|
||||
--UTeam Integration Stuff--
|
||||
---------------------------
|
||||
--Duplicate ULX's UTeam table (required for how Megiddo stores team data within the groups data)
|
||||
xgui.teams = table.Copy( ulx.teams )
|
||||
|
||||
--Load empty teams saved by XGUI (if any)
|
||||
if ULib.fileExists( "data/ulx/empty_teams.txt" ) then
|
||||
local input = ULib.fileRead( "data/ulx/empty_teams.txt" )
|
||||
input = input:match( "^.-\n(.*)$" )
|
||||
local emptyteams = ULib.parseKeyValues( input )
|
||||
for _, teamdata in ipairs( emptyteams ) do
|
||||
for k,v in pairs( teamdata ) do
|
||||
teamdata[k] = tonumber( teamdata[k] ) or teamdata[k] --Ensure any number values are read as numbers and not strings
|
||||
end
|
||||
table.insert( xgui.teams, teamdata.order, teamdata )
|
||||
end
|
||||
end
|
||||
|
||||
groups.setTeamsOrder()
|
||||
|
||||
--Uteam doesn't load the shortname for playermodels, so to make it easier for the GUI, check for model paths and see if we can use a shortname instead.
|
||||
for _, v in ipairs( xgui.teams ) do
|
||||
if v.model then
|
||||
for shortname,modelpath in pairs( player_manager.AllValidModels() ) do
|
||||
if v.model == modelpath then v.model = shortname break end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
xgui.addSVModule( "groups", groups.init, groups.postinit )
|
||||
--sv_groups -- by Stickly Man!
|
||||
--Server-side code related to the groups menu.
|
||||
|
||||
local groups = {}
|
||||
function groups.init()
|
||||
ULib.ucl.registerAccess( "xgui_managegroups", "superadmin", "Allows managing of groups, users, and access strings via the groups tab in XGUI.", "XGUI" )
|
||||
|
||||
xgui.addDataType( "playermodels", player_manager.AllValidModels, "xgui_managegroups", 0, 10 )
|
||||
xgui.addDataType( "teams", function() return xgui.teams end, "xgui_managegroups", 0, -20 )
|
||||
xgui.addDataType( "accesses", function() return xgui.accesses end, "xgui_managegroups", 0, 5 )
|
||||
xgui.addDataType( "users", function()
|
||||
local temp = groups.garryUsers
|
||||
table.Merge( temp, ULib.ucl.users )
|
||||
return temp
|
||||
end, "xgui_managegroups", 20, -10 )
|
||||
|
||||
function groups.setInheritance( ply, args )
|
||||
if ULib.ucl.query( ply, "ulx addgroup" ) then
|
||||
--Check for cycles
|
||||
local group = ULib.ucl.groupInheritsFrom( args[2] )
|
||||
while group do
|
||||
if group == args[1] or args[1] == args[2] then
|
||||
ULib.clientRPC( ply, "Derma_Message", "Cannot set inheritance! You cannot inherit from something you're inheriting to!", "XGUI NOTICE" )
|
||||
return
|
||||
end
|
||||
group = ULib.ucl.groupInheritsFrom( group )
|
||||
end
|
||||
ULib.ucl.setGroupInheritance( args[1], args[2] )
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "setinheritance", groups.setInheritance )
|
||||
|
||||
function xgui.playerExistsByID( id )
|
||||
for k, v in pairs( player.GetAll() ) do
|
||||
if v:SteamID() == id or v:UniqueID() == id or ULib.splitPort( v:IPAddress() ) == id then
|
||||
return v
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--Override adduser to (re)send the new user info to the players.
|
||||
local tempfuncadd = ULib.ucl.addUser
|
||||
ULib.ucl.addUser = function( id, allows, denies, group )
|
||||
local affectedply = xgui.playerExistsByID( id )
|
||||
if affectedply then groups.resetAllPlayerValues( affectedply ) end
|
||||
tempfuncadd( id, allows, denies, group )
|
||||
local temp = {}
|
||||
temp[id] = ULib.ucl.users[id]
|
||||
xgui.updateData( {}, "users", temp )
|
||||
end
|
||||
|
||||
--Override removeuser to resend the users table to the players.
|
||||
local tempfuncremove = ULib.ucl.removeUser
|
||||
ULib.ucl.removeUser = function( id )
|
||||
xgui.removeData( {}, "users", { id } )
|
||||
local affectedply = xgui.playerExistsByID( id )
|
||||
if affectedply then groups.resetAllPlayerValues( affectedply ) end
|
||||
tempfuncremove( id )
|
||||
end
|
||||
|
||||
---------------------------
|
||||
--UTeam Integration Stuff--
|
||||
---------------------------
|
||||
function groups.createTeam( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_managegroups" ) then
|
||||
--Check and make sure the team doesn't exist first
|
||||
local exists = false
|
||||
for i, v in ipairs( xgui.teams ) do
|
||||
if v.name == args[1] then
|
||||
exists = true
|
||||
end
|
||||
end
|
||||
if not exists then
|
||||
local team = {}
|
||||
team.name = args[1]
|
||||
team.color = Color( args[2], args[3], args[4], 255 )
|
||||
team.order = #xgui.teams+1
|
||||
team.groups = {}
|
||||
table.insert( xgui.teams, team )
|
||||
groups.refreshTeams()
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "createTeam", groups.createTeam )
|
||||
|
||||
function groups.removeTeam( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_managegroups" ) then
|
||||
for i, v in ipairs( xgui.teams ) do
|
||||
if v.name == args[1] then
|
||||
for _,group in ipairs( v.groups ) do --Unassign groups in team being deleted
|
||||
groups.doChangeGroupTeam( group, "" )
|
||||
end
|
||||
table.remove( xgui.teams, i )
|
||||
groups.setTeamsOrder()
|
||||
groups.refreshTeams()
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "removeTeam", groups.removeTeam )
|
||||
|
||||
function groups.changeGroupTeam( ply, args, norefresh )
|
||||
if ULib.ucl.query( ply, "xgui_managegroups" ) then
|
||||
groups.doChangeGroupTeam( args[1], args[2], norefresh )
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "changeGroupTeam", groups.changeGroupTeam )
|
||||
|
||||
function groups.doChangeGroupTeam( group, newteam, norefresh )
|
||||
local resettable = {}
|
||||
for _,teamdata in ipairs( xgui.teams ) do
|
||||
for i,groupname in ipairs( teamdata.groups ) do
|
||||
if group == groupname then --Found the previous team the group belonged to, remove it now!
|
||||
table.remove( teamdata.groups, i )
|
||||
--Grab old modifier info while we're here
|
||||
for modifier, _ in pairs( teamdata ) do
|
||||
if modifier ~= "order" and modifier ~= "index" and modifier ~= "groups" and modifier ~= "name" and modifier ~= "color" then
|
||||
table.insert( resettable, modifier )
|
||||
end
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
if teamdata.name == newteam then --If the team requested was found, then add it to the new team.
|
||||
table.insert( teamdata.groups, group )
|
||||
end
|
||||
end
|
||||
--Reset modifiers for affected players, then let UTeam set the new modifiers
|
||||
groups.resetTeamValue( group, resettable, newteam=="" ) --Let the function know if the new team is unassigned
|
||||
if not norefresh then groups.refreshTeams() end
|
||||
end
|
||||
|
||||
--UTeam Parameters: If values are a table, then it specifies default, min, then max. Otherwise it just specifies a min.
|
||||
--Note that the min/max values here are ABSOLUTE values, meaning values outside of this range will probably cause undesirable results.
|
||||
xgui.teamDefaults = {
|
||||
armor = { 0, 0, 255 },
|
||||
--crouchedWalkSpeed = 0.6, --Pointless setting?
|
||||
deaths = { 0, -2048, 2047 },
|
||||
duckSpeed = 0.3,
|
||||
frags = { 0, -2048, 2047 },
|
||||
gravity = 1,
|
||||
health = { 100, 1, 2.14748e+009 },
|
||||
jumpPower = 200,
|
||||
maxHealth = 100,
|
||||
--maxSpeed = 250, --Pointless setting?
|
||||
model = "scientist",
|
||||
runSpeed = { 500, 1, nil },
|
||||
stepSize = { 18, 0, 512 },
|
||||
unDuckSpeed = 0.2,
|
||||
walkSpeed = { 250, 1, nil } }
|
||||
|
||||
function groups.updateTeamValue( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_managegroups" ) then
|
||||
local modifier = args[2]
|
||||
local value = tonumber( args[3] ) or args[3] --If args[3] is a number, set value as a number.
|
||||
for k, v in ipairs( xgui.teams ) do
|
||||
if v.name == args[1] then
|
||||
if modifier == "color" then
|
||||
v.color = { r=tonumber(args[3]), g=tonumber(args[4]), b=tonumber(args[5]), a=255 }
|
||||
else
|
||||
if value ~= "" then
|
||||
--Check for out-of-bound values!
|
||||
local def = xgui.teamDefaults[modifier]
|
||||
if type(def) == "table" then
|
||||
if def[2] and value < def[2] then value = def[2] end
|
||||
if def[3] and value > def[3] then value = def[3] end
|
||||
end
|
||||
v[modifier] = value
|
||||
else
|
||||
v[modifier] = nil
|
||||
--Set the players back to the original value
|
||||
for _, group in ipairs( v.groups ) do
|
||||
groups.resetTeamValue( group, { args[2] } )
|
||||
end
|
||||
end
|
||||
end
|
||||
--Check for order updates, only refresh the teams when args[4] flag is set to prevent multiple data sendings
|
||||
if v[modifier] ~= "order" or args[4] == "true" then
|
||||
groups.refreshTeams()
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "updateTeamValue", groups.updateTeamValue )
|
||||
|
||||
function groups.refreshTeams()
|
||||
if not ULib.isSandbox() then return end --Do not perform any of the following code if UTeam is disabled.
|
||||
|
||||
ulx.teams = table.Copy( xgui.teams )
|
||||
ulx.saveTeams() --Let ULX reprocess the teams (Empty/new teams would be lost here)
|
||||
ulx.refreshTeams()
|
||||
table.sort( xgui.teams, function(a, b) return a.order < b.order end ) --Sort table by order.
|
||||
|
||||
xgui.sendDataTable( {}, "teams" )
|
||||
hook.Call( ULib.HOOK_UCLCHANGED )
|
||||
|
||||
--Save any teams that don't have a group assigned to it to a special file. (They'll be removed on changelevel if we don't)
|
||||
local emptyteams = {}
|
||||
for _, teamdata in ipairs( xgui.teams ) do
|
||||
if #teamdata.groups == 0 then
|
||||
table.insert( emptyteams, teamdata )
|
||||
end
|
||||
end
|
||||
if #emptyteams > 0 then
|
||||
local output = "//This file stores teams that do not have any groups assigned to it (Since ULX would discard them). Do not edit this file!\n"
|
||||
output = output .. ULib.makeKeyValues( emptyteams )
|
||||
ULib.fileWrite( "data/ulx/empty_teams.txt", output )
|
||||
else
|
||||
if ULib.fileExists( "data/ulx/empty_teams.txt" ) then
|
||||
ULib.fileDelete( "data/ulx/empty_teams.txt" )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function groups.resetPlayerValue( ply, values )
|
||||
for _, modifier in ipairs( values ) do
|
||||
--Code from UTeam
|
||||
local defaultvalue = xgui.teamDefaults[modifier]
|
||||
if type( defaultvalue ) == "table" then defaultvalue = xgui.teamDefaults[modifier][1] end
|
||||
ply[ "Set" .. modifier:sub( 1, 1 ):upper() .. modifier:sub( 2 ) ]( ply, defaultvalue )
|
||||
end
|
||||
end
|
||||
|
||||
--This function will locate all players affected by team modifier(s) being unset (or team being changed)
|
||||
--and will reset any related modifiers to their defaults.
|
||||
function groups.resetTeamValue( group, values, teamIsUnassigned )
|
||||
for _, ply in ipairs( player.GetAll() ) do
|
||||
if ply:GetUserGroup() == group then
|
||||
groups.resetPlayerValue( ply, values )
|
||||
if teamIsUnassigned then ply:SetTeam(1001) end --Force the player to the unassigned team
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Remove all UTeam values from a player (used when they change teams)
|
||||
function groups.resetAllPlayerValues( ply )
|
||||
for _, team in ipairs( ulx.teams ) do --Loop through each team
|
||||
for _, group in ipairs( team.groups ) do --Loop through each group per team
|
||||
if group == ply:GetUserGroup() then --Have we found our team associated with this players group?
|
||||
local resettable = {}
|
||||
for modifier, _ in pairs( team ) do --Good! Now go reset the UTeam params based on the current team.
|
||||
if modifier ~= "order" and modifier ~= "index" and modifier ~= "groups" and modifier ~= "name" and modifier ~= "color" then
|
||||
table.insert( resettable, modifier )
|
||||
end
|
||||
end
|
||||
groups.resetPlayerValue( ply, resettable )
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Check and make sure the teams have a specified order
|
||||
function groups.setTeamsOrder()
|
||||
for i, v in ipairs( xgui.teams ) do
|
||||
v.order = i --Assign based on their index, which should be in order set by the file
|
||||
end
|
||||
end
|
||||
|
||||
--Hijack the renameGroup and removeGroup ULib functions to properly update team information when these are called.
|
||||
local tempfunc = ULib.ucl.renameGroup
|
||||
ULib.ucl.renameGroup = function( orig, new )
|
||||
for _, teamdata in ipairs( xgui.teams ) do
|
||||
for i, groupname in ipairs( teamdata.groups ) do
|
||||
if groupname == orig then
|
||||
teamdata.groups[i] = new
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
tempfunc( orig, new )
|
||||
groups.refreshTeams()
|
||||
end
|
||||
|
||||
local otherfunc = ULib.ucl.removeGroup
|
||||
ULib.ucl.removeGroup = function( name )
|
||||
groups.doChangeGroupTeam( name, "", true )
|
||||
otherfunc( name )
|
||||
groups.refreshTeams()
|
||||
xgui.sendDataTable( {}, "users" ) --Resend user information in case users were bumped to another group.
|
||||
end
|
||||
end
|
||||
|
||||
function groups.postinit()
|
||||
--Get user information from Garry's users.txt
|
||||
groups.garryUsers = {}
|
||||
if ULib.fileExists( "settings/users.txt" ) then
|
||||
for group, users in pairs ( util.KeyValuesToTable( ULib.fileRead( "settings/users.txt", true ) ) ) do
|
||||
for user, steamID in pairs( users ) do
|
||||
groups.garryUsers[steamID] = { name=user, group=group }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Combine access data into one table.
|
||||
xgui.accesses = {}
|
||||
for k, v in pairs( ULib.ucl.accessStrings ) do
|
||||
xgui.accesses[k] = {}
|
||||
xgui.accesses[k].hStr = v
|
||||
end
|
||||
for k, v in pairs( ULib.ucl.accessCategories ) do
|
||||
xgui.accesses[k].cat = v
|
||||
end
|
||||
|
||||
---------------------------
|
||||
--UTeam Integration Stuff--
|
||||
---------------------------
|
||||
--Duplicate ULX's UTeam table (required for how Megiddo stores team data within the groups data)
|
||||
xgui.teams = table.Copy( ulx.teams )
|
||||
|
||||
--Load empty teams saved by XGUI (if any)
|
||||
if ULib.fileExists( "data/ulx/empty_teams.txt" ) then
|
||||
local input = ULib.fileRead( "data/ulx/empty_teams.txt" )
|
||||
input = input:match( "^.-\n(.*)$" )
|
||||
local emptyteams = ULib.parseKeyValues( input )
|
||||
for _, teamdata in ipairs( emptyteams ) do
|
||||
for k,v in pairs( teamdata ) do
|
||||
teamdata[k] = tonumber( teamdata[k] ) or teamdata[k] --Ensure any number values are read as numbers and not strings
|
||||
end
|
||||
table.insert( xgui.teams, teamdata.order, teamdata )
|
||||
end
|
||||
end
|
||||
|
||||
groups.setTeamsOrder()
|
||||
|
||||
--Uteam doesn't load the shortname for playermodels, so to make it easier for the GUI, check for model paths and see if we can use a shortname instead.
|
||||
for _, v in ipairs( xgui.teams ) do
|
||||
if v.model then
|
||||
for shortname,modelpath in pairs( player_manager.AllValidModels() ) do
|
||||
if v.model == modelpath then v.model = shortname break end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
xgui.addSVModule( "groups", groups.init, groups.postinit )
|
||||
|
@ -1,21 +1,21 @@
|
||||
--sv_maps -- by Stickly Man!
|
||||
--Server-side code related to the maps menu.
|
||||
|
||||
local function init()
|
||||
ULib.replicatedWritableCvar( "nextlevel", "rep_nextlevel", GetConVarString( "sbox_godmode" ), false, false, "ulx map" )
|
||||
|
||||
local function getVetoState( ply, args )
|
||||
if ULib.ucl.query( ply, "ulx veto" ) then
|
||||
ULib.clientRPC( ply, "xgui.updateVetoButton", ulx.timedVeto )
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "getVetoState", getVetoState )
|
||||
|
||||
local function updateVetoState()
|
||||
for _, v in ipairs( player.GetAll() ) do
|
||||
getVetoState( v )
|
||||
end
|
||||
end
|
||||
hook.Add( "ULXVetoChanged", "XGUI_ServerCatchVeto", updateVetoState )
|
||||
end
|
||||
--sv_maps -- by Stickly Man!
|
||||
--Server-side code related to the maps menu.
|
||||
|
||||
local function init()
|
||||
ULib.replicatedWritableCvar( "nextlevel", "rep_nextlevel", GetConVarString( "sbox_godmode" ), false, false, "ulx map" )
|
||||
|
||||
local function getVetoState( ply, args )
|
||||
if ULib.ucl.query( ply, "ulx veto" ) then
|
||||
ULib.clientRPC( ply, "xgui.updateVetoButton", ulx.timedVeto )
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "getVetoState", getVetoState )
|
||||
|
||||
local function updateVetoState()
|
||||
for _, v in ipairs( player.GetAll() ) do
|
||||
getVetoState( v )
|
||||
end
|
||||
end
|
||||
hook.Add( "ULXVetoChanged", "XGUI_ServerCatchVeto", updateVetoState )
|
||||
end
|
||||
xgui.addSVModule( "maps", init )
|
@ -1,45 +1,45 @@
|
||||
--sv_sandbox -- by Stickly Man!
|
||||
--Server-side code related to the sandbox menu.
|
||||
|
||||
local function init()
|
||||
if ULib.isSandbox() then --Only execute the following code if it's a sandbox gamemode
|
||||
xgui.addDataType( "sboxlimits", function() return xgui.sboxLimits end, "xgui_gmsettings", 0, -20 )
|
||||
|
||||
ULib.replicatedWritableCvar( "physgun_limited", "rep_physgun_limited", GetConVarNumber( "physgun_limited" ), false, false, "xgui_gmsettings" )
|
||||
ULib.replicatedWritableCvar( "sbox_noclip", "rep_sbox_noclip", GetConVarNumber( "sbox_noclip" ), false, false, "xgui_gmsettings" )
|
||||
ULib.replicatedWritableCvar( "sbox_godmode", "rep_sbox_godmode", GetConVarNumber( "sbox_godmode" ), false, false, "xgui_gmsettings" )
|
||||
ULib.replicatedWritableCvar( "sbox_playershurtplayers", "rep_sbox_playershurtplayers", GetConVarNumber( "sbox_playershurtplayers" ), false, false, "xgui_gmsettings" )
|
||||
ULib.replicatedWritableCvar( "sbox_weapons", "rep_sbox_weapons", GetConVarNumber( "sbox_weapons" ), false, false, "xgui_gmsettings" )
|
||||
|
||||
ULib.replicatedWritableCvar( "sbox_persist", "rep_sbox_persist", GetConVarNumber( "sbox_persist" ), false, false, "xgui_gmsettings" )
|
||||
ULib.replicatedWritableCvar( "sbox_bonemanip_misc", "rep_sbox_bonemanip_misc", GetConVarNumber( "sbox_bonemanip_misc" ), false, false, "xgui_gmsettings" )
|
||||
ULib.replicatedWritableCvar( "sbox_bonemanip_npc", "rep_sbox_bonemanip_npc", GetConVarNumber( "sbox_bonemanip_npc" ), false, false, "xgui_gmsettings" )
|
||||
ULib.replicatedWritableCvar( "sbox_bonemanip_player", "rep_sbox_bonemanip_player", GetConVarNumber( "sbox_bonemanip_player" ), false, false, "xgui_gmsettings" )
|
||||
|
||||
--Process the list of known Sandbox Cvar Limits and check if they exist
|
||||
xgui.sboxLimits = {}
|
||||
if ULib.isSandbox() then
|
||||
local curgroup
|
||||
local f = ULib.fileRead( "data/ulx/sbox_limits.txt" )
|
||||
if f == nil then Msg( "XGUI ERROR: Sandbox Cvar limits file was needed but could not be found!\n" ) return end
|
||||
local lines = string.Explode( "\n", f )
|
||||
for i,v in ipairs( lines ) do
|
||||
if v:sub( 1,1 ) ~= ";" then
|
||||
if v:sub( 1,1 ) == "|" then
|
||||
curgroup = table.insert( xgui.sboxLimits, {} )
|
||||
xgui.sboxLimits[curgroup].title = v:sub( 2 )
|
||||
else
|
||||
local data = string.Explode( " ", v ) --Split Convar name from max limit
|
||||
if ConVarExists( data[1] ) then
|
||||
--We need to create a replicated cvar so the clients can manipulate/view them:
|
||||
ULib.replicatedWritableCvar( data[1], "rep_" .. data[1], GetConVarNumber( data[1] ), false, false, "xgui_gmsettings" )
|
||||
--Add to the list of cvars to send to the client
|
||||
table.insert( xgui.sboxLimits[curgroup], v )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.addSVModule( "sandbox", init )
|
||||
--sv_sandbox -- by Stickly Man!
|
||||
--Server-side code related to the sandbox menu.
|
||||
|
||||
local function init()
|
||||
if ULib.isSandbox() then --Only execute the following code if it's a sandbox gamemode
|
||||
xgui.addDataType( "sboxlimits", function() return xgui.sboxLimits end, "xgui_gmsettings", 0, -20 )
|
||||
|
||||
ULib.replicatedWritableCvar( "physgun_limited", "rep_physgun_limited", GetConVarNumber( "physgun_limited" ), false, false, "xgui_gmsettings" )
|
||||
ULib.replicatedWritableCvar( "sbox_noclip", "rep_sbox_noclip", GetConVarNumber( "sbox_noclip" ), false, false, "xgui_gmsettings" )
|
||||
ULib.replicatedWritableCvar( "sbox_godmode", "rep_sbox_godmode", GetConVarNumber( "sbox_godmode" ), false, false, "xgui_gmsettings" )
|
||||
ULib.replicatedWritableCvar( "sbox_playershurtplayers", "rep_sbox_playershurtplayers", GetConVarNumber( "sbox_playershurtplayers" ), false, false, "xgui_gmsettings" )
|
||||
ULib.replicatedWritableCvar( "sbox_weapons", "rep_sbox_weapons", GetConVarNumber( "sbox_weapons" ), false, false, "xgui_gmsettings" )
|
||||
|
||||
ULib.replicatedWritableCvar( "sbox_persist", "rep_sbox_persist", GetConVarNumber( "sbox_persist" ), false, false, "xgui_gmsettings" )
|
||||
ULib.replicatedWritableCvar( "sbox_bonemanip_misc", "rep_sbox_bonemanip_misc", GetConVarNumber( "sbox_bonemanip_misc" ), false, false, "xgui_gmsettings" )
|
||||
ULib.replicatedWritableCvar( "sbox_bonemanip_npc", "rep_sbox_bonemanip_npc", GetConVarNumber( "sbox_bonemanip_npc" ), false, false, "xgui_gmsettings" )
|
||||
ULib.replicatedWritableCvar( "sbox_bonemanip_player", "rep_sbox_bonemanip_player", GetConVarNumber( "sbox_bonemanip_player" ), false, false, "xgui_gmsettings" )
|
||||
|
||||
--Process the list of known Sandbox Cvar Limits and check if they exist
|
||||
xgui.sboxLimits = {}
|
||||
if ULib.isSandbox() then
|
||||
local curgroup
|
||||
local f = ULib.fileRead( "data/ulx/sbox_limits.txt" )
|
||||
if f == nil then Msg( "XGUI ERROR: Sandbox Cvar limits file was needed but could not be found!\n" ) return end
|
||||
local lines = string.Explode( "\n", f )
|
||||
for i,v in ipairs( lines ) do
|
||||
if v:sub( 1,1 ) ~= ";" then
|
||||
if v:sub( 1,1 ) == "|" then
|
||||
curgroup = table.insert( xgui.sboxLimits, {} )
|
||||
xgui.sboxLimits[curgroup].title = v:sub( 2 )
|
||||
else
|
||||
local data = string.Explode( " ", v ) --Split Convar name from max limit
|
||||
if ConVarExists( data[1] ) then
|
||||
--We need to create a replicated cvar so the clients can manipulate/view them:
|
||||
ULib.replicatedWritableCvar( data[1], "rep_" .. data[1], GetConVarNumber( data[1] ), false, false, "xgui_gmsettings" )
|
||||
--Add to the list of cvars to send to the client
|
||||
table.insert( xgui.sboxLimits[curgroup], v )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.addSVModule( "sandbox", init )
|
||||
|
@ -1,287 +1,287 @@
|
||||
--sv_groups -- by Stickly Man!
|
||||
--Server-side code related to the settings menu.
|
||||
|
||||
local settings = {}
|
||||
function settings.init()
|
||||
ULib.ucl.registerAccess( "xgui_gmsettings", "superadmin", "Allows changing of gamemode-specific settings on the settings tab in XGUI.", "XGUI" )
|
||||
ULib.ucl.registerAccess( "xgui_svsettings", "superadmin", "Allows changing of server and ULX-specific settings on the settings tab in XGUI.", "XGUI" )
|
||||
|
||||
xgui.addDataType( "gimps", function() return ulx.gimpSays end, "xgui_svsettings", 0, -10 )
|
||||
xgui.addDataType( "adverts", function() return ulx.adverts end, "xgui_svsettings", 0, -10 )
|
||||
xgui.addDataType( "banreasons", function() return ulx.common_kick_reasons end, "ulx ban", 0, -10 )
|
||||
xgui.addDataType( "votemaps", function() return settings.votemaps end, nil, 0, -20 )
|
||||
|
||||
ULib.replicatedWritableCvar( "sv_voiceenable", "rep_sv_voiceenable", GetConVarNumber( "sv_voiceenable" ), false, false, "xgui_svsettings" )
|
||||
ULib.replicatedWritableCvar( "sv_alltalk", "rep_sv_alltalk", GetConVarNumber( "sv_alltalk" ), false, false, "xgui_svsettings" )
|
||||
ULib.replicatedWritableCvar( "ai_disabled", "rep_ai_disabled", GetConVarNumber( "ai_disabled" ), false, false, "xgui_svsettings" )
|
||||
ULib.replicatedWritableCvar( "ai_keepragdolls", "rep_ai_keepragdolls", GetConVarNumber( "ai_keepragdolls" ), false, false, "xgui_svsettings" )
|
||||
ULib.replicatedWritableCvar( "ai_ignoreplayers", "rep_ai_ignoreplayers", GetConVarNumber( "ai_ignoreplayers" ), false, false, "xgui_svsettings" )
|
||||
ULib.replicatedWritableCvar( "sv_gravity", "rep_sv_gravity", GetConVarNumber( "sv_gravity" ), false, false, "xgui_svsettings" )
|
||||
ULib.replicatedWritableCvar( "phys_timescale", "rep_phys_timescale", GetConVarNumber( "phys_timescale" ), false, false, "xgui_svsettings" )
|
||||
|
||||
function settings.addGimp( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
ulx.addGimpSay( args[1] )
|
||||
xgui.sendDataTable( {}, "gimps" )
|
||||
settings.saveGimps()
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "addGimp", settings.addGimp )
|
||||
|
||||
function settings.removeGimp( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
for a, b in ipairs( ulx.gimpSays ) do
|
||||
if b == args[1] then
|
||||
table.remove( ulx.gimpSays, a )
|
||||
xgui.sendDataTable( {}, "gimps" )
|
||||
settings.saveGimps()
|
||||
return nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "removeGimp", settings.removeGimp )
|
||||
|
||||
function settings.saveGimps()
|
||||
local orig_file = ULib.fileRead( "data/ulx/gimps.txt" )
|
||||
local comment = xgui.getCommentHeader( orig_file )
|
||||
|
||||
local new_file = comment
|
||||
|
||||
for i, gimpSay in ipairs( ulx.gimpSays ) do
|
||||
new_file = new_file .. gimpSay .. "\n"
|
||||
end
|
||||
|
||||
ULib.fileWrite( "data/ulx/gimps.txt", new_file )
|
||||
end
|
||||
|
||||
function settings.addBanReason( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
ulx.addKickReason( args[1] )
|
||||
xgui.sendDataTable( {}, "banreasons" )
|
||||
settings.saveBanReasons()
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "addBanReason", settings.addBanReason )
|
||||
|
||||
function settings.removeBanReason( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
for a, b in ipairs( ulx.common_kick_reasons ) do
|
||||
if b == args[1] then
|
||||
table.remove( ulx.common_kick_reasons, a )
|
||||
xgui.sendDataTable( {}, "banreasons" )
|
||||
settings.saveBanReasons()
|
||||
return nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "removeBanReason", settings.removeBanReason )
|
||||
|
||||
function settings.saveBanReasons()
|
||||
local orig_file = ULib.fileRead( "data/ulx/banreasons.txt" )
|
||||
local comment = xgui.getCommentHeader( orig_file )
|
||||
|
||||
local new_file = comment
|
||||
|
||||
for i, banReason in ipairs( ulx.common_kick_reasons ) do
|
||||
new_file = new_file .. banReason .. "\n"
|
||||
end
|
||||
|
||||
ULib.fileWrite( "data/ulx/banreasons.txt", new_file )
|
||||
end
|
||||
|
||||
--[1]Message, [2]Delay, [3]GroupName/number, [4]Red, [5]Green, [6]Blue, [7]Length, [8]Hold
|
||||
function settings.addAdvert( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
if args[3] == "<No Group>" then args[3] = nil end
|
||||
local color = { r = tonumber( args[4] ), g = tonumber( args[5] ), b = tonumber( args[6] ), a = 255 } or nil
|
||||
ulx.addAdvert( args[1], tonumber( args[2] ), args[3], color, tonumber( args[7] ) )
|
||||
if args[8] ~= "hold" then
|
||||
xgui.sendDataTable( {}, "adverts" )
|
||||
settings.saveAdverts()
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "addAdvert", settings.addAdvert )
|
||||
|
||||
--[1]Old GroupType, [2]Old GroupName, [3]Old Number (order in group)
|
||||
--[4]New Message, [5]New Repeat, [6]New Red, [7]New Green, [8]New Blue, [9]New Length
|
||||
function settings.updateAdvert( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
local group = ( args[1] == "number" ) and tonumber( args[2] ) or args[2]
|
||||
local number = tonumber( args[3] )
|
||||
local advert = ulx.adverts[group][number]
|
||||
advert.message = args[4]
|
||||
advert.rpt = tonumber( args[5] )
|
||||
advert.color = { a=255, r=tonumber( args[6] ), g=tonumber( args[7] ), b=tonumber( args[8] ) }
|
||||
advert.len = tonumber( args[9] )
|
||||
xgui.sendDataTable( {}, "adverts" )
|
||||
settings.saveAdverts()
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "updateAdvert", settings.updateAdvert )
|
||||
|
||||
--[1]Old GroupType, [2]Old GroupName, [3]Old Number, [4]New Number
|
||||
function settings.moveAdvert( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
local group = ( args[1] == "number" ) and tonumber( args[2] ) or args[2]
|
||||
local number = tonumber( args[3] )
|
||||
local advert = ulx.adverts[group][number]
|
||||
table.remove( ulx.adverts[group], args[3] )
|
||||
table.insert( ulx.adverts[group], args[4], advert )
|
||||
xgui.sendDataTable( {}, "adverts" )
|
||||
settings.saveAdverts()
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "moveAdvert", settings.moveAdvert )
|
||||
|
||||
function settings.renameAdvertGroup( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
local old = args[1]
|
||||
local new = args[2]
|
||||
if ulx.adverts[old] then
|
||||
for k, v in pairs( ulx.adverts[old] ) do
|
||||
ulx.addAdvert( v.message, v.rpt, new, v.color, v.len )
|
||||
end
|
||||
settings.removeAdvertGroup( ply, { old, type( k ) } )
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "renameAdvertGroup", settings.renameAdvertGroup )
|
||||
|
||||
--[1]GroupName, [2]Number, [3]GroupType, [4]"Ignore"
|
||||
function settings.removeAdvert( ply, args, hold )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
if args[4] == "hold" then hold = true end
|
||||
local group = ( args[3] == "number" ) and tonumber( args[1] ) or args[1]
|
||||
local number = tonumber( args[2] )
|
||||
if number == #ulx.adverts[group] then
|
||||
ulx.adverts[group].removed_last = true
|
||||
end
|
||||
table.remove( ulx.adverts[group], number )
|
||||
if #ulx.adverts[group] == 0 then --Remove the existing group if no other adverts exist
|
||||
ulx.adverts[group] = nil
|
||||
timer.Remove( "ULXAdvert" .. type( group ) .. group )
|
||||
end
|
||||
if not hold then
|
||||
xgui.sendDataTable( {}, "adverts" )
|
||||
settings.saveAdverts()
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "removeAdvert", settings.removeAdvert )
|
||||
|
||||
function settings.removeAdvertGroup( ply, args, hold )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
local group = ( args[2] == "number" ) and tonumber( args[1] ) or args[1]
|
||||
for i=#ulx.adverts[group],1,-1 do
|
||||
settings.removeAdvert( ply, { group, i, args[2] }, true )
|
||||
end
|
||||
if not hold then
|
||||
xgui.sendDataTable( {}, "adverts" )
|
||||
settings.saveAdverts()
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "removeAdvertGroup", settings.removeAdvertGroup )
|
||||
|
||||
function settings.saveAdverts()
|
||||
local orig_file = ULib.fileRead( "data/ulx/adverts.txt" )
|
||||
local comment = xgui.getCommentHeader( orig_file )
|
||||
local new_file = comment
|
||||
|
||||
for group_name, group_data in pairs( ulx.adverts ) do
|
||||
local output = ""
|
||||
for i, data in ipairs( group_data ) do
|
||||
if not data.len then -- Must be a tsay advert
|
||||
output = output .. string.format( '{\n\t"text" %q\n\t"red" %q\n\t"green" %q\n\t"blue" %q\n\t"time" %q\n}\n',
|
||||
data.message, data.color.r, data.color.g, data.color.b, data.rpt )
|
||||
else -- Must be a csay advert
|
||||
output = output .. string.format( '{\n\t"text" %q\n\t"red" %q\n\t"green" %q\n\t"blue" %q\n\t"time_on_screen" %q\n\t"time" %q\n}\n',
|
||||
data.message, data.color.r, data.color.g, data.color.b, data.len, data.rpt )
|
||||
end
|
||||
end
|
||||
|
||||
if type( group_name ) ~= "number" then
|
||||
output = string.format( "%q\n{\n\t%s}\n", group_name, output:gsub( "\n", "\n\t" ) )
|
||||
end
|
||||
new_file = new_file .. output
|
||||
end
|
||||
|
||||
ULib.fileWrite( "data/ulx/adverts.txt", new_file )
|
||||
end
|
||||
|
||||
function settings.addVotemaps( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
for _, votemap in ipairs( args ) do
|
||||
table.insert( ulx.votemaps, votemap )
|
||||
end
|
||||
end
|
||||
settings.saveVotemaps( GetConVar( "ulx_votemapMapmode" ):GetInt() )
|
||||
xgui.sendDataTable( {}, "votemaps" )
|
||||
end
|
||||
xgui.addCmd( "addVotemaps", settings.addVotemaps )
|
||||
|
||||
function settings.removeVotemaps( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
for _, votemap in ipairs( args ) do
|
||||
for i, map in ipairs( ulx.votemaps ) do
|
||||
if map == votemap then
|
||||
table.remove( ulx.votemaps, i )
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
settings.saveVotemaps( GetConVar( "ulx_votemapMapmode" ):GetInt() )
|
||||
xgui.sendDataTable( {}, "votemaps" )
|
||||
end
|
||||
xgui.addCmd( "removeVotemaps", settings.removeVotemaps )
|
||||
|
||||
function settings.updatevotemaps() --Populates a table of votemaps that gets sent to the admins.
|
||||
settings.votemaps = {}
|
||||
for _, v in ipairs( ulx.votemaps ) do
|
||||
table.insert( settings.votemaps, v )
|
||||
end
|
||||
end
|
||||
|
||||
function settings.saveVotemaps( mapmode )
|
||||
local orig_file = ULib.fileRead( "data/ulx/votemaps.txt" )
|
||||
local comment = xgui.getCommentHeader( orig_file )
|
||||
local new_file = comment
|
||||
|
||||
if mapmode == 1 then --Use all maps EXCEPT what's specified in votemaps.txt
|
||||
for _, map in ipairs( ulx.maps ) do
|
||||
if not table.HasValue( ulx.votemaps, map ) then
|
||||
new_file = new_file .. map .. "\n"
|
||||
end
|
||||
end
|
||||
elseif mapmode == 2 then --Use only the maps specified in votemaps.txt
|
||||
for _, map in ipairs( ulx.votemaps ) do
|
||||
new_file = new_file .. map .. "\n"
|
||||
end
|
||||
else
|
||||
Msg( "XGUI: Could not save votemaps- Invalid or nonexistent ulx_votemapMapmode cvar!\n" )
|
||||
return
|
||||
end
|
||||
|
||||
ULib.fileWrite( "data/ulx/votemaps.txt", new_file )
|
||||
settings.updatevotemaps()
|
||||
end
|
||||
end
|
||||
|
||||
function settings.postinit()
|
||||
settings.updatevotemaps()
|
||||
xgui.sendDataTable( {}, "adverts" )
|
||||
xgui.sendDataTable( {}, "votemaps" )
|
||||
|
||||
local function votemapCvarUpdate( sv_cvar, cl_cvar, ply, old_val, new_val )
|
||||
if cl_cvar == "ulx_votemapmapmode" then
|
||||
settings.saveVotemaps( tonumber( new_val ) )
|
||||
end
|
||||
end
|
||||
hook.Add( "ULibReplicatedCvarChanged", "XGUI_CatchVotemapCvarUpdate", votemapCvarUpdate )
|
||||
end
|
||||
|
||||
xgui.addSVModule( "settings", settings.init, settings.postinit )
|
||||
--sv_groups -- by Stickly Man!
|
||||
--Server-side code related to the settings menu.
|
||||
|
||||
local settings = {}
|
||||
function settings.init()
|
||||
ULib.ucl.registerAccess( "xgui_gmsettings", "superadmin", "Allows changing of gamemode-specific settings on the settings tab in XGUI.", "XGUI" )
|
||||
ULib.ucl.registerAccess( "xgui_svsettings", "superadmin", "Allows changing of server and ULX-specific settings on the settings tab in XGUI.", "XGUI" )
|
||||
|
||||
xgui.addDataType( "gimps", function() return ulx.gimpSays end, "xgui_svsettings", 0, -10 )
|
||||
xgui.addDataType( "adverts", function() return ulx.adverts end, "xgui_svsettings", 0, -10 )
|
||||
xgui.addDataType( "banreasons", function() return ulx.common_kick_reasons end, "ulx ban", 0, -10 )
|
||||
xgui.addDataType( "votemaps", function() return settings.votemaps end, nil, 0, -20 )
|
||||
|
||||
ULib.replicatedWritableCvar( "sv_voiceenable", "rep_sv_voiceenable", GetConVarNumber( "sv_voiceenable" ), false, false, "xgui_svsettings" )
|
||||
ULib.replicatedWritableCvar( "sv_alltalk", "rep_sv_alltalk", GetConVarNumber( "sv_alltalk" ), false, false, "xgui_svsettings" )
|
||||
ULib.replicatedWritableCvar( "ai_disabled", "rep_ai_disabled", GetConVarNumber( "ai_disabled" ), false, false, "xgui_svsettings" )
|
||||
ULib.replicatedWritableCvar( "ai_keepragdolls", "rep_ai_keepragdolls", GetConVarNumber( "ai_keepragdolls" ), false, false, "xgui_svsettings" )
|
||||
ULib.replicatedWritableCvar( "ai_ignoreplayers", "rep_ai_ignoreplayers", GetConVarNumber( "ai_ignoreplayers" ), false, false, "xgui_svsettings" )
|
||||
ULib.replicatedWritableCvar( "sv_gravity", "rep_sv_gravity", GetConVarNumber( "sv_gravity" ), false, false, "xgui_svsettings" )
|
||||
ULib.replicatedWritableCvar( "phys_timescale", "rep_phys_timescale", GetConVarNumber( "phys_timescale" ), false, false, "xgui_svsettings" )
|
||||
|
||||
function settings.addGimp( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
ulx.addGimpSay( args[1] )
|
||||
xgui.sendDataTable( {}, "gimps" )
|
||||
settings.saveGimps()
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "addGimp", settings.addGimp )
|
||||
|
||||
function settings.removeGimp( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
for a, b in ipairs( ulx.gimpSays ) do
|
||||
if b == args[1] then
|
||||
table.remove( ulx.gimpSays, a )
|
||||
xgui.sendDataTable( {}, "gimps" )
|
||||
settings.saveGimps()
|
||||
return nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "removeGimp", settings.removeGimp )
|
||||
|
||||
function settings.saveGimps()
|
||||
local orig_file = ULib.fileRead( "data/ulx/gimps.txt" )
|
||||
local comment = xgui.getCommentHeader( orig_file )
|
||||
|
||||
local new_file = comment
|
||||
|
||||
for i, gimpSay in ipairs( ulx.gimpSays ) do
|
||||
new_file = new_file .. gimpSay .. "\n"
|
||||
end
|
||||
|
||||
ULib.fileWrite( "data/ulx/gimps.txt", new_file )
|
||||
end
|
||||
|
||||
function settings.addBanReason( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
ulx.addKickReason( args[1] )
|
||||
xgui.sendDataTable( {}, "banreasons" )
|
||||
settings.saveBanReasons()
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "addBanReason", settings.addBanReason )
|
||||
|
||||
function settings.removeBanReason( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
for a, b in ipairs( ulx.common_kick_reasons ) do
|
||||
if b == args[1] then
|
||||
table.remove( ulx.common_kick_reasons, a )
|
||||
xgui.sendDataTable( {}, "banreasons" )
|
||||
settings.saveBanReasons()
|
||||
return nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "removeBanReason", settings.removeBanReason )
|
||||
|
||||
function settings.saveBanReasons()
|
||||
local orig_file = ULib.fileRead( "data/ulx/banreasons.txt" )
|
||||
local comment = xgui.getCommentHeader( orig_file )
|
||||
|
||||
local new_file = comment
|
||||
|
||||
for i, banReason in ipairs( ulx.common_kick_reasons ) do
|
||||
new_file = new_file .. banReason .. "\n"
|
||||
end
|
||||
|
||||
ULib.fileWrite( "data/ulx/banreasons.txt", new_file )
|
||||
end
|
||||
|
||||
--[1]Message, [2]Delay, [3]GroupName/number, [4]Red, [5]Green, [6]Blue, [7]Length, [8]Hold
|
||||
function settings.addAdvert( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
if args[3] == "<No Group>" then args[3] = nil end
|
||||
local color = { r = tonumber( args[4] ), g = tonumber( args[5] ), b = tonumber( args[6] ), a = 255 } or nil
|
||||
ulx.addAdvert( args[1], tonumber( args[2] ), args[3], color, tonumber( args[7] ) )
|
||||
if args[8] ~= "hold" then
|
||||
xgui.sendDataTable( {}, "adverts" )
|
||||
settings.saveAdverts()
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "addAdvert", settings.addAdvert )
|
||||
|
||||
--[1]Old GroupType, [2]Old GroupName, [3]Old Number (order in group)
|
||||
--[4]New Message, [5]New Repeat, [6]New Red, [7]New Green, [8]New Blue, [9]New Length
|
||||
function settings.updateAdvert( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
local group = ( args[1] == "number" ) and tonumber( args[2] ) or args[2]
|
||||
local number = tonumber( args[3] )
|
||||
local advert = ulx.adverts[group][number]
|
||||
advert.message = args[4]
|
||||
advert.rpt = tonumber( args[5] )
|
||||
advert.color = { a=255, r=tonumber( args[6] ), g=tonumber( args[7] ), b=tonumber( args[8] ) }
|
||||
advert.len = tonumber( args[9] )
|
||||
xgui.sendDataTable( {}, "adverts" )
|
||||
settings.saveAdverts()
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "updateAdvert", settings.updateAdvert )
|
||||
|
||||
--[1]Old GroupType, [2]Old GroupName, [3]Old Number, [4]New Number
|
||||
function settings.moveAdvert( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
local group = ( args[1] == "number" ) and tonumber( args[2] ) or args[2]
|
||||
local number = tonumber( args[3] )
|
||||
local advert = ulx.adverts[group][number]
|
||||
table.remove( ulx.adverts[group], args[3] )
|
||||
table.insert( ulx.adverts[group], args[4], advert )
|
||||
xgui.sendDataTable( {}, "adverts" )
|
||||
settings.saveAdverts()
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "moveAdvert", settings.moveAdvert )
|
||||
|
||||
function settings.renameAdvertGroup( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
local old = args[1]
|
||||
local new = args[2]
|
||||
if ulx.adverts[old] then
|
||||
for k, v in pairs( ulx.adverts[old] ) do
|
||||
ulx.addAdvert( v.message, v.rpt, new, v.color, v.len )
|
||||
end
|
||||
settings.removeAdvertGroup( ply, { old, type( k ) } )
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "renameAdvertGroup", settings.renameAdvertGroup )
|
||||
|
||||
--[1]GroupName, [2]Number, [3]GroupType, [4]"Ignore"
|
||||
function settings.removeAdvert( ply, args, hold )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
if args[4] == "hold" then hold = true end
|
||||
local group = ( args[3] == "number" ) and tonumber( args[1] ) or args[1]
|
||||
local number = tonumber( args[2] )
|
||||
if number == #ulx.adverts[group] then
|
||||
ulx.adverts[group].removed_last = true
|
||||
end
|
||||
table.remove( ulx.adverts[group], number )
|
||||
if #ulx.adverts[group] == 0 then --Remove the existing group if no other adverts exist
|
||||
ulx.adverts[group] = nil
|
||||
timer.Remove( "ULXAdvert" .. type( group ) .. group )
|
||||
end
|
||||
if not hold then
|
||||
xgui.sendDataTable( {}, "adverts" )
|
||||
settings.saveAdverts()
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "removeAdvert", settings.removeAdvert )
|
||||
|
||||
function settings.removeAdvertGroup( ply, args, hold )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
local group = ( args[2] == "number" ) and tonumber( args[1] ) or args[1]
|
||||
for i=#ulx.adverts[group],1,-1 do
|
||||
settings.removeAdvert( ply, { group, i, args[2] }, true )
|
||||
end
|
||||
if not hold then
|
||||
xgui.sendDataTable( {}, "adverts" )
|
||||
settings.saveAdverts()
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.addCmd( "removeAdvertGroup", settings.removeAdvertGroup )
|
||||
|
||||
function settings.saveAdverts()
|
||||
local orig_file = ULib.fileRead( "data/ulx/adverts.txt" )
|
||||
local comment = xgui.getCommentHeader( orig_file )
|
||||
local new_file = comment
|
||||
|
||||
for group_name, group_data in pairs( ulx.adverts ) do
|
||||
local output = ""
|
||||
for i, data in ipairs( group_data ) do
|
||||
if not data.len then -- Must be a tsay advert
|
||||
output = output .. string.format( '{\n\t"text" %q\n\t"red" %q\n\t"green" %q\n\t"blue" %q\n\t"time" %q\n}\n',
|
||||
data.message, data.color.r, data.color.g, data.color.b, data.rpt )
|
||||
else -- Must be a csay advert
|
||||
output = output .. string.format( '{\n\t"text" %q\n\t"red" %q\n\t"green" %q\n\t"blue" %q\n\t"time_on_screen" %q\n\t"time" %q\n}\n',
|
||||
data.message, data.color.r, data.color.g, data.color.b, data.len, data.rpt )
|
||||
end
|
||||
end
|
||||
|
||||
if type( group_name ) ~= "number" then
|
||||
output = string.format( "%q\n{\n\t%s}\n", group_name, output:gsub( "\n", "\n\t" ) )
|
||||
end
|
||||
new_file = new_file .. output
|
||||
end
|
||||
|
||||
ULib.fileWrite( "data/ulx/adverts.txt", new_file )
|
||||
end
|
||||
|
||||
function settings.addVotemaps( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
for _, votemap in ipairs( args ) do
|
||||
table.insert( ulx.votemaps, votemap )
|
||||
end
|
||||
end
|
||||
settings.saveVotemaps( GetConVar( "ulx_votemapMapmode" ):GetInt() )
|
||||
xgui.sendDataTable( {}, "votemaps" )
|
||||
end
|
||||
xgui.addCmd( "addVotemaps", settings.addVotemaps )
|
||||
|
||||
function settings.removeVotemaps( ply, args )
|
||||
if ULib.ucl.query( ply, "xgui_svsettings" ) then
|
||||
for _, votemap in ipairs( args ) do
|
||||
for i, map in ipairs( ulx.votemaps ) do
|
||||
if map == votemap then
|
||||
table.remove( ulx.votemaps, i )
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
settings.saveVotemaps( GetConVar( "ulx_votemapMapmode" ):GetInt() )
|
||||
xgui.sendDataTable( {}, "votemaps" )
|
||||
end
|
||||
xgui.addCmd( "removeVotemaps", settings.removeVotemaps )
|
||||
|
||||
function settings.updatevotemaps() --Populates a table of votemaps that gets sent to the admins.
|
||||
settings.votemaps = {}
|
||||
for _, v in ipairs( ulx.votemaps ) do
|
||||
table.insert( settings.votemaps, v )
|
||||
end
|
||||
end
|
||||
|
||||
function settings.saveVotemaps( mapmode )
|
||||
local orig_file = ULib.fileRead( "data/ulx/votemaps.txt" )
|
||||
local comment = xgui.getCommentHeader( orig_file )
|
||||
local new_file = comment
|
||||
|
||||
if mapmode == 1 then --Use all maps EXCEPT what's specified in votemaps.txt
|
||||
for _, map in ipairs( ulx.maps ) do
|
||||
if not table.HasValue( ulx.votemaps, map ) then
|
||||
new_file = new_file .. map .. "\n"
|
||||
end
|
||||
end
|
||||
elseif mapmode == 2 then --Use only the maps specified in votemaps.txt
|
||||
for _, map in ipairs( ulx.votemaps ) do
|
||||
new_file = new_file .. map .. "\n"
|
||||
end
|
||||
else
|
||||
Msg( "XGUI: Could not save votemaps- Invalid or nonexistent ulx_votemapMapmode cvar!\n" )
|
||||
return
|
||||
end
|
||||
|
||||
ULib.fileWrite( "data/ulx/votemaps.txt", new_file )
|
||||
settings.updatevotemaps()
|
||||
end
|
||||
end
|
||||
|
||||
function settings.postinit()
|
||||
settings.updatevotemaps()
|
||||
xgui.sendDataTable( {}, "adverts" )
|
||||
xgui.sendDataTable( {}, "votemaps" )
|
||||
|
||||
local function votemapCvarUpdate( sv_cvar, cl_cvar, ply, old_val, new_val )
|
||||
if cl_cvar == "ulx_votemapmapmode" then
|
||||
settings.saveVotemaps( tonumber( new_val ) )
|
||||
end
|
||||
end
|
||||
hook.Add( "ULibReplicatedCvarChanged", "XGUI_CatchVotemapCvarUpdate", votemapCvarUpdate )
|
||||
end
|
||||
|
||||
xgui.addSVModule( "settings", settings.init, settings.postinit )
|
||||
|
@ -1,36 +1,36 @@
|
||||
--Settings module v2 for ULX GUI -- by Stickly Man!
|
||||
--This bit of code is the base for holding the various settings modules.
|
||||
|
||||
local settings = xlib.makepanel{ parent=xgui.null }
|
||||
|
||||
local autorefreshTab
|
||||
if xgui.settings_tabs != nil then autorefreshTab = xgui.settings_tabs:GetActiveTab() end
|
||||
|
||||
xgui.settings_tabs = xlib.makepropertysheet{ x=-5, y=6, w=600, h=368, parent=settings, offloadparent=xgui.null }
|
||||
function xgui.settings_tabs:SetActiveTab( active, ignoreAnim )
|
||||
if ( self.m_pActiveTab == active ) then return end
|
||||
if ( self.m_pActiveTab ) then
|
||||
if not ignoreAnim then
|
||||
xlib.addToAnimQueue( "pnlFade", { panelOut=self.m_pActiveTab:GetPanel(), panelIn=active:GetPanel() } )
|
||||
else
|
||||
--Run this when module permissions have changed.
|
||||
xlib.addToAnimQueue( "pnlFade", { panelOut=nil, panelIn=active:GetPanel() }, 0 )
|
||||
end
|
||||
xlib.animQueue_start()
|
||||
end
|
||||
self.m_pActiveTab = active
|
||||
self:InvalidateLayout()
|
||||
end
|
||||
|
||||
local func = xgui.settings_tabs.PerformLayout
|
||||
xgui.settings_tabs.PerformLayout = function( self )
|
||||
func( self )
|
||||
self.tabScroller:SetPos( 10, 0 )
|
||||
self.tabScroller:SetWide( 555 ) --Make the tabs smaller to accommodate for the X button at the top-right corner.
|
||||
end
|
||||
|
||||
if autorefreshTab != nil then
|
||||
xgui.settings_tabs:SetActiveTab( autorefreshTab, true )
|
||||
end
|
||||
|
||||
--Settings module v2 for ULX GUI -- by Stickly Man!
|
||||
--This bit of code is the base for holding the various settings modules.
|
||||
|
||||
local settings = xlib.makepanel{ parent=xgui.null }
|
||||
|
||||
local autorefreshTab
|
||||
if xgui.settings_tabs != nil then autorefreshTab = xgui.settings_tabs:GetActiveTab() end
|
||||
|
||||
xgui.settings_tabs = xlib.makepropertysheet{ x=-5, y=6, w=600, h=368, parent=settings, offloadparent=xgui.null }
|
||||
function xgui.settings_tabs:SetActiveTab( active, ignoreAnim )
|
||||
if ( self.m_pActiveTab == active ) then return end
|
||||
if ( self.m_pActiveTab ) then
|
||||
if not ignoreAnim then
|
||||
xlib.addToAnimQueue( "pnlFade", { panelOut=self.m_pActiveTab:GetPanel(), panelIn=active:GetPanel() } )
|
||||
else
|
||||
--Run this when module permissions have changed.
|
||||
xlib.addToAnimQueue( "pnlFade", { panelOut=nil, panelIn=active:GetPanel() }, 0 )
|
||||
end
|
||||
xlib.animQueue_start()
|
||||
end
|
||||
self.m_pActiveTab = active
|
||||
self:InvalidateLayout()
|
||||
end
|
||||
|
||||
local func = xgui.settings_tabs.PerformLayout
|
||||
xgui.settings_tabs.PerformLayout = function( self )
|
||||
func( self )
|
||||
self.tabScroller:SetPos( 10, 0 )
|
||||
self.tabScroller:SetWide( 555 ) --Make the tabs smaller to accommodate for the X button at the top-right corner.
|
||||
end
|
||||
|
||||
if autorefreshTab != nil then
|
||||
xgui.settings_tabs:SetActiveTab( autorefreshTab, true )
|
||||
end
|
||||
|
||||
xgui.addModule( "Settings", settings, "icon16/wrench.png" )
|
@ -1,321 +1,321 @@
|
||||
--Client settings module for ULX GUI -- by Stickly Man!
|
||||
--A settings module for modifing XGUI-based settings, and allows for modules to add clientside setting here.
|
||||
|
||||
local client = xlib.makepanel{ parent=xgui.null }
|
||||
|
||||
client.panel = xlib.makepanel{ x=160, y=5, w=425, h=322, parent=client }
|
||||
|
||||
client.catList = xlib.makelistview{ x=5, y=5, w=150, h=302, parent=client }
|
||||
client.catList:AddColumn( "Clientside Settings" )
|
||||
client.catList.Columns[1].DoClick = function() end
|
||||
client.catList.OnRowSelected = function( self, LineID, Line )
|
||||
local nPanel = xgui.modules.submodule[Line:GetValue(2)].panel
|
||||
if nPanel ~= client.curPanel then
|
||||
nPanel:SetZPos( 0 )
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=nPanel, startx=-435, starty=0, endx=0, endy=0, setvisible=true } )
|
||||
if client.curPanel then
|
||||
client.curPanel:SetZPos( -1 )
|
||||
xlib.addToAnimQueue( client.curPanel.SetVisible, client.curPanel, false )
|
||||
end
|
||||
xlib.animQueue_start()
|
||||
client.curPanel = nPanel
|
||||
else
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=nPanel, startx=0, starty=0, endx=-435, endy=0, setvisible=false } )
|
||||
self:ClearSelection()
|
||||
client.curPanel = nil
|
||||
xlib.animQueue_start()
|
||||
end
|
||||
if nPanel.onOpen then nPanel.onOpen() end --If the panel has it, call a function when it's opened
|
||||
end
|
||||
|
||||
xlib.makebutton{ x=5, y=307, w=150, label="Save Clientside Settings", parent=client }.DoClick=function()
|
||||
xgui.saveClientSettings()
|
||||
end
|
||||
|
||||
function xgui.openClientModule( name )
|
||||
name = string.lower( name )
|
||||
for i = 1, #xgui.modules.submodule do
|
||||
local module = xgui.modules.submodule[i]
|
||||
if module.mtype == "client" and string.lower(module.name) == name then
|
||||
if module.panel ~= client.curPanel then
|
||||
client.catList:ClearSelection()
|
||||
for i=1, #client.catList.Lines do
|
||||
local line = client.catList.Lines[i]
|
||||
if string.lower(line:GetColumnText(1)) == name then
|
||||
client.catList:SelectItem( line )
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Process modular settings
|
||||
function client.processModules()
|
||||
client.catList:Clear()
|
||||
for i, module in ipairs( xgui.modules.submodule ) do
|
||||
if module.mtype == "client" and ( not module.access or LocalPlayer():query( module.access ) ) then
|
||||
local x,y = module.panel:GetSize()
|
||||
if x == y and y == 0 then module.panel:SetSize( 425, 327 ) end
|
||||
module.panel:SetParent( client.panel )
|
||||
local line = client.catList:AddLine( module.name, i )
|
||||
if ( module.panel == client.curPanel ) then
|
||||
client.curPanel = nil
|
||||
client.catList:SelectItem( line )
|
||||
else
|
||||
module.panel:SetVisible( false )
|
||||
end
|
||||
end
|
||||
end
|
||||
client.catList:SortByColumn( 1, false )
|
||||
end
|
||||
client.processModules()
|
||||
|
||||
xgui.hookEvent( "onProcessModules", nil, client.processModules, "xguiProcessModules" )
|
||||
xgui.addSettingModule( "Client", client, "icon16/layout_content.png" )
|
||||
|
||||
|
||||
--------------------General Clientside Module--------------------
|
||||
local genpnl = xlib.makepanel{ parent=xgui.null }
|
||||
|
||||
genpnl.pickupplayers = xlib.makecheckbox{ x=10, y=10, w=150, label="Enable picking up players with physgun (for yourself)", convar="cl_pickupplayers", parent=genpnl }
|
||||
function genpnl.processModules()
|
||||
genpnl.pickupplayers:SetDisabled( not LocalPlayer():query( "ulx physgunplayer" ) )
|
||||
end
|
||||
|
||||
xgui.hookEvent( "onProcessModules", nil, genpnl.processModules, "clientGeneralProcessModules" )
|
||||
xgui.addSubModule( "General Settings", genpnl, nil, "client" )
|
||||
|
||||
--------------------XGUI Clientside Module--------------------
|
||||
local xguipnl = xlib.makepanel{ parent=xgui.null }
|
||||
xlib.makebutton{ x=10, y=10, w=150, label="Refresh XGUI Modules", parent=xguipnl }.DoClick=function()
|
||||
xgui.processModules()
|
||||
end
|
||||
local databutton = xlib.makebutton{ x=10, y=30, w=150, label="Refresh Server Data", parent=xguipnl }
|
||||
databutton.DoClick=function( self )
|
||||
if xgui.offlineMode then
|
||||
self:SetDisabled( true )
|
||||
RunConsoleCommand( "_xgui", "getInstalled" )
|
||||
timer.Simple( 10, function() self:SetDisabled( false ) end )
|
||||
else
|
||||
if xgui.isInstalled then --We can't be in offline mode to do this
|
||||
self:SetDisabled( true )
|
||||
RunConsoleCommand( "xgui", "refreshdata" )
|
||||
timer.Simple( 10, function() self:SetDisabled( false ) end )
|
||||
end
|
||||
end
|
||||
end
|
||||
xlib.makelabel{ x=10, y=55, label="Animation transition time:", parent=xguipnl }
|
||||
xlib.makeslider{ x=10, y=70, w=150, label="<--->", max=2, value=xgui.settings.animTime, decimal=2, parent=xguipnl }.OnValueChanged = function( self, val )
|
||||
local testval = math.Clamp( tonumber( val ), 0, 2 )
|
||||
if testval ~= tonumber( val ) then self:SetValue( testval ) end
|
||||
xgui.settings.animTime = tonumber( val )
|
||||
end
|
||||
xlib.makecheckbox{ x=10, y=97, w=150, label="Show Startup Messages", value=xgui.settings.showLoadMsgs, parent=xguipnl }.OnChange = function( self, bVal )
|
||||
xgui.settings.showLoadMsgs = bVal
|
||||
end
|
||||
xlib.makelabel{ x=10, y=120, label="Infobar color:", parent=xguipnl }
|
||||
|
||||
xlib.makecolorpicker{ x=10, y=135, color=xgui.settings.infoColor, addalpha=true, alphamodetwo=true, parent=xguipnl }.OnChangeImmediate = function( self, color )
|
||||
xgui.settings.infoColor = color
|
||||
end
|
||||
|
||||
----------------
|
||||
--SKIN MANAGER--
|
||||
----------------
|
||||
xlib.makelabel{ x=10, y=273, label="Derma Theme:", parent=xguipnl }
|
||||
xguipnl.skinselect = xlib.makecombobox{ x=10, y=290, w=150, parent=xguipnl }
|
||||
if not derma.SkinList[xgui.settings.skin] then
|
||||
xgui.settings.skin = "Default"
|
||||
end
|
||||
xguipnl.skinselect:SetText( derma.SkinList[xgui.settings.skin].PrintName )
|
||||
xgui.base.refreshSkin = true
|
||||
xguipnl.skinselect.OnSelect = function( self, index, value, data )
|
||||
xgui.settings.skin = data
|
||||
xgui.base:SetSkin( data )
|
||||
end
|
||||
for skin, skindata in pairs( derma.SkinList ) do
|
||||
xguipnl.skinselect:AddChoice( skindata.PrintName, skin )
|
||||
end
|
||||
|
||||
----------------
|
||||
--TAB ORDERING--
|
||||
----------------
|
||||
xguipnl.mainorder = xlib.makelistview{ x=175, y=10, w=115, h=110, parent=xguipnl }
|
||||
xguipnl.mainorder:AddColumn( "Main Modules" )
|
||||
xguipnl.mainorder.OnRowSelected = function( self, LineID, Line )
|
||||
xguipnl.upbtnM:SetDisabled( LineID <= 1 )
|
||||
xguipnl.downbtnM:SetDisabled( LineID >= #xgui.settings.moduleOrder )
|
||||
end
|
||||
xguipnl.updateMainOrder = function()
|
||||
local selected = xguipnl.mainorder:GetSelectedLine() and xguipnl.mainorder:GetSelected()[1]:GetColumnText(1)
|
||||
xguipnl.mainorder:Clear()
|
||||
for i, v in ipairs( xgui.settings.moduleOrder ) do
|
||||
local found = false
|
||||
for _, tab in pairs( xgui.modules.tab ) do
|
||||
if tab.name == v then
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if found then
|
||||
local l = xguipnl.mainorder:AddLine( v )
|
||||
if v == selected then xguipnl.mainorder:SelectItem( l ) end
|
||||
else
|
||||
table.remove( xgui.settings.moduleOrder, i )
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.hookEvent( "onProcessModules", nil, xguipnl.updateMainOrder, "clientXGUIUpdateTabOrder" )
|
||||
xguipnl.upbtnM = xlib.makebutton{ x=250, y=120, w=20, icon="icon16/bullet_arrow_up.png", centericon=true, disabled=true, parent=xguipnl }
|
||||
xguipnl.upbtnM.DoClick = function( self )
|
||||
self:SetDisabled( true )
|
||||
local i = xguipnl.mainorder:GetSelectedLine()
|
||||
table.insert( xgui.settings.moduleOrder, i-1, xgui.settings.moduleOrder[i] )
|
||||
table.remove( xgui.settings.moduleOrder, i+1 )
|
||||
xgui.processModules()
|
||||
end
|
||||
xguipnl.downbtnM = xlib.makebutton{ x=270, y=120, w=20, icon="icon16/bullet_arrow_down.png", centericon=true, disabled=true, parent=xguipnl }
|
||||
xguipnl.downbtnM.DoClick = function( self )
|
||||
self:SetDisabled( true )
|
||||
local i = xguipnl.mainorder:GetSelectedLine()
|
||||
table.insert( xgui.settings.moduleOrder, i+2, xgui.settings.moduleOrder[i] )
|
||||
table.remove( xgui.settings.moduleOrder, i )
|
||||
xgui.processModules()
|
||||
end
|
||||
|
||||
|
||||
xguipnl.settingorder = xlib.makelistview{ x=300, y=10, w=115, h=110, parent=xguipnl }
|
||||
xguipnl.settingorder:AddColumn( "Setting Modules" )
|
||||
xguipnl.settingorder.OnRowSelected = function( self, LineID, Line )
|
||||
xguipnl.upbtnS:SetDisabled( LineID <= 1 )
|
||||
xguipnl.downbtnS:SetDisabled( LineID >= #xgui.settings.settingOrder )
|
||||
end
|
||||
xguipnl.updateSettingOrder = function()
|
||||
local selected = xguipnl.settingorder:GetSelectedLine() and xguipnl.settingorder:GetSelected()[1]:GetColumnText(1)
|
||||
xguipnl.settingorder:Clear()
|
||||
for i, v in ipairs( xgui.settings.settingOrder ) do
|
||||
local found = false
|
||||
for _, tab in pairs( xgui.modules.setting ) do
|
||||
if tab.name == v then
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if found then
|
||||
local l = xguipnl.settingorder:AddLine( v )
|
||||
if v == selected then xguipnl.settingorder:SelectItem( l ) end
|
||||
else
|
||||
table.remove( xgui.settings.settingOrder, i )
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.hookEvent( "onProcessModules", nil, xguipnl.updateSettingOrder, "clientXGUIUpdateSettingOrder" )
|
||||
xguipnl.upbtnS = xlib.makebutton{ x=395, y=120, w=20, icon="icon16/bullet_arrow_up.png", centericon=true, disabled=true, parent=xguipnl }
|
||||
xguipnl.upbtnS.DoClick = function( self )
|
||||
self:SetDisabled( true )
|
||||
local i = xguipnl.settingorder:GetSelectedLine()
|
||||
table.insert( xgui.settings.settingOrder, i-1, xgui.settings.settingOrder[i] )
|
||||
table.remove( xgui.settings.settingOrder, i+1 )
|
||||
xgui.processModules()
|
||||
end
|
||||
xguipnl.downbtnS = xlib.makebutton{ x=375, y=120, w=20, icon="icon16/bullet_arrow_down.png", centericon=true, disabled=true, parent=xguipnl }
|
||||
xguipnl.downbtnS.DoClick = function( self )
|
||||
self:SetDisabled( true )
|
||||
local i = xguipnl.settingorder:GetSelectedLine()
|
||||
table.insert( xgui.settings.settingOrder, i+2, xgui.settings.settingOrder[i] )
|
||||
table.remove( xgui.settings.settingOrder, i )
|
||||
xgui.processModules()
|
||||
end
|
||||
|
||||
--------------------
|
||||
--XGUI POSITIONING--
|
||||
--------------------
|
||||
xlib.makelabel{ x=175, y=145, label="XGUI Positioning:", parent=xguipnl }
|
||||
local pos = tonumber( xgui.settings.xguipos.pos )
|
||||
xguipnl.b7 = xlib.makebutton{ x=175, y=160, w=20, disabled=pos==7, parent=xguipnl }
|
||||
xguipnl.b7.DoClick = function( self ) xguipnl.updatePos( 7 ) end
|
||||
xguipnl.b8 = xlib.makebutton{ x=195, y=160, w=20, icon="icon16/arrow_up.png", centericon=true, disabled=pos==8, parent=xguipnl }
|
||||
xguipnl.b8.DoClick = function( self ) xguipnl.updatePos( 8 ) end
|
||||
xguipnl.b9 = xlib.makebutton{ x=215, y=160, w=20, disabled=pos==9, parent=xguipnl }
|
||||
xguipnl.b9.DoClick = function( self ) xguipnl.updatePos( 9 ) end
|
||||
xguipnl.b4 = xlib.makebutton{ x=175, y=180, w=20, icon="icon16/arrow_left.png", centericon=true, disabled=pos==4, parent=xguipnl }
|
||||
xguipnl.b4.DoClick = function( self ) xguipnl.updatePos( 4 ) end
|
||||
xguipnl.b5 = xlib.makebutton{ x=195, y=180, w=20, icon="icon16/bullet_green.png", centericon=true, disabled=pos==5, parent=xguipnl }
|
||||
xguipnl.b5.DoClick = function( self ) xguipnl.updatePos( 5 ) end
|
||||
xguipnl.b6 = xlib.makebutton{ x=215, y=180, w=20, icon="icon16/arrow_right.png", centericon=true, disabled=pos==6, parent=xguipnl }
|
||||
xguipnl.b6.DoClick = function( self ) xguipnl.updatePos( 6 ) end
|
||||
xguipnl.b1 = xlib.makebutton{ x=175, y=200, w=20, disabled=pos==1, parent=xguipnl }
|
||||
xguipnl.b1.DoClick = function( self ) xguipnl.updatePos( 1 ) end
|
||||
xguipnl.b2 = xlib.makebutton{ x=195, y=200, w=20, icon="icon16/arrow_down.png", centericon=true, disabled=pos==2, parent=xguipnl }
|
||||
xguipnl.b2.DoClick = function( self ) xguipnl.updatePos( 2 ) end
|
||||
xguipnl.b3 = xlib.makebutton{ x=215, y=200, w=20, disabled=pos==3, parent=xguipnl }
|
||||
xguipnl.b3.DoClick = function( self ) xguipnl.updatePos( 3 ) end
|
||||
|
||||
function xguipnl.updatePos( position, xoffset, yoffset, ignoreanim )
|
||||
position = position or 5
|
||||
xoffset = xoffset or tonumber( xgui.settings.xguipos.xoff )
|
||||
yoffset = yoffset or tonumber( xgui.settings.xguipos.yoff )
|
||||
xgui.settings.xguipos = { pos=position, xoff=xoffset, yoff=yoffset }
|
||||
xgui.SetPos( position, xoffset, yoffset, ignoreanim )
|
||||
xguipnl.b1:SetDisabled( position==1 )
|
||||
xguipnl.b2:SetDisabled( position==2 )
|
||||
xguipnl.b3:SetDisabled( position==3 )
|
||||
xguipnl.b4:SetDisabled( position==4 )
|
||||
xguipnl.b5:SetDisabled( position==5 )
|
||||
xguipnl.b6:SetDisabled( position==6 )
|
||||
xguipnl.b7:SetDisabled( position==7 )
|
||||
xguipnl.b8:SetDisabled( position==8 )
|
||||
xguipnl.b9:SetDisabled( position==9 )
|
||||
end
|
||||
|
||||
xguipnl.xwang = xlib.makenumberwang{ x=245, y=167, w=50, min=-1000, max=1000, value=xgui.settings.xguipos.xoff, decimal=0, parent=xguipnl }
|
||||
xguipnl.xwang.OnValueChanged = function( self, val )
|
||||
xguipnl.updatePos( xgui.settings.xguipos.pos, tonumber( val ), xgui.settings.xguipos.yoffset, true )
|
||||
end
|
||||
xguipnl.xwang.OnEnter = function( self )
|
||||
local val = tonumber( self:GetValue() )
|
||||
if not val then val = 0 end
|
||||
xguipnl.updatePos( xgui.settings.xguipos.pos, tonumber( val ), xgui.settings.xguipos.yoffset )
|
||||
end
|
||||
xguipnl.xwang.OnLoseFocus = function( self )
|
||||
hook.Call( "OnTextEntryLoseFocus", nil, self )
|
||||
self:OnEnter()
|
||||
end
|
||||
xlib.makelabel{ x=300, y=169, label="X Offset", parent=xguipnl }
|
||||
|
||||
xguipnl.ywang = xlib.makenumberwang{ x=245, y=193, w=50, min=-1000, max=1000, value=xgui.settings.xguipos.yoff, decimal=0, parent=xguipnl }
|
||||
xguipnl.ywang.OnValueChanged = function( self, val )
|
||||
xguipnl.updatePos( xgui.settings.xguipos.pos, xgui.settings.xguipos.xoffset, tonumber( val ), true )
|
||||
end
|
||||
xguipnl.ywang.OnEnter = function( self )
|
||||
local val = tonumber( self:GetValue() )
|
||||
if not val then val = 0 end
|
||||
xguipnl.updatePos( xgui.settings.xguipos.pos, xgui.settings.xguipos.xoffset, tonumber( val ) )
|
||||
end
|
||||
xguipnl.ywang.OnLoseFocus = function( self )
|
||||
hook.Call( "OnTextEntryLoseFocus", nil, self )
|
||||
self:OnEnter()
|
||||
end
|
||||
xlib.makelabel{ x=300, y=195, label="Y Offset", parent=xguipnl }
|
||||
|
||||
-------------------------
|
||||
--OPEN/CLOSE ANIMATIONS--
|
||||
-------------------------
|
||||
xlib.makelabel{ x=175, y=229, label="XGUI Animations:", parent=xguipnl }
|
||||
xlib.makelabel{ x=175, y=247, label="On Open:", parent=xguipnl }
|
||||
xguipnl.inAnim = xlib.makecombobox{ x=225, y=245, w=150, choices={ "Fade In", "Slide From Top", "Slide From Left", "Slide From Bottom", "Slide From Right" }, parent=xguipnl }
|
||||
xguipnl.inAnim:ChooseOptionID( tonumber( xgui.settings.animIntype ) )
|
||||
function xguipnl.inAnim:OnSelect( index, value, data )
|
||||
xgui.settings.animIntype = index
|
||||
end
|
||||
xlib.makelabel{ x=175, y=272, label="On Close:", parent=xguipnl }
|
||||
xguipnl.outAnim = xlib.makecombobox{ x=225, y=270, w=150, choices={ "Fade Out", "Slide To Top", "Slide To Left", "Slide To Bottom", "Slide To Right" }, parent=xguipnl }
|
||||
xguipnl.outAnim:ChooseOptionID( tonumber( xgui.settings.animOuttype ) )
|
||||
function xguipnl.outAnim:OnSelect( index, value, data )
|
||||
xgui.settings.animOuttype = index
|
||||
end
|
||||
|
||||
--Client settings module for ULX GUI -- by Stickly Man!
|
||||
--A settings module for modifing XGUI-based settings, and allows for modules to add clientside setting here.
|
||||
|
||||
local client = xlib.makepanel{ parent=xgui.null }
|
||||
|
||||
client.panel = xlib.makepanel{ x=160, y=5, w=425, h=322, parent=client }
|
||||
|
||||
client.catList = xlib.makelistview{ x=5, y=5, w=150, h=302, parent=client }
|
||||
client.catList:AddColumn( "Clientside Settings" )
|
||||
client.catList.Columns[1].DoClick = function() end
|
||||
client.catList.OnRowSelected = function( self, LineID, Line )
|
||||
local nPanel = xgui.modules.submodule[Line:GetValue(2)].panel
|
||||
if nPanel ~= client.curPanel then
|
||||
nPanel:SetZPos( 0 )
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=nPanel, startx=-435, starty=0, endx=0, endy=0, setvisible=true } )
|
||||
if client.curPanel then
|
||||
client.curPanel:SetZPos( -1 )
|
||||
xlib.addToAnimQueue( client.curPanel.SetVisible, client.curPanel, false )
|
||||
end
|
||||
xlib.animQueue_start()
|
||||
client.curPanel = nPanel
|
||||
else
|
||||
xlib.addToAnimQueue( "pnlSlide", { panel=nPanel, startx=0, starty=0, endx=-435, endy=0, setvisible=false } )
|
||||
self:ClearSelection()
|
||||
client.curPanel = nil
|
||||
xlib.animQueue_start()
|
||||
end
|
||||
if nPanel.onOpen then nPanel.onOpen() end --If the panel has it, call a function when it's opened
|
||||
end
|
||||
|
||||
xlib.makebutton{ x=5, y=307, w=150, label="Save Clientside Settings", parent=client }.DoClick=function()
|
||||
xgui.saveClientSettings()
|
||||
end
|
||||
|
||||
function xgui.openClientModule( name )
|
||||
name = string.lower( name )
|
||||
for i = 1, #xgui.modules.submodule do
|
||||
local module = xgui.modules.submodule[i]
|
||||
if module.mtype == "client" and string.lower(module.name) == name then
|
||||
if module.panel ~= client.curPanel then
|
||||
client.catList:ClearSelection()
|
||||
for i=1, #client.catList.Lines do
|
||||
local line = client.catList.Lines[i]
|
||||
if string.lower(line:GetColumnText(1)) == name then
|
||||
client.catList:SelectItem( line )
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Process modular settings
|
||||
function client.processModules()
|
||||
client.catList:Clear()
|
||||
for i, module in ipairs( xgui.modules.submodule ) do
|
||||
if module.mtype == "client" and ( not module.access or LocalPlayer():query( module.access ) ) then
|
||||
local x,y = module.panel:GetSize()
|
||||
if x == y and y == 0 then module.panel:SetSize( 425, 327 ) end
|
||||
module.panel:SetParent( client.panel )
|
||||
local line = client.catList:AddLine( module.name, i )
|
||||
if ( module.panel == client.curPanel ) then
|
||||
client.curPanel = nil
|
||||
client.catList:SelectItem( line )
|
||||
else
|
||||
module.panel:SetVisible( false )
|
||||
end
|
||||
end
|
||||
end
|
||||
client.catList:SortByColumn( 1, false )
|
||||
end
|
||||
client.processModules()
|
||||
|
||||
xgui.hookEvent( "onProcessModules", nil, client.processModules, "xguiProcessModules" )
|
||||
xgui.addSettingModule( "Client", client, "icon16/layout_content.png" )
|
||||
|
||||
|
||||
--------------------General Clientside Module--------------------
|
||||
local genpnl = xlib.makepanel{ parent=xgui.null }
|
||||
|
||||
genpnl.pickupplayers = xlib.makecheckbox{ x=10, y=10, w=150, label="Enable picking up players with physgun (for yourself)", convar="cl_pickupplayers", parent=genpnl }
|
||||
function genpnl.processModules()
|
||||
genpnl.pickupplayers:SetDisabled( not LocalPlayer():query( "ulx physgunplayer" ) )
|
||||
end
|
||||
|
||||
xgui.hookEvent( "onProcessModules", nil, genpnl.processModules, "clientGeneralProcessModules" )
|
||||
xgui.addSubModule( "General Settings", genpnl, nil, "client" )
|
||||
|
||||
--------------------XGUI Clientside Module--------------------
|
||||
local xguipnl = xlib.makepanel{ parent=xgui.null }
|
||||
xlib.makebutton{ x=10, y=10, w=150, label="Refresh XGUI Modules", parent=xguipnl }.DoClick=function()
|
||||
xgui.processModules()
|
||||
end
|
||||
local databutton = xlib.makebutton{ x=10, y=30, w=150, label="Refresh Server Data", parent=xguipnl }
|
||||
databutton.DoClick=function( self )
|
||||
if xgui.offlineMode then
|
||||
self:SetDisabled( true )
|
||||
RunConsoleCommand( "_xgui", "getInstalled" )
|
||||
timer.Simple( 10, function() self:SetDisabled( false ) end )
|
||||
else
|
||||
if xgui.isInstalled then --We can't be in offline mode to do this
|
||||
self:SetDisabled( true )
|
||||
RunConsoleCommand( "xgui", "refreshdata" )
|
||||
timer.Simple( 10, function() self:SetDisabled( false ) end )
|
||||
end
|
||||
end
|
||||
end
|
||||
xlib.makelabel{ x=10, y=55, label="Animation transition time:", parent=xguipnl }
|
||||
xlib.makeslider{ x=10, y=70, w=150, label="<--->", max=2, value=xgui.settings.animTime, decimal=2, parent=xguipnl }.OnValueChanged = function( self, val )
|
||||
local testval = math.Clamp( tonumber( val ), 0, 2 )
|
||||
if testval ~= tonumber( val ) then self:SetValue( testval ) end
|
||||
xgui.settings.animTime = tonumber( val )
|
||||
end
|
||||
xlib.makecheckbox{ x=10, y=97, w=150, label="Show Startup Messages", value=xgui.settings.showLoadMsgs, parent=xguipnl }.OnChange = function( self, bVal )
|
||||
xgui.settings.showLoadMsgs = bVal
|
||||
end
|
||||
xlib.makelabel{ x=10, y=120, label="Infobar color:", parent=xguipnl }
|
||||
|
||||
xlib.makecolorpicker{ x=10, y=135, color=xgui.settings.infoColor, addalpha=true, alphamodetwo=true, parent=xguipnl }.OnChangeImmediate = function( self, color )
|
||||
xgui.settings.infoColor = color
|
||||
end
|
||||
|
||||
----------------
|
||||
--SKIN MANAGER--
|
||||
----------------
|
||||
xlib.makelabel{ x=10, y=273, label="Derma Theme:", parent=xguipnl }
|
||||
xguipnl.skinselect = xlib.makecombobox{ x=10, y=290, w=150, parent=xguipnl }
|
||||
if not derma.SkinList[xgui.settings.skin] then
|
||||
xgui.settings.skin = "Default"
|
||||
end
|
||||
xguipnl.skinselect:SetText( derma.SkinList[xgui.settings.skin].PrintName )
|
||||
xgui.base.refreshSkin = true
|
||||
xguipnl.skinselect.OnSelect = function( self, index, value, data )
|
||||
xgui.settings.skin = data
|
||||
xgui.base:SetSkin( data )
|
||||
end
|
||||
for skin, skindata in pairs( derma.SkinList ) do
|
||||
xguipnl.skinselect:AddChoice( skindata.PrintName, skin )
|
||||
end
|
||||
|
||||
----------------
|
||||
--TAB ORDERING--
|
||||
----------------
|
||||
xguipnl.mainorder = xlib.makelistview{ x=175, y=10, w=115, h=110, parent=xguipnl }
|
||||
xguipnl.mainorder:AddColumn( "Main Modules" )
|
||||
xguipnl.mainorder.OnRowSelected = function( self, LineID, Line )
|
||||
xguipnl.upbtnM:SetDisabled( LineID <= 1 )
|
||||
xguipnl.downbtnM:SetDisabled( LineID >= #xgui.settings.moduleOrder )
|
||||
end
|
||||
xguipnl.updateMainOrder = function()
|
||||
local selected = xguipnl.mainorder:GetSelectedLine() and xguipnl.mainorder:GetSelected()[1]:GetColumnText(1)
|
||||
xguipnl.mainorder:Clear()
|
||||
for i, v in ipairs( xgui.settings.moduleOrder ) do
|
||||
local found = false
|
||||
for _, tab in pairs( xgui.modules.tab ) do
|
||||
if tab.name == v then
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if found then
|
||||
local l = xguipnl.mainorder:AddLine( v )
|
||||
if v == selected then xguipnl.mainorder:SelectItem( l ) end
|
||||
else
|
||||
table.remove( xgui.settings.moduleOrder, i )
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.hookEvent( "onProcessModules", nil, xguipnl.updateMainOrder, "clientXGUIUpdateTabOrder" )
|
||||
xguipnl.upbtnM = xlib.makebutton{ x=250, y=120, w=20, icon="icon16/bullet_arrow_up.png", centericon=true, disabled=true, parent=xguipnl }
|
||||
xguipnl.upbtnM.DoClick = function( self )
|
||||
self:SetDisabled( true )
|
||||
local i = xguipnl.mainorder:GetSelectedLine()
|
||||
table.insert( xgui.settings.moduleOrder, i-1, xgui.settings.moduleOrder[i] )
|
||||
table.remove( xgui.settings.moduleOrder, i+1 )
|
||||
xgui.processModules()
|
||||
end
|
||||
xguipnl.downbtnM = xlib.makebutton{ x=270, y=120, w=20, icon="icon16/bullet_arrow_down.png", centericon=true, disabled=true, parent=xguipnl }
|
||||
xguipnl.downbtnM.DoClick = function( self )
|
||||
self:SetDisabled( true )
|
||||
local i = xguipnl.mainorder:GetSelectedLine()
|
||||
table.insert( xgui.settings.moduleOrder, i+2, xgui.settings.moduleOrder[i] )
|
||||
table.remove( xgui.settings.moduleOrder, i )
|
||||
xgui.processModules()
|
||||
end
|
||||
|
||||
|
||||
xguipnl.settingorder = xlib.makelistview{ x=300, y=10, w=115, h=110, parent=xguipnl }
|
||||
xguipnl.settingorder:AddColumn( "Setting Modules" )
|
||||
xguipnl.settingorder.OnRowSelected = function( self, LineID, Line )
|
||||
xguipnl.upbtnS:SetDisabled( LineID <= 1 )
|
||||
xguipnl.downbtnS:SetDisabled( LineID >= #xgui.settings.settingOrder )
|
||||
end
|
||||
xguipnl.updateSettingOrder = function()
|
||||
local selected = xguipnl.settingorder:GetSelectedLine() and xguipnl.settingorder:GetSelected()[1]:GetColumnText(1)
|
||||
xguipnl.settingorder:Clear()
|
||||
for i, v in ipairs( xgui.settings.settingOrder ) do
|
||||
local found = false
|
||||
for _, tab in pairs( xgui.modules.setting ) do
|
||||
if tab.name == v then
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if found then
|
||||
local l = xguipnl.settingorder:AddLine( v )
|
||||
if v == selected then xguipnl.settingorder:SelectItem( l ) end
|
||||
else
|
||||
table.remove( xgui.settings.settingOrder, i )
|
||||
end
|
||||
end
|
||||
end
|
||||
xgui.hookEvent( "onProcessModules", nil, xguipnl.updateSettingOrder, "clientXGUIUpdateSettingOrder" )
|
||||
xguipnl.upbtnS = xlib.makebutton{ x=395, y=120, w=20, icon="icon16/bullet_arrow_up.png", centericon=true, disabled=true, parent=xguipnl }
|
||||
xguipnl.upbtnS.DoClick = function( self )
|
||||
self:SetDisabled( true )
|
||||
local i = xguipnl.settingorder:GetSelectedLine()
|
||||
table.insert( xgui.settings.settingOrder, i-1, xgui.settings.settingOrder[i] )
|
||||
table.remove( xgui.settings.settingOrder, i+1 )
|
||||
xgui.processModules()
|
||||
end
|
||||
xguipnl.downbtnS = xlib.makebutton{ x=375, y=120, w=20, icon="icon16/bullet_arrow_down.png", centericon=true, disabled=true, parent=xguipnl }
|
||||
xguipnl.downbtnS.DoClick = function( self )
|
||||
self:SetDisabled( true )
|
||||
local i = xguipnl.settingorder:GetSelectedLine()
|
||||
table.insert( xgui.settings.settingOrder, i+2, xgui.settings.settingOrder[i] )
|
||||
table.remove( xgui.settings.settingOrder, i )
|
||||
xgui.processModules()
|
||||
end
|
||||
|
||||
--------------------
|
||||
--XGUI POSITIONING--
|
||||
--------------------
|
||||
xlib.makelabel{ x=175, y=145, label="XGUI Positioning:", parent=xguipnl }
|
||||
local pos = tonumber( xgui.settings.xguipos.pos )
|
||||
xguipnl.b7 = xlib.makebutton{ x=175, y=160, w=20, disabled=pos==7, parent=xguipnl }
|
||||
xguipnl.b7.DoClick = function( self ) xguipnl.updatePos( 7 ) end
|
||||
xguipnl.b8 = xlib.makebutton{ x=195, y=160, w=20, icon="icon16/arrow_up.png", centericon=true, disabled=pos==8, parent=xguipnl }
|
||||
xguipnl.b8.DoClick = function( self ) xguipnl.updatePos( 8 ) end
|
||||
xguipnl.b9 = xlib.makebutton{ x=215, y=160, w=20, disabled=pos==9, parent=xguipnl }
|
||||
xguipnl.b9.DoClick = function( self ) xguipnl.updatePos( 9 ) end
|
||||
xguipnl.b4 = xlib.makebutton{ x=175, y=180, w=20, icon="icon16/arrow_left.png", centericon=true, disabled=pos==4, parent=xguipnl }
|
||||
xguipnl.b4.DoClick = function( self ) xguipnl.updatePos( 4 ) end
|
||||
xguipnl.b5 = xlib.makebutton{ x=195, y=180, w=20, icon="icon16/bullet_green.png", centericon=true, disabled=pos==5, parent=xguipnl }
|
||||
xguipnl.b5.DoClick = function( self ) xguipnl.updatePos( 5 ) end
|
||||
xguipnl.b6 = xlib.makebutton{ x=215, y=180, w=20, icon="icon16/arrow_right.png", centericon=true, disabled=pos==6, parent=xguipnl }
|
||||
xguipnl.b6.DoClick = function( self ) xguipnl.updatePos( 6 ) end
|
||||
xguipnl.b1 = xlib.makebutton{ x=175, y=200, w=20, disabled=pos==1, parent=xguipnl }
|
||||
xguipnl.b1.DoClick = function( self ) xguipnl.updatePos( 1 ) end
|
||||
xguipnl.b2 = xlib.makebutton{ x=195, y=200, w=20, icon="icon16/arrow_down.png", centericon=true, disabled=pos==2, parent=xguipnl }
|
||||
xguipnl.b2.DoClick = function( self ) xguipnl.updatePos( 2 ) end
|
||||
xguipnl.b3 = xlib.makebutton{ x=215, y=200, w=20, disabled=pos==3, parent=xguipnl }
|
||||
xguipnl.b3.DoClick = function( self ) xguipnl.updatePos( 3 ) end
|
||||
|
||||
function xguipnl.updatePos( position, xoffset, yoffset, ignoreanim )
|
||||
position = position or 5
|
||||
xoffset = xoffset or tonumber( xgui.settings.xguipos.xoff )
|
||||
yoffset = yoffset or tonumber( xgui.settings.xguipos.yoff )
|
||||
xgui.settings.xguipos = { pos=position, xoff=xoffset, yoff=yoffset }
|
||||
xgui.SetPos( position, xoffset, yoffset, ignoreanim )
|
||||
xguipnl.b1:SetDisabled( position==1 )
|
||||
xguipnl.b2:SetDisabled( position==2 )
|
||||
xguipnl.b3:SetDisabled( position==3 )
|
||||
xguipnl.b4:SetDisabled( position==4 )
|
||||
xguipnl.b5:SetDisabled( position==5 )
|
||||
xguipnl.b6:SetDisabled( position==6 )
|
||||
xguipnl.b7:SetDisabled( position==7 )
|
||||
xguipnl.b8:SetDisabled( position==8 )
|
||||
xguipnl.b9:SetDisabled( position==9 )
|
||||
end
|
||||
|
||||
xguipnl.xwang = xlib.makenumberwang{ x=245, y=167, w=50, min=-1000, max=1000, value=xgui.settings.xguipos.xoff, decimal=0, parent=xguipnl }
|
||||
xguipnl.xwang.OnValueChanged = function( self, val )
|
||||
xguipnl.updatePos( xgui.settings.xguipos.pos, tonumber( val ), xgui.settings.xguipos.yoffset, true )
|
||||
end
|
||||
xguipnl.xwang.OnEnter = function( self )
|
||||
local val = tonumber( self:GetValue() )
|
||||
if not val then val = 0 end
|
||||
xguipnl.updatePos( xgui.settings.xguipos.pos, tonumber( val ), xgui.settings.xguipos.yoffset )
|
||||
end
|
||||
xguipnl.xwang.OnLoseFocus = function( self )
|
||||
hook.Call( "OnTextEntryLoseFocus", nil, self )
|
||||
self:OnEnter()
|
||||
end
|
||||
xlib.makelabel{ x=300, y=169, label="X Offset", parent=xguipnl }
|
||||
|
||||
xguipnl.ywang = xlib.makenumberwang{ x=245, y=193, w=50, min=-1000, max=1000, value=xgui.settings.xguipos.yoff, decimal=0, parent=xguipnl }
|
||||
xguipnl.ywang.OnValueChanged = function( self, val )
|
||||
xguipnl.updatePos( xgui.settings.xguipos.pos, xgui.settings.xguipos.xoffset, tonumber( val ), true )
|
||||
end
|
||||
xguipnl.ywang.OnEnter = function( self )
|
||||
local val = tonumber( self:GetValue() )
|
||||
if not val then val = 0 end
|
||||
xguipnl.updatePos( xgui.settings.xguipos.pos, xgui.settings.xguipos.xoffset, tonumber( val ) )
|
||||
end
|
||||
xguipnl.ywang.OnLoseFocus = function( self )
|
||||
hook.Call( "OnTextEntryLoseFocus", nil, self )
|
||||
self:OnEnter()
|
||||
end
|
||||
xlib.makelabel{ x=300, y=195, label="Y Offset", parent=xguipnl }
|
||||
|
||||
-------------------------
|
||||
--OPEN/CLOSE ANIMATIONS--
|
||||
-------------------------
|
||||
xlib.makelabel{ x=175, y=229, label="XGUI Animations:", parent=xguipnl }
|
||||
xlib.makelabel{ x=175, y=247, label="On Open:", parent=xguipnl }
|
||||
xguipnl.inAnim = xlib.makecombobox{ x=225, y=245, w=150, choices={ "Fade In", "Slide From Top", "Slide From Left", "Slide From Bottom", "Slide From Right" }, parent=xguipnl }
|
||||
xguipnl.inAnim:ChooseOptionID( tonumber( xgui.settings.animIntype ) )
|
||||
function xguipnl.inAnim:OnSelect( index, value, data )
|
||||
xgui.settings.animIntype = index
|
||||
end
|
||||
xlib.makelabel{ x=175, y=272, label="On Close:", parent=xguipnl }
|
||||
xguipnl.outAnim = xlib.makecombobox{ x=225, y=270, w=150, choices={ "Fade Out", "Slide To Top", "Slide To Left", "Slide To Bottom", "Slide To Right" }, parent=xguipnl }
|
||||
xguipnl.outAnim:ChooseOptionID( tonumber( xgui.settings.animOuttype ) )
|
||||
function xguipnl.outAnim:OnSelect( index, value, data )
|
||||
xgui.settings.animOuttype = index
|
||||
end
|
||||
|
||||
xgui.addSubModule( "XGUI Settings", xguipnl, nil, "client" )
|
File diff suppressed because it is too large
Load Diff
36
ulx_motd.txt
36
ulx_motd.txt
@ -1,19 +1,19 @@
|
||||
<html>
|
||||
<body bgcolor=#dbdbdb>
|
||||
<div style="text-align: center;">
|
||||
<div style="width: 80%; margin: 0px auto; border: 10px solid #c9d6e4; background-color: #ededed; padding: 10px; font-size: 12px; font-family: Tahoma; margin-top: 30px; color: #818181; text-align: left;">
|
||||
<div style="font-size: 30px; font-family: impact; width: 100%; margin-bottom: 5px;">My Server Name</div>
|
||||
<br>
|
||||
This Server uses the following mods:<br>
|
||||
ULX, PropDefender, and VMFLoader.<br>
|
||||
<br>
|
||||
<h2>Rules</h2>
|
||||
1. DON'T MESS WITH OTHER PLAYERS STUFF. If they want help, they'll ask!<br>
|
||||
2. Don't spam.<br>
|
||||
3. Have fun.<br>
|
||||
<div style="width: 100%; text-align: center; margin: 10px; font-weight: bold;">- The Admins</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
<html>
|
||||
<body bgcolor=#dbdbdb>
|
||||
<div style="text-align: center;">
|
||||
<div style="width: 80%; margin: 0px auto; border: 10px solid #c9d6e4; background-color: #ededed; padding: 10px; font-size: 12px; font-family: Tahoma; margin-top: 30px; color: #818181; text-align: left;">
|
||||
<div style="font-size: 30px; font-family: impact; width: 100%; margin-bottom: 5px;">My Server Name</div>
|
||||
<br>
|
||||
This Server uses the following mods:<br>
|
||||
ULX, PropDefender, and VMFLoader.<br>
|
||||
<br>
|
||||
<h2>Rules</h2>
|
||||
1. DON'T MESS WITH OTHER PLAYERS STUFF. If they want help, they'll ask!<br>
|
||||
2. Don't spam.<br>
|
||||
3. Have fun.<br>
|
||||
<div style="width: 100%; text-align: center; margin: 10px; font-weight: bold;">- The Admins</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
896
ulx_readme.txt
896
ulx_readme.txt
@ -1,448 +1,448 @@
|
||||
Title: ULX Readme
|
||||
|
||||
__ULX__
|
||||
Version 3.70
|
||||
|
||||
*ULX v3.70 (released 00/00/00)*
|
||||
|
||||
ULX is an admin mod for GMod (<http://garrysmod.com/>).
|
||||
|
||||
ULX offers server admins an AMXX-style support. It allows multiple admins with different access levels on the same server.
|
||||
It has features from basic kick, ban, and slay to fancier commands such as blind, freeze, voting, and more.
|
||||
|
||||
Visit our homepage at <http://ulyssesmod.net/>.
|
||||
|
||||
You can talk to us on our forums at <http://forums.ulyssesmod.net/>
|
||||
|
||||
Group: Author
|
||||
|
||||
ULX is brought to you by..
|
||||
|
||||
* Brett "Megiddo" Smith - Contact: <megiddo@ulyssesmod.net>
|
||||
* JamminR - Contact: <jamminr@ulyssesmod.net>
|
||||
* Stickly Man! - Contact: <sticklyman@ulyssesmod.net>
|
||||
* MrPresident - Contact: <mrpresident@ulyssesmod.net>
|
||||
|
||||
Group: Requirements
|
||||
|
||||
ULX requires the latest ULib to be installed on the server. You can get ULib from the ULX homepage.
|
||||
|
||||
Group: Installation
|
||||
|
||||
To install ULX, simply extract the files from the archive to your garrysmod/addons folder.
|
||||
When you've done this, you should have a file structure like this--
|
||||
<garrysmod>/addons/ulx/lua/ULib/modules/ulx_init.lua
|
||||
<garrysmod>/addons/ulx/lua/ulx/modules/fun.lua
|
||||
etc..
|
||||
|
||||
Note that installation for dedicated servers is EXACTLY the same!
|
||||
|
||||
You absolutely, positively have to do a full server restart after installing the files. A simple map
|
||||
change will not cut it!
|
||||
|
||||
Group: Usage
|
||||
|
||||
To use ULX, simply type in whatever command or cvar you want to use. If you're not running a listen server,
|
||||
or if you want to give access to other users, you must add users.
|
||||
|
||||
You can either follow the standard gmod way of adding users
|
||||
(http://maurits.tv/data/garrysmod/wiki/wiki.garrysmod.com/index0c18.html?title=Player_Groups), or you can add yourself directly to the
|
||||
data/ulib/users.txt file. DO NOT EDIT THE ULIB FILE UNLESS YOU KNOW WHAT YOU'RE DOING.
|
||||
|
||||
A word about superadmins: Superadmins are considered the highest usergroup. They have access to all the
|
||||
commands in ULX, override other user's immunity, and are shown otherwise hidden log messages (IE, shown
|
||||
rcon commands admins are running, when they spectate others). Superadmins also have the power to give and
|
||||
revoke access to commands using userallow and userdeny (though they can't use this command on eachother).
|
||||
|
||||
All commands are preceded by "ulx ". Type "ulx help" in a console without the quotes for help.
|
||||
|
||||
__To give yourself a jump start into ulx, simply remember the commands "ulx help" and "ulx menu". You can
|
||||
also access the menu by saying "!menu".__
|
||||
|
||||
Check out the configs folder in ulx for some more goodies.
|
||||
|
||||
Group: Changelog
|
||||
v3.70 - *(00/00/00)*
|
||||
* [ADD] XGUI: Ability to set the 'nextlevel' cvar from the maps tab, if you have access to "ulx map".
|
||||
* [ADD] Reason to votekick log (Thanks, CSchulz).
|
||||
* [ADD] Steam ID parameter to "ulx who" to lookup users by Steam ID.
|
||||
* [ADD] Cvar "ulx meChatEnabled" added to enable or disable the /me chat feature, or set it to Sandbox only.
|
||||
* [ADD] XGUI: Added methods for developers to be able to open a specific client or server setting module.
|
||||
* [FIX] The usual random slew of Garry-breakages (Thanks, Fuzzik).
|
||||
* [FIX] Changing weapons while cloaked would keep them hidden when uncloaked. (Thanks, TheRealAyCe).
|
||||
* [FIX] XGUI: Error if the default settings/users.txt file was missing.
|
||||
* [FIX] Gamemode list includes workshop addons now (Thanks, jason2010).
|
||||
* [FIX] "ulx ent" parameter parsing (Thanks, Zombine).
|
||||
* [FIX] "ulx voteban" can now ban the user even if they disconnect after the vote starts.
|
||||
* [FIX] Vote commands now work properly from server console.
|
||||
* [FIX] XGUI: Numerous issues with selecting a custom Derma/GWEN skin.
|
||||
* [FIX] XGUI: Clientside settings would not save if the client's data/ulx folder did not exist.
|
||||
* [FIX] Improved how well ULX/XGUI files and XGUI clientside/serverside modules handle being autorefreshed.
|
||||
* [FIX] ulx.addToHelpManually now checks for and removes and previously added manual help entries with the same command name.
|
||||
* [FIX] XGUI: Bug where ulx_showMotd cvar would not be updated properly when changed by someone else.
|
||||
* [FIX] XGUI: Minor performance exploit involving serverside ban sorting. (Thanks, TomatoCo).
|
||||
* [FIX] Exploit involving gmod filesystem mounting. (Thanks, Willox).
|
||||
* [FIX] Minor issue where opposite commands might not be run due to case sensitivity.
|
||||
* [FIX] Duplicate help entries due to autorefresh and overriding commands. (Thanks iSnipeu).
|
||||
* [FIX] Ragdolled players were getting removed on map cleanup.
|
||||
* [FIX] XGUI: Server error in some cases when sorting bans by Unban Date after a new ban has been added.
|
||||
* [CHANGE] MOTD now uses DHTML (Awesomium framework).
|
||||
* [CHANGE] Hook calls to match ULib's new format.
|
||||
* [CHANGE] ULX convar updates will now append an entry to data/config.txt if it is not defined in the file. Previously, these changes would not be saved.
|
||||
* [CHANGE] XGUI: No longer autoexecutes skins to ensure they have been installed.
|
||||
* [CHANGE] XGUI: Added "name" parameter to xgui.hookEvent to prevent event duplication. (Aids with autorefresh, is backwards compatible with old XGUI modules)
|
||||
* [CHANGE] XGUI: Modules that no longer exist will be removed from the customizable sort order.
|
||||
* [CHANGE] XGUI: Sliders for arguments on the Cmds tab with a small min/max delta (e.g. from 0 to 1) will now allow up to 2 decimal places, if the arg does not have cmds.round flag.
|
||||
|
||||
v3.62 - *(03/09/15)*
|
||||
* [ADD] "ulx return" to return target to previous location they were in before a teleport command was used (Thanks for the idea, ludalex).
|
||||
* [ADD] Networked variables for gimp, mute, and gag (Thanks iSnipeu).
|
||||
* [ADD] XGUI: Added more sorting and filtering options for bans.
|
||||
* [ADD] "ulx stopvote" to stop a vote currently in progress (Thanks, LuaTenshi).
|
||||
* [ADD] XGUI: Added "onClose" event for modules that need it. (Suggested by arduinium).
|
||||
* [FIX] Ban reason and the person who started the voteban is now reported in "ulx voteban" bans (Thanks iSnipeu).
|
||||
* [FIX] An API change causing an error to be thrown at the end of "ulx maul" (Thanks Decicus).
|
||||
* [FIX] NULL entity error after votekick on a player that left the server, now sends message stating that votekicked player already left.
|
||||
* [FIX] PlayerDeath hook errors in certain gamemodes where invalid entites are sent as the killer or victim. (Thanks Mechanical Mind).
|
||||
* [FIX] JailTP command now saves last player position, now works with "ulx return". (Thanks jakej78b).
|
||||
* [FIX] XGUI: Slider label widths were extra large due to a slight change in default numslider behavior. (Thanks Fuzzik).
|
||||
* [FIX] Garry's Mod update caused users to be banned faster than expected, log then incorrectly stated that (Console) was banned.
|
||||
* [FIX] Garry's Mod update prevented votebans from working.
|
||||
* [FIX] Garry's Mod update caused server crash when kicking/banning yourself via chat command.
|
||||
* [FIX] Bug with spectate and respawning (Thanks Sjokomelk).
|
||||
* [FIX] Bug when changing weapons while cloaked, weapons would stay invisible after uncloaking. (Thanks Z0mb1n3).
|
||||
* [FIX] Could not assign BOTs to groups via ulx adduserid or XGUI. (Thanks RhapsodySL).
|
||||
* [FIX] Fixed bug where XGUI would not start on dev branch of Garry's Mod. Changed to init on ULib.HOOK_LOCALPLAYERREADY instead of ULib.HOOK_UCLAUTH.
|
||||
* [FIX] MOTD not enabled message would display for all players instead of the player who tried to open the motd. (Thanks TheClonker).
|
||||
* [CHANGE] "PlayerSay" hooks are now only called serverside. (Thanks NoBrainCZ).
|
||||
* [CHANGE] Logging now prints how long a user took to join the server.
|
||||
* [CHANGE] XGUI: Updated cvarlist for sandbox and wiremod limits.
|
||||
* [CHANGE] XGUI: Many Ban menu improvements. Entire banlist is no longer sent on join- data subset is now requested by the client and sent from the server.
|
||||
* [CHANGE] XGUI: Ban list is now paginated instead of a giant scrollable list.
|
||||
* [CHANGE] XGUI: ULX Bans and other (or "Source Bans") are no longer separated.
|
||||
* [CHANGE] ULX vote variable is now global so other addons can tell if a vote is in progress. ulx.doVote() also returns whether or not it actually started a vote (Thanks for the ideas, arduinium).
|
||||
* [CHANGE] XGUI: Changed gamemode dropdown on maps tab to honor player/group restrictions. (Thanks chaos12135).
|
||||
|
||||
v3.61 - *(08/30/13)*
|
||||
* [ADD] cl_pickupplayers (defaults to 1) to allow an admin to disable the ability to pickup players (so they don't do it on accident). Done in collaboration with FPtje.
|
||||
* [ADD] %curmap% and %steamid% variables in "ulx showMotd" URL for custom-served MOTDs (Thanks Mors-Quaedam).
|
||||
* [ADD] XGUI: Bans are now searchable. (Thanks to iSnipeu for the code contribution!)
|
||||
* [FIX] "#" (Pound signs) removing content in ulx asay (Thanks bener180).
|
||||
* [FIX] Reserved slot mode 3 not kicking the shortest connected player as it is supposed to (Thanks monkstick).
|
||||
* [FIX] No longer able to physgun frozen players (Thanks ms333).
|
||||
* [FIX] XGUI: Added checks to prevent admins from being able to edit ban information past their restrictions (Thanks Zaph).
|
||||
* [FIX] XGUI: Infobar text no longer displaying.
|
||||
* [FIX] XGUI: Error caused when closing the fban window after the targeted player has left the server (Thanks nathan736).
|
||||
* [FIX] XGUI: Issues with handling min / max number restrictions.
|
||||
* [FIX] XGUI: Map icons not loading.
|
||||
* [FIX] XGUI: Ban menu bugfixes.
|
||||
* [CHANGE] Jail models. The jail is slightly bigger and can't be shot through anymore (Thanks Mors-Quaedam).
|
||||
* [CHANGE] Updated PvP damage cvar to reflect Garry's changes (Thanks Mors-Quadam).
|
||||
* [CHANGE] "ulx gag" now uses a server-side hook (much more robust).
|
||||
|
||||
v3.60 - *(01/27/13)*
|
||||
* [ADD] "ulx jailtp" - A combination of tp <player> and jail <player> (Thanks HellFox).
|
||||
* [ADD] "ulx resettodefaults" - Resets ULX and ULib config to defaults.
|
||||
* [ADD] XGUI: Added ability to edit lower-level restrictions from a higher-level group.
|
||||
* [CHANGE] ULX ban now supports restricting of time/string formats.
|
||||
* [CHANGE] !teleport chat command is now also aliased as !tp.
|
||||
* [CHANGE] XGUI: Utilizes ULib's more robust ID Targeting system.
|
||||
* [CHANGE] XGUI: Controls added to utilize time/string formats and restrictions.
|
||||
* [CHANGE] XGUI: No longer duplicates ULX replicated cvars (ulx_cl_) due to ULib changes. Uses the regular ulx_ cvars directly.
|
||||
* [CHANGE] XGUI: Supports new values for sv_alltalk.
|
||||
* [CHANGE] XGUI: A few changes to update look and feel. Matches Derma/GWEN skin colors better in some areas.
|
||||
* [CHANGE] XGUI: No longer retrieves sandbox limits from the web. Included with download.
|
||||
* [FIX] Garry breakages in GM13.
|
||||
* [FIX] An exclusivity bug in "ulx freeze" (Thanks infinitywraith).
|
||||
* [FIX] A console bug when trying to ulx teleport another player (Thanks infinitywraith).
|
||||
* [FIX] "ulx gimp" not obeying chat anti-spam (Thanks ruok2bu).
|
||||
* [FIX] "ulx userdeny" not logging properly in some cases.
|
||||
* [FIX] An echo incorrectly going to all users for "ulx votekick" (Thanks JackYack13).
|
||||
* [FIX] Module cross-contamination in end.lua (Thanks Pon-3).
|
||||
* [FIX] Team vs public chat doing the opposite of what it should for logs and "/me" actions. Wonder how long ago Garry needlessly changed that API without us noticing.
|
||||
* [FIX] Promotion bug after using "ulx userallow" on a regular user. (Thanks JackYack13).
|
||||
* [FIX] Server crash when jail is placed inside trigger_remove brush. (Thanks HellFox).
|
||||
* [FIX] XGUI: Changed startup code to initialize faster, handle strange server load scenarios better.
|
||||
* [FIX] XGUI: BoolArgs in the Cmds tab now obey restrictions.
|
||||
|
||||
v3.54 - *(04/27/12)*
|
||||
* [FIX] XGUI: Hard crash with the os.date function when bans have an extremely long unban time.
|
||||
|
||||
v3.53 - *(01/01/12)*
|
||||
* [FIX] Garry breakages.
|
||||
|
||||
v3.52 - *(09/22/11)*
|
||||
* [ADD] Support for "time strings" in ulx ban and ulx banid. EG, "5w4d3h2" would ban for 5 weeks, 4 days, 3 hours, 2 minutes (Thanks lavacano201014).
|
||||
* [ADD] XGUI: New customization options-- You can now change XGUI's position and the open/close animations.
|
||||
* [ADD] XGUI: Double-click a player on the commands tab to execute the command with the parameters on the right.
|
||||
* [ADD] XLIB: Additional layout for xlib.makecolorpicker with alphabar.
|
||||
* [FIX] No longer able to make a player invincible by freezing then mauling.
|
||||
* [FIX] XGUI: Selected svsetting/clsetting modules no longer close when XGUI modules get reprocessed.
|
||||
* [FIX] XGUI: Error caused when a bans unban time was changed, causing the ban to expire.
|
||||
* [FIX] XGUI: Adding details to SBans would throw an error on server, wouldn't refresh on clients properly.
|
||||
* [FIX] XGUI: Expired bans were not removing themselves from the client lists.
|
||||
* [FIX] XGUI: Somehow managed to duplicate the entire bans module code within the same file. X|
|
||||
* [FIX] XGUI: Rare error causing votemap settings to not load properly (which was previously fixable after a mapchange)
|
||||
* [FIX] XGUI: Non-harmful Lua error occuring during data transfer when running XGUI on a non-sandbox game mode. (Thanks Synergy Connections!)
|
||||
* [FIX] XGUI: The button for scrolling through tab names of settings modules (if there were too many) was being obscured by the close button. (Thanks [eVo]Lead4u!)
|
||||
* [FIX] XGUI: UTeam information would be lost when changing UTeam settings on non sandbox-derived gamemodes
|
||||
* [FIX] XGUI: DNumberWangs on color panels being extra long (due to garry update?)
|
||||
* [FIX] XGUI: ULib team data not sent after making changes to teams.
|
||||
* [FIX] XGUI: Users in the groups tab were not being updated when a group was removed and users in that group were moved to a new group.
|
||||
* [FIX] XGUI: Issue where a group's team wasn't getting unassigned when the unassigned team had no more groups associated with it.
|
||||
* [FIX] XGUI: Players' UTeam parameters update properly when their group is changed by addons that call ULib's addUser/removeUser functions directly.
|
||||
* [FIX] XGUI: In the groups menu, when selecting a player and clicking "change", the list of groups was not in inherited-based order.
|
||||
* [FIX] XGUI: Users table was pointlessly being sent when a groups inheritance was changed.
|
||||
* [CHANGE] "ulx gag" uses a slightly more robust method of gagging now.
|
||||
* [CHANGE] Using file.Append for logging now that it's available to us.
|
||||
* [CHANGE] XGUI: "XGUI module" is now the "Clientside Settings Module", which contains the XGUI settings.
|
||||
* [CHANGE] XGUI: Optimized sending of ULib users data-- Only sends the data when it needs to (no longer on UCLChanged), and when changed, only sends the updated info.
|
||||
* [CHANGE] XGUI: Optimized client-side processing of users data, how often it updated, and lowered priority of users data processing.
|
||||
* [CHANGE] XGUI: Added a data chunksize to users to help alleviate some major lag issues on servers with large users lists.
|
||||
* [CHANGE] XGUI: The Groups module shows some useful stuff in the event that it wasn't able to grab data from the server.
|
||||
* [CHANGE] XGUI: Modifying UTeam settings is now disabled on non sandbox-derived gamemodes.
|
||||
* [CHANGE] XGUI: Serverside xgui.removeData much more more robust.
|
||||
* [REMOVE] XGUI: xgui_oldcheck.lua (No longer checks for a pre-svn version of XGUI installed.)
|
||||
|
||||
v3.51 - *(05/14/11)*
|
||||
* [FIX] XGUI: Votemaps and kick/ban reasons not getting refreshed properly.
|
||||
* [FIX] XGUI: Ban menu was incorrectly visible to everyone.
|
||||
|
||||
v3.50 - *(05/13/11)*
|
||||
* [ADD] Autocomplete to ulx playsound.
|
||||
* [ADD] Hook, "ULXLoaded".
|
||||
* [ADD] Documentation for new keywords to "ulx help". Keywords for target self, target group, target picker, and negate.
|
||||
* [ADD] Ability to specify a URL in "ulx showMotd" to show a URL.
|
||||
* [ADD] ulx removeuserid, userallowid, userdenyid.
|
||||
* [ADD] Integrated UTeam.
|
||||
* [ADD] Colored action echoes.
|
||||
* [ADD] ulx logJoinLeaveEchoes to echo player steamid's to admins when players join and leave.
|
||||
* [FIX] Problem when ulx votemapMintime or votemapWaittime was more than 59 minutes (Thanks Stickly Man!).
|
||||
* [FIX] Improved error checking on "ulx ent" (Thanks Python1320).
|
||||
* [FIX] Error when running "ulx whip" from dedicated console (Thanks AtomicSpark).
|
||||
* [FIX] Can no longer use "ulx motd" if the server has motd disabled, made it so you can change "ulx showMotd" on-the-fly (Thanks AtomicSpark).
|
||||
* [FIX] "ulx groupallow" error when used from outside the server console (Thanks AtomicSpark).
|
||||
* [FIX] ULX done loading hook removal on listen servers (Thanks Stickly Man!).
|
||||
* [FIX] Fixed "ulx unspectate" not working in DarkRP (Thanks Ayran).
|
||||
* [FIX] Fixed "ulx unragdoll" not working in DarkRP (Thanks Ayran).
|
||||
* [FIX] Fixed an issue with dying while frozen (Thanks Stickly Man!).
|
||||
* [FIX] Can't repeatedly slay someone anymore.
|
||||
* [FIX] Can't attempt to ban a bot anymore (Thanks Stickly Man!).
|
||||
* [FIX] Asay being printed to console twice if the console used the command.
|
||||
* [FIX] Ragdolling a player with the Eli Vance model no longer throws an error (Thanks Insano-Man).
|
||||
* [FIX] Admin approval box timing out and not allowing any more votes to be taken (Thanks Rambomst).
|
||||
* [FIX] Various garry breakages.
|
||||
* [FIX] A bug with ulx whip where a timer would never be removed if the player left during whipping.
|
||||
* [FIX] Can no longer ragdoll a dead person (Thanks RiftNinja).
|
||||
* [FIX] Jails are much more robust (if you get out, it puts you back, and you can't get physgunned out) (Thanks RiftNinja).
|
||||
* [FIX] Can no longer slay frozen players (Thanks RiftNinja).
|
||||
* [FIX] Can no longer whip or slap frozen players, and freezing a whipped player stops the whip (Thanks Stickly Man!).
|
||||
* [CHANGE] Usermanagement commands, ulx who, and various other functions to better take advantage of the new UCL system
|
||||
* [CHANGE] ulx ignite no longer spreads. Spreading messed up UPS protection.
|
||||
* [CHANGE] Lots of various accessibility changes for XGUI.
|
||||
* [CHANGE] Lowered priority of gimp check, you can now ungimp yourself while gimped.
|
||||
* [CHANGE] Replaced cvar implementation for XGUI. Uses replicated cvars now for easy menu access.
|
||||
* [CHANGE] Errors now show in red.
|
||||
* [CHANGE] "ulx ent" can now be undone using garry's undo system.
|
||||
* [CHANGE] Dropped requirement to read usermanagementhelp before using those commands.
|
||||
* [CHANGE] Player isn't allowed to suicide while in a lot of the different ulx-states now.
|
||||
* [CHANGE] Lots of changes to support new command system.
|
||||
* [CHANGE] Moved config system to data folder, separated out some of the configs to separate files.
|
||||
* [CHANGE] Shortened maul time considerably.
|
||||
* [CHANGE] Added ability to get the return of ulx luarun by using '=', IE "ulx luarun =2+2" (also handles tables!).
|
||||
* [CHANGE] Added uid to debuginfo.
|
||||
* [CHANGE] tsay and csay now log who used the command.
|
||||
* [CHANGE] Can specify '-1' to ulx logSpawnsEcho to disable echoing to dedicated console.
|
||||
* [CHANGE] ulx adduser will use your existing id you're currently authed by if it exists, instead of always using steam id.
|
||||
* [REMOVE] ulx ghost, I was never happy with it.
|
||||
* [REMOVE] Old menus, uses XGUI now.
|
||||
|
||||
v3.40 - *(06/20/09)*
|
||||
* [ADD] Alltalk to the admin menu
|
||||
* [FIX] Umsgs being sent too early in certain circumstances.
|
||||
* [FIX] The .ini files not loading properly on listen servers.
|
||||
* [FIX] Problems introduced by garry's changes in handling concommands
|
||||
* [FIX] Changed ULX_README.TXT file to point to proper instruction link for editing Gmod default users.
|
||||
* [FIX] Removed a patch for a garrysmod autocomplete bug that's now fixed.
|
||||
* [FIX] Maps not being sent correctly to the client.
|
||||
* [FIX] Can't create a vote twice anymore.
|
||||
* [FIX] A bug with loading the map list on listen server hosts.
|
||||
* [FIX] An unfreeze bug with the ulx jail walls.
|
||||
* [FIX] A caps bug with ulx adduserid.
|
||||
* [FIX] You can now unragdoll yourself even if a third party addon removes the ragdoll.
|
||||
* [FIX] Various formatting issues with ulx ban and ulx banid.
|
||||
* [CHANGE] ulx ragdoll and unragdoll now preserve angle and velocity.
|
||||
* [CHANGE] motdfile cvar now defaults to ulx_motd.txt. Sick of forcefully overriding other mod's motds. Renamed our motd to match.
|
||||
* [CHANGE] ulx slap, whip, hp to further prevent being "stuck in ground".
|
||||
* [CHANGE] Menus are derma'tized.
|
||||
* [CHANGE] Updated how it handles svn version information.
|
||||
|
||||
v3.31 - *(06/08/08)*
|
||||
* [ADD] ulx adduserid - Add a user by steam id (ie STEAM_0:1:1234...) (Does not actually verify user validity) (Thanks Mr.President)
|
||||
* [FIX] Garry's 1/29/08 update breaking MOTD.
|
||||
* [FIX] Links not working on MOTD.
|
||||
* [FIX] Bug where you'd be stuck if someone disconnected while you were spectating them.
|
||||
* [FIX] TF2 motd showing by default.
|
||||
* [FIX] The usual assortment of small fixes not worth mentioning.
|
||||
* [CHANGE] Unignite help command changed to be more standardized with other help.
|
||||
* [CHANGE] Help indicates that multiple users can now also be command targeted using an asterisk "*". (ULib change added this)
|
||||
* [CHANGE] Miscellaneous spelling corrections.
|
||||
* [CHANGE] ulx chattime so that if your chat doesn't go through it is not counted towards your time.
|
||||
* [CHANGE] Can no longer set hp or armor to less than 0.
|
||||
* [REMOVE] ulx mingekick, useless now.
|
||||
|
||||
v3.30 - *(01/26/08)*
|
||||
* [ADD] ulx strip - Strips player(s) weapons
|
||||
* [ADD] ulx armor - Sets player(s) armor
|
||||
* [ADD] We now log NPC spawns
|
||||
* [ADD] ulx unignite - Unignites individual player, <all> players, or <everything> Any entity/player on fire.
|
||||
* [FIX] ulx ban requiring a reason.
|
||||
* [FIX] Added some more sanity checks to ulx maul.
|
||||
* [FIX] The usual assortment of small fixes not worth mentioning.
|
||||
* [FIX] ulx usermanagementhelp erroring out.
|
||||
* [FIX] .ini's not loading for listen servers.
|
||||
* [FIX] Case sensitivity problem with addgroup and removegroup.
|
||||
* [FIX] ulx ent incorrectly requiring at least one flag.
|
||||
* [FIX] All command inputs involving numbers should now be sanitized.
|
||||
* [FIX] Autocomplete send in a multi-layer authentication environment (probably doesn't affect anyone)
|
||||
* [CHANGE] The 0-255 scale for "ulx cloak" has been reversed.
|
||||
* [CHANGE] Model paths in logging is now standardized (linux notation, single slashes)
|
||||
* [CHANGE] The user initiating a silent logged command still sees the echo, even if they don't have access to see it normally.
|
||||
* [CHANGE] Various misc things for new engine compatibility (IE, ulx clientmenu got a major change and other menu changes)
|
||||
* [CHANGE] Removed all timers dealing with initialization and now rely on flags from the client. This makes the ULX initialization much more dependable.
|
||||
* [CHANGE] Name change watching is now taken care of by ULib.
|
||||
* [CHANGE] Converted all calls from ULib.consoleCommand( "exec ..." ) to ULib.execFile() to avoid running into the block on "exec" without our module.
|
||||
|
||||
|
||||
v3.20 - *(09/23/07)*
|
||||
* [ADD] ulx send - Allows admin to transport a player to another player (no more goto then bring!)
|
||||
* [ADD] ulx maul - Maul a player with fast zombies
|
||||
* [ADD] ulx gag - Silence individual player's microphone/sound input on voice enabled servers.
|
||||
* [ADD] New module system. It's now easier than ever to add, remove, or change ULX commands!
|
||||
* [ADD] ulx.addToMenu(). Use this function if you want a module to add something to any of the ULX menu.
|
||||
* [ADD] ulx debuginfo. Use this function to get information to give us when you're asking support questions.
|
||||
* [ADD] Votes now have a background behind them.
|
||||
* [ADD] ulx voteEcho. A config option to enable echo of votes. Does not apply to votemap.
|
||||
* [ADD] Maps menu now has option for gamemode.
|
||||
* [ADD] Ban menu to view and remove bans.
|
||||
* [ADD] ulx removeruser, addgroup, removegroup, groupallow, groupdeny, usermanagementhelp
|
||||
* [FIX] ulx whip - No longer allows multiple whip sessions of an individual player at same time.
|
||||
* [FIX] ulx adduser - You no longer have to reconnect to get given access.
|
||||
* [FIX] Vastly improved ulx send, goto, and teleport. You should never get stuck in anything ever again.
|
||||
* [FIX] Various initialization functions trying to access a disconnected player
|
||||
* [FIX] Vastly improved reserved slots
|
||||
* [FIX] Can't spawn junk or suicide while frozen now.
|
||||
* [FIX] Coming out of spectate keeps god mode (if the player was given god with "ulx god")
|
||||
* [FIX] Can't use "ulx hp" to give 100000+ hp anymore (crashes players with default HUD).
|
||||
* [FIX] If you're authed twice, you won't get duplicates in autocomplete
|
||||
* [FIX] ulx votemapmapmode and votemapaddmap not working
|
||||
* [CHANGE] /me <action> can now be used in ulx asay/chat @ admin chat. "@ /me bashes spammer over the head"
|
||||
* [CHANGE] Commands that used player:spawn (ragdoll,spectate, more) now return player to health/armor they had previously.
|
||||
* [CHANGE] ulx teleport. Can now teleport a player to where you are looking. Logs it if a player is specified.
|
||||
* [CHANGE] You can now specify entire directories in ulx addForcedDownload
|
||||
* [CHANGE] A few internal changes to the ULX base to compliment the new ULib UCL access string system
|
||||
* [CHANGE] ULX echoes come after the command now.
|
||||
* [CHANGE] Configs are now under /cfg/* instead of /lua/ulx/configs/*
|
||||
* [CHANGE] bring goto and teleport now zero out your velocity after moving you.
|
||||
* [CHANGE] bring and goto can now still move you when you would get stuck if you're noclipped.
|
||||
* [CHANGE] A hidden echo that is still shown to admins is now clearly labeled as such.
|
||||
* [CHANGE] ulx cexec now takes multiple targets. (This was the intended behavior)
|
||||
* [CHANGE] Lots of minor tweaks that would take too long to list. ;)
|
||||
* [CHANGE] All say commands require spaces after them except the "@" commands. (IE, "!slapbob" no longer slaps bob)
|
||||
* [CHANGE] Access to physgun players now uses the access string "ulx physgunplayer"
|
||||
* [CHANGE] Access to reserved slots now uses the access string "ulx reservedslots"
|
||||
* [CHANGE] Complete rewrite of advert system. You probably won't notice any difference (except hostname fix), but the code is leaner and meaner.
|
||||
* [CHANGE] No interval option for ulx whip anymore, too easy to abuse.
|
||||
* [CHANGE] Menus now use derma
|
||||
* [CHANGE] The ULX configs should now really and truly load after the default configs
|
||||
* [CHANGE] Votemap, votekick, voteban now all require the approval of the admin that started the vote if it wins.
|
||||
* [CHANGE] Voteban can now receive a parameter for ban time.
|
||||
* [CHANGE] ulx map can now receive gamemode for a parameter.
|
||||
* [CHANGE] You can now use newlines in adverts.
|
||||
* [CHANGE] Dropped requirement of being at least an opper for userallow/deny
|
||||
* [CHANGE] ulx who has an updated format that includes custom groups.
|
||||
* [CHANGE] ulx help is now categorized. (Reserved slots, teleportation, chat, etc )
|
||||
* [CHANGE] ulx thetime can now only be used once every minute (server wide)
|
||||
|
||||
v3.11 - *(06/19/07)*
|
||||
* [FIX] ulx vote. No longer public, people can't vote more than once, won't continue to hog the binds.
|
||||
* [FIX] rslots will now set rslots on dedicated server start
|
||||
* [FIX] Bring/goto getting you stuck in player sometimes.
|
||||
* [FIX] Can't use vehicles from inside a jail now.
|
||||
* [CHANGE] bring and goto now place teleporting player behind target
|
||||
* [CHANGE] Upped votemapMinvotes to 3 (was 2).
|
||||
* [CHANGE] Player physgun now only works in sandbox, lower admins can't physgun immune admins, freezes player while held.
|
||||
* [CHANGE] Unblocked custom groups from ulx adduser.
|
||||
|
||||
v3.10 - *(05/05/07)*
|
||||
* [ADD] Admins with slap access can move players now.
|
||||
* [ADD] Chat anti-spam
|
||||
* [ADD] ulx addForcedDownload for configs
|
||||
* [ADD] Per-gamemode config folder
|
||||
* [ADD] Voting! ulx vote, ulx votemap2, ulx voteban, ulx votekick
|
||||
* [ADD] Maps menu
|
||||
* [ADD] Lots more features to logging, like object spawn logging.
|
||||
* [ADD] Reserved slots
|
||||
* [FIX] Lots of minor insignificant bugs
|
||||
* [FIX] Jail issues
|
||||
* [FIX] Logging player connect on dedicated server issues
|
||||
* [FIX] Now takes advantage of fixed umsgs. Fixes rare crash.
|
||||
* [FIX] Can now psay immune players
|
||||
* [FIX] Minor bugs in logs
|
||||
* [CHANGE] Logs will now wrap to new date if server's on past midnight
|
||||
* [CHANGE] You can now use the admin menu in gamemodes derived from sandbox.
|
||||
* [CHANGE] Cleaned up now obsolete GetTable() calls
|
||||
* [CHANGE] Motd is now driven by lua. Much easier to deal with, fixes many problems.
|
||||
* [CHANGE] Can now use sv_cheats 1/0 from ulx rcon (dodges block)
|
||||
* [CHANGE] ulx lua_run is now ulx luarun to dodge another block
|
||||
* [CHANGE] Now in addon format
|
||||
* [CHANGE] ulx ignite will now last until you die and can spread.
|
||||
* [CHANGE] Global toolmode deny doesn't affect admins.
|
||||
|
||||
v3.02 - *(01/10/07)*
|
||||
* [CHANGE] Admin menu won't spam console so bad now
|
||||
* [FIX] Some more command crossbreeding issues (IE ragdolling jailed player)
|
||||
* [FIX] Teleport commands able to put someone in a wall. This is still possible, but much less likely.
|
||||
* [ADD] Motd manipulation. Auto-shows on startup and !motd
|
||||
* [ADD] toolallow, tooldeny, tooluserallow, tooluserdeny. Works fine, but is EXPERIMENTAL!
|
||||
|
||||
v3.01 - *(01/07/07)*
|
||||
* [ADD] ulx whip
|
||||
* [ADD] ulx adduser
|
||||
* [ADD] ulx userallow - Allow users access to commands
|
||||
* [ADD] ulx userdeny - Deny users access to commands
|
||||
* [ADD] ulx bring - Bring a user to you
|
||||
* [ADD] ulx goto - Goto a user
|
||||
* [ADD] ulx teleport - Teleport to where you're looking
|
||||
* [ADD] IRC-style "/me" command
|
||||
* [FIX] You can't use the adminmenu outside sandbox now
|
||||
* [FIX] Vastly improved "ulx jail"
|
||||
* [FIX] Improved "ulx ragdoll"
|
||||
* [FIX] pvp damage checkbox in adminmenu not working.
|
||||
* [FIX] Ban button
|
||||
* [FIX] Ban not kicking users
|
||||
* [FIX] Blinded users being able to see through the camera tool
|
||||
* [FIX] Admin menu not showing values on a dedicated server
|
||||
* [FIX] Admin menu checkboxes (which are now buttons!)
|
||||
* [FIX] Ulx commands much more usable from dedicated server console.
|
||||
* [FIX] Dedicated server spam (IsListenServerHost)
|
||||
* [FIX] Uncloak works properly now
|
||||
* [FIX] Various problems using commands on users in vehicles. (Thanks Jalit)
|
||||
|
||||
v3.0 - *(01/01/07)*
|
||||
* Initial version for GM10
|
||||
|
||||
Group: Credits
|
||||
|
||||
Thanks to everyone in #ulysses in irc.gamesurge.net for not giving up on me :)
|
||||
A big thanks to JamminR for listening to me ramble on and for giving the project fresh insights.
|
||||
|
||||
Group: License
|
||||
|
||||
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License.
|
||||
To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to
|
||||
Creative Commons
|
||||
543 Howard Street
|
||||
5th Floor
|
||||
San Francisco, California 94105
|
||||
USA
|
||||
Title: ULX Readme
|
||||
|
||||
__ULX__
|
||||
Version 3.70
|
||||
|
||||
*ULX v3.70 (released 00/00/00)*
|
||||
|
||||
ULX is an admin mod for GMod (<http://garrysmod.com/>).
|
||||
|
||||
ULX offers server admins an AMXX-style support. It allows multiple admins with different access levels on the same server.
|
||||
It has features from basic kick, ban, and slay to fancier commands such as blind, freeze, voting, and more.
|
||||
|
||||
Visit our homepage at <http://ulyssesmod.net/>.
|
||||
|
||||
You can talk to us on our forums at <http://forums.ulyssesmod.net/>
|
||||
|
||||
Group: Author
|
||||
|
||||
ULX is brought to you by..
|
||||
|
||||
* Brett "Megiddo" Smith - Contact: <megiddo@ulyssesmod.net>
|
||||
* JamminR - Contact: <jamminr@ulyssesmod.net>
|
||||
* Stickly Man! - Contact: <sticklyman@ulyssesmod.net>
|
||||
* MrPresident - Contact: <mrpresident@ulyssesmod.net>
|
||||
|
||||
Group: Requirements
|
||||
|
||||
ULX requires the latest ULib to be installed on the server. You can get ULib from the ULX homepage.
|
||||
|
||||
Group: Installation
|
||||
|
||||
To install ULX, simply extract the files from the archive to your garrysmod/addons folder.
|
||||
When you've done this, you should have a file structure like this--
|
||||
<garrysmod>/addons/ulx/lua/ULib/modules/ulx_init.lua
|
||||
<garrysmod>/addons/ulx/lua/ulx/modules/fun.lua
|
||||
etc..
|
||||
|
||||
Note that installation for dedicated servers is EXACTLY the same!
|
||||
|
||||
You absolutely, positively have to do a full server restart after installing the files. A simple map
|
||||
change will not cut it!
|
||||
|
||||
Group: Usage
|
||||
|
||||
To use ULX, simply type in whatever command or cvar you want to use. If you're not running a listen server,
|
||||
or if you want to give access to other users, you must add users.
|
||||
|
||||
You can either follow the standard gmod way of adding users
|
||||
(http://maurits.tv/data/garrysmod/wiki/wiki.garrysmod.com/index0c18.html?title=Player_Groups), or you can add yourself directly to the
|
||||
data/ulib/users.txt file. DO NOT EDIT THE ULIB FILE UNLESS YOU KNOW WHAT YOU'RE DOING.
|
||||
|
||||
A word about superadmins: Superadmins are considered the highest usergroup. They have access to all the
|
||||
commands in ULX, override other user's immunity, and are shown otherwise hidden log messages (IE, shown
|
||||
rcon commands admins are running, when they spectate others). Superadmins also have the power to give and
|
||||
revoke access to commands using userallow and userdeny (though they can't use this command on eachother).
|
||||
|
||||
All commands are preceded by "ulx ". Type "ulx help" in a console without the quotes for help.
|
||||
|
||||
__To give yourself a jump start into ulx, simply remember the commands "ulx help" and "ulx menu". You can
|
||||
also access the menu by saying "!menu".__
|
||||
|
||||
Check out the configs folder in ulx for some more goodies.
|
||||
|
||||
Group: Changelog
|
||||
v3.70 - *(00/00/00)*
|
||||
* [ADD] XGUI: Ability to set the 'nextlevel' cvar from the maps tab, if you have access to "ulx map".
|
||||
* [ADD] Reason to votekick log (Thanks, CSchulz).
|
||||
* [ADD] Steam ID parameter to "ulx who" to lookup users by Steam ID.
|
||||
* [ADD] Cvar "ulx meChatEnabled" added to enable or disable the /me chat feature, or set it to Sandbox only.
|
||||
* [ADD] XGUI: Added methods for developers to be able to open a specific client or server setting module.
|
||||
* [FIX] The usual random slew of Garry-breakages (Thanks, Fuzzik).
|
||||
* [FIX] Changing weapons while cloaked would keep them hidden when uncloaked. (Thanks, TheRealAyCe).
|
||||
* [FIX] XGUI: Error if the default settings/users.txt file was missing.
|
||||
* [FIX] Gamemode list includes workshop addons now (Thanks, jason2010).
|
||||
* [FIX] "ulx ent" parameter parsing (Thanks, Zombine).
|
||||
* [FIX] "ulx voteban" can now ban the user even if they disconnect after the vote starts.
|
||||
* [FIX] Vote commands now work properly from server console.
|
||||
* [FIX] XGUI: Numerous issues with selecting a custom Derma/GWEN skin.
|
||||
* [FIX] XGUI: Clientside settings would not save if the client's data/ulx folder did not exist.
|
||||
* [FIX] Improved how well ULX/XGUI files and XGUI clientside/serverside modules handle being autorefreshed.
|
||||
* [FIX] ulx.addToHelpManually now checks for and removes and previously added manual help entries with the same command name.
|
||||
* [FIX] XGUI: Bug where ulx_showMotd cvar would not be updated properly when changed by someone else.
|
||||
* [FIX] XGUI: Minor performance exploit involving serverside ban sorting. (Thanks, TomatoCo).
|
||||
* [FIX] Exploit involving gmod filesystem mounting. (Thanks, Willox).
|
||||
* [FIX] Minor issue where opposite commands might not be run due to case sensitivity.
|
||||
* [FIX] Duplicate help entries due to autorefresh and overriding commands. (Thanks iSnipeu).
|
||||
* [FIX] Ragdolled players were getting removed on map cleanup.
|
||||
* [FIX] XGUI: Server error in some cases when sorting bans by Unban Date after a new ban has been added.
|
||||
* [CHANGE] MOTD now uses DHTML (Awesomium framework).
|
||||
* [CHANGE] Hook calls to match ULib's new format.
|
||||
* [CHANGE] ULX convar updates will now append an entry to data/config.txt if it is not defined in the file. Previously, these changes would not be saved.
|
||||
* [CHANGE] XGUI: No longer autoexecutes skins to ensure they have been installed.
|
||||
* [CHANGE] XGUI: Added "name" parameter to xgui.hookEvent to prevent event duplication. (Aids with autorefresh, is backwards compatible with old XGUI modules)
|
||||
* [CHANGE] XGUI: Modules that no longer exist will be removed from the customizable sort order.
|
||||
* [CHANGE] XGUI: Sliders for arguments on the Cmds tab with a small min/max delta (e.g. from 0 to 1) will now allow up to 2 decimal places, if the arg does not have cmds.round flag.
|
||||
|
||||
v3.62 - *(03/09/15)*
|
||||
* [ADD] "ulx return" to return target to previous location they were in before a teleport command was used (Thanks for the idea, ludalex).
|
||||
* [ADD] Networked variables for gimp, mute, and gag (Thanks iSnipeu).
|
||||
* [ADD] XGUI: Added more sorting and filtering options for bans.
|
||||
* [ADD] "ulx stopvote" to stop a vote currently in progress (Thanks, LuaTenshi).
|
||||
* [ADD] XGUI: Added "onClose" event for modules that need it. (Suggested by arduinium).
|
||||
* [FIX] Ban reason and the person who started the voteban is now reported in "ulx voteban" bans (Thanks iSnipeu).
|
||||
* [FIX] An API change causing an error to be thrown at the end of "ulx maul" (Thanks Decicus).
|
||||
* [FIX] NULL entity error after votekick on a player that left the server, now sends message stating that votekicked player already left.
|
||||
* [FIX] PlayerDeath hook errors in certain gamemodes where invalid entites are sent as the killer or victim. (Thanks Mechanical Mind).
|
||||
* [FIX] JailTP command now saves last player position, now works with "ulx return". (Thanks jakej78b).
|
||||
* [FIX] XGUI: Slider label widths were extra large due to a slight change in default numslider behavior. (Thanks Fuzzik).
|
||||
* [FIX] Garry's Mod update caused users to be banned faster than expected, log then incorrectly stated that (Console) was banned.
|
||||
* [FIX] Garry's Mod update prevented votebans from working.
|
||||
* [FIX] Garry's Mod update caused server crash when kicking/banning yourself via chat command.
|
||||
* [FIX] Bug with spectate and respawning (Thanks Sjokomelk).
|
||||
* [FIX] Bug when changing weapons while cloaked, weapons would stay invisible after uncloaking. (Thanks Z0mb1n3).
|
||||
* [FIX] Could not assign BOTs to groups via ulx adduserid or XGUI. (Thanks RhapsodySL).
|
||||
* [FIX] Fixed bug where XGUI would not start on dev branch of Garry's Mod. Changed to init on ULib.HOOK_LOCALPLAYERREADY instead of ULib.HOOK_UCLAUTH.
|
||||
* [FIX] MOTD not enabled message would display for all players instead of the player who tried to open the motd. (Thanks TheClonker).
|
||||
* [CHANGE] "PlayerSay" hooks are now only called serverside. (Thanks NoBrainCZ).
|
||||
* [CHANGE] Logging now prints how long a user took to join the server.
|
||||
* [CHANGE] XGUI: Updated cvarlist for sandbox and wiremod limits.
|
||||
* [CHANGE] XGUI: Many Ban menu improvements. Entire banlist is no longer sent on join- data subset is now requested by the client and sent from the server.
|
||||
* [CHANGE] XGUI: Ban list is now paginated instead of a giant scrollable list.
|
||||
* [CHANGE] XGUI: ULX Bans and other (or "Source Bans") are no longer separated.
|
||||
* [CHANGE] ULX vote variable is now global so other addons can tell if a vote is in progress. ulx.doVote() also returns whether or not it actually started a vote (Thanks for the ideas, arduinium).
|
||||
* [CHANGE] XGUI: Changed gamemode dropdown on maps tab to honor player/group restrictions. (Thanks chaos12135).
|
||||
|
||||
v3.61 - *(08/30/13)*
|
||||
* [ADD] cl_pickupplayers (defaults to 1) to allow an admin to disable the ability to pickup players (so they don't do it on accident). Done in collaboration with FPtje.
|
||||
* [ADD] %curmap% and %steamid% variables in "ulx showMotd" URL for custom-served MOTDs (Thanks Mors-Quaedam).
|
||||
* [ADD] XGUI: Bans are now searchable. (Thanks to iSnipeu for the code contribution!)
|
||||
* [FIX] "#" (Pound signs) removing content in ulx asay (Thanks bener180).
|
||||
* [FIX] Reserved slot mode 3 not kicking the shortest connected player as it is supposed to (Thanks monkstick).
|
||||
* [FIX] No longer able to physgun frozen players (Thanks ms333).
|
||||
* [FIX] XGUI: Added checks to prevent admins from being able to edit ban information past their restrictions (Thanks Zaph).
|
||||
* [FIX] XGUI: Infobar text no longer displaying.
|
||||
* [FIX] XGUI: Error caused when closing the fban window after the targeted player has left the server (Thanks nathan736).
|
||||
* [FIX] XGUI: Issues with handling min / max number restrictions.
|
||||
* [FIX] XGUI: Map icons not loading.
|
||||
* [FIX] XGUI: Ban menu bugfixes.
|
||||
* [CHANGE] Jail models. The jail is slightly bigger and can't be shot through anymore (Thanks Mors-Quaedam).
|
||||
* [CHANGE] Updated PvP damage cvar to reflect Garry's changes (Thanks Mors-Quadam).
|
||||
* [CHANGE] "ulx gag" now uses a server-side hook (much more robust).
|
||||
|
||||
v3.60 - *(01/27/13)*
|
||||
* [ADD] "ulx jailtp" - A combination of tp <player> and jail <player> (Thanks HellFox).
|
||||
* [ADD] "ulx resettodefaults" - Resets ULX and ULib config to defaults.
|
||||
* [ADD] XGUI: Added ability to edit lower-level restrictions from a higher-level group.
|
||||
* [CHANGE] ULX ban now supports restricting of time/string formats.
|
||||
* [CHANGE] !teleport chat command is now also aliased as !tp.
|
||||
* [CHANGE] XGUI: Utilizes ULib's more robust ID Targeting system.
|
||||
* [CHANGE] XGUI: Controls added to utilize time/string formats and restrictions.
|
||||
* [CHANGE] XGUI: No longer duplicates ULX replicated cvars (ulx_cl_) due to ULib changes. Uses the regular ulx_ cvars directly.
|
||||
* [CHANGE] XGUI: Supports new values for sv_alltalk.
|
||||
* [CHANGE] XGUI: A few changes to update look and feel. Matches Derma/GWEN skin colors better in some areas.
|
||||
* [CHANGE] XGUI: No longer retrieves sandbox limits from the web. Included with download.
|
||||
* [FIX] Garry breakages in GM13.
|
||||
* [FIX] An exclusivity bug in "ulx freeze" (Thanks infinitywraith).
|
||||
* [FIX] A console bug when trying to ulx teleport another player (Thanks infinitywraith).
|
||||
* [FIX] "ulx gimp" not obeying chat anti-spam (Thanks ruok2bu).
|
||||
* [FIX] "ulx userdeny" not logging properly in some cases.
|
||||
* [FIX] An echo incorrectly going to all users for "ulx votekick" (Thanks JackYack13).
|
||||
* [FIX] Module cross-contamination in end.lua (Thanks Pon-3).
|
||||
* [FIX] Team vs public chat doing the opposite of what it should for logs and "/me" actions. Wonder how long ago Garry needlessly changed that API without us noticing.
|
||||
* [FIX] Promotion bug after using "ulx userallow" on a regular user. (Thanks JackYack13).
|
||||
* [FIX] Server crash when jail is placed inside trigger_remove brush. (Thanks HellFox).
|
||||
* [FIX] XGUI: Changed startup code to initialize faster, handle strange server load scenarios better.
|
||||
* [FIX] XGUI: BoolArgs in the Cmds tab now obey restrictions.
|
||||
|
||||
v3.54 - *(04/27/12)*
|
||||
* [FIX] XGUI: Hard crash with the os.date function when bans have an extremely long unban time.
|
||||
|
||||
v3.53 - *(01/01/12)*
|
||||
* [FIX] Garry breakages.
|
||||
|
||||
v3.52 - *(09/22/11)*
|
||||
* [ADD] Support for "time strings" in ulx ban and ulx banid. EG, "5w4d3h2" would ban for 5 weeks, 4 days, 3 hours, 2 minutes (Thanks lavacano201014).
|
||||
* [ADD] XGUI: New customization options-- You can now change XGUI's position and the open/close animations.
|
||||
* [ADD] XGUI: Double-click a player on the commands tab to execute the command with the parameters on the right.
|
||||
* [ADD] XLIB: Additional layout for xlib.makecolorpicker with alphabar.
|
||||
* [FIX] No longer able to make a player invincible by freezing then mauling.
|
||||
* [FIX] XGUI: Selected svsetting/clsetting modules no longer close when XGUI modules get reprocessed.
|
||||
* [FIX] XGUI: Error caused when a bans unban time was changed, causing the ban to expire.
|
||||
* [FIX] XGUI: Adding details to SBans would throw an error on server, wouldn't refresh on clients properly.
|
||||
* [FIX] XGUI: Expired bans were not removing themselves from the client lists.
|
||||
* [FIX] XGUI: Somehow managed to duplicate the entire bans module code within the same file. X|
|
||||
* [FIX] XGUI: Rare error causing votemap settings to not load properly (which was previously fixable after a mapchange)
|
||||
* [FIX] XGUI: Non-harmful Lua error occuring during data transfer when running XGUI on a non-sandbox game mode. (Thanks Synergy Connections!)
|
||||
* [FIX] XGUI: The button for scrolling through tab names of settings modules (if there were too many) was being obscured by the close button. (Thanks [eVo]Lead4u!)
|
||||
* [FIX] XGUI: UTeam information would be lost when changing UTeam settings on non sandbox-derived gamemodes
|
||||
* [FIX] XGUI: DNumberWangs on color panels being extra long (due to garry update?)
|
||||
* [FIX] XGUI: ULib team data not sent after making changes to teams.
|
||||
* [FIX] XGUI: Users in the groups tab were not being updated when a group was removed and users in that group were moved to a new group.
|
||||
* [FIX] XGUI: Issue where a group's team wasn't getting unassigned when the unassigned team had no more groups associated with it.
|
||||
* [FIX] XGUI: Players' UTeam parameters update properly when their group is changed by addons that call ULib's addUser/removeUser functions directly.
|
||||
* [FIX] XGUI: In the groups menu, when selecting a player and clicking "change", the list of groups was not in inherited-based order.
|
||||
* [FIX] XGUI: Users table was pointlessly being sent when a groups inheritance was changed.
|
||||
* [CHANGE] "ulx gag" uses a slightly more robust method of gagging now.
|
||||
* [CHANGE] Using file.Append for logging now that it's available to us.
|
||||
* [CHANGE] XGUI: "XGUI module" is now the "Clientside Settings Module", which contains the XGUI settings.
|
||||
* [CHANGE] XGUI: Optimized sending of ULib users data-- Only sends the data when it needs to (no longer on UCLChanged), and when changed, only sends the updated info.
|
||||
* [CHANGE] XGUI: Optimized client-side processing of users data, how often it updated, and lowered priority of users data processing.
|
||||
* [CHANGE] XGUI: Added a data chunksize to users to help alleviate some major lag issues on servers with large users lists.
|
||||
* [CHANGE] XGUI: The Groups module shows some useful stuff in the event that it wasn't able to grab data from the server.
|
||||
* [CHANGE] XGUI: Modifying UTeam settings is now disabled on non sandbox-derived gamemodes.
|
||||
* [CHANGE] XGUI: Serverside xgui.removeData much more more robust.
|
||||
* [REMOVE] XGUI: xgui_oldcheck.lua (No longer checks for a pre-svn version of XGUI installed.)
|
||||
|
||||
v3.51 - *(05/14/11)*
|
||||
* [FIX] XGUI: Votemaps and kick/ban reasons not getting refreshed properly.
|
||||
* [FIX] XGUI: Ban menu was incorrectly visible to everyone.
|
||||
|
||||
v3.50 - *(05/13/11)*
|
||||
* [ADD] Autocomplete to ulx playsound.
|
||||
* [ADD] Hook, "ULXLoaded".
|
||||
* [ADD] Documentation for new keywords to "ulx help". Keywords for target self, target group, target picker, and negate.
|
||||
* [ADD] Ability to specify a URL in "ulx showMotd" to show a URL.
|
||||
* [ADD] ulx removeuserid, userallowid, userdenyid.
|
||||
* [ADD] Integrated UTeam.
|
||||
* [ADD] Colored action echoes.
|
||||
* [ADD] ulx logJoinLeaveEchoes to echo player steamid's to admins when players join and leave.
|
||||
* [FIX] Problem when ulx votemapMintime or votemapWaittime was more than 59 minutes (Thanks Stickly Man!).
|
||||
* [FIX] Improved error checking on "ulx ent" (Thanks Python1320).
|
||||
* [FIX] Error when running "ulx whip" from dedicated console (Thanks AtomicSpark).
|
||||
* [FIX] Can no longer use "ulx motd" if the server has motd disabled, made it so you can change "ulx showMotd" on-the-fly (Thanks AtomicSpark).
|
||||
* [FIX] "ulx groupallow" error when used from outside the server console (Thanks AtomicSpark).
|
||||
* [FIX] ULX done loading hook removal on listen servers (Thanks Stickly Man!).
|
||||
* [FIX] Fixed "ulx unspectate" not working in DarkRP (Thanks Ayran).
|
||||
* [FIX] Fixed "ulx unragdoll" not working in DarkRP (Thanks Ayran).
|
||||
* [FIX] Fixed an issue with dying while frozen (Thanks Stickly Man!).
|
||||
* [FIX] Can't repeatedly slay someone anymore.
|
||||
* [FIX] Can't attempt to ban a bot anymore (Thanks Stickly Man!).
|
||||
* [FIX] Asay being printed to console twice if the console used the command.
|
||||
* [FIX] Ragdolling a player with the Eli Vance model no longer throws an error (Thanks Insano-Man).
|
||||
* [FIX] Admin approval box timing out and not allowing any more votes to be taken (Thanks Rambomst).
|
||||
* [FIX] Various garry breakages.
|
||||
* [FIX] A bug with ulx whip where a timer would never be removed if the player left during whipping.
|
||||
* [FIX] Can no longer ragdoll a dead person (Thanks RiftNinja).
|
||||
* [FIX] Jails are much more robust (if you get out, it puts you back, and you can't get physgunned out) (Thanks RiftNinja).
|
||||
* [FIX] Can no longer slay frozen players (Thanks RiftNinja).
|
||||
* [FIX] Can no longer whip or slap frozen players, and freezing a whipped player stops the whip (Thanks Stickly Man!).
|
||||
* [CHANGE] Usermanagement commands, ulx who, and various other functions to better take advantage of the new UCL system
|
||||
* [CHANGE] ulx ignite no longer spreads. Spreading messed up UPS protection.
|
||||
* [CHANGE] Lots of various accessibility changes for XGUI.
|
||||
* [CHANGE] Lowered priority of gimp check, you can now ungimp yourself while gimped.
|
||||
* [CHANGE] Replaced cvar implementation for XGUI. Uses replicated cvars now for easy menu access.
|
||||
* [CHANGE] Errors now show in red.
|
||||
* [CHANGE] "ulx ent" can now be undone using garry's undo system.
|
||||
* [CHANGE] Dropped requirement to read usermanagementhelp before using those commands.
|
||||
* [CHANGE] Player isn't allowed to suicide while in a lot of the different ulx-states now.
|
||||
* [CHANGE] Lots of changes to support new command system.
|
||||
* [CHANGE] Moved config system to data folder, separated out some of the configs to separate files.
|
||||
* [CHANGE] Shortened maul time considerably.
|
||||
* [CHANGE] Added ability to get the return of ulx luarun by using '=', IE "ulx luarun =2+2" (also handles tables!).
|
||||
* [CHANGE] Added uid to debuginfo.
|
||||
* [CHANGE] tsay and csay now log who used the command.
|
||||
* [CHANGE] Can specify '-1' to ulx logSpawnsEcho to disable echoing to dedicated console.
|
||||
* [CHANGE] ulx adduser will use your existing id you're currently authed by if it exists, instead of always using steam id.
|
||||
* [REMOVE] ulx ghost, I was never happy with it.
|
||||
* [REMOVE] Old menus, uses XGUI now.
|
||||
|
||||
v3.40 - *(06/20/09)*
|
||||
* [ADD] Alltalk to the admin menu
|
||||
* [FIX] Umsgs being sent too early in certain circumstances.
|
||||
* [FIX] The .ini files not loading properly on listen servers.
|
||||
* [FIX] Problems introduced by garry's changes in handling concommands
|
||||
* [FIX] Changed ULX_README.TXT file to point to proper instruction link for editing Gmod default users.
|
||||
* [FIX] Removed a patch for a garrysmod autocomplete bug that's now fixed.
|
||||
* [FIX] Maps not being sent correctly to the client.
|
||||
* [FIX] Can't create a vote twice anymore.
|
||||
* [FIX] A bug with loading the map list on listen server hosts.
|
||||
* [FIX] An unfreeze bug with the ulx jail walls.
|
||||
* [FIX] A caps bug with ulx adduserid.
|
||||
* [FIX] You can now unragdoll yourself even if a third party addon removes the ragdoll.
|
||||
* [FIX] Various formatting issues with ulx ban and ulx banid.
|
||||
* [CHANGE] ulx ragdoll and unragdoll now preserve angle and velocity.
|
||||
* [CHANGE] motdfile cvar now defaults to ulx_motd.txt. Sick of forcefully overriding other mod's motds. Renamed our motd to match.
|
||||
* [CHANGE] ulx slap, whip, hp to further prevent being "stuck in ground".
|
||||
* [CHANGE] Menus are derma'tized.
|
||||
* [CHANGE] Updated how it handles svn version information.
|
||||
|
||||
v3.31 - *(06/08/08)*
|
||||
* [ADD] ulx adduserid - Add a user by steam id (ie STEAM_0:1:1234...) (Does not actually verify user validity) (Thanks Mr.President)
|
||||
* [FIX] Garry's 1/29/08 update breaking MOTD.
|
||||
* [FIX] Links not working on MOTD.
|
||||
* [FIX] Bug where you'd be stuck if someone disconnected while you were spectating them.
|
||||
* [FIX] TF2 motd showing by default.
|
||||
* [FIX] The usual assortment of small fixes not worth mentioning.
|
||||
* [CHANGE] Unignite help command changed to be more standardized with other help.
|
||||
* [CHANGE] Help indicates that multiple users can now also be command targeted using an asterisk "*". (ULib change added this)
|
||||
* [CHANGE] Miscellaneous spelling corrections.
|
||||
* [CHANGE] ulx chattime so that if your chat doesn't go through it is not counted towards your time.
|
||||
* [CHANGE] Can no longer set hp or armor to less than 0.
|
||||
* [REMOVE] ulx mingekick, useless now.
|
||||
|
||||
v3.30 - *(01/26/08)*
|
||||
* [ADD] ulx strip - Strips player(s) weapons
|
||||
* [ADD] ulx armor - Sets player(s) armor
|
||||
* [ADD] We now log NPC spawns
|
||||
* [ADD] ulx unignite - Unignites individual player, <all> players, or <everything> Any entity/player on fire.
|
||||
* [FIX] ulx ban requiring a reason.
|
||||
* [FIX] Added some more sanity checks to ulx maul.
|
||||
* [FIX] The usual assortment of small fixes not worth mentioning.
|
||||
* [FIX] ulx usermanagementhelp erroring out.
|
||||
* [FIX] .ini's not loading for listen servers.
|
||||
* [FIX] Case sensitivity problem with addgroup and removegroup.
|
||||
* [FIX] ulx ent incorrectly requiring at least one flag.
|
||||
* [FIX] All command inputs involving numbers should now be sanitized.
|
||||
* [FIX] Autocomplete send in a multi-layer authentication environment (probably doesn't affect anyone)
|
||||
* [CHANGE] The 0-255 scale for "ulx cloak" has been reversed.
|
||||
* [CHANGE] Model paths in logging is now standardized (linux notation, single slashes)
|
||||
* [CHANGE] The user initiating a silent logged command still sees the echo, even if they don't have access to see it normally.
|
||||
* [CHANGE] Various misc things for new engine compatibility (IE, ulx clientmenu got a major change and other menu changes)
|
||||
* [CHANGE] Removed all timers dealing with initialization and now rely on flags from the client. This makes the ULX initialization much more dependable.
|
||||
* [CHANGE] Name change watching is now taken care of by ULib.
|
||||
* [CHANGE] Converted all calls from ULib.consoleCommand( "exec ..." ) to ULib.execFile() to avoid running into the block on "exec" without our module.
|
||||
|
||||
|
||||
v3.20 - *(09/23/07)*
|
||||
* [ADD] ulx send - Allows admin to transport a player to another player (no more goto then bring!)
|
||||
* [ADD] ulx maul - Maul a player with fast zombies
|
||||
* [ADD] ulx gag - Silence individual player's microphone/sound input on voice enabled servers.
|
||||
* [ADD] New module system. It's now easier than ever to add, remove, or change ULX commands!
|
||||
* [ADD] ulx.addToMenu(). Use this function if you want a module to add something to any of the ULX menu.
|
||||
* [ADD] ulx debuginfo. Use this function to get information to give us when you're asking support questions.
|
||||
* [ADD] Votes now have a background behind them.
|
||||
* [ADD] ulx voteEcho. A config option to enable echo of votes. Does not apply to votemap.
|
||||
* [ADD] Maps menu now has option for gamemode.
|
||||
* [ADD] Ban menu to view and remove bans.
|
||||
* [ADD] ulx removeruser, addgroup, removegroup, groupallow, groupdeny, usermanagementhelp
|
||||
* [FIX] ulx whip - No longer allows multiple whip sessions of an individual player at same time.
|
||||
* [FIX] ulx adduser - You no longer have to reconnect to get given access.
|
||||
* [FIX] Vastly improved ulx send, goto, and teleport. You should never get stuck in anything ever again.
|
||||
* [FIX] Various initialization functions trying to access a disconnected player
|
||||
* [FIX] Vastly improved reserved slots
|
||||
* [FIX] Can't spawn junk or suicide while frozen now.
|
||||
* [FIX] Coming out of spectate keeps god mode (if the player was given god with "ulx god")
|
||||
* [FIX] Can't use "ulx hp" to give 100000+ hp anymore (crashes players with default HUD).
|
||||
* [FIX] If you're authed twice, you won't get duplicates in autocomplete
|
||||
* [FIX] ulx votemapmapmode and votemapaddmap not working
|
||||
* [CHANGE] /me <action> can now be used in ulx asay/chat @ admin chat. "@ /me bashes spammer over the head"
|
||||
* [CHANGE] Commands that used player:spawn (ragdoll,spectate, more) now return player to health/armor they had previously.
|
||||
* [CHANGE] ulx teleport. Can now teleport a player to where you are looking. Logs it if a player is specified.
|
||||
* [CHANGE] You can now specify entire directories in ulx addForcedDownload
|
||||
* [CHANGE] A few internal changes to the ULX base to compliment the new ULib UCL access string system
|
||||
* [CHANGE] ULX echoes come after the command now.
|
||||
* [CHANGE] Configs are now under /cfg/* instead of /lua/ulx/configs/*
|
||||
* [CHANGE] bring goto and teleport now zero out your velocity after moving you.
|
||||
* [CHANGE] bring and goto can now still move you when you would get stuck if you're noclipped.
|
||||
* [CHANGE] A hidden echo that is still shown to admins is now clearly labeled as such.
|
||||
* [CHANGE] ulx cexec now takes multiple targets. (This was the intended behavior)
|
||||
* [CHANGE] Lots of minor tweaks that would take too long to list. ;)
|
||||
* [CHANGE] All say commands require spaces after them except the "@" commands. (IE, "!slapbob" no longer slaps bob)
|
||||
* [CHANGE] Access to physgun players now uses the access string "ulx physgunplayer"
|
||||
* [CHANGE] Access to reserved slots now uses the access string "ulx reservedslots"
|
||||
* [CHANGE] Complete rewrite of advert system. You probably won't notice any difference (except hostname fix), but the code is leaner and meaner.
|
||||
* [CHANGE] No interval option for ulx whip anymore, too easy to abuse.
|
||||
* [CHANGE] Menus now use derma
|
||||
* [CHANGE] The ULX configs should now really and truly load after the default configs
|
||||
* [CHANGE] Votemap, votekick, voteban now all require the approval of the admin that started the vote if it wins.
|
||||
* [CHANGE] Voteban can now receive a parameter for ban time.
|
||||
* [CHANGE] ulx map can now receive gamemode for a parameter.
|
||||
* [CHANGE] You can now use newlines in adverts.
|
||||
* [CHANGE] Dropped requirement of being at least an opper for userallow/deny
|
||||
* [CHANGE] ulx who has an updated format that includes custom groups.
|
||||
* [CHANGE] ulx help is now categorized. (Reserved slots, teleportation, chat, etc )
|
||||
* [CHANGE] ulx thetime can now only be used once every minute (server wide)
|
||||
|
||||
v3.11 - *(06/19/07)*
|
||||
* [FIX] ulx vote. No longer public, people can't vote more than once, won't continue to hog the binds.
|
||||
* [FIX] rslots will now set rslots on dedicated server start
|
||||
* [FIX] Bring/goto getting you stuck in player sometimes.
|
||||
* [FIX] Can't use vehicles from inside a jail now.
|
||||
* [CHANGE] bring and goto now place teleporting player behind target
|
||||
* [CHANGE] Upped votemapMinvotes to 3 (was 2).
|
||||
* [CHANGE] Player physgun now only works in sandbox, lower admins can't physgun immune admins, freezes player while held.
|
||||
* [CHANGE] Unblocked custom groups from ulx adduser.
|
||||
|
||||
v3.10 - *(05/05/07)*
|
||||
* [ADD] Admins with slap access can move players now.
|
||||
* [ADD] Chat anti-spam
|
||||
* [ADD] ulx addForcedDownload for configs
|
||||
* [ADD] Per-gamemode config folder
|
||||
* [ADD] Voting! ulx vote, ulx votemap2, ulx voteban, ulx votekick
|
||||
* [ADD] Maps menu
|
||||
* [ADD] Lots more features to logging, like object spawn logging.
|
||||
* [ADD] Reserved slots
|
||||
* [FIX] Lots of minor insignificant bugs
|
||||
* [FIX] Jail issues
|
||||
* [FIX] Logging player connect on dedicated server issues
|
||||
* [FIX] Now takes advantage of fixed umsgs. Fixes rare crash.
|
||||
* [FIX] Can now psay immune players
|
||||
* [FIX] Minor bugs in logs
|
||||
* [CHANGE] Logs will now wrap to new date if server's on past midnight
|
||||
* [CHANGE] You can now use the admin menu in gamemodes derived from sandbox.
|
||||
* [CHANGE] Cleaned up now obsolete GetTable() calls
|
||||
* [CHANGE] Motd is now driven by lua. Much easier to deal with, fixes many problems.
|
||||
* [CHANGE] Can now use sv_cheats 1/0 from ulx rcon (dodges block)
|
||||
* [CHANGE] ulx lua_run is now ulx luarun to dodge another block
|
||||
* [CHANGE] Now in addon format
|
||||
* [CHANGE] ulx ignite will now last until you die and can spread.
|
||||
* [CHANGE] Global toolmode deny doesn't affect admins.
|
||||
|
||||
v3.02 - *(01/10/07)*
|
||||
* [CHANGE] Admin menu won't spam console so bad now
|
||||
* [FIX] Some more command crossbreeding issues (IE ragdolling jailed player)
|
||||
* [FIX] Teleport commands able to put someone in a wall. This is still possible, but much less likely.
|
||||
* [ADD] Motd manipulation. Auto-shows on startup and !motd
|
||||
* [ADD] toolallow, tooldeny, tooluserallow, tooluserdeny. Works fine, but is EXPERIMENTAL!
|
||||
|
||||
v3.01 - *(01/07/07)*
|
||||
* [ADD] ulx whip
|
||||
* [ADD] ulx adduser
|
||||
* [ADD] ulx userallow - Allow users access to commands
|
||||
* [ADD] ulx userdeny - Deny users access to commands
|
||||
* [ADD] ulx bring - Bring a user to you
|
||||
* [ADD] ulx goto - Goto a user
|
||||
* [ADD] ulx teleport - Teleport to where you're looking
|
||||
* [ADD] IRC-style "/me" command
|
||||
* [FIX] You can't use the adminmenu outside sandbox now
|
||||
* [FIX] Vastly improved "ulx jail"
|
||||
* [FIX] Improved "ulx ragdoll"
|
||||
* [FIX] pvp damage checkbox in adminmenu not working.
|
||||
* [FIX] Ban button
|
||||
* [FIX] Ban not kicking users
|
||||
* [FIX] Blinded users being able to see through the camera tool
|
||||
* [FIX] Admin menu not showing values on a dedicated server
|
||||
* [FIX] Admin menu checkboxes (which are now buttons!)
|
||||
* [FIX] Ulx commands much more usable from dedicated server console.
|
||||
* [FIX] Dedicated server spam (IsListenServerHost)
|
||||
* [FIX] Uncloak works properly now
|
||||
* [FIX] Various problems using commands on users in vehicles. (Thanks Jalit)
|
||||
|
||||
v3.0 - *(01/01/07)*
|
||||
* Initial version for GM10
|
||||
|
||||
Group: Credits
|
||||
|
||||
Thanks to everyone in #ulysses in irc.gamesurge.net for not giving up on me :)
|
||||
A big thanks to JamminR for listening to me ramble on and for giving the project fresh insights.
|
||||
|
||||
Group: License
|
||||
|
||||
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License.
|
||||
To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to
|
||||
Creative Commons
|
||||
543 Howard Street
|
||||
5th Floor
|
||||
San Francisco, California 94105
|
||||
USA
|
||||
|
Loading…
Reference in New Issue
Block a user