Compare commits

...

7 Commits

Author SHA1 Message Date
SticklyMan
32c96d56ef Update ulx.build 2024-03-24 11:39:35 -06:00
Brett Smith
42a9e9711c Update ulx.build 2017-03-21 15:37:12 -05:00
Brett Smith
daca5a6d9e Update ulx.build 2017-03-19 13:43:18 -05:00
Brett Smith
bd975c0392 Update ulx.build 2016-05-22 14:38:20 -04:00
Brett Smith
78451f1574 Update ulx.build 2016-02-15 19:36:05 -05:00
Nayruden
22b173d0eb more cleanup 2015-11-19 20:12:02 -06:00
Nayruden
943ce45991 Clean up gh-pages 2015-11-19 20:10:21 -06:00
49 changed files with 1 additions and 12520 deletions

View File

@ -1,12 +0,0 @@
#!/bin/sh
#
# .git/hooks/post-commit
#
if [ -a .commit ]
then
rm .commit
echo `date '+%s'` > ulx.build
git add ulx.build
git commit --amend -C HEAD --no-verify
fi

View File

@ -1,7 +0,0 @@
#!/bin/sh
#
# .git/hooks/pre-commit
#
# Prevent infinite loops on post-commit
touch .commit

View File

@ -1,14 +0,0 @@
{
"title" : "ULX",
"type" : "ServerContent",
"tags" : [ "fun", "build" ],
"ignore" :
[
"addon.txt",
".editorconfig",
".git*",
"ulx.build",
"ulx_readme.txt"
],
"workshopid": 557962280
}

View File

@ -1,11 +0,0 @@
"AddonInfo"
{
"name" "ULX"
"version" "3.62d"
"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"
}

View File

@ -1,5 +0,0 @@
if SERVER then
include( "ulx/init.lua" )
else
include( "ulx/cl_init.lua" )
end

View File

@ -1,121 +0,0 @@
--[[
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=#ulx.cmdsByCategory[ category ],1,-1 do
existingCmd = ulx.cmdsByCategory[ category ][i]
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 _, _, b, w = ulx.getVersion()
ULib.clientRPC( ply, "ulx.clInit", b, w )
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

View File

@ -1,27 +0,0 @@
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( b, w )
ulx.build = b
ulx.usingWorkshop = w
Msg( "ULX version " .. ulx.getVersion() .. " loaded.\n" )
end
usermessage.Hook( "ulx_initplayer", init )

View File

@ -1,132 +0,0 @@
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!
local versionStr
local build = ulx.build
local usingWorkshop = ulx.usingWorkshop
if ulx.release then
versionStr = string.format( "v%.02f", ulx.version )
elseif usingWorkshop then
versionStr = string.format( "v%.02fw", ulx.version )
elseif build then -- It's not release and it's not workshop
versionStr = string.format( "v%.02fd (%s)", ulx.version, os.date( "%x", build ) )
else -- Not sure what this version is, but it's not a release
versionStr = string.format( "v%.02fd", ulx.version )
end
return versionStr, ulx.version, build, usingWorkshop
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" )

View File

@ -1,343 +0,0 @@
-- This file populates the data folder. We can't just ship these files, because Steam Workshop disallows that.
local files = {}
files["adverts.txt"] =
[[; Here's where you put advertisements
;
; Whether an advertisement is a center advertisement (csay) or text box advertisement (tsay) is determined by
; whether or not the "time_on_screen" key is present. If it is present, it's a csay.
;
; The 'time' argument inside a center advertisement and the number following a chat advertisement are the
; time it takes between each showing of this advertisement in seconds. Set it to 300 and the advertisement
; will show every five minutes.
;
; If you want to make it so that one advertisement is shown and then will always be followed by another,
; put them in a table. For example, if you add the following to the bottom of the file, A will always show
; first followed by B.
; "my_group"
; {
; {
; "text" "Advertisement A"
; "time" "200"
; }
; {
; "text" "Advertisement B"
; "time" "300"
; }
; }
{
"text" "You're playing on %host%, enjoy your stay!"
"red" "100"
"green" "255"
"blue" "200"
"time_on_screen" "10"
"time" "300"
}
{
"text" "This server is running ULX Admin Mod %ulx_version% by Team Ulysses from ulyssesmod.net"
"time" "635"
}
]]
files["banreasons.txt"] =
[[; This file is used to store default reasons for kicking and banning users.
; These reasons show up in console autocomplete and in XGUI dropdowns.
Spammer
Crashed server
Minge
Griefer
Foul language
Disobeying the rules
]]
files["config.txt"] =
[[;Any of the settings in here can be added to the per-map or per-gamemode configs.
;To add per-map and per-gamemode configs, create data/ulx/maps/<mapname>/config.txt
;and data/ulx/gamemodes/<gamemodename>/config.txt files. This can also be done for
;All other configuration files (adverts.txt, downloads.txt, gimps.txt, votemaps.txt)
;All configurations add to each other except gimps and votemaps, which takes the most
;specific config only.
;Any line starting with a ';' is a comment!
ulx showMotd 1 ; Set to 0 to disable showing motd on connect. Shows the file the cvar motdfile says to.
; Set showMotd to a URL to show a URL. You can use %curmap% and %steamid% in the URL to have it automagically parsed for you (eg, server.com/?map=%curmap%&id=%steamid%).
motdfile ulx_motd.txt ; The motd to show, if using a file.
ulx chattime 0 ; Players can only chat every x seconds (anti-spam). 0 to disable
ulx meChatEnabled 1 ; Allow players to use '/me' in chat. 0 = Disabled, 1 = Sandbox only (Default), 2 = Enabled
; This is what the players will see when they join, set it to "" to disable.
; You can use %host% and %curmap% in your text and have it automagically parsed for you
ulx welcomemessage "Welcome to %host%! We're playing %curmap%."
ulx logFile 1 ; Log to file (Can still echo if off). This is a global setting, nothing will be logged to file with this off.
ulx logEvents 1 ; Log events (player connect, disconnect, death)
ulx logChat 1 ; Log player chat
ulx logSpawns 1 ; Log when players spawn objects (props, effects, etc)
ulx logSpawnsEcho 1 ; Echo spawns to players in server. -1 = Off, 0 = Dedicated console only, 1 = Admins only, 2 = All players. (Echoes to console)
ulx logJoinLeaveEcho 1 ; Echo players leaves and joins to admins in the server (useful for banning minges)
ulx logDir "ulx_logs" ; The log dir under garrysmod/data
ulx logEcho 1 ; Echo mode
; Echo modes:
; 0 - OFF No output to any players when an admin command is used
; 1 - ANONYMOUS Output to players without access to see who used the command (admins by default) similar to "(Someone) slapped Bob with 0 damage"
; 2 - FULL Output to players similar to "Foo slapped Bob with 0 damage"
ulx logEchoColors 1 ; Whether or not echoed commands in chat are colored
ulx logEchoColorDefault "151 211 255" ; The default text color (RGB)
ulx logEchoColorConsole "0 0 0" ; The color that Console gets when using actions
ulx logEchoColorSelf "75 0 130" ; The color for yourself in echoes
ulx logEchoColorEveryone "0 128 128" ; The color to use when everyone is targeted in echoes
ulx logEchoColorPlayerAsGroup 1 ; Whether or not to use group colors for players. If false, it uses the color below.
ulx logEchoColorPlayer "255 255 0" ; The color to use for players when ulx logEchoColorPlayerAsGroup is set to 0.
ulx logEchoColorMisc "0 255 0" ; The color for anything else in echoes
ulx rslotsMode 0
ulx rslots 2
ulx rslotsVisible 1 ; When this is 0, sv_visiblemaxplayers will be set to maxplayers - slots_currently_reserved
;Modes:
;0 - Off
;1 - Keep # of slots reserved for admins, admins fill slots.
;2 - Keep # of slots reserved for admins, admins don't fill slots, they'll be freed when a player leaves.
;3 - Always keep 1 slot open for admins, kick the user with the shortest connection time if an admin joins.
;Difference between 1 and 2:
;I realize it's a bit confusing, so here's an example.
;On mode 1--
; You have maxplayers set to 10, rslots set to 2, and there are currently 8 non-admins connected.
; If a non-admin tries to join, they'll be kicked to keep the reserved slots open. Two admins join
; and fill the two reserved slots. When non-admins leave, the two admins will still be filling the
; two reserved slots, so another regular player can join and fill the server up again without being
; kicked by the slots system
;On mode 2--
; Same setup as mode 1, you have the two admins in the server and the server is full. Now, when a
; non-admin leaves the server, reserved slots will pick up the slot again as reserved. If a regular
; player tries to join and fill the server again, even though there are two admins connected, it will
; kick the regular player to keep the slot open
;So, the basic difference between these two is mode 1 will subtract currently connected admins from the slot
;pool, while mode 2 while always be attempting to reclaim slots if it doesn't currently have enough when
;players leave no matter how many admins are connected.
;rslotsVisible:
; If you set this variable to 0, ULX will automatically change sv_visiblemaxplayers for you so that if
; there are no regular player slots available in your server, it will appear that the server is full.
; The major downside to this is that admins can't connect to the server using the "find server" dialog
; when it appears full. Instead, they have to go to console and use the command "connect <ip>".
; NOTE THIS DOES NOT CHANGE YOUR MAXPLAYERS VARIABLE, ONLY HOW MANY MAXPLAYERS IT _LOOKS_ LIKE YOUR
; SERVER HAS. YOU CAN NEVER, EVER HAVE MORE PLAYERS IN YOUR SERVER THAN THE MAXPLAYERS VARIABLE.
ulx votemapEnabled 1 ; Enable/Disable the entire votemap command
ulx votemapMintime 10 ; Time after map change before votes count.
ulx votemapWaittime 5 ; Time before a user must wait before they can change their vote.
ulx votemapSuccessratio 0.4 ; Ratio of (votes for map)/(total players) needed to change map. (Rounds up)
ulx votemapMinvotes 3 ; Number of minimum votes needed to change map (Prevents llamas). This supercedes the above convar on small servers.
ulx votemapVetotime 30 ; Time in seconds an admin has after a successful votemap to veto the vote. Set to 0 to disable.
ulx votemapMapmode 1 ; 1 = Use all maps but what's specified in votemaps.txt, 2 = Use only the maps specified in votemaps.txt.
ulx voteEcho 0 ; 1 = Echo what every player votes (this does not apply to votemap). 0 = Don't echo
ulx votemap2Successratio 0.5 ; Ratio of (votes for map)/(total players) needed to change map. (Rounds up)
ulx votemap2Minvotes 3 ; Number of minimum votes needed to change map (Pevents llamas). This supercedes the above convar on small servers.
ulx votekickSuccessratio 0.6 ; Ratio of (votes for kick)/(total players) needed to kick player. (Rounds up)
ulx votekickMinvotes 2 ; Number of minimum votes needed to kick player (Pevents llamas). This supercedes the above convar on small servers.
ulx votebanSuccessratio 0.7 ; Ratio of (votes for ban)/(total players) needed to ban player. (Rounds up)
ulx votebanMinvotes 3 ; Number of minimum votes needed to ban player (Pevents llamas). This supercedes the above convar on small servers.
]]
files["downloads.txt"] =
[[; 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
]]
files["gimps.txt"] =
[[; Add gimp says in this file, one per line.
; Any line starting with a ';' is a comment
I'm a llama.
How do you fly?
baaaaaaaaaah.
Llama power!
Llamas are the coolest!
What's that gun to move stuff?
I'm a soulless approximation of a cheese danish!
Hold up guys, I'm watching The Powerpuff Girls.
Not yet, I'm being attacked by an... OH CRAP!
]]
files["sbox_limits.txt"] =
[[;The number by each cvar indicates the maximum value for the slider in XGUI.
|Sandbox
sbox_maxballoons 100
sbox_maxbuttons 200
sbox_maxdynamite 75
sbox_maxeffects 200
sbox_maxemitters 100
sbox_maxhoverballs 200
sbox_maxlamps 50
sbox_maxlights 50
sbox_maxnpcs 50
sbox_maxprops 1000
sbox_maxragdolls 50
sbox_maxsents 1024
sbox_maxspawners 50
sbox_maxthrusters 200
sbox_maxturrets 50
sbox_maxvehicles 50
sbox_maxwheels 200
|Other
sbox_maxdoors 100
sbox_maxhoverboards 10
sbox_maxkeypads 100
sbox_maxwire_keypads 100
sbox_maxpylons 100
|Wire
sbox_maxwire_addressbuss 100
sbox_maxwire_adv_emarkers 50
sbox_maxwire_adv_inputs 100
sbox_maxwire_buttons 100
sbox_maxwire_cameracontrollers 100
sbox_maxwire_cd_disks 100
sbox_maxwire_cd_locks 100
sbox_maxwire_cd_rays 100
sbox_maxwire_clutchs 10
sbox_maxwire_colorers 100
sbox_maxwire_consolescreens 100
sbox_maxwire_cpus 10
sbox_maxwire_damage_detectors 50
sbox_maxwire_data_satellitedishs 100
sbox_maxwire_data_stores 100
sbox_maxwire_data_transferers 100
sbox_maxwire_dataplugs 100
sbox_maxwire_dataports 100
sbox_maxwire_datarates 100
sbox_maxwire_datasockets 100
sbox_maxwire_deployers 5
sbox_maxwire_detonators 100
sbox_maxwire_dhdds 100
sbox_maxwire_digitalscreens 100
sbox_maxwire_dual_inputs 100
sbox_maxwire_dynamic_buttons 100
sbox_maxwire_egps 10
sbox_maxwire_emarkers 30
sbox_maxwire_exit_points 10
sbox_maxwire_explosives 50
sbox_maxwire_expressions 100
sbox_maxwire_extbuss 100
sbox_maxwire_eyepods 15
sbox_maxwire_forcers 100
sbox_maxwire_freezers 50
sbox_maxwire_fx_emitters 100
sbox_maxwire_gate_angles 30
sbox_maxwire_gate_arithmetics 30
sbox_maxwire_gate_arrays 30
sbox_maxwire_gate_bitwises 30
sbox_maxwire_gate_comparisons 30
sbox_maxwire_gate_entitys 30
sbox_maxwire_gate_logics 30
sbox_maxwire_gate_memorys 30
sbox_maxwire_gate_rangers 30
sbox_maxwire_gate_selections 30
sbox_maxwire_gate_strings 30
sbox_maxwire_gate_times 30
sbox_maxwire_gate_trigs 30
sbox_maxwire_gate_vectors 30
sbox_maxwire_gates 30
sbox_maxwire_gimbals 10
sbox_maxwire_gpss 50
sbox_maxwire_gpus 10
sbox_maxwire_grabbers 100
sbox_maxwire_graphics_tablets 100
sbox_maxwire_gyroscopes 50
sbox_maxwire_hdds 100
sbox_maxwire_holoemitters 50
sbox_maxwire_hologrids 100
sbox_maxwire_hoverballs 30
sbox_maxwire_hoverdrivecontrolers 5
sbox_maxwire_hudindicators 100
sbox_maxwire_hydraulics 16
sbox_maxwire_igniters 100
sbox_maxwire_indicators 100
sbox_maxwire_inputs 100
sbox_maxwire_keyboards 100
sbox_maxwire_keypads 50
sbox_maxwire_lamps 50
sbox_maxwire_las_receivers 100
sbox_maxwire_latchs 15
sbox_maxwire_levers 50
sbox_maxwire_lights 10
sbox_maxwire_locators 30
sbox_maxwire_motors 50
sbox_maxwire_nailers 100
sbox_maxwire_numpads 100
sbox_maxwire_oscilloscopes 100
sbox_maxwire_outputs 50
sbox_maxwire_pixels 100
sbox_maxwire_plugs 100
sbox_maxwire_pods 100
sbox_maxwire_radios 100
sbox_maxwire_rangers 50
sbox_maxwire_relays 100
sbox_maxwire_screens 100
sbox_maxwire_sensors 100
sbox_maxwire_simple_explosives 100
sbox_maxwire_sockets 100
sbox_maxwire_soundemitters 50
sbox_maxwire_spawners 50
sbox_maxwire_speedometers 50
sbox_maxwire_spus 10
sbox_maxwire_target_finders 100
sbox_maxwire_textreceivers 50
sbox_maxwire_textscreens 100
sbox_maxwire_thrusters 50
sbox_maxwire_trails 100
sbox_maxwire_turrets 100
sbox_maxwire_twoway_radios 100
sbox_maxwire_users 100
sbox_maxwire_values 100
sbox_maxwire_vectorthrusters 50
sbox_maxwire_vehicles 100
sbox_maxwire_watersensors 100
sbox_maxwire_waypoints 30
sbox_maxwire_weights 100
sbox_maxwire_wheels 30
]]
files["votemaps.txt"] =
[[; List of maps that are either included in the votemap command or excluded from it
; Make sure to set votemapMapmode in config.txt to what you want.
background01
background02
background03
background04
background05
background06
background07
credits
intro
test_hardware
test_speakers
]]
ULib.fileCreateDir( "data/ulx" ) -- This is ignored if the folder already exists
for filename, content in pairs( files ) do
local filepath = "data/ulx/" .. filename
if not ULib.fileExists( filepath, true ) then
ULib.fileWrite( filepath, content )
end
end
files = nil -- Cleanup

View File

@ -1,142 +0,0 @@
-- 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.namedQueueFunctionCall( "ULXConfigExec", 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

View File

@ -1,55 +0,0 @@
if not ulx then
ulx = {}
-- Get data folder up to speed
include( "data.lua" )
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

View File

@ -1,110 +0,0 @@
-- 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 versionStr
local build = nil
local usingWorkshop = false
-- Get workshop information, if available
local addons = engine.GetAddons()
for i=1, #addons do
-- Ideally we'd use the "wsid" from this table
-- But, as of 19 Nov 2015, that is broken, so we'll work around it
if addons[i].file:find(tostring(ulx.WORKSHOPID)) then
usingWorkshop = true
end
end
-- If we have good build data, set it in "build"
if ULib.fileExists( "ulx.build" ) then
local buildStr = ULib.fileRead( "ulx.build" )
local buildNum = tonumber(buildStr)
-- Make sure the time is something reasonable -- between the year 2014 and 2128
if buildNum and buildNum > 1400000000 and buildNum < 5000000000 then
build = buildNum
end
end
if ulx.release then
versionStr = string.format( "v%.02f", ulx.version )
elseif usingWorkshop then
versionStr = string.format( "v%.02fw", ulx.version )
elseif build then -- It's not release and it's not workshop
versionStr = string.format( "v%.02fd (%s)", ulx.version, os.date( "%x", build ) )
else -- Not sure what this version is, but it's not a release
versionStr = string.format( "v%.02fd", ulx.version )
end
return versionStr, ulx.version, build, usingWorkshop
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

View File

@ -1,515 +0,0 @@
local logEcho = ulx.convar( "logEcho", "2", "Echo mode 0-Off 1-Anonymous 2-Full", ULib.ACCESS_SUPERADMIN )
local logEchoColors = ulx.convar( "logEchoColors", "1", "Whether or not echoed commands in chat are colored", ULib.ACCESS_SUPERADMIN )
local logEchoColorDefault = ulx.convar( "logEchoColorDefault", "151 211 255", "The default text color (RGB)", ULib.ACCESS_SUPERADMIN )
local logEchoColorConsole = ulx.convar( "logEchoColorConsole", "0 0 0", "The color that Console gets when using actions", ULib.ACCESS_SUPERADMIN )
local logEchoColorSelf = ulx.convar( "logEchoColorSelf", "75 0 130", "The color for yourself in echoes", ULib.ACCESS_SUPERADMIN )
local logEchoColorEveryone = ulx.convar( "logEchoColorEveryone", "0 128 128", "The color to use when everyone is targeted in echoes", ULib.ACCESS_SUPERADMIN )
local logEchoColorPlayerAsGroup = ulx.convar( "logEchoColorPlayerAsGroup", "1", "Whether or not to use group colors for players.", ULib.ACCESS_SUPERADMIN )
local logEchoColorPlayer = ulx.convar( "logEchoColorPlayer", "255 255 0", "The color to use for players when ulx logEchoColorPlayerAsGroup is set to 0.", ULib.ACCESS_SUPERADMIN )
local logEchoColorMisc = ulx.convar( "logEchoColorMisc", "0 255 0", "The color for anything else in echoes", ULib.ACCESS_SUPERADMIN )
local logFile = ulx.convar( "logFile", "1", "Log to file (Can still echo if off). This is a global setting, nothing will be logged to file with this off.", ULib.ACCESS_SUPERADMIN )
local logEvents = ulx.convar( "logEvents", "1", "Log events (player connect, disconnect, death)", ULib.ACCESS_SUPERADMIN )
local logChat = ulx.convar( "logChat", "1", "Log player chat", ULib.ACCESS_SUPERADMIN )
local logSpawns = ulx.convar( "logSpawns", "1", "Log when players spawn objects (props, effects, etc)", ULib.ACCESS_SUPERADMIN )
local logSpawnsEcho = ulx.convar( "logSpawnsEcho", "1", "Echo spawns to players in server. -1 = Off, 0 = Console only, 1 = Admins only, 2 = All players. (Echoes to console)", ULib.ACCESS_SUPERADMIN )
local logJoinLeaveEcho = ulx.convar( "logJoinLeaveEcho", "1", "Echo players leaves and joins to admins in the server (useful for banning minges)", ULib.ACCESS_SUPERADMIN )
local logDir = ulx.convar( "logDir", "ulx_logs", "The log dir under garrysmod/data", ULib.ACCESS_SUPERADMIN )
local hiddenechoAccess = "ulx hiddenecho"
ULib.ucl.registerAccess( hiddenechoAccess, ULib.ACCESS_SUPERADMIN, "Ability to see hidden echoes", "Other" ) -- Give superadmins access to see hidden echoes by default
local seeanonymousechoAccess = "ulx seeanonymousechoes"
ULib.ucl.registerAccess( seeanonymousechoAccess, ULib.ACCESS_ADMIN, "Ability to see who uses a command even with ulx logEcho set to 1", "Other" )
local spawnechoAccess = "ulx spawnecho"
ULib.ucl.registerAccess( spawnechoAccess, ULib.ACCESS_ADMIN, "Ability to see spawn echoes and steamids from joined players in console", "Other" ) -- Give admins access to see spawn echoes by default
local curDateStr = os.date( "%Y-%m-%d" ) -- This will hold the date string (YYYY-mm-dd) we think it is right now.
-- Utility stuff for our logs...
ulx.log_file = ulx.log_file or nil
local function init()
curDateStr = os.date( "%Y-%m-%d" )
if logFile:GetBool() then
ULib.fileCreateDir( "data/" .. logDir:GetString() )
ulx.log_file = os.date( "data/" .. logDir:GetString() .. "/" .. "%m-%d-%y" .. ".txt" )
if not ULib.fileExists( ulx.log_file ) then
ULib.fileWrite( ulx.log_file, "" )
else
ulx.logWriteln( "\r\n\r\n" ) -- Make some space
end
ulx.logString( "New map: " .. game.GetMap() )
end
end
hook.Add( ulx.HOOK_ULXDONELOADING, "InitULX", init ) -- So we load the settings first
local function next_log()
if logFile:GetBool() then
local new_log = os.date( "data/" .. logDir:GetString() .. "/" .. "%m-%d-%y" .. ".txt" )
if new_log == ulx.log_file then -- Make sure the date has changed.
return
end
local old_log = ulx.log_file
ulx.logWriteln( "<Logging continued in \"" .. new_log .. "\">" )
ulx.log_file = new_log
ULib.fileWrite( ulx.log_file, "" )
ulx.logWriteln( "<Logging continued from \"" .. old_log .. "\">" )
end
curDateStr = os.date( "%Y-%m-%d" )
end
function ulx.logUserAct( ply, target, action, hide_echo )
local nick
if ply:IsValid() then
if not ply:IsConnected() or not target:IsConnected() then return end
nick = ply:Nick()
else
nick = "(Console)"
end
action = action:gsub( "#T", target:Nick(), 1 ) -- Everything needs this replacement
local level = logEcho:GetInt()
if not hide_echo and level > 0 then
local echo
if level == 1 then
echo = action:gsub( "#A", nick, 1 )
ULib.tsay( _, echo, true )
end
elseif level > 0 then
local echo = action:gsub( "#A", "(SILENT)" .. nick, 1 )
ULib.tsay( ply, echo, true ) -- Whether or not the originating player has access, they're getting the echo.
local players = player.GetAll()
for _, player in ipairs( players ) do
if ULib.ucl.query( player, hiddenechoAccess ) and player ~= ply then
ULib.tsay( player, echo, true )
end
end
end
if game.IsDedicated() then
Msg( action:gsub( "#A", nick, 1 ) .. "\n" )
end
if logFile:GetBool() then
ulx.logString( action:gsub( "#A", nick, 1 ), true )
end
end
function ulx.logServAct( ply, action, hide_echo )
local nick
if ply:IsValid() then
if not ply:IsConnected() then return end
nick = ply:Nick()
else
nick = "(Console)"
end
local level = logEcho:GetInt()
if not hide_echo and level > 0 then
local echo
if level == 1 then
echo = action:gsub( "#A", nick, 1 )
ULib.tsay( _, echo, true )
end
elseif level > 0 then
local echo = action:gsub( "#A", "(SILENT)" .. nick, 1 )
ULib.tsay( ply, echo, true ) -- Whether or not the originating player has access, they're getting the echo.
local players = player.GetAll()
for _, player in ipairs( players ) do
if ULib.ucl.query( player, hiddenechoAccess ) and player ~= ply then
ULib.tsay( player, echo, true )
end
end
end
if game.IsDedicated() then
Msg( action:gsub( "#A", nick, 1 ) .. "\n" )
end
if logFile:GetBool() then
ulx.logString( action:gsub( "#A", nick, 1 ), true )
end
end
function ulx.logString( str, log_to_main )
if not ulx.log_file then return end
local dateStr = os.date( "%Y-%m-%d" )
if curDateStr < dateStr then
next_log()
end
if log_to_main then
ServerLog( "[ULX] " .. str .. "\n" )
end
local date = os.date( "*t" )
ulx.logWriteln( string.format( "[%02i:%02i:%02i] ", date.hour, date.min, date.sec ) .. str )
end
function ulx.logWriteln( str )
if not ulx.log_file then return end
if logFile:GetBool() and ulx.log_file then
ULib.fileAppend( ulx.log_file, str .. "\r\n" )
end
end
local function echoToAdmins( txt )
local players = player.GetAll()
for _, ply in ipairs( players ) do
if ULib.ucl.authed[ ply:UniqueID() ] and ULib.ucl.query( ply, spawnechoAccess ) then
ULib.console( ply, txt )
end
end
end
local function playerSay( ply, text, private )
if logChat:GetBool() then
if private then
ulx.logString( string.format( "(TEAM) %s: %s", ply:Nick(), text ) )
else
ulx.logString( string.format( "%s: %s", ply:Nick(), text ) )
end
end
end
hook.Add( "PlayerSay", "ULXLogSay", playerSay, HOOK_MONITOR_LOW )
local joinTimer = {}
local mapStartTime = os.time()
local function playerConnect( name, address )
joinTimer[address] = os.time()
if logEvents:GetBool() then
ulx.logString( string.format( "Client \"%s\" connected.", name ) )
end
end
hook.Add( "PlayerConnect", "ULXLogConnect", playerConnect, HOOK_MONITOR_HIGH )
local function playerInitialSpawn( ply )
local ip = ply:IPAddress()
local seconds = os.time() - (joinTimer[ip] or mapStartTime)
joinTimer[ip] = nil
local txt = string.format( "Client \"%s\" spawned in server <%s> (took %i seconds).", ply:Nick(), ply:SteamID(), seconds )
if logEvents:GetBool() then
ulx.logString( txt )
end
if logJoinLeaveEcho:GetBool() then
echoToAdmins( txt )
end
end
hook.Add( "PlayerInitialSpawn", "ULXLogInitialSpawn", playerInitialSpawn, HOOK_MONITOR_HIGH )
local function playerDisconnect( ply )
local txt = string.format( "Dropped \"%s\" from server<%s>", ply:Nick(), ply:SteamID() )
if logEvents:GetBool() then
ulx.logString( txt )
end
if logJoinLeaveEcho:GetBool() then
echoToAdmins( txt )
end
end
hook.Add( "PlayerDisconnected", "ULXLogDisconnect", playerDisconnect, HOOK_MONITOR_HIGH )
local function playerDeath( victim, weapon, killer )
if logEvents:GetBool() then
if not IsValid( victim ) then return end
if not IsValid( killer ) then return end
if not killer:IsPlayer() then
ulx.logString( string.format( "%s was killed by %s", victim:Nick(), killer:GetClass() ) )
elseif weapon == nil or not weapon:IsValid() then
ulx.logString( string.format( "%s killed %s", killer:Nick(), victim:Nick() ) )
elseif victim ~= killer then
ulx.logString( string.format( "%s killed %s using %s", killer:Nick(), victim:Nick(), weapon:GetClass() ) )
else
ulx.logString( string.format( "%s suicided!", victim:Nick() ) )
end
end
end
hook.Add( "PlayerDeath", "ULXLogDeath", playerDeath, HOOK_MONITOR_HIGH )
-- Check name changes
local function nameCheck( ply, oldnick, newnick )
local msg = string.format( "%s<%s> changed their name to %s", oldnick, ply:SteamID(), newnick )
if game.IsDedicated() then
Msg( msg .. "\n" )
end
if logEvents:GetBool() then
ulx.logString( msg )
end
end
hook.Add( "ULibPlayerNameChanged", "ULXNameChange", nameCheck )
local function shutDown()
if logEvents:GetBool() then
ulx.logString( "Server is shutting down/changing levels." )
end
end
hook.Add( "ShutDown", "ULXLogShutDown", shutDown, HOOK_MONITOR_HIGH )
function ulx.logSpawn( txt )
if logSpawns:GetBool() then
ulx.logString( txt, true )
end
if logSpawnsEcho:GetInt() >= 0 and game.IsDedicated() then
Msg( txt .. "\n" )
end
if logSpawnsEcho:GetInt() == 1 then
echoToAdmins( txt )
elseif logSpawnsEcho:GetInt() == 2 then -- All players
ULib.console( _, txt )
end
end
local function propSpawn( ply, model, ent )
ulx.logSpawn( string.format( "%s<%s> spawned model %s", ply:Nick(), ply:SteamID(), ulx.standardizeModel( model ) ) )
end
hook.Add( "PlayerSpawnedProp", "ULXLogPropSpawn", propSpawn, HOOK_MONITOR_LOW )
local function ragdollSpawn( ply, model, ent )
ulx.logSpawn( string.format( "%s<%s> spawned ragdoll %s", ply:Nick(), ply:SteamID(), ulx.standardizeModel( model ) ) )
end
hook.Add( "PlayerSpawnedRagdoll", "ULXLogRagdollSpawn", ragdollSpawn, HOOK_MONITOR_LOW )
local function effectSpawn( ply, model, ent )
ulx.logSpawn( string.format( "%s<%s> spawned effect %s", ply:Nick(), ply:SteamID(), ulx.standardizeModel( model ) ) )
end
hook.Add( "PlayerSpawnedEffect", "ULXLogEffectSpawn", effectSpawn, HOOK_MONITOR_LOW )
local function vehicleSpawn( ply, ent )
ulx.logSpawn( string.format( "%s<%s> spawned vehicle %s", ply:Nick(), ply:SteamID(), ulx.standardizeModel( ent:GetModel() or "unknown" ) ) )
end
hook.Add( "PlayerSpawnedVehicle", "ULXLogVehicleSpawn", vehicleSpawn, HOOK_MONITOR_LOW )
local function sentSpawn( ply, ent )
ulx.logSpawn( string.format( "%s<%s> spawned sent %s", ply:Nick(), ply:SteamID(), ent:GetClass() ) )
end
hook.Add( "PlayerSpawnedSENT", "ULXLogSentSpawn", sentSpawn, HOOK_MONITOR_LOW )
local function NPCSpawn( ply, ent )
ulx.logSpawn( string.format( "%s<%s> spawned NPC %s", ply:Nick(), ply:SteamID(), ent:GetClass() ) )
end
hook.Add( "PlayerSpawnedNPC", "ULXLogNPCSpawn", NPCSpawn, HOOK_MONITOR_LOW )
local default_color
local console_color
local self_color
local misc_color
local everyone_color
local player_color
local function updateColors()
local cvars = { logEchoColorDefault, logEchoColorConsole, logEchoColorSelf, logEchoColorEveryone, logEchoColorPlayer, logEchoColorMisc }
for i=1, #cvars do
local cvar = cvars[ i ]
local pieces = ULib.explode( "%s+", cvar:GetString() )
if not #pieces == 3 then Msg( "Warning: Tried to set ulx log color cvar with bad data\n" ) return end
local color = Color( tonumber( pieces[ 1 ] ), tonumber( pieces[ 2 ] ), tonumber( pieces[ 3 ] ) )
if cvar == logEchoColorDefault then default_color = color
elseif cvar == logEchoColorConsole then console_color = color
elseif cvar == logEchoColorSelf then self_color = color
elseif cvar == logEchoColorEveryone then everyone_color = color
elseif cvar == logEchoColorPlayer then player_color = color
elseif cvar == logEchoColorMisc then misc_color = color
end
end
end
hook.Add( ulx.HOOK_ULXDONELOADING, "UpdateEchoColors", updateColors )
updateColors() -- Update colors right away in case of autorefresh
local function cvarChanged( sv_cvar, cl_cvar, ply, old_value, new_value )
sv_cvar = sv_cvar:lower()
if not sv_cvar:find( "^ulx_logechocolor" ) then return end
if sv_cvar ~= "ulx_logechocolorplayerasgroup" then timer.Simple( 0.1, updateColors ) end
end
hook.Add( ULib.HOOK_REPCVARCHANGED, "ULXCheckLogColorCvar", cvarChanged )
local function plyColor( target_ply, showing_ply )
if not target_ply:IsValid() then
return console_color
elseif showing_ply == target_ply then
return self_color
elseif logEchoColorPlayerAsGroup:GetBool() then
return team.GetColor( target_ply:Team() )
else
return player_color
end
end
local function makePlayerList( calling_ply, target_list, showing_ply, use_self_suffix, is_admin_part )
local players = player.GetAll()
-- Is the calling player acting anonymously in the eyes of the player this is being showed to?
local anonymous = showing_ply ~= "CONSOLE" and not ULib.ucl.query( showing_ply, seeanonymousechoAccess ) and logEcho:GetInt() == 1
if #players > 1 and #target_list == #players then
return { everyone_color, "Everyone" }
elseif is_admin_part then
local target = target_list[ 1 ] -- Only one target here
if anonymous and target ~= showing_ply then
return { everyone_color, "(Someone)" }
elseif not target:IsValid() then
return { console_color, "(Console)" }
end
end
local strs = {}
-- Put self, then them to the front of the list.
table.sort( target_list, function( ply_a, ply_b )
if ply_a == showing_ply then return true end
if ply_b == showing_ply then return false end
if ply_a == calling_ply then return true end
if ply_b == calling_ply then return false end
return ply_a:Nick() < ply_b:Nick()
end )
for i=1, #target_list do
local target = target_list[ i ]
table.insert( strs, plyColor( target, showing_ply ) )
if target == showing_ply then
if not use_self_suffix or calling_ply ~= showing_ply then
table.insert( strs, "You" )
else
table.insert( strs, "Yourself" )
end
elseif not use_self_suffix or calling_ply ~= target_list[ i ] or anonymous then
table.insert( strs, target_list[ i ]:IsValid() and target_list[ i ]:Nick() or "(Console)" )
else
table.insert( strs, "Themself" )
end
table.insert( strs, default_color )
table.insert( strs, "," )
end
-- Remove last comma and coloring
table.remove( strs )
table.remove( strs )
return strs
end
local function insertToAll( t, data )
for i=1, #t do
table.insert( t[ i ], data )
end
end
function ulx.fancyLogAdmin( calling_ply, format, ... )
local use_self_suffix = false
local hide_echo = false
local players = {}
if logEcho:GetInt() ~= 0 then
players = player.GetAll()
end
local arg_pos = 1
local args = { ... }
if type( format ) == "boolean" then
hide_echo = format
format = args[ 1 ]
arg_pos = arg_pos + 1
end
if type( format ) == "table" then
players = format
format = args[ 1 ]
arg_pos = arg_pos + 1
end
if hide_echo then
for i=#players, 1, -1 do
if not ULib.ucl.query( players[ i ], hiddenechoAccess ) and players[ i ] ~= calling_ply then
table.remove( players, i )
end
end
end
table.insert( players, "CONSOLE" ) -- Dummy player used for logging and printing to dedicated console window
local playerStrs = {}
for i=1, #players do
playerStrs[ i ] = {}
end
if hide_echo then
insertToAll( playerStrs, default_color )
insertToAll( playerStrs, "(SILENT) " )
end
local no_targets = false
format:gsub( "([^#]*)#([%.%d]*[%a])([^#]*)", function( prefix, tag, postfix )
if prefix and prefix ~= "" then
insertToAll( playerStrs, default_color )
insertToAll( playerStrs, prefix )
end
local specifier = tag:sub( -1, -1 )
local arg = args[ arg_pos ]
arg_pos = arg_pos + 1
local color, str
if specifier == "T" or specifier == "P" or (specifier == "A" and calling_ply) then
if specifier == "A" then
arg_pos = arg_pos - 1 -- This doesn't have an arg since it's at the start
arg = { calling_ply }
elseif type( arg ) ~= "table" then
arg = { arg }
end
if #arg == 0 then no_targets = true end -- NO PLAYERS, NO LOG!!
for i=1, #players do
table.Add( playerStrs[ i ], makePlayerList( calling_ply, arg, players[ i ], use_self_suffix, specifier == "A" ) )
end
use_self_suffix = true
else
insertToAll( playerStrs, misc_color )
insertToAll( playerStrs, string.format( "%" .. tag, arg ) )
end
if postfix and postfix ~= "" then
insertToAll( playerStrs, default_color )
insertToAll( playerStrs, postfix )
end
end )
if no_targets then -- We don't want to log if there's nothing being targetted
return
end
for i=1, #players do
if not logEchoColors:GetBool() or players[ i ] == "CONSOLE" then -- They don't want coloring :)
for j=#playerStrs[ i ], 1, -1 do
if type( playerStrs[ i ][ j ] ) == "table" then
table.remove( playerStrs[ i ], j )
end
end
end
if players[ i ] ~= "CONSOLE" then
ULib.tsayColor( players[ i ], true, unpack( playerStrs[ i ] ) )
else
local msg = table.concat( playerStrs[ i ] )
if game.IsDedicated() then
Msg( msg .. "\n" )
end
if logFile:GetBool() then
ulx.logString( msg, true )
end
end
end
end
function ulx.fancyLog( format, ... )
ulx.fancyLogAdmin( _, format, ... )
end

View File

@ -1,49 +0,0 @@
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

View File

@ -1,10 +0,0 @@
ulx.teams = ulx.teams or {}
function ulx.populateClTeams( teams )
ulx.teams = teams
for i=1, #teams do
local team_data = teams[ i ]
team.SetUp( team_data.index, team_data.name, team_data.color )
end
end

View File

@ -1,566 +0,0 @@
--XGUI: A GUI for ULX -- by Stickly Man!
xgui = xgui or {}
--Make a spot for modules to store data and hooks
xgui.data = xgui.data or {}
xgui.hook = xgui.hook or { onProcessModules={}, onOpen={}, onClose={} }
--Call this function in your client-side module code to ensure the data types have been instantiated on the client.
function xgui.prepareDataType( dtype, location )
if not xgui.data[dtype] then
xgui.data[dtype] = location or {}
xgui.hook[dtype] = { clear={}, process={}, done={}, add={}, update={}, remove={}, data={} }
end
end
--Set up various hooks modules can "hook" into.
function xgui.hookEvent( dtype, event, func, name )
if not xgui.hook[dtype] or ( event and not xgui.hook[dtype][event] ) then
Msg( "XGUI: Attempted to add to invalid type or event to a hook! (" .. dtype .. ", " .. ( event or "nil" ) .. ")\n" )
else
if not name then name = "FixMe" .. math.floor(math.random()*10000) end -- Backwards compatibility for older XGUI modules
if not event then
xgui.hook[dtype][name] = func
else
xgui.hook[dtype][event][name] = func
end
end
end
--Set up tables and functions for creating and storing modules
xgui.modules = xgui.modules or {}
xgui.modules.tab = xgui.modules.tab or {}
function xgui.addModule( name, panel, icon, access, tooltip )
local refreshModules = false
for i = #xgui.modules.tab, 1, -1 do
if xgui.modules.tab[i].name == name then
xgui.modules.tab[i].panel:Remove()
xgui.modules.tab[i].tabpanel:Remove()
xgui.modules.tab[i].xbutton:Remove()
table.remove(xgui.modules.tab, i)
refreshModules = true
end
end
table.insert( xgui.modules.tab, { name=name, panel=panel, icon=icon, access=access, tooltip=tooltip } )
if refreshModules then xgui.processModules() end
end
xgui.modules.setting = xgui.modules.setting or {}
function xgui.addSettingModule( name, panel, icon, access, tooltip )
local refreshModules = false
for i = #xgui.modules.setting, 1, -1 do
if xgui.modules.setting[i].name == name then
xgui.modules.setting[i].panel:Remove()
xgui.modules.setting[i].tabpanel:Remove()
table.remove(xgui.modules.setting, i)
refreshModules = true
end
end
table.insert( xgui.modules.setting, { name=name, panel=panel, icon=icon, access=access, tooltip=tooltip } )
if refreshModules then xgui.processModules() end
end
xgui.modules.submodule = xgui.modules.submodule or {}
function xgui.addSubModule( name, panel, access, mtype )
local refreshModules = false
for i = #xgui.modules.submodule, 1, -1 do
if xgui.modules.submodule[i].name == name then
xgui.modules.submodule[i].panel:Remove()
table.remove(xgui.modules.submodule, i)
refreshModules = true
end
end
table.insert( xgui.modules.submodule, { name=name, panel=panel, access=access, mtype=mtype } )
if refreshModules then xgui.processModules() end
end
--Set up a spot to store entries for autocomplete.
xgui.tabcompletes = xgui.tabcompletes or {}
xgui.ulxmenucompletes = xgui.ulxmenucompletes or {}
--Set up XGUI clientside settings, load settings from file if it exists
xgui.settings = xgui.settings or {}
if ULib.fileExists( "data/ulx/xgui_settings.txt" ) then
local input = ULib.fileRead( "data/ulx/xgui_settings.txt" )
input = input:match( "^.-\n(.*)$" )
xgui.settings = ULib.parseKeyValues( input )
end
--Set default settings if they didn't get loaded
if not xgui.settings.moduleOrder then xgui.settings.moduleOrder = { "Cmds", "Groups", "Maps", "Settings", "Bans" } end
if not xgui.settings.settingOrder then xgui.settings.settingOrder = { "Sandbox", "Server", "Client" } end
if not xgui.settings.animTime then xgui.settings.animTime = 0.22 else xgui.settings.animTime = tonumber( xgui.settings.animTime ) end
if not xgui.settings.infoColor then
--Default color
xgui.settings.infoColor = Color( 100, 255, 255, 128 )
else
--Ensure that the color contains numbers, not strings
xgui.settings.infoColor = Color(xgui.settings.infoColor.r, xgui.settings.infoColor.g, xgui.settings.infoColor.b, xgui.settings.infoColor.a)
end
if not xgui.settings.showLoadMsgs then xgui.settings.showLoadMsgs = true else xgui.settings.showLoadMsgs = ULib.toBool( xgui.settings.showLoadMsgs ) end
if not xgui.settings.skin then xgui.settings.skin = "Default" end
if not xgui.settings.xguipos then xgui.settings.xguipos = { pos=5, xoff=0, yoff=0 } end
if not xgui.settings.animIntype then xgui.settings.animIntype = 1 end
if not xgui.settings.animOuttype then xgui.settings.animOuttype = 1 end
function xgui.init( ply )
xgui.load_helpers()
--Initiate the base window (see xgui_helpers.lua for code)
xgui.makeXGUIbase{}
--Create the bottom infobar
xgui.infobar = xlib.makepanel{ x=10, y=399, w=580, h=20, parent=xgui.anchor }
xgui.infobar:NoClipping( true )
xgui.infobar.Paint = function( self, w, h )
draw.RoundedBoxEx( 4, 0, 1, 580, 20, xgui.settings.infoColor, false, false, true, true )
end
xlib.makelabel{ x=5, y=-10, label="\nULX Admin Mod :: XGUI - by Stickly Man! :: v15.11.7 | ULX " .. ulx.getVersion() .. " | ULib " .. ULib.getVersion(), parent=xgui.infobar }:NoClipping( true )
xgui.thetime = xlib.makelabel{ x=515, y=-10, label="", parent=xgui.infobar }
xgui.thetime:NoClipping( true )
xgui.thetime.check = function()
xgui.thetime:SetText( os.date( "\n%I:%M:%S %p" ) )
xgui.thetime:SizeToContents()
timer.Simple( 1, xgui.thetime.check )
end
xgui.thetime.check()
--Create an offscreen place to parent modules that the player can't access
xgui.null = xlib.makepanel{ x=-10, y=-10, w=0, h=0 }
xgui.null:SetVisible( false )
--Load modules
local sm = xgui.settings.showLoadMsgs
if sm then
Msg( "\n///////////////////////////////////////\n" )
Msg( "// ULX GUI -- Made by Stickly Man! //\n" )
Msg( "///////////////////////////////////////\n" )
Msg( "// Loading GUI Modules... //\n" )
end
for _, file in ipairs( file.Find( "ulx/xgui/*.lua", "LUA" ) ) do
include( "ulx/xgui/" .. file )
if sm then Msg( "// " .. file .. string.rep( " ", 32 - file:len() ) .. "//\n" ) end
end
if sm then Msg( "// Loading Setting Modules... //\n" ) end
for _, file in ipairs( file.Find( "ulx/xgui/settings/*.lua", "LUA" ) ) do
include( "ulx/xgui/settings/" .. file )
if sm then Msg( "// " .. file .. string.rep( " ", 32 - file:len() ) .. "//\n" ) end
end
if sm then Msg( "// Loading Gamemode Module(s)... //\n" ) end
if ULib.isSandbox() and GAMEMODE.FolderName ~= "sandbox" then -- If the gamemode sandbox-derived (but not sandbox, that will get added later), then add the sandbox Module
include( "ulx/xgui/gamemodes/sandbox.lua" )
if sm then Msg( "// sandbox.lua //\n" ) end
end
for _, file in ipairs( file.Find( "ulx/xgui/gamemodes/*.lua", "LUA" ) ) do
if string.lower( file ) == string.lower( GAMEMODE.FolderName .. ".lua" ) then
include( "ulx/xgui/gamemodes/" .. file )
if sm then Msg( "// " .. file .. string.rep( " ", 32 - file:len() ) .. "//\n" ) end
break
end
if sm then Msg( "// No module found! //\n" ) end
end
if sm then Msg( "// Modules Loaded! //\n" ) end
if sm then Msg( "///////////////////////////////////////\n\n" ) end
--Find any existing modules that aren't listed in the requested order.
local function checkModulesOrder( moduleTable, sortTable )
for _, m in ipairs( moduleTable ) do
local notlisted = true
for _, existing in ipairs( sortTable ) do
if m.name == existing then
notlisted = false
break
end
end
if notlisted then
table.insert( sortTable, m.name )
end
end
end
checkModulesOrder( xgui.modules.tab, xgui.settings.moduleOrder )
checkModulesOrder( xgui.modules.setting, xgui.settings.settingOrder )
--Check if the server has XGUI installed
RunConsoleCommand( "_xgui", "getInstalled" )
xgui.initialized = true
xgui.processModules()
end
hook.Add( ULib.HOOK_LOCALPLAYERREADY, "InitXGUI", xgui.init, HOOK_MONITOR_LOW )
function xgui.saveClientSettings()
if not ULib.fileIsDir( "data/ulx" ) then
ULib.fileCreateDir( "data/ulx" )
end
local output = "// This file stores clientside settings for XGUI.\n"
output = output .. ULib.makeKeyValues( xgui.settings )
ULib.fileWrite( "data/ulx/xgui_settings.txt", output )
end
function xgui.checkModuleExists( modulename, moduletable )
for k, v in ipairs( moduletable ) do
if v.name == modulename then
return k
end
end
return false
end
function xgui.processModules()
local activetab = nil
if xgui.base:GetActiveTab() then
activetab = xgui.base:GetActiveTab():GetValue()
end
local activesettingstab = nil
if xgui.settings_tabs:GetActiveTab() then
activesettingstab = xgui.settings_tabs:GetActiveTab():GetValue()
end
xgui.base:Clear() --We need to remove any existing tabs in the GUI
xgui.tabcompletes = {}
xgui.ulxmenucompletes = {}
for _, modname in ipairs( xgui.settings.moduleOrder ) do
local module = xgui.checkModuleExists( modname, xgui.modules.tab )
if module then
module = xgui.modules.tab[module]
if module.xbutton == nil then
module.xbutton = xlib.makebutton{ x=555, y=-5, w=32, h=32, btype="close", parent=module.panel }
module.xbutton.DoClick = function()
xgui.hide()
end
end
if LocalPlayer():query( module.access ) then
xgui.base:AddSheet( module.name, module.panel, module.icon, false, false, module.tooltip )
module.tabpanel = xgui.base.Items[#xgui.base.Items].Tab
table.insert( xgui.tabcompletes, "xgui show " .. modname )
table.insert( xgui.ulxmenucompletes, "ulx menu " .. modname )
else
module.tabpanel = nil
module.panel:SetParent( xgui.null )
end
end
end
xgui.settings_tabs:Clear() --Clear out settings tabs for reprocessing
for _, modname in ipairs( xgui.settings.settingOrder ) do
local module = xgui.checkModuleExists( modname, xgui.modules.setting )
if module then
module = xgui.modules.setting[module]
if LocalPlayer():query( module.access ) then
xgui.settings_tabs:AddSheet( module.name, module.panel, module.icon, false, false, module.tooltip )
module.tabpanel = xgui.settings_tabs.Items[#xgui.settings_tabs.Items].Tab
table.insert( xgui.tabcompletes, "xgui show " .. modname )
table.insert( xgui.ulxmenucompletes, "ulx menu " .. modname )
else
module.tabpanel = nil
module.panel:SetParent( xgui.null )
end
end
end
--Call any functions that requested to be called when permissions change
xgui.callUpdate( "onProcessModules" )
table.sort( xgui.tabcompletes )
table.sort( xgui.ulxmenucompletes )
local hasFound = false
if activetab then
for _, v in pairs( xgui.base.Items ) do
if v.Tab:GetValue() == activetab then
xgui.base:SetActiveTab( v.Tab, true )
hasFound = true
break
end
end
if not hasFound then
xgui.base.m_pActiveTab = "none"
xgui.base:SetActiveTab( xgui.base.Items[1].Tab, true )
end
end
hasFound = false
if activesettingstab then
for _, v in pairs( xgui.settings_tabs.Items ) do
if v.Tab:GetValue() == activesettingstab then
xgui.settings_tabs:SetActiveTab( v.Tab, true )
hasFound = true
break
end
end
if not hasFound then
xgui.settings_tabs.m_pActiveTab = "none"
xgui.settings_tabs:SetActiveTab( xgui.settings_tabs.Items[1].Tab, true )
end
end
end
function xgui.checkNotInstalled( tabname )
if xgui.notInstalledWarning then return end
gui.EnableScreenClicker( true )
RestoreCursorPosition()
xgui.notInstalledWarning = xlib.makeframe{ label="XGUI Warning!", w=375, h=110, nopopup=true, showclose=false, skin=xgui.settings.skin }
xlib.makelabel{ x=10, y=30, wordwrap=true, w=365, label="XGUI has not initialized properly with the server. This could be caused by a heavy server load after a mapchange, a major error during XGUI server startup, or XGUI not being installed.", parent=xgui.notInstalledWarning }
xlib.makebutton{ x=37, y=83, w=80, label="Offline Mode", parent=xgui.notInstalledWarning }.DoClick = function()
xgui.notInstalledWarning:Remove()
xgui.notInstalledWarning = nil
offlineWarning = xlib.makeframe{ label="XGUI Warning!", w=375, h=110, nopopup=true, showclose=false, skin=xgui.settings.skin }
xlib.makelabel{ x=10, y=30, wordwrap=true, w=365, label="XGUI will run locally in offline mode. Some features will not work, and information will be missing. You can attempt to reconnect to the server using the 'Refresh Server Data' button in the XGUI client menu.", parent=offlineWarning }
xlib.makebutton{ x=77, y=83, w=80, label="OK", parent=offlineWarning }.DoClick = function()
offlineWarning:Remove()
xgui.offlineMode = true
xgui.show( tabname )
end
xlib.makebutton{ x=217, y=83, w=80, label="Cancel", parent=offlineWarning }.DoClick = function()
offlineWarning:Remove()
RememberCursorPosition()
gui.EnableScreenClicker( false )
end
end
xlib.makebutton{ x=257, y=83, w=80, label="Close", parent=xgui.notInstalledWarning }.DoClick = function()
xgui.notInstalledWarning:Remove()
xgui.notInstalledWarning = nil
RememberCursorPosition()
gui.EnableScreenClicker( false )
end
xlib.makebutton{ x=147, y=83, w=80, label="Try Again", parent=xgui.notInstalledWarning }.DoClick = function()
xgui.notInstalledWarning:Remove()
xgui.notInstalledWarning = nil
RememberCursorPosition()
gui.EnableScreenClicker( false )
local reattempt = xlib.makeframe{ label="XGUI: Attempting reconnection...", w=200, h=20, nopopup=true, showclose=false, skin=xgui.settings.skin }
timer.Simple( 1, function()
RunConsoleCommand( "_xgui", "getInstalled" )
reattempt:Remove()
timer.Simple( 0.5, function() xgui.show( tabname ) end )
end )
end
end
function xgui.show( tabname )
if not xgui.anchor then return end
if not xgui.initialized then return end
--Check if XGUI is not installed, display the warning if hasn't been shown yet.
if not xgui.isInstalled and not xgui.offlineMode then
xgui.checkNotInstalled( tabname )
return
end
if not game.SinglePlayer() and not ULib.ucl.authed[LocalPlayer():UniqueID()] then
local unauthedWarning = xlib.makeframe{ label="XGUI Error!", w=250, h=90, showclose=true, skin=xgui.settings.skin }
xlib.makelabel{ label="Your ULX player has not been Authed!", x=10, y=30, parent=unauthedWarning }
xlib.makelabel{ label="Please wait a couple seconds and try again.", x=10, y=45, parent=unauthedWarning }
xlib.makebutton{ x=50, y=63, w=60, label="Try Again", parent=unauthedWarning }.DoClick = function()
unauthedWarning:Remove()
xgui.show( tabname )
end
xlib.makebutton{ x=140, y=63, w=60, label="Close", parent=unauthedWarning }.DoClick = function()
unauthedWarning:Remove()
end
return
end
if xgui.base.refreshSkin then
xgui.base:SetSkin( xgui.settings.skin )
xgui.base.refreshSkin = nil
end
--In case the string name had spaces, it sent the whole argument table. Convert it to a string here!
if type( tabname ) == "table" then
tabname = table.concat( tabname, " " )
end
--Sets the active tab to tabname if it was specified
if tabname and tabname ~= "" then
local found, settingsTab
for _, v in ipairs( xgui.modules.tab ) do
if string.lower( v.name ) == "settings" then settingsTab = v.tabpanel end
if string.lower( v.name ) == string.lower( tabname ) and v.panel:GetParent() ~= xgui.null then
xgui.base:SetActiveTab( v.tabpanel )
if xgui.anchor:IsVisible() then return end
found = true
break
end
end
if not found then
for _, v in ipairs( xgui.modules.setting ) do
if string.lower( v.name ) == string.lower( tabname ) and v.panel:GetParent() ~= xgui.null then
xgui.base:SetActiveTab( settingsTab )
xgui.settings_tabs:SetActiveTab( v.tabpanel )
if xgui.anchor:IsVisible() then return end
found = true
break
end
end
end
if not found then return end --If invalid input was taken, then do nothing.
end
xgui.base.animOpen()
gui.EnableScreenClicker( true )
RestoreCursorPosition()
xgui.anchor:SetMouseInputEnabled( true )
--Calls the functions requesting to hook when XGUI is opened
xgui.callUpdate( "onOpen" )
end
function xgui.hide()
if not xgui.anchor then return end
if not xgui.anchor:IsVisible() then return end
RememberCursorPosition()
gui.EnableScreenClicker( false )
xgui.anchor:SetMouseInputEnabled( false )
xgui.base.animClose()
CloseDermaMenus()
--Calls the functions requesting to hook when XGUI is closed
xgui.callUpdate( "onClose" )
end
function xgui.toggle( tabname )
if xgui.anchor and ( not xgui.anchor:IsVisible() or ( tabname and #tabname ~= 0 ) ) then
xgui.show( tabname )
else
xgui.hide()
end
end
--New XGUI Data stuff
function xgui.expectChunks( numofchunks )
if xgui.isInstalled then
xgui.expectingdata = true
xgui.chunkbox.max = numofchunks
xgui.chunkbox.value = 0
xgui.chunkbox:SetFraction( 0 )
xgui.chunkbox.Label:SetText( "Getting data: Waiting for server..." )
xgui.chunkbox:SetVisible( true )
xgui.chunkbox:SetSkin( xgui.settings.skin )
xgui.flushQueue( "chunkbox" ) --Remove the queue entry that would hide the chunkbox
end
end
function xgui.getChunk( flag, datatype, data )
if xgui.expectingdata then
--print( datatype, flag ) --Debug
xgui.chunkbox:Progress( datatype )
if flag == -1 then return --Ignore these chunks
elseif flag == 0 then --Data should be purged
if xgui.data[datatype] then
table.Empty( xgui.data[datatype] )
end
xgui.flushQueue( datatype )
xgui.callUpdate( datatype, "clear" )
elseif flag == 1 then
if not xgui.mergeData then --A full data table is coming in
if not data then data = {} end --Failsafe for no table being sent
xgui.flushQueue( datatype )
table.Empty( xgui.data[datatype] )
table.Merge( xgui.data[datatype], data )
xgui.callUpdate( datatype, "clear" )
xgui.callUpdate( datatype, "process", data )
xgui.callUpdate( datatype, "done" )
else --A chunk of data is coming in
table.Merge( xgui.data[datatype], data )
xgui.callUpdate( datatype, "process", data )
end
elseif flag == 2 or flag == 3 then --Add/Update a portion of data
table.Merge( xgui.data[datatype], data )
xgui.callUpdate( datatype, flag == 2 and "add" or "update", data )
elseif flag == 4 then --Remove a key from the table
xgui.removeDataEntry( xgui.data[datatype], data ) --Needs to be called recursively!
xgui.callUpdate( datatype, "remove", data )
elseif flag == 5 then --Begin a set of chunks (Clear the old data, then flag to merge incoming data)
table.Empty( xgui.data[datatype] )
xgui.mergeData = true
xgui.flushQueue( datatype )
xgui.callUpdate( datatype, "clear" )
elseif flag == 6 then --End a set of chunks (Clear the merge flag)
xgui.mergeData = nil
xgui.callUpdate( datatype, "done" )
elseif flag == 7 then --Pass the data directly to the module to be handled.
xgui.callUpdate( datatype, "data", data )
end
end
end
function xgui.removeDataEntry( data, entry )
for k, v in pairs( entry ) do
if type( v ) == "table" then
xgui.removeDataEntry( data[k], v )
else
if type(v) == "number" then
table.remove( data, v )
else
data[v] = nil
end
end
end
end
function xgui.callUpdate( dtype, event, data )
--Run any functions that request to be called when "curtable" is updated
if not xgui.hook[dtype] or ( event and not xgui.hook[dtype][event] ) then
Msg( "XGUI: Attempted to call non-existent type or event to a hook! (" .. dtype .. ", " .. ( event or "nil" ) .. ")\n" )
else
if not event then
for name, func in pairs( xgui.hook[dtype] ) do func( data ) end
else
for name, func in pairs( xgui.hook[dtype][event] ) do func( data ) end
end
end
end
--If the player's group is changed, reprocess the XGUI modules for permissions, and request for extra data if needed
function xgui.PermissionsChanged( ply )
if ply == LocalPlayer() and xgui.isInstalled then
xgui.processModules()
local types = {}
for dtype, data in pairs( xgui.data ) do
if table.Count( data ) > 0 then table.insert( types, dtype ) end
end
RunConsoleCommand( "xgui", "refreshdata", unpack( types ) )
end
end
hook.Add( "UCLAuthed", "XGUI_PermissionsChanged", xgui.PermissionsChanged )
function xgui.getInstalled()
if not xgui.isInstalled then
if xgui.notInstalledWarning then
xgui.notInstalledWarning:Remove()
xgui.notInstalledWarning = nil
end
xgui.isInstalled = true
xgui.offlineMode = false
RunConsoleCommand( "xgui", "getdata" )
end
end
function xgui.cmd_base( ply, func, args )
if not args[ 1 ] then
xgui.toggle()
elseif xgui.isInstalled then --First check that it's installed
RunConsoleCommand( "_xgui", unpack( args ) )
end
end
function xgui.tab_completes()
return xgui.tabcompletes
end
function xgui.ulxmenu_tab_completes()
return xgui.ulxmenucompletes
end
ULib.cmds.addCommandClient( "xgui", xgui.cmd_base )
ULib.cmds.addCommandClient( "xgui show", function( ply, cmd, args ) xgui.show( args ) end, xgui.tab_completes )
ULib.cmds.addCommandClient( "xgui hide", xgui.hide )
ULib.cmds.addCommandClient( "xgui toggle", function() xgui.toggle() end )
--local ulxmenu = ulx.command( CATEGORY_NAME, "ulx menu", ulx.menu, "!menu" )
ULib.cmds.addCommandClient( "ulx menu", function( ply, cmd, args ) xgui.toggle( args ) end, xgui.ulxmenu_tab_completes )

View File

@ -1,406 +0,0 @@
--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

View File

@ -1,316 +0,0 @@
-- This module holds any type of chatting functions
CATEGORY_NAME = "Chat"
------------------------------ Psay ------------------------------
function ulx.psay( calling_ply, target_ply, message )
ulx.fancyLog( { target_ply, calling_ply }, "#P to #P: " .. message, calling_ply, target_ply )
end
local psay = ulx.command( CATEGORY_NAME, "ulx psay", ulx.psay, "!p", true )
psay:addParam{ type=ULib.cmds.PlayerArg, target="!^", ULib.cmds.ignoreCanTarget }
psay:addParam{ type=ULib.cmds.StringArg, hint="message", ULib.cmds.takeRestOfLine }
psay:defaultAccess( ULib.ACCESS_ALL )
psay:help( "Send a private message to target." )
------------------------------ Asay ------------------------------
local seeasayAccess = "ulx seeasay"
if SERVER then ULib.ucl.registerAccess( seeasayAccess, ULib.ACCESS_OPERATOR, "Ability to see 'ulx asay'", "Other" ) end -- Give operators access to see asays echoes by default
function ulx.asay( calling_ply, message )
local format
local me = "/me "
if message:sub( 1, me:len() ) == me then
format = "(ADMINS) *** #P #s"
message = message:sub( me:len() + 1 )
else
format = "#P to admins: #s"
end
local players = player.GetAll()
for i=#players, 1, -1 do
local v = players[ i ]
if not ULib.ucl.query( v, seeasayAccess ) and v ~= calling_ply then -- Calling player always gets to see the echo
table.remove( players, i )
end
end
ulx.fancyLog( players, format, calling_ply, message )
end
local asay = ulx.command( CATEGORY_NAME, "ulx asay", ulx.asay, "@", true, true )
asay:addParam{ type=ULib.cmds.StringArg, hint="message", ULib.cmds.takeRestOfLine }
asay:defaultAccess( ULib.ACCESS_ALL )
asay:help( "Send a message to currently connected admins." )
------------------------------ Tsay ------------------------------
function ulx.tsay( calling_ply, message )
ULib.tsay( _, message )
if ULib.toBool( GetConVarNumber( "ulx_logChat" ) ) then
ulx.logString( string.format( "(tsay from %s) %s", calling_ply:IsValid() and calling_ply:Nick() or "Console", message ) )
end
end
local tsay = ulx.command( CATEGORY_NAME, "ulx tsay", ulx.tsay, "@@", true, true )
tsay:addParam{ type=ULib.cmds.StringArg, hint="message", ULib.cmds.takeRestOfLine }
tsay:defaultAccess( ULib.ACCESS_ADMIN )
tsay:help( "Send a message to everyone in the chat box." )
------------------------------ Csay ------------------------------
function ulx.csay( calling_ply, message )
ULib.csay( _, message )
if ULib.toBool( GetConVarNumber( "ulx_logChat" ) ) then
ulx.logString( string.format( "(csay from %s) %s", calling_ply:IsValid() and calling_ply:Nick() or "Console", message ) )
end
end
local csay = ulx.command( CATEGORY_NAME, "ulx csay", ulx.csay, "@@@", true, true )
csay:addParam{ type=ULib.cmds.StringArg, hint="message", ULib.cmds.takeRestOfLine }
csay:defaultAccess( ULib.ACCESS_ADMIN )
csay:help( "Send a message to everyone in the middle of their screen." )
------------------------------ Thetime ------------------------------
local waittime = 60
local lasttimeusage = -waittime
function ulx.thetime( calling_ply )
if lasttimeusage + waittime > CurTime() then
ULib.tsayError( calling_ply, "I just told you what time it is! Please wait " .. waittime .. " seconds before using this command again", true )
return
end
lasttimeusage = CurTime()
ulx.fancyLog( "The time is now #s.", os.date( "%I:%M %p") )
end
local thetime = ulx.command( CATEGORY_NAME, "ulx thetime", ulx.thetime, "!thetime" )
thetime:defaultAccess( ULib.ACCESS_ALL )
thetime:help( "Shows you the server time." )
------------------------------ Adverts ------------------------------
ulx.adverts = ulx.adverts or {}
local adverts = ulx.adverts -- For XGUI, too lazy to change all refs
local function doAdvert( group, id )
if adverts[ group ][ id ] == nil then
if adverts[ group ].removed_last then
adverts[ group ].removed_last = nil
id = 1
else
id = #adverts[ group ]
end
end
local info = adverts[ group ][ id ]
local message = string.gsub( info.message, "%%curmap%%", game.GetMap() )
message = string.gsub( message, "%%host%%", GetConVarString( "hostname" ) )
message = string.gsub( message, "%%ulx_version%%", ulx.getVersion() )
if not info.len then -- tsay
local lines = ULib.explode( "\\n", message )
for i, line in ipairs( lines ) do
local trimmed = line:Trim()
if trimmed:len() > 0 then
ULib.tsayColor( _, true, info.color, trimmed ) -- Delaying runs one message every frame (to ensure correct order)
end
end
else
ULib.csay( _, message, info.color, info.len )
end
ULib.queueFunctionCall( function()
local nextid = math.fmod( id, #adverts[ group ] ) + 1
timer.Remove( "ULXAdvert" .. type( group ) .. group )
timer.Create( "ULXAdvert" .. type( group ) .. group, adverts[ group ][ nextid ].rpt, 1, function() doAdvert( group, nextid ) end )
end )
end
-- Whether or not it's a csay is determined by whether there's a value specified in "len"
function ulx.addAdvert( message, rpt, group, color, len )
local t
if group then
t = adverts[ tostring( group ) ]
if not t then
t = {}
adverts[ tostring( group ) ] = t
end
else
group = table.insert( adverts, {} )
t = adverts[ group ]
end
local id = table.insert( t, { message=message, rpt=rpt, color=color, len=len } )
if not timer.Exists( "ULXAdvert" .. type( group ) .. group ) then
timer.Create( "ULXAdvert" .. type( group ) .. group, rpt, 1, function() doAdvert( group, id ) end )
end
end
------------------------------ Gimp ------------------------------
ulx.gimpSays = ulx.gimpSays or {} -- Holds gimp says
local gimpSays = ulx.gimpSays -- For XGUI, too lazy to change all refs
local ID_GIMP = 1
local ID_MUTE = 2
function ulx.addGimpSay( say )
table.insert( gimpSays, say )
end
function ulx.clearGimpSays()
table.Empty( gimpSays )
end
function ulx.gimp( calling_ply, target_plys, should_ungimp )
for i=1, #target_plys do
local v = target_plys[ i ]
if should_ungimp then
v.gimp = nil
else
v.gimp = ID_GIMP
end
v:SetNWBool("ulx_gimped", not should_ungimp)
end
if not should_ungimp then
ulx.fancyLogAdmin( calling_ply, "#A gimped #T", target_plys )
else
ulx.fancyLogAdmin( calling_ply, "#A ungimped #T", target_plys )
end
end
local gimp = ulx.command( CATEGORY_NAME, "ulx gimp", ulx.gimp, "!gimp" )
gimp:addParam{ type=ULib.cmds.PlayersArg }
gimp:addParam{ type=ULib.cmds.BoolArg, invisible=true }
gimp:defaultAccess( ULib.ACCESS_ADMIN )
gimp:help( "Gimps target(s) so they are unable to chat normally." )
gimp:setOpposite( "ulx ungimp", {_, _, true}, "!ungimp" )
------------------------------ Mute ------------------------------
function ulx.mute( calling_ply, target_plys, should_unmute )
for i=1, #target_plys do
local v = target_plys[ i ]
if should_unmute then
v.gimp = nil
else
v.gimp = ID_MUTE
end
v:SetNWBool("ulx_muted", not should_unmute)
end
if not should_unmute then
ulx.fancyLogAdmin( calling_ply, "#A muted #T", target_plys )
else
ulx.fancyLogAdmin( calling_ply, "#A unmuted #T", target_plys )
end
end
local mute = ulx.command( CATEGORY_NAME, "ulx mute", ulx.mute, "!mute" )
mute:addParam{ type=ULib.cmds.PlayersArg }
mute:addParam{ type=ULib.cmds.BoolArg, invisible=true }
mute:defaultAccess( ULib.ACCESS_ADMIN )
mute:help( "Mutes target(s) so they are unable to chat." )
mute:setOpposite( "ulx unmute", {_, _, true}, "!unmute" )
if SERVER then
local function gimpCheck( ply, strText )
if ply.gimp == ID_MUTE then return "" end
if ply.gimp == ID_GIMP then
if #gimpSays < 1 then return nil end
return gimpSays[ math.random( #gimpSays ) ]
end
end
hook.Add( "PlayerSay", "ULXGimpCheck", gimpCheck, HOOK_LOW )
end
------------------------------ Gag ------------------------------
function ulx.gag( calling_ply, target_plys, should_ungag )
local players = player.GetAll()
for i=1, #target_plys do
local v = target_plys[ i ]
v.ulx_gagged = not should_ungag
v:SetNWBool("ulx_gagged", v.ulx_gagged)
end
if not should_ungag then
ulx.fancyLogAdmin( calling_ply, "#A gagged #T", target_plys )
else
ulx.fancyLogAdmin( calling_ply, "#A ungagged #T", target_plys )
end
end
local gag = ulx.command( CATEGORY_NAME, "ulx gag", ulx.gag, "!gag" )
gag:addParam{ type=ULib.cmds.PlayersArg }
gag:addParam{ type=ULib.cmds.BoolArg, invisible=true }
gag:defaultAccess( ULib.ACCESS_ADMIN )
gag:help( "Gag target(s), disables microphone." )
gag:setOpposite( "ulx ungag", {_, _, true}, "!ungag" )
local function gagHook( listener, talker )
if talker.ulx_gagged then
return false
end
end
hook.Add( "PlayerCanHearPlayersVoice", "ULXGag", gagHook )
-- Anti-spam stuff
if SERVER then
local chattime_cvar = ulx.convar( "chattime", "1.5", "<time> - Players can only chat every x seconds (anti-spam). 0 to disable.", ULib.ACCESS_ADMIN )
local function playerSay( ply )
if not ply.lastChatTime then ply.lastChatTime = 0 end
local chattime = chattime_cvar:GetFloat()
if chattime <= 0 then return end
if ply.lastChatTime + chattime > CurTime() then
return ""
else
ply.lastChatTime = CurTime()
return
end
end
hook.Add( "PlayerSay", "ulxPlayerSay", playerSay, HOOK_LOW )
local function meCheck( ply, strText, bTeam )
local meChatEnabled = GetConVarNumber( "ulx_meChatEnabled" )
if ply.gimp or meChatEnabled == 0 or (meChatEnabled ~= 2 and GAMEMODE.Name ~= "Sandbox") then return end -- Don't mess
if strText:sub( 1, 4 ) == "/me " then
strText = string.format( "*** %s %s", ply:Nick(), strText:sub( 5 ) )
if not bTeam then
ULib.tsay( _, strText )
else
strText = "(TEAM) " .. strText
local teamid = ply:Team()
local players = team.GetPlayers( teamid )
for _, ply2 in ipairs( players ) do
ULib.tsay( ply2, strText )
end
end
if game.IsDedicated() then
Msg( strText .. "\n" ) -- Log to console
end
if ULib.toBool( GetConVarNumber( "ulx_logChat" ) ) then
ulx.logString( strText )
end
return ""
end
end
hook.Add( "PlayerSay", "ULXMeCheck", meCheck, HOOK_LOW ) -- Extremely low priority
end
local function showWelcome( ply )
local message = GetConVarString( "ulx_welcomemessage" )
if not message or message == "" then return end
message = string.gsub( message, "%%curmap%%", game.GetMap() )
message = string.gsub( message, "%%host%%", GetConVarString( "hostname" ) )
message = string.gsub( message, "%%ulx_version%%", ulx.getVersion() )
ply:ChatPrint( message ) -- We're not using tsay because ULib might not be loaded yet. (client side)
end
hook.Add( "PlayerInitialSpawn", "ULXWelcome", showWelcome )
if SERVER then
ulx.convar( "meChatEnabled", "1", "Allow players to use '/me' in chat. 0 = Disabled, 1 = Sandbox only (Default), 2 = Enabled", ULib.ACCESS_ADMIN )
ulx.convar( "welcomemessage", "", "<msg> - This is shown to players on join.", ULib.ACCESS_ADMIN )
end

File diff suppressed because it is too large Load Diff

View File

@ -1,48 +0,0 @@
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

View File

@ -1,120 +0,0 @@
-- This module holds any type of remote execution functions (IE, 'dangerous')
local CATEGORY_NAME = "Rcon"
function ulx.rcon( calling_ply, command )
ULib.consoleCommand( command .. "\n" )
ulx.fancyLogAdmin( calling_ply, true, "#A ran rcon command: #s", command )
end
local rcon = ulx.command( CATEGORY_NAME, "ulx rcon", ulx.rcon, "!rcon", true )
rcon:addParam{ type=ULib.cmds.StringArg, hint="command", ULib.cmds.takeRestOfLine }
rcon:defaultAccess( ULib.ACCESS_SUPERADMIN )
rcon:help( "Execute command on server console." )
function ulx.luaRun( calling_ply, command )
local return_results = false
if command:sub( 1, 1 ) == "=" then
command = "tmp_var" .. command
return_results = true
end
RunString( command )
if return_results then
if type( tmp_var ) == "table" then
ULib.console( calling_ply, "Result:" )
local lines = ULib.explode( "\n", ulx.dumpTable( tmp_var ) )
local chunk_size = 50
for i=1, #lines, chunk_size do -- Break it up so we don't overflow the client
ULib.queueFunctionCall( function()
for j=i, math.min( i+chunk_size-1, #lines ) do
ULib.console( calling_ply, lines[ j ]:gsub( "%%", "<p>" ) )
end
end )
end
else
ULib.console( calling_ply, "Result: " .. tostring( tmp_var ):gsub( "%%", "<p>" ) )
end
end
ulx.fancyLogAdmin( calling_ply, true, "#A ran lua: #s", command )
end
local luarun = ulx.command( CATEGORY_NAME, "ulx luarun", ulx.luaRun )
luarun:addParam{ type=ULib.cmds.StringArg, hint="command", ULib.cmds.takeRestOfLine }
luarun:defaultAccess( ULib.ACCESS_SUPERADMIN )
luarun:help( "Executes lua in server console. (Use '=' for output)" )
function ulx.exec( calling_ply, config )
if string.sub( config, -4 ) ~= ".cfg" then config = config .. ".cfg" end
if not ULib.fileExists( "cfg/" .. config ) then
ULib.tsayError( calling_ply, "That config does not exist!", true )
return
end
ULib.execFile( "cfg/" .. config )
ulx.fancyLogAdmin( calling_ply, "#A executed file #s", config )
end
local exec = ulx.command( CATEGORY_NAME, "ulx exec", ulx.exec )
exec:addParam{ type=ULib.cmds.StringArg, hint="file" }
exec:defaultAccess( ULib.ACCESS_SUPERADMIN )
exec:help( "Execute a file from the cfg directory on the server." )
function ulx.cexec( calling_ply, target_plys, command )
for _, v in ipairs( target_plys ) do
v:ConCommand( command )
end
ulx.fancyLogAdmin( calling_ply, "#A ran #s on #T", command, target_plys )
end
local cexec = ulx.command( CATEGORY_NAME, "ulx cexec", ulx.cexec, "!cexec" )
cexec:addParam{ type=ULib.cmds.PlayersArg }
cexec:addParam{ type=ULib.cmds.StringArg, hint="command", ULib.cmds.takeRestOfLine }
cexec:defaultAccess( ULib.ACCESS_SUPERADMIN )
cexec:help( "Run a command on console of target(s)." )
function ulx.ent( calling_ply, classname, params )
if not calling_ply:IsValid() then
Msg( "Can't create entities from dedicated server console.\n" )
return
end
classname = classname:lower()
newEnt = ents.Create( classname )
-- Make sure it's a valid ent
if not newEnt or not newEnt:IsValid() then
ULib.tsayError( calling_ply, "Unknown entity type (" .. classname .. "), aborting.", true )
return
end
local trace = calling_ply:GetEyeTrace()
local vector = trace.HitPos
vector.z = vector.z + 20
newEnt:SetPos( vector ) -- Note that the position can be overridden by the user's flags
params:gsub( "([^|:\"]+)\"?:\"?([^|]+)", function( key, value )
key = key:Trim()
value = value:Trim()
newEnt:SetKeyValue( key, value )
end )
newEnt:Spawn()
newEnt:Activate()
undo.Create( "ulx_ent" )
undo.AddEntity( newEnt )
undo.SetPlayer( calling_ply )
undo.Finish()
if not params or params == "" then
ulx.fancyLogAdmin( calling_ply, "#A created ent #s", classname )
else
ulx.fancyLogAdmin( calling_ply, "#A created ent #s with params #s", classname, params )
end
end
local ent = ulx.command( CATEGORY_NAME, "ulx ent", ulx.ent )
ent:addParam{ type=ULib.cmds.StringArg, hint="classname" }
ent:addParam{ type=ULib.cmds.StringArg, hint="<flag> : <value> |", ULib.cmds.takeRestOfLine, ULib.cmds.optional }
ent:defaultAccess( ULib.ACCESS_SUPERADMIN )
ent:help( "Spawn an ent, separate flag and value with ':', flag:value pairs with '|'." )

View File

@ -1,288 +0,0 @@
CATEGORY_NAME = "Teleport"
-- Utility function for bring, goto, and send
local function playerSend( from, to, force )
if not to:IsInWorld() and not force then return false end -- No way we can do this one
local yawForward = to:EyeAngles().yaw
local directions = { -- Directions to try
math.NormalizeAngle( yawForward - 180 ), -- Behind first
math.NormalizeAngle( yawForward + 90 ), -- Right
math.NormalizeAngle( yawForward - 90 ), -- Left
yawForward,
}
local t = {}
t.start = to:GetPos() + Vector( 0, 0, 32 ) -- Move them up a bit so they can travel across the ground
t.filter = { to, from }
local i = 1
t.endpos = to:GetPos() + Angle( 0, directions[ i ], 0 ):Forward() * 47 -- (33 is player width, this is sqrt( 33^2 * 2 ))
local tr = util.TraceEntity( t, from )
while tr.Hit do -- While it's hitting something, check other angles
i = i + 1
if i > #directions then -- No place found
if force then
from.ulx_prevpos = from:GetPos()
from.ulx_prevang = from:EyeAngles()
return to:GetPos() + Angle( 0, directions[ 1 ], 0 ):Forward() * 47
else
return false
end
end
t.endpos = to:GetPos() + Angle( 0, directions[ i ], 0 ):Forward() * 47
tr = util.TraceEntity( t, from )
end
from.ulx_prevpos = from:GetPos()
from.ulx_prevang = from:EyeAngles()
return tr.HitPos
end
function ulx.bring( calling_ply, target_ply )
if not calling_ply:IsValid() then
Msg( "If you brought someone to you, they would instantly be destroyed by the awesomeness that is console.\n" )
return
end
if ulx.getExclusive( calling_ply, calling_ply ) then
ULib.tsayError( calling_ply, ulx.getExclusive( calling_ply, calling_ply ), true )
return
end
if ulx.getExclusive( target_ply, calling_ply ) then
ULib.tsayError( calling_ply, ulx.getExclusive( target_ply, calling_ply ), true )
return
end
if not target_ply:Alive() then
ULib.tsayError( calling_ply, target_ply:Nick() .. " is dead!", true )
return
end
if not calling_ply:Alive() then
ULib.tsayError( calling_ply, "You are dead!", true )
return
end
if calling_ply:InVehicle() then
ULib.tsayError( calling_ply, "Please leave the vehicle first!", true )
return
end
local newpos = playerSend( target_ply, calling_ply, target_ply:GetMoveType() == MOVETYPE_NOCLIP )
if not newpos then
ULib.tsayError( calling_ply, "Can't find a place to put the target!", true )
return
end
if target_ply:InVehicle() then
target_ply:ExitVehicle()
end
local newang = (calling_ply:GetPos() - newpos):Angle()
target_ply:SetPos( newpos )
target_ply:SetEyeAngles( newang )
target_ply:SetLocalVelocity( Vector( 0, 0, 0 ) ) -- Stop!
ulx.fancyLogAdmin( calling_ply, "#A brought #T", target_ply )
end
local bring = ulx.command( CATEGORY_NAME, "ulx bring", ulx.bring, "!bring" )
bring:addParam{ type=ULib.cmds.PlayerArg, target="!^" }
bring:defaultAccess( ULib.ACCESS_ADMIN )
bring:help( "Brings target to you." )
function ulx.goto( calling_ply, target_ply )
if not calling_ply:IsValid() then
Msg( "You may not step down into the mortal world from console.\n" )
return
end
if ulx.getExclusive( calling_ply, calling_ply ) then
ULib.tsayError( calling_ply, ulx.getExclusive( calling_ply, calling_ply ), true )
return
end
if not target_ply:Alive() then
ULib.tsayError( calling_ply, target_ply:Nick() .. " is dead!", true )
return
end
if not calling_ply:Alive() then
ULib.tsayError( calling_ply, "You are dead!", true )
return
end
if target_ply:InVehicle() and calling_ply:GetMoveType() ~= MOVETYPE_NOCLIP then
ULib.tsayError( calling_ply, "Target is in a vehicle! Noclip and use this command to force a goto.", true )
return
end
local newpos = playerSend( calling_ply, target_ply, calling_ply:GetMoveType() == MOVETYPE_NOCLIP )
if not newpos then
ULib.tsayError( calling_ply, "Can't find a place to put you! Noclip and use this command to force a goto.", true )
return
end
if calling_ply:InVehicle() then
calling_ply:ExitVehicle()
end
local newang = (target_ply:GetPos() - newpos):Angle()
calling_ply:SetPos( newpos )
calling_ply:SetEyeAngles( newang )
calling_ply:SetLocalVelocity( Vector( 0, 0, 0 ) ) -- Stop!
ulx.fancyLogAdmin( calling_ply, "#A teleported to #T", target_ply )
end
local goto = ulx.command( CATEGORY_NAME, "ulx goto", ulx.goto, "!goto" )
goto:addParam{ type=ULib.cmds.PlayerArg, target="!^", ULib.cmds.ignoreCanTarget }
goto:defaultAccess( ULib.ACCESS_ADMIN )
goto:help( "Goto target." )
function ulx.send( calling_ply, target_from, target_to )
if target_from == target_to then
ULib.tsayError( calling_ply, "You listed the same target twice! Please use two different targets.", true )
return
end
if ulx.getExclusive( target_from, calling_ply ) then
ULib.tsayError( calling_ply, ulx.getExclusive( target_from, calling_ply ), true )
return
end
if ulx.getExclusive( target_to, calling_ply ) then
ULib.tsayError( calling_ply, ulx.getExclusive( target_to, calling_ply ), true )
return
end
local nick = target_from:Nick() -- Going to use this for our error (if we have one)
if not target_from:Alive() or not target_to:Alive() then
if not target_to:Alive() then
nick = target_to:Nick()
end
ULib.tsayError( calling_ply, nick .. " is dead!", true )
return
end
if target_to:InVehicle() and target_from:GetMoveType() ~= MOVETYPE_NOCLIP then
ULib.tsayError( calling_ply, "Target is in a vehicle!", true )
return
end
local newpos = playerSend( target_from, target_to, target_from:GetMoveType() == MOVETYPE_NOCLIP )
if not newpos then
ULib.tsayError( calling_ply, "Can't find a place to put them!", true )
return
end
if target_from:InVehicle() then
target_from:ExitVehicle()
end
local newang = (target_from:GetPos() - newpos):Angle()
target_from:SetPos( newpos )
target_from:SetEyeAngles( newang )
target_from:SetLocalVelocity( Vector( 0, 0, 0 ) ) -- Stop!
ulx.fancyLogAdmin( calling_ply, "#A transported #T to #T", target_from, target_to )
end
local send = ulx.command( CATEGORY_NAME, "ulx send", ulx.send, "!send" )
send:addParam{ type=ULib.cmds.PlayerArg, target="!^" }
send:addParam{ type=ULib.cmds.PlayerArg, target="!^" }
send:defaultAccess( ULib.ACCESS_ADMIN )
send:help( "Goto target." )
function ulx.teleport( calling_ply, target_ply )
if not calling_ply:IsValid() then
Msg( "You are the console, you can't teleport or teleport others since you can't see the world!\n" )
return
end
if ulx.getExclusive( target_ply, calling_ply ) then
ULib.tsayError( calling_ply, ulx.getExclusive( target_ply, calling_ply ), true )
return
end
if not target_ply:Alive() then
ULib.tsayError( calling_ply, target_ply:Nick() .. " is dead!", true )
return
end
local t = {}
t.start = calling_ply:GetPos() + Vector( 0, 0, 32 ) -- Move them up a bit so they can travel across the ground
t.endpos = calling_ply:GetPos() + calling_ply:EyeAngles():Forward() * 16384
t.filter = target_ply
if target_ply ~= calling_ply then
t.filter = { target_ply, calling_ply }
end
local tr = util.TraceEntity( t, target_ply )
local pos = tr.HitPos
if target_ply == calling_ply and pos:Distance( target_ply:GetPos() ) < 64 then -- Laughable distance
return
end
target_ply.ulx_prevpos = target_ply:GetPos()
target_ply.ulx_prevang = target_ply:EyeAngles()
if target_ply:InVehicle() then
target_ply:ExitVehicle()
end
target_ply:SetPos( pos )
target_ply:SetLocalVelocity( Vector( 0, 0, 0 ) ) -- Stop!
if target_ply ~= calling_ply then
ulx.fancyLogAdmin( calling_ply, "#A teleported #T", target_ply ) -- We don't want to log otherwise
end
end
local teleport = ulx.command( CATEGORY_NAME, "ulx teleport", ulx.teleport, {"!tp", "!teleport"} )
teleport:addParam{ type=ULib.cmds.PlayerArg, ULib.cmds.optional }
teleport:defaultAccess( ULib.ACCESS_ADMIN )
teleport:help( "Teleports target." )
function ulx.retrn( calling_ply, target_ply )
if not target_ply:IsValid() then
Msg( "Return where? The console may never return to the mortal realm.\n" )
return
end
if not target_ply.ulx_prevpos then
ULib.tsayError( calling_ply, target_ply:Nick() .. " does not have any previous locations to send them to.", true )
return
end
if ulx.getExclusive( target_ply, calling_ply ) then
ULib.tsayError( calling_ply, ulx.getExclusive( target_ply, calling_ply ), true )
return
end
if not target_ply:Alive() then
ULib.tsayError( calling_ply, target_ply:Nick() .. " is dead!", true )
return
end
if target_ply:InVehicle() then
target_ply:ExitVehicle()
end
target_ply:SetPos( target_ply.ulx_prevpos )
target_ply:SetEyeAngles( target_ply.ulx_prevang )
target_ply.ulx_prevpos = nil
target_ply.ulx_prevang = nil
target_ply:SetLocalVelocity( Vector( 0, 0, 0 ) ) -- Stop!
ulx.fancyLogAdmin( calling_ply, "#A returned #T to their original position", target_ply )
end
local retrn = ulx.command( CATEGORY_NAME, "ulx return", ulx.retrn, "!return" )
retrn:addParam{ type=ULib.cmds.PlayerArg, ULib.cmds.optional }
retrn:defaultAccess( ULib.ACCESS_ADMIN )
retrn:help( "Returns target to last position before a teleport." )

View File

@ -1,364 +0,0 @@
local CATEGORY_NAME = "User Management"
local function checkForValidId( calling_ply, id )
if id == "BOT" or id == "NULL" then -- Bot check
return true
elseif id:find( "%." ) then -- Assume IP and check
if not ULib.isValidIP( id ) then
ULib.tsayError( calling_ply, "Invalid IP.", true )
return false
end
elseif id:find( ":" ) then
if not ULib.isValidSteamID( id ) then -- Assume steamid and check
ULib.tsayError( calling_ply, "Invalid steamid.", true )
return false
end
elseif not tonumber( id ) then -- Assume uniqueid and check
ULib.tsayError( calling_ply, "Invalid Unique ID", true )
return false
end
return true
end
ulx.group_names = {}
ulx.group_names_no_user = {}
local function updateNames()
table.Empty( ulx.group_names ) -- Don't reassign so we don't lose our refs
table.Empty( ulx.group_names_no_user )
for group_name, _ in pairs( ULib.ucl.groups ) do
table.insert( ulx.group_names, group_name )
if group_name ~= ULib.ACCESS_ALL then
table.insert( ulx.group_names_no_user, group_name )
end
end
end
hook.Add( ULib.HOOK_UCLCHANGED, "ULXGroupNamesUpdate", updateNames )
updateNames() -- Init
function ulx.usermanagementhelp( calling_ply )
if calling_ply:IsValid() then
ULib.clientRPC( calling_ply, "ulx.showUserHelp" )
else
ulx.showUserHelp()
end
end
local usermanagementhelp = ulx.command( CATEGORY_NAME, "ulx usermanagementhelp", ulx.usermanagementhelp )
usermanagementhelp:defaultAccess( ULib.ACCESS_ALL )
usermanagementhelp:help( "See the user management help." )
function ulx.adduser( calling_ply, target_ply, group_name )
local userInfo = ULib.ucl.authed[ target_ply:UniqueID() ]
local id = ULib.ucl.getUserRegisteredID( target_ply )
if not id then id = target_ply:SteamID() end
ULib.ucl.addUser( id, userInfo.allow, userInfo.deny, group_name )
ulx.fancyLogAdmin( calling_ply, "#A added #T to group #s", target_ply, group_name )
end
local adduser = ulx.command( CATEGORY_NAME, "ulx adduser", ulx.adduser )
adduser:addParam{ type=ULib.cmds.PlayerArg }
adduser:addParam{ type=ULib.cmds.StringArg, completes=ulx.group_names_no_user, hint="group", error="invalid group \"%s\" specified", ULib.cmds.restrictToCompletes }
adduser:defaultAccess( ULib.ACCESS_SUPERADMIN )
adduser:help( "Add a user to specified group." )
function ulx.adduserid( calling_ply, id, group_name )
id = id:upper() -- Steam id needs to be upper
-- Check for valid and properly formatted ID
if not checkForValidId( calling_ply, id ) then return false end
-- Now add the fool!
ULib.ucl.addUser( id, allows, denies, group_name )
if ULib.ucl.users[ id ] and ULib.ucl.users[ id ].name then
ulx.fancyLogAdmin( calling_ply, "#A added #s to group #s", ULib.ucl.users[ id ].name, group_name )
else
ulx.fancyLogAdmin( calling_ply, "#A added userid #s to group #s", id, group_name )
end
end
local adduserid = ulx.command( CATEGORY_NAME, "ulx adduserid", ulx.adduserid )
adduserid:addParam{ type=ULib.cmds.StringArg, hint="SteamID, IP, or UniqueID" }
adduserid:addParam{ type=ULib.cmds.StringArg, completes=ulx.group_names_no_user, hint="group", error="invalid group \"%s\" specified", ULib.cmds.restrictToCompletes }
adduserid:defaultAccess( ULib.ACCESS_SUPERADMIN )
adduserid:help( "Add a user by ID to specified group." )
function ulx.removeuser( calling_ply, target_ply )
ULib.ucl.removeUser( target_ply:UniqueID() )
ulx.fancyLogAdmin( calling_ply, "#A removed all access rights from #T", target_ply )
end
local removeuser = ulx.command( CATEGORY_NAME, "ulx removeuser", ulx.removeuser )
removeuser:addParam{ type=ULib.cmds.PlayerArg }
removeuser:defaultAccess( ULib.ACCESS_SUPERADMIN )
removeuser:help( "Permanently removes a user's access." )
function ulx.removeuserid( calling_ply, id )
id = id:upper() -- Steam id needs to be upper
-- Check for valid and properly formatted ID
if not checkForValidId( calling_ply, id ) then return false end
if not ULib.ucl.authed[ id ] and not ULib.ucl.users[ id ] then
ULib.tsayError( calling_ply, "No player with id \"" .. id .. "\" exists in the ULib user list", true )
return false
end
local name = (ULib.ucl.authed[ id ] and ULib.ucl.authed[ id ].name) or (ULib.ucl.users[ id ] and ULib.ucl.users[ id ].name)
ULib.ucl.removeUser( id )
if name then
ulx.fancyLogAdmin( calling_ply, "#A removed all access rights from #s", name )
else
ulx.fancyLogAdmin( calling_ply, "#A removed all access rights from #s", id )
end
end
local removeuserid = ulx.command( CATEGORY_NAME, "ulx removeuserid", ulx.removeuserid )
removeuserid:addParam{ type=ULib.cmds.StringArg, hint="SteamID, IP, or UniqueID" }
removeuserid:defaultAccess( ULib.ACCESS_SUPERADMIN )
removeuserid:help( "Permanently removes a user's access by ID." )
function ulx.userallow( calling_ply, target_ply, access_string, access_tag )
if access_tag then access_tag = access_tag end
local accessTable
if access_tag and access_tag ~= "" then
accessTable = { [access_string]=access_tag }
else
accessTable = { access_string }
end
local id = ULib.ucl.getUserRegisteredID( target_ply )
if not id then id = target_ply:SteamID() end
local success = ULib.ucl.userAllow( id, accessTable )
if not success then
ULib.tsayError( calling_ply, string.format( "User \"%s\" already has access to \"%s\"", target_ply:Nick(), access_string ), true )
else
if not access_tag or access_tag == "" then
ulx.fancyLogAdmin( calling_ply, "#A granted access #q to #T", access_string, target_ply )
else
ulx.fancyLogAdmin( calling_ply, "#A granted access #q with tag #q to #T", access_string, access_tag, target_ply )
end
end
end
local userallow = ulx.command( CATEGORY_NAME, "ulx userallow", ulx.userallow )
userallow:addParam{ type=ULib.cmds.PlayerArg }
userallow:addParam{ type=ULib.cmds.StringArg, hint="command" } -- TODO, add completes for this
userallow:addParam{ type=ULib.cmds.StringArg, hint="access tag", ULib.cmds.optional }
userallow:defaultAccess( ULib.ACCESS_SUPERADMIN )
userallow:help( "Add to a user's access." )
function ulx.userallowid( calling_ply, id, access_string, access_tag )
if access_tag then access_tag = access_tag end
id = id:upper() -- Steam id needs to be upper
-- Check for valid and properly formatted ID
if not checkForValidId( calling_ply, id ) then return false end
if not ULib.ucl.authed[ id ] and not ULib.ucl.users[ id ] then
ULib.tsayError( calling_ply, "No player with id \"" .. id .. "\" exists in the ULib user list", true )
return false
end
local accessTable
if access_tag and access_tag ~= "" then
accessTable = { [access_string]=access_tag }
else
accessTable = { access_string }
end
local success = ULib.ucl.userAllow( id, accessTable )
local name = (ULib.ucl.authed[ id ] and ULib.ucl.authed[ id ].name) or (ULib.ucl.users[ id ] and ULib.ucl.users[ id ].name) or id
if not success then
ULib.tsayError( calling_ply, string.format( "User \"%s\" already has access to \"%s\"", name, access_string ), true )
else
if not access_tag or access_tag == "" then
ulx.fancyLogAdmin( calling_ply, "#A granted access #q to #s", access_string, name )
else
ulx.fancyLogAdmin( calling_ply, "#A granted access #q with tag #q to #s", access_string, access_tag, name )
end
end
end
local userallowid = ulx.command( CATEGORY_NAME, "ulx userallowid", ulx.userallowid )
userallowid:addParam{ type=ULib.cmds.StringArg, hint="SteamID, IP, or UniqueID" }
userallowid:addParam{ type=ULib.cmds.StringArg, hint="command" } -- TODO, add completes for this
userallowid:addParam{ type=ULib.cmds.StringArg, hint="access tag", ULib.cmds.optional }
userallowid:defaultAccess( ULib.ACCESS_SUPERADMIN )
userallowid:help( "Add to a user's access." )
function ulx.userdeny( calling_ply, target_ply, access_string, should_use_neutral )
local success = ULib.ucl.userAllow( target_ply:UniqueID(), access_string, should_use_neutral, true )
if should_use_neutral then
success = success or ULib.ucl.userAllow( target_ply:UniqueID(), access_string, should_use_neutral, false ) -- Remove from both lists
end
if should_use_neutral then
if success then
ulx.fancyLogAdmin( calling_ply, "#A made access #q neutral to #T", access_string, target_ply )
else
ULib.tsayError( calling_ply, string.format( "User \"%s\" isn't denied or allowed access to \"%s\"", target_ply:Nick(), access_string ), true )
end
else
if not success then
ULib.tsayError( calling_ply, string.format( "User \"%s\" is already denied access to \"%s\"", target_ply:Nick(), access_string ), true )
else
ulx.fancyLogAdmin( calling_ply, "#A denied access #q to #T", access_string, target_ply )
end
end
end
local userdeny = ulx.command( CATEGORY_NAME, "ulx userdeny", ulx.userdeny )
userdeny:addParam{ type=ULib.cmds.PlayerArg }
userdeny:addParam{ type=ULib.cmds.StringArg, hint="command" } -- TODO, add completes for this
userdeny:addParam{ type=ULib.cmds.BoolArg, hint="remove explicit allow or deny instead of outright denying", ULib.cmds.optional }
userdeny:defaultAccess( ULib.ACCESS_SUPERADMIN )
userdeny:help( "Remove from a user's access." )
function ulx.userdenyid( calling_ply, id, access_string, should_use_neutral )
id = id:upper() -- Steam id needs to be upper
-- Check for valid and properly formatted ID
if not checkForValidId( calling_ply, id ) then return false end
if not ULib.ucl.authed[ id ] and not ULib.ucl.users[ id ] then
ULib.tsayError( calling_ply, "No player with id \"" .. id .. "\" exists in the ULib user list", true )
return false
end
local success = ULib.ucl.userAllow( id, access_string, should_use_neutral, true )
if should_use_neutral then
success = success or ULib.ucl.userAllow( id, access_string, should_use_neutral, false ) -- Remove from both lists
end
local name = (ULib.ucl.authed[ id ] and ULib.ucl.authed[ id ].name) or (ULib.ucl.users[ id ] and ULib.ucl.users[ id ].name) or id
if should_use_neutral then
if success then
ulx.fancyLogAdmin( calling_ply, "#A made access #q neutral to #s", access_string, name )
else
ULib.tsayError( calling_ply, string.format( "User \"%s\" isn't denied or allowed access to \"%s\"", name, access_string ), true )
end
else
if not success then
ULib.tsayError( calling_ply, string.format( "User \"%s\" is already denied access to \"%s\"", name, access_string ), true )
else
ulx.fancyLogAdmin( calling_ply, "#A denied access #q to #s", access_string, name )
end
end
end
local userdenyid = ulx.command( CATEGORY_NAME, "ulx userdenyid", ulx.userdenyid )
userdenyid:addParam{ type=ULib.cmds.StringArg, hint="SteamID, IP, or UniqueID" }
userdenyid:addParam{ type=ULib.cmds.StringArg, hint="command" } -- TODO, add completes for this
userdenyid:addParam{ type=ULib.cmds.BoolArg, hint="remove explicit allow or deny instead of outright denying", ULib.cmds.optional }
userdenyid:defaultAccess( ULib.ACCESS_SUPERADMIN )
userdenyid:help( "Remove from a user's access." )
function ulx.addgroup( calling_ply, group_name, inherit_from )
if ULib.ucl.groups[ group_name ] ~= nil then
ULib.tsayError( calling_ply, "This group already exists!", true )
return
end
if not ULib.ucl.groups[ inherit_from ] then
ULib.tsayError( calling_ply, "The group you specified for inheritence doesn't exist!", true )
return
end
ULib.ucl.addGroup( group_name, _, inherit_from )
ulx.fancyLogAdmin( calling_ply, "#A created group #s which inherits rights from group #s", group_name, inherit_from )
end
local addgroup = ulx.command( CATEGORY_NAME, "ulx addgroup", ulx.addgroup )
addgroup:addParam{ type=ULib.cmds.StringArg, hint="group" }
addgroup:addParam{ type=ULib.cmds.StringArg, completes=ulx.group_names, hint="inherits from", error="invalid group \"%s\" specified", ULib.cmds.restrictToCompletes, default="user", ULib.cmds.optional }
addgroup:defaultAccess( ULib.ACCESS_SUPERADMIN )
addgroup:help( "Create a new group with optional inheritance." )
function ulx.renamegroup( calling_ply, current_group, new_group )
if ULib.ucl.groups[ new_group ] then
ULib.tsayError( calling_ply, "The target group already exists!", true )
return
end
ULib.ucl.renameGroup( current_group, new_group )
ulx.fancyLogAdmin( calling_ply, "#A renamed group #s to #s", current_group, new_group )
end
local renamegroup = ulx.command( CATEGORY_NAME, "ulx renamegroup", ulx.renamegroup )
renamegroup:addParam{ type=ULib.cmds.StringArg, completes=ulx.group_names_no_user, hint="current group", error="invalid group \"%s\" specified", ULib.cmds.restrictToCompletes }
renamegroup:addParam{ type=ULib.cmds.StringArg, hint="new group" }
renamegroup:defaultAccess( ULib.ACCESS_SUPERADMIN )
renamegroup:help( "Renames a group." )
function ulx.setGroupCanTarget( calling_ply, group, can_target )
if can_target and can_target ~= "" and can_target ~= "*" then
ULib.ucl.setGroupCanTarget( group, can_target )
ulx.fancyLogAdmin( calling_ply, "#A changed group #s to only be able to target #s", group, can_target )
else
ULib.ucl.setGroupCanTarget( group, nil )
ulx.fancyLogAdmin( calling_ply, "#A changed group #s to be able to target anyone", group )
end
end
local setgroupcantarget = ulx.command( CATEGORY_NAME, "ulx setgroupcantarget", ulx.setGroupCanTarget )
setgroupcantarget:addParam{ type=ULib.cmds.StringArg, completes=ulx.group_names, hint="group", error="invalid group \"%s\" specified", ULib.cmds.restrictToCompletes }
setgroupcantarget:addParam{ type=ULib.cmds.StringArg, hint="target string", ULib.cmds.optional }
setgroupcantarget:defaultAccess( ULib.ACCESS_SUPERADMIN )
setgroupcantarget:help( "Sets what a group is allowed to target" )
function ulx.removegroup( calling_ply, group_name )
ULib.ucl.removeGroup( group_name )
ulx.fancyLogAdmin( calling_ply, "#A removed group #s", group_name )
end
local removegroup = ulx.command( CATEGORY_NAME, "ulx removegroup", ulx.removegroup )
removegroup:addParam{ type=ULib.cmds.StringArg, completes=ulx.group_names_no_user, hint="group", error="invalid group \"%s\" specified", ULib.cmds.restrictToCompletes }
removegroup:defaultAccess( ULib.ACCESS_SUPERADMIN )
removegroup:help( "Removes a group. USE WITH CAUTION." )
function ulx.groupallow( calling_ply, group_name, access_string, access_tag )
access_tag = access_tag
local accessTable
if access_tag and access_tag ~= "" then
accessTable = { [access_string]=access_tag }
else
accessTable = { access_string }
end
local success = ULib.ucl.groupAllow( group_name, accessTable )
if not success then
ULib.tsayError( calling_ply, string.format( "Group \"%s\" already has access to \"%s\"", group_name, access_string ), true )
else
if not access_tag or access_tag == "" then
ulx.fancyLogAdmin( calling_ply, "#A granted access #q to group #s", access_string, group_name )
else
ulx.fancyLogAdmin( calling_ply, "#A granted access #q with tag #q to group #s", access_string, access_tag, group_name )
end
end
end
local groupallow = ulx.command( CATEGORY_NAME, "ulx groupallow", ulx.groupallow )
groupallow:addParam{ type=ULib.cmds.StringArg, completes=ulx.group_names, hint="group", error="invalid group \"%s\" specified", ULib.cmds.restrictToCompletes }
groupallow:addParam{ type=ULib.cmds.StringArg, hint="command" } -- TODO, add completes for this
groupallow:addParam{ type=ULib.cmds.StringArg, hint="access tag", ULib.cmds.optional }
groupallow:defaultAccess( ULib.ACCESS_SUPERADMIN )
groupallow:help( "Add to a group's access." )
function ulx.groupdeny( calling_ply, group_name, access_string )
local accessTable
if access_tag and access_tag ~= "" then
accessTable = { [access_string]=access_tag }
else
accessTable = { access_string }
end
local success = ULib.ucl.groupAllow( group_name, access_string, true )
if success then
ulx.fancyLogAdmin( calling_ply, "#A revoked access #q to group #s", access_string, group_name )
else
ULib.tsayError( calling_ply, string.format( "Group \"%s\" doesn't have access to \"%s\"", group_name, access_string ), true )
end
end
local groupdeny = ulx.command( CATEGORY_NAME, "ulx groupdeny", ulx.groupdeny )
groupdeny:addParam{ type=ULib.cmds.StringArg, completes=ulx.group_names, hint="group", error="invalid group \"%s\" specified", ULib.cmds.restrictToCompletes }
groupdeny:addParam{ type=ULib.cmds.StringArg, hint="command" } -- TODO, add completes for this
groupdeny:defaultAccess( ULib.ACCESS_SUPERADMIN )
groupdeny:help( "Remove from a group's access." )

View File

@ -1,85 +0,0 @@
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

View File

@ -1,426 +0,0 @@
local CATEGORY_NAME = "Utility"
function ulx.who( calling_ply, steamid )
if not steamid or steamid == "" then
ULib.console( calling_ply, "ID Name Group" )
local players = player.GetAll()
for _, player in ipairs( players ) do
local id = tostring( player:UserID() )
local nick = player:Nick()
local text = string.format( "%i%s %s%s ", id, string.rep( " ", 2 - id:len() ), nick, string.rep( " ", 31 - nick:len() ) )
text = text .. player:GetUserGroup()
ULib.console( calling_ply, text )
end
else
data = ULib.ucl.getUserInfoFromID( steamid )
if not data then
ULib.console( calling_ply, "No information for provided id exists" )
else
ULib.console( calling_ply, " ID: " .. steamid )
ULib.console( calling_ply, " Name: " .. data.name )
ULib.console( calling_ply, "Group: " .. data.group )
end
end
end
local who = ulx.command( CATEGORY_NAME, "ulx who", ulx.who )
who:addParam{ type=ULib.cmds.StringArg, hint="steamid", ULib.cmds.optional }
who:defaultAccess( ULib.ACCESS_ALL )
who:help( "See information about currently online users." )
function ulx.map( calling_ply, map, gamemode )
if not gamemode or gamemode == "" then
ulx.fancyLogAdmin( calling_ply, "#A changed the map to #s", map )
else
ulx.fancyLogAdmin( calling_ply, "#A changed the map to #s with gamemode #s", map, gamemode )
end
if gamemode and gamemode ~= "" then
game.ConsoleCommand( "gamemode " .. gamemode .. "\n" )
end
game.ConsoleCommand( "changelevel " .. map .. "\n" )
end
local map = ulx.command( CATEGORY_NAME, "ulx map", ulx.map, "!map" )
map:addParam{ type=ULib.cmds.StringArg, completes=ulx.maps, hint="map", error="invalid map \"%s\" specified", ULib.cmds.restrictToCompletes }
map:addParam{ type=ULib.cmds.StringArg, completes=ulx.gamemodes, hint="gamemode", error="invalid gamemode \"%s\" specified", ULib.cmds.restrictToCompletes, ULib.cmds.optional }
map:defaultAccess( ULib.ACCESS_ADMIN )
map:help( "Changes map and gamemode." )
function ulx.kick( calling_ply, target_ply, reason )
if reason and reason ~= "" then
ulx.fancyLogAdmin( calling_ply, "#A kicked #T (#s)", target_ply, reason )
else
reason = nil
ulx.fancyLogAdmin( calling_ply, "#A kicked #T", target_ply )
end
-- Delay by 1 frame to ensure the chat hook finishes with player intact. Prevents a crash.
ULib.queueFunctionCall( ULib.kick, target_ply, reason, calling_ply )
end
local kick = ulx.command( CATEGORY_NAME, "ulx kick", ulx.kick, "!kick" )
kick:addParam{ type=ULib.cmds.PlayerArg }
kick:addParam{ type=ULib.cmds.StringArg, hint="reason", ULib.cmds.optional, ULib.cmds.takeRestOfLine, completes=ulx.common_kick_reasons }
kick:defaultAccess( ULib.ACCESS_ADMIN )
kick:help( "Kicks target." )
function ulx.ban( calling_ply, target_ply, minutes, reason )
if target_ply:IsBot() then
ULib.tsayError( calling_ply, "Cannot ban a bot", true )
return
end
local time = "for #i minute(s)"
if minutes == 0 then time = "permanently" end
local str = "#A banned #T " .. time
if reason and reason ~= "" then str = str .. " (#s)" end
ulx.fancyLogAdmin( calling_ply, str, target_ply, minutes ~= 0 and minutes or reason, reason )
-- Delay by 1 frame to ensure any chat hook finishes with player intact. Prevents a crash.
ULib.queueFunctionCall( ULib.kickban, target_ply, minutes, reason, calling_ply )
end
local ban = ulx.command( CATEGORY_NAME, "ulx ban", ulx.ban, "!ban" )
ban:addParam{ type=ULib.cmds.PlayerArg }
ban:addParam{ type=ULib.cmds.NumArg, hint="minutes, 0 for perma", ULib.cmds.optional, ULib.cmds.allowTimeString, min=0 }
ban:addParam{ type=ULib.cmds.StringArg, hint="reason", ULib.cmds.optional, ULib.cmds.takeRestOfLine, completes=ulx.common_kick_reasons }
ban:defaultAccess( ULib.ACCESS_ADMIN )
ban:help( "Bans target." )
function ulx.banid( calling_ply, steamid, minutes, reason )
steamid = steamid:upper()
if not ULib.isValidSteamID( steamid ) then
ULib.tsayError( calling_ply, "Invalid steamid." )
return
end
local name
local plys = player.GetAll()
for i=1, #plys do
if plys[ i ]:SteamID() == steamid then
name = plys[ i ]:Nick()
break
end
end
local time = "for #i minute(s)"
if minutes == 0 then time = "permanently" end
local str = "#A banned steamid #s "
displayid = steamid
if name then
displayid = displayid .. "(" .. name .. ") "
end
str = str .. time
if reason and reason ~= "" then str = str .. " (#4s)" end
ulx.fancyLogAdmin( calling_ply, str, displayid, minutes ~= 0 and minutes or reason, reason )
-- Delay by 1 frame to ensure any chat hook finishes with player intact. Prevents a crash.
ULib.queueFunctionCall( ULib.addBan, steamid, minutes, reason, name, calling_ply )
end
local banid = ulx.command( CATEGORY_NAME, "ulx banid", ulx.banid )
banid:addParam{ type=ULib.cmds.StringArg, hint="steamid" }
banid:addParam{ type=ULib.cmds.NumArg, hint="minutes, 0 for perma", ULib.cmds.optional, ULib.cmds.allowTimeString, min=0 }
banid:addParam{ type=ULib.cmds.StringArg, hint="reason", ULib.cmds.optional, ULib.cmds.takeRestOfLine, completes=ulx.common_kick_reasons }
banid:defaultAccess( ULib.ACCESS_SUPERADMIN )
banid:help( "Bans steamid." )
function ulx.unban( calling_ply, steamid )
steamid = steamid:upper()
if not ULib.isValidSteamID( steamid ) then
ULib.tsayError( calling_ply, "Invalid steamid." )
return
end
name = ULib.bans[ steamid ] and ULib.bans[ steamid ].name
ULib.unban( steamid, calling_ply )
if name then
ulx.fancyLogAdmin( calling_ply, "#A unbanned steamid #s", steamid .. " (" .. name .. ")" )
else
ulx.fancyLogAdmin( calling_ply, "#A unbanned steamid #s", steamid )
end
end
local unban = ulx.command( CATEGORY_NAME, "ulx unban", ulx.unban )
unban:addParam{ type=ULib.cmds.StringArg, hint="steamid" }
unban:defaultAccess( ULib.ACCESS_ADMIN )
unban:help( "Unbans steamid." )
------------------------------ Noclip ------------------------------
function ulx.noclip( calling_ply, target_plys )
if not target_plys[ 1 ]:IsValid() then
Msg( "You are god, you are not constrained by walls built by mere mortals.\n" )
return
end
local affected_plys = {}
for i=1, #target_plys do
local v = target_plys[ i ]
if v.NoNoclip then
ULib.tsayError( calling_ply, v:Nick() .. " can't be noclipped right now.", true )
else
if v:GetMoveType() == MOVETYPE_WALK then
v:SetMoveType( MOVETYPE_NOCLIP )
table.insert( affected_plys, v )
elseif v:GetMoveType() == MOVETYPE_NOCLIP then
v:SetMoveType( MOVETYPE_WALK )
table.insert( affected_plys, v )
else -- Ignore if they're an observer
ULib.tsayError( calling_ply, v:Nick() .. " can't be noclipped right now.", true )
end
end
end
end
local noclip = ulx.command( CATEGORY_NAME, "ulx noclip", ulx.noclip, "!noclip" )
noclip:addParam{ type=ULib.cmds.PlayersArg, ULib.cmds.optional }
noclip:defaultAccess( ULib.ACCESS_ADMIN )
noclip:help( "Toggles noclip on target(s)." )
function ulx.spectate( calling_ply, target_ply )
if not calling_ply:IsValid() then
Msg( "You can't spectate from dedicated server console.\n" )
return
end
-- Check if player is already spectating. If so, stop spectating so we can start again
local hookTable = hook.GetTable()["KeyPress"]
if hookTable and hookTable["ulx_unspectate_" .. calling_ply:EntIndex()] then
-- Simulate keypress to properly exit spectate.
hook.Call( "KeyPress", _, calling_ply, IN_FORWARD )
end
if ulx.getExclusive( calling_ply, calling_ply ) then
ULib.tsayError( calling_ply, ulx.getExclusive( calling_ply, calling_ply ), true )
return
end
ULib.getSpawnInfo( calling_ply )
local pos = calling_ply:GetPos()
local ang = calling_ply:GetAngles()
local function stopSpectate( player )
if player ~= calling_ply then -- For the spawning, make sure it's them doing the spawning
return
end
hook.Remove( "PlayerSpawn", "ulx_unspectatedspawn_" .. calling_ply:EntIndex() )
hook.Remove( "KeyPress", "ulx_unspectate_" .. calling_ply:EntIndex() )
hook.Remove( "PlayerDisconnected", "ulx_unspectatedisconnect_" .. calling_ply:EntIndex() )
if player.ULXHasGod then player:GodEnable() end -- Restore if player had ulx god.
player:UnSpectate() -- Need this for DarkRP for some reason, works fine without it in sbox
ulx.fancyLogAdmin( calling_ply, true, "#A stopped spectating #T", target_ply )
ulx.clearExclusive( calling_ply )
end
hook.Add( "PlayerSpawn", "ulx_unspectatedspawn_" .. calling_ply:EntIndex(), stopSpectate, HOOK_MONITOR_HIGH )
local function unspectate( player, key )
if calling_ply ~= player then return end -- Not the person we want
if key ~= IN_FORWARD and key ~= IN_BACK and key ~= IN_MOVELEFT and key ~= IN_MOVERIGHT then return end -- Not a key we're interested in
hook.Remove( "PlayerSpawn", "ulx_unspectatedspawn_" .. calling_ply:EntIndex() ) -- Otherwise spawn would cause infinite loop
ULib.spawn( player, true ) -- Get out of spectate.
stopSpectate( player )
player:SetPos( pos )
player:SetAngles( ang )
end
hook.Add( "KeyPress", "ulx_unspectate_" .. calling_ply:EntIndex(), unspectate, HOOK_MONITOR_LOW )
local function disconnect( player ) -- We want to watch for spectator or target disconnect
if player == target_ply or player == calling_ply then -- Target or spectator disconnecting
unspectate( calling_ply, IN_FORWARD )
end
end
hook.Add( "PlayerDisconnected", "ulx_unspectatedisconnect_" .. calling_ply:EntIndex(), disconnect, HOOK_MONITOR_HIGH )
calling_ply:Spectate( OBS_MODE_IN_EYE )
calling_ply:SpectateEntity( target_ply )
calling_ply:StripWeapons() -- Otherwise they can use weapons while spectating
ULib.tsay( calling_ply, "To get out of spectate, move forward.", true )
ulx.setExclusive( calling_ply, "spectating" )
ulx.fancyLogAdmin( calling_ply, true, "#A began spectating #T", target_ply )
end
local spectate = ulx.command( CATEGORY_NAME, "ulx spectate", ulx.spectate, "!spectate", true )
spectate:addParam{ type=ULib.cmds.PlayerArg, target="!^" }
spectate:defaultAccess( ULib.ACCESS_ADMIN )
spectate:help( "Spectate target." )
function ulx.addForcedDownload( path )
if ULib.fileIsDir( path ) then
files = ULib.filesInDir( path )
for _, v in ipairs( files ) do
ulx.addForcedDownload( path .. "/" .. v )
end
elseif ULib.fileExists( path ) then
resource.AddFile( path )
else
Msg( "[ULX] ERROR: Tried to add nonexistent or empty file to forced downloads '" .. path .. "'\n" )
end
end
function ulx.debuginfo( calling_ply )
local str = string.format( "ULX version: %s\nULib version: %.2f\n", ulx.getVersion(), ULib.VERSION )
str = str .. string.format( "Gamemode: %s\nMap: %s\n", GAMEMODE.Name, game.GetMap() )
str = str .. "Dedicated server: " .. tostring( game.IsDedicated() ) .. "\n\n"
local players = player.GetAll()
str = str .. string.format( "Currently connected players:\nNick%s steamid%s uid%s id lsh\n", str.rep( " ", 27 ), str.rep( " ", 11 ), str.rep( " ", 7 ) )
for _, ply in ipairs( players ) do
local id = string.format( "%i", ply:EntIndex() )
local steamid = ply:SteamID()
local uid = tostring( ply:UniqueID() )
local plyline = ply:Nick() .. str.rep( " ", 32 - ply:Nick():len() ) -- Name
plyline = plyline .. steamid .. str.rep( " ", 19 - steamid:len() ) -- Steamid
plyline = plyline .. uid .. str.rep( " ", 11 - uid:len() ) -- Steamid
plyline = plyline .. id .. str.rep( " ", 3 - id:len() ) -- id
if ply:IsListenServerHost() then
plyline = plyline .. "y "
else
plyline = plyline .. "n "
end
str = str .. plyline .. "\n"
end
local gmoddefault = util.KeyValuesToTable( ULib.fileRead( "settings/users.txt", true ) )
str = str .. "\n\nULib.ucl.users (#=" .. table.Count( ULib.ucl.users ) .. "):\n" .. ulx.dumpTable( ULib.ucl.users, 1 ) .. "\n\n"
str = str .. "ULib.ucl.groups (#=" .. table.Count( ULib.ucl.groups ) .. "):\n" .. ulx.dumpTable( ULib.ucl.groups, 1 ) .. "\n\n"
str = str .. "ULib.ucl.authed (#=" .. table.Count( ULib.ucl.authed ) .. "):\n" .. ulx.dumpTable( ULib.ucl.authed, 1 ) .. "\n\n"
str = str .. "Garrysmod default file (#=" .. table.Count( gmoddefault ) .. "):\n" .. ulx.dumpTable( gmoddefault, 1 ) .. "\n\n"
str = str .. "Active workshop addons on this server:\n"
local addons = engine.GetAddons()
for i=1, #addons do
local addon = addons[i]
if addon.mounted then
local name = addon.title
str = str .. string.format( "%s%s workshop ID %s\n", name, str.rep( " ", 24 - name:len() ), addon.file:gsub( "%D", "" ) )
end
end
str = str .. "\n"
str = str .. "Active legacy addons on this server:\n"
local _, possibleaddons = file.Find( "addons/*", "GAME" )
for _, addon in ipairs( possibleaddons ) do
if ULib.fileExists( "addons/" .. addon .. "/addon.txt" ) then
local t = util.KeyValuesToTable( ULib.fileRead( "addons/" .. addon .. "/addon.txt" ) )
if tonumber( t.version ) then t.version = string.format( "%g", t.version ) end -- Removes innaccuracy in floating point numbers
str = str .. string.format( "%s%s by %s, version %s (%s)\n", addon, str.rep( " ", 24 - addon:len() ), t.author_name, t.version, t.up_date )
end
end
ULib.fileWrite( "data/ulx/debugdump.txt", str )
Msg( "Debug information written to garrysmod/data/ulx/debugdump.txt on server.\n" )
end
local debuginfo = ulx.command( CATEGORY_NAME, "ulx debuginfo", ulx.debuginfo )
debuginfo:help( "Dump some debug information." )
function ulx.resettodefaults( calling_ply, param )
if param ~= "FORCE" then
local str = "Are you SURE about this? It will remove ulx-created temporary bans, configs, groups, EVERYTHING!"
local str2 = "If you're sure, type \"ulx resettodefaults FORCE\""
if calling_ply:IsValid() then
ULib.tsayError( calling_ply, str, true )
ULib.tsayError( calling_ply, str2, true )
else
Msg( str .. "\n" )
Msg( str2 .. "\n" )
end
return
end
ULib.fileDelete( "data/ulx/adverts.txt" )
ULib.fileDelete( "data/ulx/banreasons.txt" )
ULib.fileDelete( "data/ulx/config.txt" )
ULib.fileDelete( "data/ulx/downloads.txt" )
ULib.fileDelete( "data/ulx/gimps.txt" )
ULib.fileDelete( "data/ulx/sbox_limits.txt" )
ULib.fileDelete( "data/ulx/votemaps.txt" )
ULib.fileDelete( "data/ulib/bans.txt" )
ULib.fileDelete( "data/ulib/groups.txt" )
ULib.fileDelete( "data/ulib/misc_registered.txt" )
ULib.fileDelete( "data/ulib/users.txt" )
local str = "Please change levels to finish the reset"
if calling_ply:IsValid() then
ULib.tsayError( calling_ply, str, true )
else
Msg( str .. "\n" )
end
ulx.fancyLogAdmin( calling_ply, "#A reset all ULX and ULib configuration" )
end
local resettodefaults = ulx.command( CATEGORY_NAME, "ulx resettodefaults", ulx.resettodefaults )
resettodefaults:addParam{ type=ULib.cmds.StringArg, ULib.cmds.optional }
resettodefaults:help( "Resets ALL ULX and ULib configuration!" )
if SERVER then
local ulx_kickAfterNameChanges = ulx.convar( "kickAfterNameChanges", "0", "<number> - Players can only change their name x times every ulx_kickAfterNameChangesCooldown seconds. 0 to disable.", ULib.ACCESS_ADMIN )
local ulx_kickAfterNameChangesCooldown = ulx.convar( "kickAfterNameChangesCooldown", "60", "<time> - Players can change their name ulx_kickAfterXNameChanges times every x seconds.", ULib.ACCESS_ADMIN )
local ulx_kickAfterNameChangesWarning = ulx.convar( "kickAfterNameChangesWarning", "1", "<1/0> - Display a warning to users to let them know how many more times they can change their name.", ULib.ACCESS_ADMIN )
ulx.nameChangeTable = ulx.nameChangeTable or {}
local function checkNameChangeLimit( ply, oldname, newname )
local maxAttempts = ulx_kickAfterNameChanges:GetInt()
local duration = ulx_kickAfterNameChangesCooldown:GetInt()
local showWarning = ulx_kickAfterNameChangesWarning:GetInt()
if maxAttempts ~= 0 then
if not ulx.nameChangeTable[ply:SteamID()] then
ulx.nameChangeTable[ply:SteamID()] = {}
end
for i=#ulx.nameChangeTable[ply:SteamID()], 1, -1 do
if CurTime() - ulx.nameChangeTable[ply:SteamID()][i] > duration then
table.remove( ulx.nameChangeTable[ply:SteamID()], i )
end
end
table.insert( ulx.nameChangeTable[ply:SteamID()], CurTime() )
local curAttempts = #ulx.nameChangeTable[ply:SteamID()]
if curAttempts >= maxAttempts then
ULib.kick( ply, "Changed name too many times" )
else
if showWarning == 1 then
ULib.tsay( ply, "Warning: You have changed your name " .. curAttempts .. " out of " .. maxAttempts .. " time" .. ( maxAttempts ~= 1 and "s" ) .. " in the past " .. duration .. " second" .. ( duration ~= 1 and "s" ) )
end
end
end
end
hook.Add( "ULibPlayerNameChanged", "ULXCheckNameChangeLimit", checkNameChangeLimit )
end
--------------------
-- Hooks --
--------------------
-- This cvar also exists in DarkRP (thanks, FPtje)
local cl_cvar_pickup = "cl_pickupplayers"
if CLIENT then CreateClientConVar( cl_cvar_pickup, "1", true, true ) end
local function playerPickup( ply, ent )
local access, tag = ULib.ucl.query( ply, "ulx physgunplayer" )
if ent:GetClass() == "player" and ULib.isSandbox() and access and not ent.NoNoclip and not ent.frozen and ply:GetInfoNum( cl_cvar_pickup, 1 ) == 1 then
-- Extra restrictions! UCL wasn't designed to handle this sort of thing so we're putting it in by hand...
local restrictions = {}
ULib.cmds.PlayerArg.processRestrictions( restrictions, ply, {}, tag and ULib.splitArgs( tag )[ 1 ] )
if restrictions.restrictedTargets == false or (restrictions.restrictedTargets and not table.HasValue( restrictions.restrictedTargets, ent )) then
return
end
ent:SetMoveType( MOVETYPE_NONE ) -- So they don't bounce
return true
end
end
hook.Add( "PhysgunPickup", "ulxPlayerPickup", playerPickup, HOOK_HIGH ) -- Allow admins to move players. Call before the prop protection hook.
if SERVER then ULib.ucl.registerAccess( "ulx physgunplayer", ULib.ACCESS_ADMIN, "Ability to physgun other players", "Other" ) end
local function playerDrop( ply, ent )
if ent:GetClass() == "player" then
ent:SetMoveType( MOVETYPE_WALK )
end
end
hook.Add( "PhysgunDrop", "ulxPlayerDrop", playerDrop )

View File

@ -1,405 +0,0 @@
local CATEGORY_NAME = "Voting"
---------------
--Public vote--
---------------
if SERVER then ulx.convar( "voteEcho", "0", _, ULib.ACCESS_SUPERADMIN ) end -- Echo votes?
-- First, our helper function to make voting so much easier!
function ulx.doVote( title, options, callback, timeout, filter, noecho, ... )
timeout = timeout or 20
if ulx.voteInProgress then
Msg( "Error! ULX tried to start a vote when another vote was in progress!\n" )
return false
end
if not options[ 1 ] or not options[ 2 ] then
Msg( "Error! ULX tried to start a vote without at least two options!\n" )
return false
end
local voters = 0
local rp = RecipientFilter()
if not filter then
rp:AddAllPlayers()
voters = #player.GetAll()
else
for _, ply in ipairs( filter ) do
rp:AddPlayer( ply )
voters = voters + 1
end
end
umsg.Start( "ulx_vote", rp )
umsg.String( title )
umsg.Short( timeout )
ULib.umsgSend( options )
umsg.End()
ulx.voteInProgress = { callback=callback, options=options, title=title, results={}, voters=voters, votes=0, noecho=noecho, args={...} }
timer.Create( "ULXVoteTimeout", timeout, 1, ulx.voteDone )
return true
end
function ulx.voteCallback( ply, command, argv )
if not ulx.voteInProgress then
ULib.tsayError( ply, "There is not a vote in progress" )
return
end
if not argv[ 1 ] or not tonumber( argv[ 1 ] ) or not ulx.voteInProgress.options[ tonumber( argv[ 1 ] ) ] then
ULib.tsayError( ply, "Invalid or out of range vote." )
return
end
if ply.ulxVoted then
ULib.tsayError( ply, "You have already voted!" )
return
end
local echo = ULib.toBool( GetConVarNumber( "ulx_voteEcho" ) )
local id = tonumber( argv[ 1 ] )
ulx.voteInProgress.results[ id ] = ulx.voteInProgress.results[ id ] or 0
ulx.voteInProgress.results[ id ] = ulx.voteInProgress.results[ id ] + 1
ulx.voteInProgress.votes = ulx.voteInProgress.votes + 1
ply.ulxVoted = true -- Tag them as having voted
local str = ply:Nick() .. " voted for: " .. ulx.voteInProgress.options[ id ]
if echo and not ulx.voteInProgress.noecho then
ULib.tsay( _, str ) -- TODO, color?
end
ulx.logString( str )
if game.IsDedicated() then Msg( str .. "\n" ) end
if ulx.voteInProgress.votes >= ulx.voteInProgress.voters then
ulx.voteDone()
end
end
if SERVER then concommand.Add( "ulx_vote", ulx.voteCallback ) end
function ulx.voteDone( cancelled )
local players = player.GetAll()
for _, ply in ipairs( players ) do -- Clear voting tags
ply.ulxVoted = nil
end
local vip = ulx.voteInProgress
ulx.voteInProgress = nil
timer.Remove( "ULXVoteTimeout" )
if not cancelled then
ULib.pcallError( vip.callback, vip, unpack( vip.args, 1, 10 ) ) -- Unpack is explicit in length to avoid odd LuaJIT quirk.
end
end
-- End our helper functions
local function voteDone( t )
local results = t.results
local winner
local winnernum = 0
for id, numvotes in pairs( results ) do
if numvotes > winnernum then
winner = id
winnernum = numvotes
end
end
local str
if not winner then
str = "Vote results: No option won because no one voted!"
else
str = "Vote results: Option '" .. t.options[ winner ] .. "' won. (" .. winnernum .. "/" .. t.voters .. ")"
end
ULib.tsay( _, str ) -- TODO, color?
ulx.logString( str )
Msg( str .. "\n" )
end
function ulx.vote( calling_ply, title, ... )
if ulx.voteInProgress then
ULib.tsayError( calling_ply, "There is already a vote in progress. Please wait for the current one to end.", true )
return
end
ulx.doVote( title, { ... }, voteDone )
ulx.fancyLogAdmin( calling_ply, "#A started a vote (#s)", title )
end
local vote = ulx.command( CATEGORY_NAME, "ulx vote", ulx.vote, "!vote" )
vote:addParam{ type=ULib.cmds.StringArg, hint="title" }
vote:addParam{ type=ULib.cmds.StringArg, hint="options", ULib.cmds.takeRestOfLine, repeat_min=2, repeat_max=10 }
vote:defaultAccess( ULib.ACCESS_ADMIN )
vote:help( "Starts a public vote." )
-- Stop a vote in progress
function ulx.stopVote( calling_ply )
if not ulx.voteInProgress then
ULib.tsayError( calling_ply, "There is no vote currently in progress.", true )
return
end
ulx.voteDone( true )
ulx.fancyLogAdmin( calling_ply, "#A has stopped the current vote." )
end
local stopvote = ulx.command( CATEGORY_NAME, "ulx stopvote", ulx.stopVote, "!stopvote" )
stopvote:defaultAccess( ULib.ACCESS_SUPERADMIN )
stopvote:help( "Stops a vote in progress." )
local function voteMapDone2( t, changeTo, ply )
local shouldChange = false
if t.results[ 1 ] and t.results[ 1 ] > 0 then
ulx.logServAct( ply, "#A approved the votemap" )
shouldChange = true
else
ulx.logServAct( ply, "#A denied the votemap" )
end
if shouldChange then
ULib.consoleCommand( "changelevel " .. changeTo .. "\n" )
end
end
local function voteMapDone( t, argv, ply )
local results = t.results
local winner
local winnernum = 0
for id, numvotes in pairs( results ) do
if numvotes > winnernum then
winner = id
winnernum = numvotes
end
end
local ratioNeeded = GetConVarNumber( "ulx_votemap2Successratio" )
local minVotes = GetConVarNumber( "ulx_votemap2Minvotes" )
local str
local changeTo
-- Figure out the map to change to, if we're changing
if #argv > 1 then
changeTo = t.options[ winner ]
else
changeTo = argv[ 1 ]
end
if (#argv < 2 and winner ~= 1) or not winner or winnernum < minVotes or winnernum / t.voters < ratioNeeded then
str = "Vote results: Vote was unsuccessful."
elseif ply:IsValid() then
str = "Vote results: Option '" .. t.options[ winner ] .. "' won, changemap pending approval. (" .. winnernum .. "/" .. t.voters .. ")"
ulx.doVote( "Accept result and changemap to " .. changeTo .. "?", { "Yes", "No" }, voteMapDone2, 30000, { ply }, true, changeTo, ply )
else -- It's the server console, let's roll with it
str = "Vote results: Option '" .. t.options[ winner ] .. "' won. (" .. winnernum .. "/" .. t.voters .. ")"
ULib.tsay( _, str )
ulx.logString( str )
ULib.consoleCommand( "changelevel " .. changeTo .. "\n" )
return
end
ULib.tsay( _, str ) -- TODO, color?
ulx.logString( str )
if game.IsDedicated() then Msg( str .. "\n" ) end
end
function ulx.votemap2( calling_ply, ... )
local argv = { ... }
if ulx.voteInProgress then
ULib.tsayError( calling_ply, "There is already a vote in progress. Please wait for the current one to end.", true )
return
end
for i=2, #argv do
if ULib.findInTable( argv, argv[ i ], 1, i-1 ) then
ULib.tsayError( calling_ply, "Map " .. argv[ i ] .. " was listed twice. Please try again" )
return
end
end
if #argv > 1 then
ulx.doVote( "Change map to..", argv, voteMapDone, _, _, _, argv, calling_ply )
ulx.fancyLogAdmin( calling_ply, "#A started a votemap with options" .. string.rep( " #s", #argv ), ... )
else
ulx.doVote( "Change map to " .. argv[ 1 ] .. "?", { "Yes", "No" }, voteMapDone, _, _, _, argv, calling_ply )
ulx.fancyLogAdmin( calling_ply, "#A started a votemap for #s", argv[ 1 ] )
end
end
local votemap2 = ulx.command( CATEGORY_NAME, "ulx votemap2", ulx.votemap2, "!votemap2" )
votemap2:addParam{ type=ULib.cmds.StringArg, completes=ulx.maps, hint="map", error="invalid map \"%s\" specified", ULib.cmds.restrictToCompletes, ULib.cmds.takeRestOfLine, repeat_min=1, repeat_max=10 }
votemap2:defaultAccess( ULib.ACCESS_ADMIN )
votemap2:help( "Starts a public map vote." )
if SERVER then ulx.convar( "votemap2Successratio", "0.5", _, ULib.ACCESS_ADMIN ) end -- The ratio needed for a votemap2 to succeed
if SERVER then ulx.convar( "votemap2Minvotes", "3", _, ULib.ACCESS_ADMIN ) end -- Minimum votes needed for votemap2
local function voteKickDone2( t, target, time, ply, reason )
local shouldKick = false
if t.results[ 1 ] and t.results[ 1 ] > 0 then
ulx.logUserAct( ply, target, "#A approved the votekick against #T (" .. (reason or "") .. ")" )
shouldKick = true
else
ulx.logUserAct( ply, target, "#A denied the votekick against #T" )
end
if shouldKick then
if reason and reason ~= "" then
ULib.kick( target, "Vote kick successful. (" .. reason .. ")" )
else
ULib.kick( target, "Vote kick successful." )
end
end
end
local function voteKickDone( t, target, time, ply, reason )
local results = t.results
local winner
local winnernum = 0
for id, numvotes in pairs( results ) do
if numvotes > winnernum then
winner = id
winnernum = numvotes
end
end
local ratioNeeded = GetConVarNumber( "ulx_votekickSuccessratio" )
local minVotes = GetConVarNumber( "ulx_votekickMinvotes" )
local str
if winner ~= 1 or winnernum < minVotes or winnernum / t.voters < ratioNeeded then
str = "Vote results: User will not be kicked. (" .. (results[ 1 ] or "0") .. "/" .. t.voters .. ")"
else
if not target:IsValid() then
str = "Vote results: User voted to be kicked, but has already left."
elseif ply:IsValid() then
str = "Vote results: User will now be kicked, pending approval. (" .. winnernum .. "/" .. t.voters .. ")"
ulx.doVote( "Accept result and kick " .. target:Nick() .. "?", { "Yes", "No" }, voteKickDone2, 30000, { ply }, true, target, time, ply, reason )
else -- Vote from server console, roll with it
str = "Vote results: User will now be kicked. (" .. winnernum .. "/" .. t.voters .. ")"
ULib.kick( target, "Vote kick successful." )
end
end
ULib.tsay( _, str ) -- TODO, color?
ulx.logString( str )
if game.IsDedicated() then Msg( str .. "\n" ) end
end
function ulx.votekick( calling_ply, target_ply, reason )
if ulx.voteInProgress then
ULib.tsayError( calling_ply, "There is already a vote in progress. Please wait for the current one to end.", true )
return
end
local msg = "Kick " .. target_ply:Nick() .. "?"
if reason and reason ~= "" then
msg = msg .. " (" .. reason .. ")"
end
ulx.doVote( msg, { "Yes", "No" }, voteKickDone, _, _, _, target_ply, time, calling_ply, reason )
if reason and reason ~= "" then
ulx.fancyLogAdmin( calling_ply, "#A started a votekick against #T (#s)", minutes, target_ply, reason )
else
ulx.fancyLogAdmin( calling_ply, "#A started a votekick against #T", minutes, target_ply )
end
end
local votekick = ulx.command( CATEGORY_NAME, "ulx votekick", ulx.votekick, "!votekick" )
votekick:addParam{ type=ULib.cmds.PlayerArg }
votekick:addParam{ type=ULib.cmds.StringArg, hint="reason", ULib.cmds.optional, ULib.cmds.takeRestOfLine, completes=ulx.common_kick_reasons }
votekick:defaultAccess( ULib.ACCESS_ADMIN )
votekick:help( "Starts a public kick vote against target." )
if SERVER then ulx.convar( "votekickSuccessratio", "0.6", _, ULib.ACCESS_ADMIN ) end -- The ratio needed for a votekick to succeed
if SERVER then ulx.convar( "votekickMinvotes", "2", _, ULib.ACCESS_ADMIN ) end -- Minimum votes needed for votekick
local function voteBanDone2( t, nick, steamid, time, ply, reason )
local shouldBan = false
if t.results[ 1 ] and t.results[ 1 ] > 0 then
ulx.fancyLogAdmin( ply, "#A approved the voteban against #s (#s minutes) (#s))", nick, time, reason or "" )
shouldBan = true
else
ulx.fancyLogAdmin( ply, "#A denied the voteban against #s", nick )
end
if shouldBan then
ULib.addBan( steamid, time, reason, nick, ply )
end
end
local function voteBanDone( t, nick, steamid, time, ply, reason )
local results = t.results
local winner
local winnernum = 0
for id, numvotes in pairs( results ) do
if numvotes > winnernum then
winner = id
winnernum = numvotes
end
end
local ratioNeeded = GetConVarNumber( "ulx_votebanSuccessratio" )
local minVotes = GetConVarNumber( "ulx_votebanMinvotes" )
local str
if winner ~= 1 or winnernum < minVotes or winnernum / t.voters < ratioNeeded then
str = "Vote results: User will not be banned. (" .. (results[ 1 ] or "0") .. "/" .. t.voters .. ")"
else
reason = ("[ULX Voteban] " .. (reason or "")):Trim()
if ply:IsValid() then
str = "Vote results: User will now be banned, pending approval. (" .. winnernum .. "/" .. t.voters .. ")"
ulx.doVote( "Accept result and ban " .. nick .. "?", { "Yes", "No" }, voteBanDone2, 30000, { ply }, true, nick, steamid, time, ply, reason )
else -- Vote from server console, roll with it
str = "Vote results: User will now be banned. (" .. winnernum .. "/" .. t.voters .. ")"
ULib.addBan( steamid, time, reason, nick, ply )
end
end
ULib.tsay( _, str ) -- TODO, color?
ulx.logString( str )
Msg( str .. "\n" )
end
function ulx.voteban( calling_ply, target_ply, minutes, reason )
if ulx.voteInProgress then
ULib.tsayError( calling_ply, "There is already a vote in progress. Please wait for the current one to end.", true )
return
end
local msg = "Ban " .. target_ply:Nick() .. " for " .. minutes .. " minutes?"
if reason and reason ~= "" then
msg = msg .. " (" .. reason .. ")"
end
ulx.doVote( msg, { "Yes", "No" }, voteBanDone, _, _, _, target_ply:Nick(), target_ply:SteamID(), minutes, calling_ply, reason )
if reason and reason ~= "" then
ulx.fancyLogAdmin( calling_ply, "#A started a voteban of #i minute(s) against #T (#s)", minutes, target_ply, reason )
else
ulx.fancyLogAdmin( calling_ply, "#A started a voteban of #i minute(s) against #T", minutes, target_ply )
end
end
local voteban = ulx.command( CATEGORY_NAME, "ulx voteban", ulx.voteban, "!voteban" )
voteban:addParam{ type=ULib.cmds.PlayerArg }
voteban:addParam{ type=ULib.cmds.NumArg, min=0, default=1440, hint="minutes", ULib.cmds.allowTimeString, ULib.cmds.optional }
voteban:addParam{ type=ULib.cmds.StringArg, hint="reason", ULib.cmds.optional, ULib.cmds.takeRestOfLine, completes=ulx.common_kick_reasons }
voteban:defaultAccess( ULib.ACCESS_ADMIN )
voteban:help( "Starts a public ban vote against target." )
if SERVER then ulx.convar( "votebanSuccessratio", "0.7", _, ULib.ACCESS_ADMIN ) end -- The ratio needed for a voteban to succeed
if SERVER then ulx.convar( "votebanMinvotes", "3", _, ULib.ACCESS_ADMIN ) end -- Minimum votes needed for voteban
-- Our regular votemap command
local votemap = ulx.command( CATEGORY_NAME, "ulx votemap", ulx.votemap, "!votemap" )
votemap:addParam{ type=ULib.cmds.StringArg, completes=ulx.votemaps, hint="map", ULib.cmds.takeRestOfLine, ULib.cmds.optional }
votemap:defaultAccess( ULib.ACCESS_ALL )
votemap:help( "Vote for a map, no args lists available maps." )
-- Our veto command
local veto = ulx.command( CATEGORY_NAME, "ulx veto", ulx.votemapVeto, "!veto" )
veto:defaultAccess( ULib.ACCESS_ADMIN )
veto:help( "Veto a successful votemap." )

View File

@ -1,89 +0,0 @@
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 ULib.ucl.authed[ player:UniqueID() ] 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

View File

@ -1,149 +0,0 @@
local next_team_index
local starting_team_index = 21
ulx.teams = ulx.teams or {}
local team_by_name = {}
local function sortTeams( team_a, team_b )
if team_a.order then
if team_a.order ~= team_b.order then
return not team_b.order or team_a.order < team_b.order
end
elseif team_b.order then
return false -- Ordered always comes before non-ordered
end
return team_a.name < team_b.name
end
local function sendDataTo( ply )
ULib.clientRPC( ply, "ulx.populateClTeams", ulx.teams )
end
local function assignTeam( ply )
local team = ULib.ucl.groups[ ply:GetUserGroup() ].team
if team then
local team_data = team_by_name[ team.name ]
ULib.queueFunctionCall( function()
if not ply:IsValid() then return end -- In case they drop quickly
ply:SetTeam( team_data.index )
if team_data.model then
ply:SetModel( team_data.model )
end
for key, value in pairs( team_data ) do
local candidate_function = ply[ "Set" .. key:sub( 1, 1 ):upper() .. key:sub( 2 ) ]
if type( value ) == "number" and type( candidate_function ) == "function" then
candidate_function( ply, value )
end
end
end )
elseif ply:Team() >= starting_team_index and ply:Team() < next_team_index then
ULib.queueFunctionCall( ply.SetTeam, ply, 1001 ) -- Unassigned
end
end
function ulx.saveTeams()
-- First clear the teams
for group_name, group_data in pairs( ULib.ucl.groups ) do
group_data.team = nil
end
local to_remove = {}
for i=1, #ulx.teams do
local teamdata = table.Copy( ulx.teams[ i ] ) -- Copy since we'll be removing data as we go
if not teamdata.groups or #teamdata.groups == 0 then
table.insert( to_remove, 1, i )
else
local groupdata = {}
local groups = teamdata.groups
teamdata.groups = nil
if teamdata.color then
groupdata.color_red = teamdata.color.r
groupdata.color_green = teamdata.color.g
groupdata.color_blue = teamdata.color.b
teamdata.color = nil
end
table.Merge( groupdata, teamdata )
ULib.ucl.groups[ groups[ 1 ] ].team = groupdata
for i = 2, #groups do
ULib.ucl.groups[ groups[ i ] ].team = {
name = teamdata.name,
order = teamdata.order
}
end
end
end
for i=1, #to_remove do
table.remove( ulx.teams, to_remove[ i ] )
end
ULib.ucl.saveGroups()
end
function ulx.refreshTeams()
if not ULib.isSandbox() then
return
end
next_team_index = starting_team_index
ulx.teams = {}
team_by_name = {}
for group_name, group_data in pairs( ULib.ucl.groups ) do
if group_data.team then
local team_name = group_data.team.name or ("Team" .. tostring( next_team_index ))
group_data.team.name = team_name
local team_color
if group_data.team.color_red or group_data.team.color_green or group_data.team.color_blue then
team_color = Color( tonumber( group_data.team.color_red ) or 255, tonumber( group_data.team.color_green ) or 255, tonumber( group_data.team.color_blue ) or 255 )
end
local team_model
if group_data.team.model then
team_model = group_data.team.model
if not ULib.fileExists( team_model ) then
team_model = player_manager.TranslatePlayerModel( team_model )
end
end
local new_team = {
name = team_name,
color = team_color,
model = team_model,
}
for key, value in pairs( group_data.team ) do
if key ~= "model" and key ~= "name" and not key:find( "color" ) then
new_team[ key ] = tonumber( value )
end
end
if team_by_name[ team_name ] then
table.insert( team_by_name[ team_name ].groups, group_name )
table.Merge( team_by_name[ team_name ], new_team )
else
-- Make sure there's a color
new_team.color = new_team.color or Color( 255, 255, 255, 255 )
new_team.groups = { group_name }
table.insert( ulx.teams, new_team )
team_by_name[ team_name ] = new_team
end
end
end
table.sort( ulx.teams, sortTeams )
for i=1, #ulx.teams do
local team_data = ulx.teams[ i ]
team.SetUp( next_team_index, team_data.name, team_data.color )
team_data.index = next_team_index
next_team_index = next_team_index + 1
end
local plys = player.GetAll()
for i=1, #plys do
local ply = plys[ i ]
sendDataTo( ply )
assignTeam( ply )
end
hook.Add( "PlayerInitialSpawn", "UTeamInitialSpawn", sendDataTo, HOOK_MONITOR_HIGH )
hook.Add( "PlayerSpawn", "UTeamSpawnAuth", assignTeam, HOOK_MONITOR_HIGH )
hook.Add( "UCLAuthed", "UTeamAuth", assignTeam, HOOK_MONITOR_HIGH )
end
hook.Add( "Initialize", "UTeamInitialize", ulx.refreshTeams, HOOK_MONITOR_HIGH )

View File

@ -1,181 +0,0 @@
------------------
--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 )

View File

@ -1,302 +0,0 @@
--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 )

View File

@ -1,158 +0,0 @@
local ulxCommand = inheritsFrom( ULib.cmds.TranslateCommand )
function ulxCommand:logString( str )
Msg( "Warning: <ulx command>:logString() was called, this function is being phased out!\n" )
end
function ulxCommand:oppositeLogString( str )
Msg( "Warning: <ulx command>:oppositeLogString() was called, this function is being phased out!\n" )
end
function ulxCommand:help( str )
self.helpStr = str
end
function ulxCommand:getUsage( ply )
local str = self:superClass().getUsage( self, ply )
if self.helpStr or self.say_cmd or self.opposite then
str = str:Trim() .. " - "
if self.helpStr then
str = str .. self.helpStr
end
if self.helpStr and self.say_cmd then
str = str .. " "
end
if self.say_cmd then
str = str .. "(say: " .. self.say_cmd[1] .. ")"
end
if self.opposite and (self.helpStr or self.say_cmd) then
str = str .. " "
end
if self.opposite then
str = str .. "(opposite: " .. self.opposite .. ")"
end
end
return str
end
ulx.cmdsByCategory = ulx.cmdsByCategory or {}
function ulx.command( category, command, fn, say_cmd, hide_say, nospace )
if type( say_cmd ) == "string" then say_cmd = { say_cmd } end
local obj = ulxCommand( command, fn, say_cmd, hide_say, nospace )
obj:addParam{ type=ULib.cmds.CallingPlayerArg }
ulx.cmdsByCategory[ category ] = ulx.cmdsByCategory[ category ] or {}
for cat, cmds in pairs( ulx.cmdsByCategory ) do
for i=1, #cmds do
if cmds[i].cmd == command then
table.remove( ulx.cmdsByCategory[ cat ], i )
break
end
end
end
table.insert( ulx.cmdsByCategory[ category ], obj )
obj.category = category
obj.say_cmd = say_cmd
obj.hide_say = hide_say
return obj
end
local function cc_ulx( ply, command, argv )
local argn = #argv
if argn == 0 then
ULib.console( ply, "No command entered. If you need help, please type \"ulx help\" in your console." )
else
-- TODO, need to make this cvar hack actual commands for sanity and autocomplete
-- First, check if this is a cvar and they just want the value of the cvar
local cvar = ulx.cvars[ argv[ 1 ]:lower() ]
if cvar and not argv[ 2 ] then
ULib.console( ply, "\"ulx " .. argv[ 1 ] .. "\" = \"" .. GetConVarString( "ulx_" .. cvar.cvar ) .. "\"" )
if cvar.help and cvar.help ~= "" then
ULib.console( ply, cvar.help .. "\n CVAR generated by ULX" )
else
ULib.console( ply, " CVAR generated by ULX" )
end
return
elseif cvar then -- Second, check if this is a cvar and they specified a value
local args = table.concat( argv, " ", 2, argn )
if ply:IsValid() then
-- Workaround: gmod seems to choke on '%' when sending commands to players.
-- But it's only the '%', or we'd use ULib.makePatternSafe instead of this.
ply:ConCommand( "ulx_" .. cvar.cvar .. " \"" .. args:gsub( "(%%)", "%%%1" ) .. "\"" )
else
RunConsoleCommand( "ulx_" .. cvar.cvar, argv[ 2 ] )
end
return
end
ULib.console( ply, "Invalid command entered. If you need help, please type \"ulx help\" in your console." )
end
end
ULib.cmds.addCommand( "ulx", cc_ulx )
function ulx.help( ply )
ULib.console( ply, "ULX Help:" )
ULib.console( ply, "If a command can take multiple targets, it will usually let you use the keywords '*' for target" )
ULib.console( ply, "all, '^' to target yourself, '@' for target your picker, '$<userid>' to target by ID (steamid," )
ULib.console( ply, "uniqueid, userid, ip), '#<group>' to target users in a specific group, and '%<group>' to target" )
ULib.console( ply, "users with access to the group (inheritance counts). IE, ulx slap #user slaps all players who are" )
ULib.console( ply, "in the default guest access group. Any of these keywords can be preceded by '!' to negate it." )
ULib.console( ply, "EG, ulx slap !^ slaps everyone but you." )
ULib.console( ply, "You can also separate multiple targets by commas. IE, ulx slap bob,jeff,henry.")
ULib.console( ply, "All commands must be preceded by \"ulx \", ie \"ulx slap\"" )
ULib.console( ply, "\nCommand Help:\n" )
for category, cmds in pairs( ulx.cmdsByCategory ) do
local lines = {}
for _, cmd in ipairs( cmds ) do
local tag = cmd.cmd
if cmd.manual then tag = cmd.access_tag end
if ULib.ucl.query( ply, tag ) then
local usage
if not cmd.manual then
usage = cmd:getUsage( ply )
else
usage = cmd.helpStr
end
table.insert( lines, string.format( "\to %s %s", cmd.cmd, usage:Trim() ) )
end
end
if #lines > 0 then
table.sort( lines )
ULib.console( ply, "\nCategory: " .. category )
for _, line in ipairs( lines ) do
ULib.console( ply, line )
end
ULib.console( ply, "" ) -- New line
end
end
ULib.console( ply, "\n-End of help\nULX version: " .. ulx.getVersion() .. "\n" )
end
local help = ulx.command( "Utility", "ulx help", ulx.help )
help:help( "Shows this help." )
help:defaultAccess( ULib.ACCESS_ALL )
function ulx.dumpTable( t, indent, done )
done = done or {}
indent = indent or 0
local str = ""
for k, v in pairs( t ) do
str = str .. string.rep( "\t", indent )
if type( v ) == "table" and not done[ v ] then
done[ v ] = true
str = str .. tostring( k ) .. ":" .. "\n"
str = str .. ulx.dumpTable( v, indent + 1, done )
else
str = str .. tostring( k ) .. "\t=\t" .. tostring( v ) .. "\n"
end
end
return str
end

View File

@ -1,17 +0,0 @@
ulx.LOW_ARGS = "You did not specify enough arguments for this command. Type 'ulx help' in console for help."
ulx.version = 3.62 -- Current release version. Don't access directly, use ulx.getVersion instead. (Git/Workshop 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.WORKSHOPID = 557962280

View File

@ -1,508 +0,0 @@
--Bans module for ULX GUI -- by Stickly Man!
--Manages banned users and shows ban details
xgui.prepareDataType( "bans" )
local xbans = xlib.makepanel{ parent=xgui.null }
xbans.banlist = xlib.makelistview{ x=5, y=30, w=572, h=310, multiselect=false, parent=xbans }
xbans.banlist:AddColumn( "Name/SteamID" )
xbans.banlist:AddColumn( "Banned By" )
xbans.banlist:AddColumn( "Unban Date" )
xbans.banlist:AddColumn( "Reason" )
xbans.banlist.DoDoubleClick = function( self, LineID, line )
xbans.ShowBanDetailsWindow( xgui.data.bans.cache[LineID] )
end
xbans.banlist.OnRowRightClick = function( self, LineID, line )
local menu = DermaMenu()
menu:SetSkin(xgui.settings.skin)
menu:AddOption( "Details...", function() xbans.ShowBanDetailsWindow( xgui.data.bans.cache[LineID] ) end )
menu:AddOption( "Edit Ban...", function() xgui.ShowBanWindow( nil, line:GetValue( 5 ), nil, true, xgui.data.bans.cache[LineID] ) end )
menu:AddOption( "Remove", function() xbans.RemoveBan( line:GetValue( 5 ), xgui.data.bans.cache[LineID] ) end )
menu:Open()
end
-- Change the column sorting method to hook into our own custom sort stuff.
xbans.banlist.SortByColumn = function( self, ColumnID, Desc )
local index = ColumnID == 1 and 2 or -- Sort by Name
ColumnID == 2 and 4 or -- Sort by Admin
ColumnID == 3 and 6 or -- Sort by Unban Date
ColumnID == 4 and 5 or -- Sort by Reason
1 -- Otherwise sort by Date
xbans.sortbox:ChooseOptionID( index )
end
local searchFilter = ""
xbans.searchbox = xlib.maketextbox{ x=5, y=6, w=175, text="Search...", selectall=true, parent=xbans }
local txtCol = xbans.searchbox:GetTextColor()
xbans.searchbox:SetTextColor( Color( txtCol.r, txtCol.g, txtCol.b, 196 ) ) -- Set initial color
xbans.searchbox.OnChange = function( pnl )
if pnl:GetText() == "" then
pnl:SetText( "Search..." )
pnl:SelectAll()
pnl:SetTextColor( Color( txtCol.r, txtCol.g, txtCol.b, 196 ) )
else
pnl:SetTextColor( Color( txtCol.r, txtCol.g, txtCol.b, 255 ) )
end
end
xbans.searchbox.OnLoseFocus = function( pnl )
if pnl:GetText() == "Search..." then
searchFilter = ""
else
searchFilter = pnl:GetText()
end
xbans.setPage( 1 )
xbans.retrieveBans()
hook.Call( "OnTextEntryLoseFocus", nil, pnl )
end
local sortMode = 0
local sortAsc = false
xbans.sortbox = xlib.makecombobox{ x=185, y=6, w=150, text="Sort: Date (Desc.)", choices={ "Date", "Name", "Steam ID", "Admin", "Reason", "Unban Date", "Ban Length" }, parent=xbans }
function xbans.sortbox:OnSelect( i, v )
if i-1 == sortMode then
sortAsc = not sortAsc
else
sortMode = i-1
sortAsc = false
end
self:SetValue( "Sort: " .. v .. (sortAsc and " (Asc.)" or " (Desc.)") )
xbans.setPage( 1 )
xbans.retrieveBans()
end
local hidePerma = 0
xlib.makebutton{ x=355, y=6, w=95, label="Permabans: Show", parent=xbans }.DoClick = function( self )
hidePerma = hidePerma + 1
if hidePerma == 1 then
self:SetText( "Permabans: Hide" )
elseif hidePerma == 2 then
self:SetText( "Permabans: Only" )
elseif hidePerma == 3 then
hidePerma = 0
self:SetText( "Permabans: Show" )
end
xbans.setPage( 1 )
xbans.retrieveBans()
end
local hideIncomplete = 0
xlib.makebutton{ x=455, y=6, w=95, label="Incomplete: Show", parent=xbans, tooltip="Filters bans that are loaded by ULib, but do not have any metadata associated with them." }.DoClick = function( self )
hideIncomplete = hideIncomplete + 1
if hideIncomplete == 1 then
self:SetText( "Incomplete: Hide" )
elseif hideIncomplete == 2 then
self:SetText( "Incomplete: Only" )
elseif hideIncomplete == 3 then
hideIncomplete = 0
self:SetText( "Incomplete: Show" )
end
xbans.setPage( 1 )
xbans.retrieveBans()
end
local function banUserList( doFreeze )
local menu = DermaMenu()
menu:SetSkin(xgui.settings.skin)
for k, v in ipairs( player.GetAll() ) do
menu:AddOption( v:Nick(), function() xgui.ShowBanWindow( v, v:SteamID(), doFreeze ) end )
end
menu:AddSpacer()
if LocalPlayer():query("ulx banid") then menu:AddOption( "Ban by STEAMID...", function() xgui.ShowBanWindow() end ) end
menu:Open()
end
xlib.makebutton{ x=5, y=340, w=70, label="Ban...", parent=xbans }.DoClick = function() banUserList( false ) end
xbans.btnFreezeBan = xlib.makebutton{ x=80, y=340, w=95, label="Freeze Ban...", parent=xbans }
xbans.btnFreezeBan.DoClick = function() banUserList( true ) end
xbans.infoLabel = xlib.makelabel{ x=204, y=344, label="Right-click on a ban for more options", parent=xbans }
xbans.resultCount = xlib.makelabel{ y=344, parent=xbans }
function xbans.setResultCount( count )
local pnl = xbans.resultCount
pnl:SetText( count .. " results" )
pnl:SizeToContents()
local width = pnl:GetWide()
local x, y = pnl:GetPos()
pnl:SetPos( 475 - width, y )
local ix, iy = xbans.infoLabel:GetPos()
xbans.infoLabel:SetPos( ( 130 - width ) / 2 + 175, y )
end
local numPages = 1
local pageNumber = 1
xbans.pgleft = xlib.makebutton{ x=480, y=340, w=20, icon="icon16/arrow_left.png", centericon=true, disabled=true, parent=xbans }
xbans.pgleft.DoClick = function()
xbans.setPage( pageNumber - 1 )
xbans.retrieveBans()
end
xbans.pageSelector = xlib.makecombobox{ x=500, y=340, w=57, text="1", enableinput=true, parent=xbans }
function xbans.pageSelector:OnSelect( index )
xbans.setPage( index )
xbans.retrieveBans()
end
function xbans.pageSelector.TextEntry:OnEnter()
pg = math.Clamp( tonumber( self:GetValue() ) or 1, 1, numPages )
xbans.setPage( pg )
xbans.retrieveBans()
end
xbans.pgright = xlib.makebutton{ x=557, y=340, w=20, icon="icon16/arrow_right.png", centericon=true, disabled=true, parent=xbans }
xbans.pgright.DoClick = function()
xbans.setPage( pageNumber + 1 )
xbans.retrieveBans()
end
xbans.setPage = function( newPage )
pageNumber = newPage
xbans.pgleft:SetDisabled( pageNumber <= 1 )
xbans.pgright:SetDisabled( pageNumber >= numPages )
xbans.pageSelector.TextEntry:SetText( pageNumber )
end
function xbans.RemoveBan( ID, bandata )
local tempstr = "<Unknown>"
if bandata then tempstr = bandata.name or "<Unknown>" end
Derma_Query( "Are you sure you would like to unban " .. tempstr .. " - " .. ID .. "?", "XGUI WARNING",
"Remove", function()
RunConsoleCommand( "ulx", "unban", ID )
xbans.RemoveBanDetailsWindow( ID )
end,
"Cancel", function() end )
end
xbans.openWindows = {}
function xbans.RemoveBanDetailsWindow( ID )
if xbans.openWindows[ID] then
xbans.openWindows[ID]:Remove()
xbans.openWindows[ID] = nil
end
end
function xbans.ShowBanDetailsWindow( bandata )
local wx, wy
if xbans.openWindows[bandata.steamID] then
wx, wy = xbans.openWindows[bandata.steamID]:GetPos()
xbans.openWindows[bandata.steamID]:Remove()
end
xbans.openWindows[bandata.steamID] = xlib.makeframe{ label="Ban Details", x=wx, y=wy, w=285, h=295, skin=xgui.settings.skin }
local panel = xbans.openWindows[bandata.steamID]
local name = xlib.makelabel{ x=50, y=30, label="Name:", parent=panel }
xlib.makelabel{ x=90, y=30, w=190, label=( bandata.name or "<Unknown>" ), parent=panel, tooltip=bandata.name }
xlib.makelabel{ x=36, y=50, label="SteamID:", parent=panel }
xlib.makelabel{ x=90, y=50, label=bandata.steamID, parent=panel }
xlib.makelabel{ x=33, y=70, label="Ban Date:", parent=panel }
xlib.makelabel{ x=90, y=70, label=bandata.time and ( os.date( "%b %d, %Y - %I:%M:%S %p", tonumber( bandata.time ) ) ) or "<This ban has no metadata>", parent=panel }
xlib.makelabel{ x=20, y=90, label="Unban Date:", parent=panel }
xlib.makelabel{ x=90, y=90, label=( tonumber( bandata.unban ) == 0 and "Never" or os.date( "%b %d, %Y - %I:%M:%S %p", math.min( tonumber( bandata.unban ), 4294967295 ) ) ), parent=panel }
xlib.makelabel{ x=10, y=110, label="Length of Ban:", parent=panel }
xlib.makelabel{ x=90, y=110, label=( tonumber( bandata.unban ) == 0 and "Permanent" or xgui.ConvertTime( tonumber( bandata.unban ) - bandata.time ) ), parent=panel }
xlib.makelabel{ x=33, y=130, label="Time Left:", parent=panel }
local timeleft = xlib.makelabel{ x=90, y=130, label=( tonumber( bandata.unban ) == 0 and "N/A" or xgui.ConvertTime( tonumber( bandata.unban ) - os.time() ) ), parent=panel }
xlib.makelabel{ x=26, y=150, label="Banned By:", parent=panel }
if bandata.admin then xlib.makelabel{ x=90, y=150, label=string.gsub( bandata.admin, "%(STEAM_%w:%w:%w*%)", "" ), parent=panel } end
if bandata.admin then xlib.makelabel{ x=90, y=165, label=string.match( bandata.admin, "%(STEAM_%w:%w:%w*%)" ), parent=panel } end
xlib.makelabel{ x=41, y=185, label="Reason:", parent=panel }
xlib.makelabel{ x=90, y=185, w=190, label=bandata.reason, parent=panel, tooltip=bandata.reason ~= "" and bandata.reason or nil }
xlib.makelabel{ x=13, y=205, label="Last Updated:", parent=panel }
xlib.makelabel{ x=90, y=205, label=( ( bandata.modified_time == nil ) and "Never" or os.date( "%b %d, %Y - %I:%M:%S %p", tonumber( bandata.modified_time ) ) ), parent=panel }
xlib.makelabel{ x=21, y=225, label="Updated by:", parent=panel }
if bandata.modified_admin then xlib.makelabel{ x=90, y=225, label=string.gsub( bandata.modified_admin, "%(STEAM_%w:%w:%w*%)", "" ), parent=panel } end
if bandata.modified_admin then xlib.makelabel{ x=90, y=240, label=string.match( bandata.modified_admin, "%(STEAM_%w:%w:%w*%)" ), parent=panel } end
panel.data = bandata -- Store data on panel for future reference.
xlib.makebutton{ x=5, y=265, w=89, label="Edit Ban...", parent=panel }.DoClick = function()
xgui.ShowBanWindow( nil, panel.data.steamID, nil, true, panel.data )
end
xlib.makebutton{ x=99, y=265, w=89, label="Unban", parent=panel }.DoClick = function()
xbans.RemoveBan( panel.data.steamID, panel.data )
end
xlib.makebutton{ x=192, y=265, w=88, label="Close", parent=panel }.DoClick = function()
xbans.RemoveBanDetailsWindow( panel.data.steamID )
end
panel.btnClose.DoClick = function ( button )
xbans.RemoveBanDetailsWindow( panel.data.steamID )
end
if timeleft:GetValue() ~= "N/A" then
function panel.OnTimer()
if panel:IsVisible() then
local bantime = tonumber( panel.data.unban ) - os.time()
if bantime <= 0 then
xbans.RemoveBanDetailsWindow( panel.data.steamID )
return
else
timeleft:SetText( xgui.ConvertTime( bantime ) )
end
timeleft:SizeToContents()
timer.Simple( 1, panel.OnTimer )
end
end
panel.OnTimer()
end
end
function xgui.ShowBanWindow( ply, ID, doFreeze, isUpdate, bandata )
if not LocalPlayer():query( "ulx ban" ) and not LocalPlayer():query( "ulx banid" ) then return end
local xgui_banwindow = xlib.makeframe{ label=( isUpdate and "Edit Ban" or "Ban Player" ), w=285, h=180, skin=xgui.settings.skin }
xlib.makelabel{ x=37, y=33, label="Name:", parent=xgui_banwindow }
xlib.makelabel{ x=23, y=58, label="SteamID:", parent=xgui_banwindow }
xlib.makelabel{ x=28, y=83, label="Reason:", parent=xgui_banwindow }
xlib.makelabel{ x=10, y=108, label="Ban Length:", parent=xgui_banwindow }
local reason = xlib.makecombobox{ x=75, y=80, w=200, parent=xgui_banwindow, enableinput=true, selectall=true, choices=ULib.cmds.translatedCmds["ulx ban"].args[4].completes }
local banpanel = ULib.cmds.NumArg.x_getcontrol( ULib.cmds.translatedCmds["ulx ban"].args[3], 2, xgui_banwindow )
banpanel.interval:SetParent( xgui_banwindow )
banpanel.interval:SetPos( 200, 105 )
banpanel.val:SetParent( xgui_banwindow )
banpanel.val:SetPos( 75, 125 )
banpanel.val:SetWidth( 200 )
local name
if not isUpdate then
name = xlib.makecombobox{ x=75, y=30, w=200, parent=xgui_banwindow, enableinput=true, selectall=true }
for k,v in pairs( player.GetAll() ) do
name:AddChoice( v:Nick(), v:SteamID() )
end
name.OnSelect = function( self, index, value, data )
self.steamIDbox:SetText( data )
end
else
name = xlib.maketextbox{ x=75, y=30, w=200, parent=xgui_banwindow, selectall=true }
if bandata then
name:SetText( bandata.name or "" )
reason:SetText( bandata.reason or "" )
if tonumber( bandata.unban ) ~= 0 then
local btime = ( tonumber( bandata.unban ) - tonumber( bandata.time ) )
if btime % 31536000 == 0 then
if #banpanel.interval.Choices >= 6 then
banpanel.interval:ChooseOptionID(6)
else
banpanel.interval:SetText( "Years" )
end
btime = btime / 31536000
elseif btime % 604800 == 0 then
if #banpanel.interval.Choices >= 5 then
banpanel.interval:ChooseOptionID(5)
else
banpanel.interval:SetText( "Weeks" )
end
btime = btime / 604800
elseif btime % 86400 == 0 then
if #banpanel.interval.Choices >= 4 then
banpanel.interval:ChooseOptionID(4)
else
banpanel.interval:SetText( "Days" )
end
btime = btime / 86400
elseif btime % 3600 == 0 then
if #banpanel.interval.Choices >= 3 then
banpanel.interval:ChooseOptionID(3)
else
banpanel.interval:SetText( "Hours" )
end
btime = btime / 3600
else
btime = btime / 60
if #banpanel.interval.Choices >= 2 then
banpanel.interval:ChooseOptionID(2)
else
banpanel.interval:SetText( "Minutes" )
end
end
banpanel.val:SetValue( btime )
end
end
end
local steamID = xlib.maketextbox{ x=75, y=55, w=200, selectall=true, disabled=( isUpdate or not LocalPlayer():query( "ulx banid" ) ), parent=xgui_banwindow }
name.steamIDbox = steamID --Make a reference to the steamID textbox so it can change the value easily without needing a global variable
if doFreeze and ply then
if LocalPlayer():query( "ulx freeze" ) then
RunConsoleCommand( "ulx", "freeze", "$" .. ULib.getUniqueIDForPlayer( ply ) )
steamID:SetDisabled( true )
name:SetDisabled( true )
xgui_banwindow:ShowCloseButton( false )
else
doFreeze = false
end
end
xlib.makebutton{ x=165, y=150, w=75, label="Cancel", parent=xgui_banwindow }.DoClick = function()
if doFreeze and ply and ply:IsValid() then
RunConsoleCommand( "ulx", "unfreeze", "$" .. ULib.getUniqueIDForPlayer( ply ) )
end
xgui_banwindow:Remove()
end
xlib.makebutton{ x=45, y=150, w=75, label=( isUpdate and "Update" or "Ban!" ), parent=xgui_banwindow }.DoClick = function()
if isUpdate then
local function performUpdate(btime)
RunConsoleCommand( "xgui", "updateBan", steamID:GetValue(), btime, reason:GetValue(), name:GetValue() )
xgui_banwindow:Remove()
end
btime = banpanel:GetMinutes()
if btime ~= 0 and bandata and btime * 60 + bandata.time < os.time() then
Derma_Query( "WARNING! The new ban time you have specified will cause this ban to expire.\nThe minimum time required in order to change the ban length successfully is "
.. xgui.ConvertTime( os.time() - bandata.time ) .. ".\nAre you sure you wish to continue?", "XGUI WARNING",
"Expire Ban", function()
performUpdate(btime)
xbans.RemoveBanDetailsWindow( bandata.steamID )
end,
"Cancel", function() end )
else
performUpdate(btime)
end
return
end
if ULib.isValidSteamID( steamID:GetValue() ) then
local isOnline = false
for k, v in ipairs( player.GetAll() ) do
if v:SteamID() == steamID:GetValue() then
isOnline = v
break
end
end
if not isOnline then
if name:GetValue() == "" then
RunConsoleCommand( "ulx", "banid", steamID:GetValue(), banpanel:GetValue(), reason:GetValue() )
else
RunConsoleCommand( "xgui", "updateBan", steamID:GetValue(), banpanel:GetMinutes(), reason:GetValue(), ( name:GetValue() ~= "" and name:GetValue() or nil ) )
end
else
RunConsoleCommand( "ulx", "ban", "$" .. ULib.getUniqueIDForPlayer( isOnline ), banpanel:GetValue(), reason:GetValue() )
end
xgui_banwindow:Remove()
else
local ply = ULib.getUser( name:GetValue() )
if ply then
RunConsoleCommand( "ulx", "ban", "$" .. ULib.getUniqueIDForPlayer( ply ), banpanel:GetValue(), reason:GetValue() )
xgui_banwindow:Remove()
return
end
Derma_Message( "Invalid SteamID, player name, or multiple player targets found!" )
end
end
if ply then name:SetText( ply:Nick() ) end
if ID then steamID:SetText( ID ) else steamID:SetText( "STEAM_0:" ) end
end
function xgui.ConvertTime( seconds )
--Convert number of seconds remaining to something more legible (Thanks JamminR!)
local years = math.floor( seconds / 31536000 )
seconds = seconds - ( years * 31536000 )
local weeks = math.floor( seconds / 604800 )
seconds = seconds - ( weeks * 604800 )
local days = math.floor( seconds / 86400 )
seconds = seconds - ( days * 86400 )
local hours = math.floor( seconds/3600 )
seconds = seconds - ( hours * 3600 )
local minutes = math.floor( seconds/60 )
seconds = seconds - ( minutes * 60 )
local curtime = ""
if years ~= 0 then curtime = curtime .. years .. " year" .. ( ( years > 1 ) and "s, " or ", " ) end
if weeks ~= 0 then curtime = curtime .. weeks .. " week" .. ( ( weeks > 1 ) and "s, " or ", " ) end
if days ~= 0 then curtime = curtime .. days .. " day" .. ( ( days > 1 ) and "s, " or ", " ) end
curtime = curtime .. ( ( hours < 10 ) and "0" or "" ) .. hours .. ":"
curtime = curtime .. ( ( minutes < 10 ) and "0" or "" ) .. minutes .. ":"
return curtime .. ( ( seconds < 10 and "0" or "" ) .. seconds )
end
---Update stuff
function xbans.bansRefreshed()
xgui.data.bans.cache = {} -- Clear the bans cache
-- Retrieve bans if XGUI is open, otherwise it will be loaded later.
if xgui.anchor:IsVisible() then
xbans.retrieveBans()
end
end
xgui.hookEvent( "bans", "process", xbans.bansRefreshed, "bansRefresh" )
function xbans.banPageRecieved( data )
xgui.data.bans.cache = data
xbans.clearbans()
xbans.populateBans()
end
xgui.hookEvent( "bans", "data", xbans.banPageRecieved, "bansGotPage" )
function xbans.checkCache()
if xgui.data.bans.cache and xgui.data.bans.count ~= 0 and table.Count(xgui.data.bans.cache) == 0 then
xbans.retrieveBans()
end
end
xgui.hookEvent( "onOpen", nil, xbans.checkCache, "bansCheckCache" )
function xbans.clearbans()
xbans.banlist:Clear()
end
function xbans.retrieveBans()
RunConsoleCommand( "xgui", "getbans",
sortMode, -- Sort Type
searchFilter, -- Filter String
hidePerma, -- Hide permabans?
hideIncomplete, -- Hide bans that don't have full ULX metadata?
pageNumber, -- Page number
sortAsc and 1 or 0) -- Ascending/Descending
end
function xbans.populateBans()
if xgui.data.bans.cache == nil then return end
local cache = xgui.data.bans.cache
local count = cache.count or xgui.data.bans.count
numPages = math.max( 1, math.ceil( count / 17 ) )
xbans.setResultCount( count )
xbans.pageSelector:SetDisabled( numPages == 1 )
xbans.pageSelector:Clear()
for i=1, numPages do
xbans.pageSelector:AddChoice(i)
end
xbans.setPage( math.Clamp( pageNumber, 1, numPages ) )
cache.count = nil
for _, baninfo in pairs( cache ) do
xbans.banlist:AddLine( baninfo.name or baninfo.steamID,
( baninfo.admin ) and string.gsub( baninfo.admin, "%(STEAM_%w:%w:%w*%)", "" ) or "",
(( tonumber( baninfo.unban ) ~= 0 ) and os.date( "%c", math.min( tonumber( baninfo.unban ), 4294967295 ) )) or "Never",
baninfo.reason,
baninfo.steamID,
tonumber( baninfo.unban ) )
end
end
xbans.populateBans() --For autorefresh
function xbans.xban( ply, cmd, args, dofreeze )
if args[1] and args[1] ~= "" then
local target = ULib.getUser( args[1] )
if target then
xgui.ShowBanWindow( target, target:SteamID(), dofreeze )
end
else
xgui.ShowBanWindow()
end
end
ULib.cmds.addCommandClient( "xgui xban", xbans.xban )
function xbans.fban( ply, cmd, args )
xbans.xban( ply, cmd, args, true )
end
ULib.cmds.addCommandClient( "xgui fban", xbans.fban )
function xbans.UCLChanged()
xbans.btnFreezeBan:SetDisabled( not LocalPlayer():query("ulx freeze") )
end
hook.Add( "UCLChanged", "xgui_RefreshBansMenu", xbans.UCLChanged )
xgui.addModule( "Bans", xbans, "icon16/exclamation.png", "xgui_managebans" )

View File

@ -1,394 +0,0 @@
--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" )

View File

@ -1,39 +0,0 @@
--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

View File

@ -1,176 +0,0 @@
--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" )

View File

@ -1,281 +0,0 @@
--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 )

View File

@ -1,341 +0,0 @@
--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
if team.groups == nil then break end
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 )

View File

@ -1,21 +0,0 @@
--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 )

View File

@ -1,45 +0,0 @@
--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 )

View File

@ -1,287 +0,0 @@
--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 )

View File

@ -1,36 +0,0 @@
--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" )

View File

@ -1,321 +0,0 @@
--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" )

View File

@ -1,694 +0,0 @@
--Server settings module for ULX GUI -- by Stickly Man!
--A settings module for modifying server and ULX based settings. Also has the base code for loading the server settings modules.
local server = xlib.makepanel{ parent=xgui.null }
--------------------------GMOD Settings--------------------------
xlib.makecheckbox{ x=10, y=10, label="Enable Voice Chat", repconvar="rep_sv_voiceenable", parent=server }
xlib.makelabel{ x=10, y=33, label="Alltalk setting:", parent=server }
xlib.makecombobox{ x=10, y=50, w=120, repconvar="rep_sv_alltalk", isNumberConvar=true, choices={ "Team near you", "Team only", "Everyone near you", "Everyone" }, parent=server }
xlib.makecheckbox{ x=10, y=75, label="Disable AI", repconvar="rep_ai_disabled", parent=server }
xlib.makecheckbox{ x=10, y=95, label="AI Ignore Players", repconvar="rep_ai_ignoreplayers", parent=server }
local offset = 0
if game.SinglePlayer() then
offset = 20
xlib.makecheckbox{ x=10, y=115, label="Keep AI Ragdolls", repconvar="rep_ai_keepragdolls", parent=server }
end
xlib.makelabel{ x=10, y=120+offset, label="sv_gravity", parent=server }
xlib.makeslider{ x=10, y=135+offset, label="<--->", w=125, min=-1000, max=1000, repconvar="rep_sv_gravity", parent=server }
xlib.makelabel{ x=10, y=165+offset, label="phys_timescale", parent=server }
xlib.makeslider{ x=10, y=180+offset, label="<--->", w=125, min=0, max=4, decimal=2, repconvar="rep_phys_timescale", parent=server }
------------------------ULX Category Menu------------------------
server.mask = xlib.makepanel{ x=295, y=5, w=290, h=322, parent=server }
server.panel = xlib.makepanel{ x=5, w=285, h=322, parent=server.mask }
server.catList = xlib.makelistview{ x=145, y=5, w=150, h=322, parent=server }
server.catList:AddColumn( "Server Setting Modules" )
server.catList.Columns[1].DoClick = function() end
server.catList.OnRowSelected = function( self, LineID, Line )
local nPanel = xgui.modules.submodule[Line:GetValue(2)].panel
if nPanel ~= server.curPanel then
if server.curPanel then
local temppanel = server.curPanel
--Close before opening new one
xlib.addToAnimQueue( "pnlSlide", { panel=server.panel, startx=5, starty=0, endx=-285, endy=0, setvisible=false } )
xlib.addToAnimQueue( function() temppanel:SetVisible( false ) end )
end
--Open
server.curPanel = nPanel
xlib.addToAnimQueue( function() nPanel:SetVisible( true ) end )
if nPanel.onOpen then xlib.addToAnimQueue( nPanel.onOpen ) end --If the panel has it, call a function when it's opened
xlib.addToAnimQueue( "pnlSlide", { panel=server.panel, startx=-285, starty=0, endx=5, endy=0, setvisible=true } )
else
--Close
server.curPanel = nil
self:ClearSelection()
xlib.addToAnimQueue( "pnlSlide", { panel=server.panel, startx=5, starty=0, endx=-285, endy=0, setvisible=false } )
xlib.addToAnimQueue( function() nPanel:SetVisible( false ) end )
end
xlib.animQueue_start()
end
function xgui.openServerModule( name )
name = string.lower( name )
for i = 1, #xgui.modules.submodule do
local module = xgui.modules.submodule[i]
if module.mtype == "server" and string.lower(module.name) == name then
if module.panel ~= server.curPanel then
server.catList:ClearSelection()
for i=1, #server.catList.Lines do
local line = server.catList.Lines[i]
if string.lower(line:GetColumnText(1)) == name then
server.catList:SelectItem( line )
break
end
end
end
break
end
end
end
--Process modular settings
function server.processModules()
server.catList:Clear()
for i, module in ipairs( xgui.modules.submodule ) do
if module.mtype == "server" and ( not module.access or LocalPlayer():query( module.access ) ) then
local w,h = module.panel:GetSize()
if w == h and h == 0 then module.panel:SetSize( 275, 322 ) end
if module.panel.scroll then --For DListLayouts
module.panel.scroll.panel = module.panel
module.panel = module.panel.scroll
end
module.panel:SetParent( server.panel )
local line = server.catList:AddLine( module.name, i )
if ( module.panel == server.curPanel ) then
server.curPanel = nil
server.catList:SelectItem( line )
else
module.panel:SetVisible( false )
end
end
end
server.catList:SortByColumn( 1, false )
end
server.processModules()
xgui.hookEvent( "onProcessModules", nil, server.processModules, "serverSettingsProcessModules" )
xgui.addSettingModule( "Server", server, "icon16/server.png", "xgui_svsettings" )
---------------------------
--Server Settings Modules--
---------------------------
--These are submodules that load into the server settings module above.
-------------------------Admin Votemaps--------------------------
local plist = xlib.makelistlayout{ w=275, h=322, parent=xgui.null }
plist:Add( xlib.makelabel{ label="Admin Votemap Settings" } )
plist:Add( xlib.makelabel{ label="Ratio of votes needed to accept a mapchange" } )
plist:Add( xlib.makeslider{ label="<--->", min=0, max=1, decimal=2, repconvar="ulx_votemap2Successratio" } )
plist:Add( xlib.makelabel{ label="Minimum votes for a successful mapchange" } )
plist:Add( xlib.makeslider{ label="<--->", min=0, max=10, repconvar="ulx_votemap2Minvotes" } )
xgui.addSubModule( "ULX Admin Votemaps", plist, nil, "server" )
-----------------------------Adverts-----------------------------
xgui.prepareDataType( "adverts" )
local adverts = xlib.makepanel{ parent=xgui.null }
adverts.tree = xlib.maketree{ w=120, h=296, parent=adverts }
adverts.tree.DoClick = function( self, node )
adverts.removebutton:SetDisabled( false )
adverts.updatebutton:SetDisabled( not node.data )
adverts.nodeup:SetDisabled( not node.data or type( node.group ) == "number" )
adverts.nodedown:SetDisabled( not node.data or not type( node.group ) == "number" or adverts.isBottomNode( node ) )
adverts.group:SetText( type(node.group) ~= "number" and node.group or "<No Group>" )
if node.data then
adverts.message:SetText( node.data.message )
adverts.time:SetValue( node.data.rpt )
adverts.color:SetColor( node.data.color )
adverts.csay:SetOpen( node.data.len )
adverts.csay:InvalidateLayout()
adverts.display:SetValue( node.data.len or 10 )
end
end
function adverts.isBottomNode( node )
local parentnode = node:GetParentNode()
local parentchildren = parentnode.ChildNodes:GetChildren()
if parentnode:GetParentNode().ChildNodes then --Is node within a subgroup?
local parentparentchildren = parentnode:GetParentNode().ChildNodes:GetChildren()
return parentchildren[#parentchildren] == node and parentparentchildren[#parentparentchildren] == parentnode
else
return not adverts.hasGroups or parentchildren[#parentchildren] == node
end
end
--0 middle, 1 bottom, 2 top, 3 top and bottom
function adverts.getNodePos( node )
if type( node.group ) == "number" then return 1 end
local parentchildren = node:GetParentNode().ChildNodes:GetChildren()
local output = 0
if parentchildren[#parentchildren] == node then output = 1 end
if parentchildren[1] == node then output = output + 2 end
return output
end
adverts.tree.DoRightClick = function( self, node )
self:SetSelectedItem( node )
local menu = DermaMenu()
menu:SetSkin(xgui.settings.skin)
if not node.data then
menu:AddOption( "Rename Group...", function() adverts.RenameAdvert( node:GetText() ) end )
end
menu:AddOption( "Delete", function() adverts.removeAdvert( node ) end )
menu:Open()
end
adverts.seloffset = 0
adverts.message = xlib.maketextbox{ x=125, w=150, h=20, text="Enter a message...", parent=adverts, selectall=true }
xlib.makelabel{ x=125, y=25, label="Time until advert repeats:", parent=adverts }
adverts.time = xlib.makeslider{ x=125, y=40, w=150, label="<--->", value=60, min=1, max=1000, tooltip="Time in seconds till the advert is shown/repeated.", parent=adverts }
adverts.group = xlib.makecombobox{ x=125, y=65, w=150, enableinput=true, parent=adverts, tooltip="Select or create a new advert group." }
adverts.color = xlib.makecolorpicker{ x=135, y=90, parent=adverts }
local panel = xlib.makelistlayout{ w=150, h=45, spacing=4, parent=xgui.null }
panel:Add( xlib.makelabel{ label="Display Time (seconds)" } )
adverts.display = xlib.makeslider{ label="<--->", min=1, max=60, value=10, tooltip="The time in seconds the CSay advert is displayed" }
panel:Add( adverts.display )
adverts.csay = xlib.makecat{ x=125, y=230, w=150, label="Display in center", checkbox=true, contents=panel, parent=adverts, expanded=false }
xlib.makebutton{ x=200, y=302, w=75, label="Create", parent=adverts }.DoClick = function()
local col = adverts.color:GetColor()
local rpt = tonumber( adverts.time:GetValue() )
RunConsoleCommand( "xgui", "addAdvert", adverts.message:GetValue(), ( rpt < 0.1 ) and 0.1 or rpt, adverts.group:GetValue(), col.r, col.g, col.b, adverts.csay:GetExpanded() and adverts.display:GetValue() or nil)
end
adverts.removebutton = xlib.makebutton{ y=302, w=75, label="Remove", disabled=true, parent=adverts }
adverts.removebutton.DoClick = function( node )
adverts.removeAdvert( adverts.tree:GetSelectedItem() )
end
adverts.updatebutton = xlib.makebutton{ x=125, y=302, w=75, label="Update", parent=adverts, disabled=true }
adverts.updatebutton.DoClick = function( node )
local node = adverts.tree:GetSelectedItem()
local col = adverts.color:GetColor()
if ((( type( node.group ) == "number" ) and "<No Group>" or node.group ) == adverts.group:GetValue() ) then
RunConsoleCommand( "xgui", "updateAdvert", type( node.group ), node.group, node.number, adverts.message:GetValue(), ( adverts.time:GetValue() < 0.1 ) and 0.1 or adverts.time:GetValue(), col.r, col.g, col.b, adverts.csay:GetExpanded() and adverts.display:GetValue() or nil )
else
RunConsoleCommand( "xgui", "removeAdvert", node.group, node.number, type( node.group ), "hold" )
RunConsoleCommand( "xgui", "addAdvert", adverts.message:GetValue(), ( adverts.time:GetValue() < 0.1 ) and 0.1 or adverts.time:GetValue(), adverts.group:GetValue(), col.r, col.g, col.b, adverts.csay:GetExpanded() and adverts.display:GetValue() or nil)
adverts.selnewgroup = adverts.group:GetValue()
if xgui.data.adverts[adverts.group:GetValue()] then
adverts.seloffset = #xgui.data.adverts[adverts.group:GetValue()]+1
else
adverts.seloffset = 1
end
end
end
adverts.nodeup = xlib.makebutton{ x=80, y=302, w=20, icon="icon16/bullet_arrow_up.png", centericon=true, parent=adverts, disabled=true }
adverts.nodeup.DoClick = function()
adverts.nodedown:SetDisabled( true )
adverts.nodeup:SetDisabled( true )
local node = adverts.tree:GetSelectedItem()
local state = adverts.getNodePos( node )
if state <= 1 then
RunConsoleCommand( "xgui", "moveAdvert", type( node.group ), node.group, node.number, node.number-1 )
adverts.seloffset = adverts.seloffset - 1
else
local parentnode = node:GetParentNode()
local parentparentchildren = parentnode:GetParentNode().ChildNodes:GetChildren()
local newgroup = "<No Group>"
for i,v in ipairs( parentparentchildren ) do
if v == parentnode then
if parentparentchildren[i-1] and type( parentparentchildren[i-1].group ) ~= "number" then
newgroup = parentparentchildren[i-1].group
adverts.selnewgroup = newgroup
adverts.seloffset = #xgui.data.adverts[newgroup]+1
end
break
end
end
RunConsoleCommand( "xgui", "removeAdvert", node.group, node.number, type( node.group ), "hold" )
RunConsoleCommand( "xgui", "addAdvert", node.data.message, node.data.rpt, newgroup, node.data.color.r, node.data.color.g, node.data.color.b, node.data.len)
if newgroup == "<No Group>" then
adverts.selnewgroup = #xgui.data.adverts+1
adverts.seloffset = 1
end
end
end
adverts.nodedown = xlib.makebutton{ x=100, y=302, w=20, icon="icon16/bullet_arrow_down.png", centericon=true, parent=adverts, disabled=true }
adverts.nodedown.DoClick = function()
adverts.nodedown:SetDisabled( true )
adverts.nodeup:SetDisabled( true )
local node = adverts.tree:GetSelectedItem()
local state = adverts.getNodePos( node )
if state == 1 or state == 3 then
local parentnode = type( node.group ) == "string" and node:GetParentNode() or node
local parentchildren = parentnode:GetParentNode().ChildNodes:GetChildren()
local newgroup = "<No Group>"
for index,v in ipairs( parentchildren ) do
if v == parentnode then
local temp = 1
while( type( parentchildren[index+temp].group ) == "number" ) do
temp = temp + 1
end
if type( parentchildren[index+temp].group ) ~= "number" then
newgroup = parentchildren[index+temp].group
adverts.selnewgroup = newgroup
adverts.seloffset = 1
end
break
end
end
RunConsoleCommand( "xgui", "removeAdvert", node.group, node.number, type( node.group ), "hold" )
RunConsoleCommand( "xgui", "addAdvert", node.data.message, node.data.rpt, newgroup, node.data.color.r, node.data.color.g, node.data.color.b, node.data.len or "", "hold" )
RunConsoleCommand( "xgui", "moveAdvert", type( newgroup ), newgroup, #xgui.data.adverts[newgroup]+1, 1 )
else
RunConsoleCommand( "xgui", "moveAdvert", type( node.group ), node.group, node.number, node.number+1 )
adverts.seloffset = adverts.seloffset + 1
end
end
function adverts.removeAdvert( node )
if node then
Derma_Query( "Are you sure you want to delete this " .. ( node.data and "advert?" or "advert group?" ), "XGUI WARNING",
"Delete", function()
if node.data then --Remove a single advert
RunConsoleCommand( "xgui", "removeAdvert", node.group, node.number, type( node.group ) )
else --Remove an advert group
RunConsoleCommand( "xgui", "removeAdvertGroup", node.group, type( node.group ) )
end
adverts.tree:SetSelectedItem( nil )
end, "Cancel", function() end )
end
end
function adverts.RenameAdvert( old )
advertRename = xlib.makeframe{ label="Set Name of Advert Group - " .. old, w=400, h=80, showclose=true, skin=xgui.settings.skin }
advertRename.text = xlib.maketextbox{ x=10, y=30, w=380, h=20, text=old, parent=advertRename }
advertRename.text.OnEnter = function( self )
RunConsoleCommand( "xgui", "renameAdvertGroup", old, self:GetValue() )
advertRename:Remove()
end
xlib.makebutton{ x=175, y=55, w=50, label="OK", parent=advertRename }.DoClick = function()
advertRename.text:OnEnter()
end
end
function adverts.updateAdverts()
adverts.updatebutton:SetDisabled( true )
adverts.nodeup:SetDisabled( true )
adverts.nodedown:SetDisabled( true )
adverts.removebutton:SetDisabled( true )
--Store the currently selected node, if any
local lastNode = adverts.tree:GetSelectedItem()
if adverts.selnewgroup then
lastNode.group = adverts.selnewgroup
lastNode.number = adverts.seloffset
adverts.selnewgroup = nil
adverts.seloffset = 0
end
--Check for any previously expanded group nodes
local groupStates = {}
if adverts.tree.RootNode.ChildNodes then
for _, node in ipairs( adverts.tree.RootNode.ChildNodes:GetChildren() ) do
if node.m_bExpanded then
groupStates[node:GetText()] = true
end
end
end
adverts.hasGroups = false
adverts.tree:Clear()
adverts.group:Clear()
adverts.group:AddChoice( "<No Group>" )
adverts.group:ChooseOptionID( 1 )
local sortGroups = {}
local sortSingle = {}
for group, advertgroup in pairs( xgui.data.adverts ) do
if type( group ) == "string" then --Check if it's a group or a single advert
table.insert( sortGroups, group )
else
table.insert( sortSingle, { group=group, message=advertgroup[1].message } )
end
end
table.sort( sortSingle, function(a,b) return string.lower( a.message ) < string.lower( b.message ) end )
table.sort( sortGroups, function(a,b) return string.lower( a ) < string.lower( b ) end )
for _, advert in ipairs( sortSingle ) do
adverts.createNode( adverts.tree, xgui.data.adverts[advert.group][1], advert.group, 1, xgui.data.adverts[advert.group][1].message, lastNode )
end
for _, group in ipairs( sortGroups ) do
advertgroup = xgui.data.adverts[group]
adverts.hasGroups = true
local foldernode = adverts.tree:AddNode( group, "icon16/folder.png" )
adverts.group:AddChoice( group )
foldernode.group = group
--Check if folder was previously selected
if lastNode and not lastNode.data and lastNode:GetValue() == group then
adverts.tree:SetSelectedItem( foldernode )
adverts.removebutton:SetDisabled( false )
end
for advert, data in ipairs( advertgroup ) do
adverts.createNode( foldernode, data, group, advert, data.message, lastNode )
end
--Expand folder if it was expanded previously
if groupStates[group] then foldernode:SetExpanded( true, true ) end
end
adverts.tree:InvalidateLayout()
local node = adverts.tree:GetSelectedItem()
if node then
if adverts.seloffset ~= 0 then
for i,v in ipairs( node:GetParentNode().ChildNodes:GetChildren() ) do
if v == node then
node = node:GetParentNode().ChildNodes:GetChildren()[i+adverts.seloffset]
adverts.tree:SetSelectedItem( node )
break
end
end
adverts.seloffset = 0
end
if adverts.isBottomNode( node ) then adverts.nodedown:SetDisabled( true ) end
adverts.nodeup:SetDisabled( type( node.group ) == "number" )
end
end
function adverts.createNode( parent, data, group, number, message, lastNode )
local node = parent:AddNode( message, data.len and "icon16/style.png" or "icon16/text_smallcaps.png" )
node.data = data
node.group = group
node.number = number
node:SetTooltip( xlib.wordWrap( message, 250, "Default" ) )
if lastNode and lastNode.data then
--Check if node was previously selected
if lastNode.group == group and lastNode.number == number then
adverts.tree:SetSelectedItem( node )
adverts.group:SetText( type(node.group) ~= "number" and node.group or "<No Group>" )
adverts.updatebutton:SetDisabled( false )
adverts.nodeup:SetDisabled( false )
adverts.nodedown:SetDisabled( false )
adverts.removebutton:SetDisabled( false )
end
end
end
function adverts.onOpen()
ULib.queueFunctionCall( adverts.tree.InvalidateLayout, adverts.tree )
end
adverts.updateAdverts() -- For autorefresh
xgui.hookEvent( "adverts", "process", adverts.updateAdverts, "serverUpdateAdverts" )
xgui.addSubModule( "ULX Adverts", adverts, nil, "server" )
------------------------------Echo-------------------------------
local plist = xlib.makelistlayout{ w=275, h=322, parent=xgui.null }
plist:Add( xlib.makelabel{ label="Command/Event echo settings" } )
plist:Add( xlib.makecheckbox{ label="Echo players vote choices", repconvar="ulx_voteEcho" } )
plist:Add( xlib.makecombobox{ repconvar="ulx_logEcho", isNumberConvar=true, choices={ "Do not echo admin commands", "Echo admin commands anonymously", "Echo commands and identify admin" } } )
plist:Add( xlib.makecombobox{ repconvar="ulx_logSpawnsEcho", isNumberConvar=true, choices={ "Do not echo spawns", "Echo spawns to admins only", "Echo spawns to everyone" } } )
plist:Add( xlib.makecheckbox{ label="Enable colored event echoes", repconvar="ulx_logEchoColors" } )
plist:Add( xlib.makelabel{ label="Default text color" } )
plist:Add( xlib.makecolorpicker{ repconvar="ulx_logEchoColorDefault", noalphamodetwo=true } )
plist:Add( xlib.makelabel{ label="Color for console" } )
plist:Add( xlib.makecolorpicker{ repconvar="ulx_logEchoColorConsole", noalphamodetwo=true } )
plist:Add( xlib.makelabel{ label="Color for self" } )
plist:Add( xlib.makecolorpicker{ repconvar="ulx_logEchoColorSelf", noalphamodetwo=true } )
plist:Add( xlib.makelabel{ label="Color for everyone" } )
plist:Add( xlib.makecolorpicker{ repconvar="ulx_logEchoColorEveryone", noalphamodetwo=true } )
plist:Add( xlib.makecheckbox{ label="Show team colors for players", repconvar="ulx_logEchoColorPlayerAsGroup" } )
plist:Add( xlib.makelabel{ label="Color for players (when above is disabled)" } )
plist:Add( xlib.makecolorpicker{ repconvar="ulx_logEchoColorPlayer", noalphamodetwo=true } )
plist:Add( xlib.makelabel{ label="Color for everything else" } )
plist:Add( xlib.makecolorpicker{ repconvar="ulx_logEchoColorMisc", noalphamodetwo=true } )
xgui.addSubModule( "ULX Command/Event Echoes", plist, nil, "server" )
------------------------General Settings-------------------------
local plist = xlib.makelistlayout{ w=275, h=322, parent=xgui.null }
plist:Add( xlib.makelabel{ label="General ULX Settings" } )
plist:Add( xlib.makeslider{ label="Chat spam time", min=0, max=5, decimal=1, repconvar="ulx_chattime" } )
plist:Add( xlib.makelabel{ label="Allow '/me' chat feature" } )
plist:Add( xlib.makecombobox{ repconvar="ulx_meChatEnabled", isNumberConvar=true, choices={ "Disabled", "Sandbox Only", "Enabled" } } )
plist:Add( xlib.makelabel{ label="\nMOTD Settings" } )
--Very custom convar handling for ulx_showMotd
plist.motdEnabled = xlib.makecheckbox{ label="Show MOTD when players join" }
function plist.motdEnabled:Toggle() self.Button:DoClick() end
plist.motdEnabled.Button.DoClick = function( self )
self:Toggle()
local bVal = self:GetChecked()
if bVal == true then
if plist.motdURLEnabled:GetChecked() then
RunConsoleCommand( "ulx_showMotd", plist.motdURLText:GetValue() )
else
RunConsoleCommand( "ulx_showMotd", "1" )
end
else
RunConsoleCommand( "ulx_showMotd", "0" )
end
end
plist.motdURLEnabled = xlib.makecheckbox{ label="Get MOTD from URL instead of motd.txt:" }
function plist.motdURLEnabled:Toggle() self.Button:DoClick() end
plist.motdURLEnabled.Button.DoClick = function( self )
self:Toggle()
local bVal = self:GetChecked()
if bVal == true then
if plist.motdURLText:GetValue() ~= "" then
RunConsoleCommand( "ulx_showMotd", plist.motdURLText:GetValue() )
end
plist.motdURLText:SetDisabled( false )
else
RunConsoleCommand( "ulx_showMotd", "1" )
plist.motdURLText:SetDisabled( true )
end
end
plist.motdURLText = xlib.maketextbox{ selectall=true }
function plist.motdURLText:UpdateConvarValue()
if plist.motdURLText:GetValue() ~= "" then
RunConsoleCommand( "ulx_showMotd", self:GetValue() )
end
end
function plist.motdURLText:OnEnter() self:UpdateConvarValue() end
function plist.ConVarUpdated( sv_cvar, cl_cvar, ply, old_val, new_val )
if string.lower( cl_cvar ) == "ulx_showmotd" then
if tonumber( new_val ) == nil then --MOTD is enabled and set to a URL
plist.motdEnabled:SetValue( 1 )
plist.motdURLEnabled:SetValue( 1 )
plist.motdURLEnabled:SetDisabled( false )
plist.motdURLText:SetValue( new_val )
plist.motdURLText:SetDisabled( false )
else
plist.motdEnabled:SetValue( new_val )
if new_val == "1" then
plist.motdURLEnabled:SetValue( 0 )
plist.motdURLEnabled:SetDisabled( false )
plist.motdURLText:SetDisabled( true )
elseif new_val == "0" then
plist.motdURLEnabled:SetDisabled( true )
plist.motdURLText:SetDisabled( true )
end
end
end
end
hook.Add( "ULibReplicatedCvarChanged", "XGUI_ulx_showMotd", plist.ConVarUpdated )
plist:Add( plist.motdEnabled )
plist:Add( plist.motdURLEnabled )
plist:Add( plist.motdURLText )
plist:Add( xlib.makelabel{ label="Allowed variables: %curmap%, %steamid%" } )
plist:Add( xlib.makelabel{ label="\nWelcome Message" } )
plist:Add( xlib.maketextbox{ repconvar="ulx_welcomemessage", selectall=true } )
plist:Add( xlib.makelabel{ label="Allowed variables: %curmap%, %host%" } )
plist:Add( xlib.makelabel{ label="\nAuto Name-Changing Kicker" } )
plist:Add( xlib.makelabel{ label="Number of name changes till kicked (0 disables)" } )
plist:Add( xlib.makeslider{ label="<--->", min=0, max=10, decimal=0, repconvar="ulx_kickAfterNameChanges" } )
plist:Add( xlib.makeslider{ label="Cooldown time (seconds)", min=0, max=600, decimal=0, repconvar="ulx_kickAfterNameChangesCooldown" } )
plist:Add( xlib.makecheckbox{ label="Warn players how many name-changes remain", repconvar="ulx_kickAfterNameChangesWarning" } )
xlib.checkRepCvarCreated( "ulx_showMotd" )
plist.ConVarUpdated( nil, "ulx_showMotd", nil, nil, GetConVar( "ulx_showMotd" ):GetString() )
xgui.addSubModule( "ULX General Settings", plist, nil, "server" )
------------------------------Gimps------------------------------
xgui.prepareDataType( "gimps" )
local gimps = xlib.makepanel{ parent=xgui.null }
gimps.textbox = xlib.maketextbox{ w=225, h=20, parent=gimps, selectall=true }
gimps.textbox.OnEnter = function( self )
if self:GetValue() then
RunConsoleCommand( "xgui", "addGimp", self:GetValue() )
self:SetText( "" )
end
end
gimps.textbox.OnGetFocus = function( self )
gimps.button:SetText( "Add" )
self:SelectAllText()
xgui.anchor:SetKeyboardInputEnabled( true )
end
gimps.button = xlib.makebutton{ x=225, w=50, label="Add", parent=gimps }
gimps.button.DoClick = function( self )
if self:GetValue() == "Add" then
gimps.textbox:OnEnter()
elseif gimps.list:GetSelectedLine() then
RunConsoleCommand( "xgui", "removeGimp", gimps.list:GetSelected()[1]:GetColumnText(1) )
end
end
gimps.list = xlib.makelistview{ y=20, w=275, h=302, multiselect=false, headerheight=0, parent=gimps }
gimps.list:AddColumn( "Gimp Sayings" )
gimps.list.OnRowSelected = function( self, LineID, Line )
gimps.button:SetText( "Remove" )
end
gimps.updateGimps = function()
gimps.list:Clear()
for k, v in pairs( xgui.data.gimps ) do
gimps.list:AddLine( v )
end
end
gimps.updateGimps()
xgui.hookEvent( "gimps", "process", gimps.updateGimps, "serverUpdateGimps" )
xgui.addSubModule( "ULX Gimps", gimps, nil, "server" )
------------------------Kick/Ban Reasons-------------------------
xgui.prepareDataType( "banreasons", ulx.common_kick_reasons )
local panel = xlib.makepanel{ parent=xgui.null }
panel.textbox = xlib.maketextbox{ w=225, h=20, parent=panel, selectall=true }
panel.textbox.OnEnter = function( self )
if self:GetValue() then
RunConsoleCommand( "xgui", "addBanReason", self:GetValue() )
self:SetText( "" )
end
end
panel.textbox.OnGetFocus = function( self )
panel.button:SetText( "Add" )
self:SelectAllText()
xgui.anchor:SetKeyboardInputEnabled( true )
end
panel.button = xlib.makebutton{ x=225, w=50, label="Add", parent=panel }
panel.button.DoClick = function( self )
if self:GetValue() == "Add" then
panel.textbox:OnEnter()
elseif panel.list:GetSelectedLine() then
RunConsoleCommand( "xgui", "removeBanReason", panel.list:GetSelected()[1]:GetColumnText(1) )
end
end
panel.list = xlib.makelistview{ y=20, w=275, h=302, multiselect=false, headerheight=0, parent=panel }
panel.list:AddColumn( "Kick/Ban Reasons" )
panel.list.OnRowSelected = function()
panel.button:SetText( "Remove" )
end
panel.updateBanReasons = function()
panel.list:Clear()
for k, v in pairs( ulx.common_kick_reasons ) do
panel.list:AddLine( v )
end
end
panel.updateBanReasons()
xgui.hookEvent( "banreasons", "process", panel.updateBanReasons, "serverUpdateBanReasons" )
xgui.addSubModule( "ULX Kick/Ban Reasons", panel, "xgui_managebans", "server" )
--------------------------Log Settings---------------------------
local plist = xlib.makelistlayout{ w=275, h=322, parent=xgui.null }
plist:Add( xlib.makelabel{ label="Logging Settings" } )
plist:Add( xlib.makecheckbox{ label="Enable Logging to Files", repconvar="ulx_logFile" } )
plist:Add( xlib.makecheckbox{ label="Log Chat", repconvar="ulx_logChat" } )
plist:Add( xlib.makecheckbox{ label="Log Player Events (Connects, Deaths, etc.)", repconvar="ulx_logEvents" } )
plist:Add( xlib.makecheckbox{ label="Log Spawns (Props, Effects, Ragdolls, etc.)", repconvar="ulx_logSpawns" } )
plist:Add( xlib.makelabel{ label="Save log files to this directory:" } )
local logdirbutton = xlib.makebutton{}
xlib.checkRepCvarCreated( "ulx_logdir" )
logdirbutton:SetText( "data/" .. GetConVar( "ulx_logDir" ):GetString() )
function logdirbutton.ConVarUpdated( sv_cvar, cl_cvar, ply, old_val, new_val )
if cl_cvar == "ulx_logdir" then
logdirbutton:SetText( "data/" .. new_val )
end
end
hook.Add( "ULibReplicatedCvarChanged", "XGUI_ulx_logDir", logdirbutton.ConVarUpdated )
plist:Add( logdirbutton )
xgui.addSubModule( "ULX Logs", plist, nil, "server" )
-----------------------Player Votemap List-----------------------
xgui.prepareDataType( "votemaps", ulx.votemaps )
local panel = xlib.makepanel{ w=285, h=322, parent=xgui.null }
xlib.makelabel{ label="Allowed Votemaps", x=5, y=3, parent=panel }
xlib.makelabel{ label="Excluded Votemaps", x=150, y=3, parent=panel }
panel.votemaps = xlib.makelistview{ y=20, w=135, h=262, multiselect=true, headerheight=0, parent=panel }
panel.votemaps:AddColumn( "" )
panel.votemaps.OnRowSelected = function( self, LineID, Line )
panel.add:SetDisabled( true )
panel.remove:SetDisabled( false )
panel.remainingmaps:ClearSelection()
end
panel.remainingmaps = xlib.makelistview{ x=140, y=20, w=135, h=262, multiselect=true, headerheight=0, parent=panel }
panel.remainingmaps:AddColumn( "" )
panel.remainingmaps.OnRowSelected = function( self, LineID, Line )
panel.add:SetDisabled( false )
panel.remove:SetDisabled( true )
panel.votemaps:ClearSelection()
end
panel.remove = xlib.makebutton{ y=282, w=135, label="Remove -->", disabled=true, parent=panel }
panel.remove.DoClick = function()
panel.remove:SetDisabled( true )
local temp = {}
for _, v in ipairs( panel.votemaps:GetSelected() ) do
table.insert( temp, v:GetColumnText(1) )
end
RunConsoleCommand( "xgui", "removeVotemaps", unpack( temp ) )
end
panel.add = xlib.makebutton{ x=140, y=282, w=135, label="<-- Add", disabled=true, parent=panel }
panel.add.DoClick = function()
panel.add:SetDisabled( true )
local temp = {}
for _, v in ipairs( panel.remainingmaps:GetSelected() ) do
table.insert( temp, v:GetColumnText(1) )
end
RunConsoleCommand( "xgui", "addVotemaps", unpack( temp ) )
end
panel.votemapmode = xlib.makecombobox{ y=302, w=275, repconvar="ulx_votemapMapmode", isNumberConvar=true, numOffset=0, choices={ "Include new maps by default", "Exclude new maps by default" }, parent=panel }
panel.updateList = function()
if #ulx.maps ~= 0 then
panel.votemaps:Clear()
panel.remainingmaps:Clear()
panel.add:SetDisabled( true )
panel.remove:SetDisabled( true )
for _, v in ipairs( ulx.maps ) do
if table.HasValue( ulx.votemaps, v ) then
panel.votemaps:AddLine( v )
else
panel.remainingmaps:AddLine( v )
end
end
end
end
panel.updateList()
xgui.hookEvent( "votemaps", "process", panel.updateList, "serverUpdateVotemapList" )
xgui.addSubModule( "ULX Player Votemap List", panel, nil, "server" )
---------------------Player Votemap Settings---------------------
local plist = xlib.makelistlayout{ w=275, h=322, parent=xgui.null }
plist:Add( xlib.makelabel{ label="Player Votemap Settings" } )
plist:Add( xlib.makecheckbox{ label="Enable Player Votemaps", repconvar="ulx_votemapEnabled" } )
plist:Add( xlib.makelabel{ label="Time (min) before a user can vote for a map" } )
plist:Add( xlib.makeslider{ label="<--->", min=0, max=300, repconvar="ulx_votemapMintime" } )
plist:Add( xlib.makelabel{ label="Time (min) until a user can change their vote" } )
plist:Add( xlib.makeslider{ label="<--->", min=0, max=60, decimal=1, repconvar="ulx_votemapWaittime" } )
plist:Add( xlib.makelabel{ label="Ratio of votes needed to accept mapchange" } )
plist:Add( xlib.makeslider{ label="<--->", min=0, max=1, decimal=2, repconvar="ulx_votemapSuccessratio" } )
plist:Add( xlib.makelabel{ label="Minimum votes for a successful mapchange" } )
plist:Add( xlib.makeslider{ label="<--->", min=0, max=10, repconvar="ulx_votemapMinvotes" } )
plist:Add( xlib.makelabel{ label="Time (sec) for an admin to veto a mapchange" } )
plist:Add( xlib.makeslider{ label="<--->", min=0, max=300, repconvar="ulx_votemapVetotime" } )
xgui.addSubModule( "ULX Player Votemap Settings", plist, nil, "server" )
-------------------------Reserved Slots--------------------------
local plist = xlib.makelistlayout{ w=275, h=322, parent=xgui.null }
plist:Add( xlib.makelabel{ label="Reserved Slots Settings" } )
plist:Add( xlib.makecombobox{ repconvar="ulx_rslotsMode", isNumberConvar=true, choices={ "0 - Reserved slots disabled", "1 - Admins fill slots", "2 - Admins don't fill slots", "3 - Admins kick newest player" } } )
plist:Add( xlib.makeslider{ label="Number of Reserved Slots", min=0, max=game.MaxPlayers(), repconvar="ulx_rslots" } )
plist:Add( xlib.makecheckbox{ label="Reserved Slots Visible", repconvar="ulx_rslotsVisible" } )
plist:Add( xlib.makelabel{ w=265, wordwrap=true, label="Reserved slots mode info:\n1 - Set a certain number of slots reserved for admins-- As admins join, they will fill up these slots.\n2 - Same as #1, but admins will not fill the slots-- they'll be freed when players leave.\n3 - Always keep 1 slot open for admins, and, if full, kick the user with the shortest connection time when an admin joins, thus keeping 1 slot open.\n\nReserved Slots Visible:\nWhen enabled, if there are no regular player slots available in your server, it will appear that the server is full. The major downside to this is that admins can't connect to the server using the 'find server' dialog. Instead, they have to go to console and use the command 'connect <ip>'" } )
xgui.addSubModule( "ULX Reserved Slots", plist, nil, "server" )
------------------------Votekick/Voteban-------------------------
local plist = xlib.makelistlayout{ w=275, h=322, parent=xgui.null }
plist:Add( xlib.makelabel{ label="Votekick Settings" } )
plist:Add( xlib.makelabel{ label="Ratio of votes needed to accept votekick" } )
plist:Add( xlib.makeslider{ label="<--->", min=0, max=1, decimal=2, repconvar="ulx_votekickSuccessratio" } )
plist:Add( xlib.makelabel{ label="Minimum votes required for a successful votekick" } )
plist:Add( xlib.makeslider{ label="<--->", min=0, max=10, repconvar="ulx_votekickMinvotes" } )
plist:Add( xlib.makelabel{ label="\nVoteban Settings" } )
plist:Add( xlib.makelabel{ label="Ratio of votes needed to accept voteban" } )
plist:Add( xlib.makeslider{ label="<--->", min=0, max=1, decimal=2, repconvar="ulx_votebanSuccessratio" } )
plist:Add( xlib.makelabel{ label="Minimum votes required for a successful voteban" } )
plist:Add( xlib.makeslider{ label="<--->", min=0, max=10, repconvar="ulx_votebanMinvotes" } )
xgui.addSubModule( "ULX Votekick/Voteban", plist, nil, "server" )

View File

@ -1 +1 @@
1447985314
1711250983

View File

@ -1,19 +0,0 @@
<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>

View File

@ -1,450 +0,0 @@
Title: ULX Readme
__ULX__
Version 3.62d
*ULX v3.62d (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.
* [FIX] XGUI: Right-clicking an advert group and renaming it was broken.
* [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] You can now spectate another player while spectating someone else.
* [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