forked from TeamUlysses/ulx
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
32c96d56ef | ||
![]() |
42a9e9711c | ||
![]() |
daca5a6d9e | ||
![]() |
bd975c0392 | ||
![]() |
78451f1574 | ||
![]() |
22b173d0eb | ||
![]() |
943ce45991 |
@ -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
|
@ -1,7 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# .git/hooks/pre-commit
|
||||
#
|
||||
|
||||
# Prevent infinite loops on post-commit
|
||||
touch .commit
|
14
addon.json
14
addon.json
@ -1,14 +0,0 @@
|
||||
{
|
||||
"title" : "ULX",
|
||||
"type" : "ServerContent",
|
||||
"tags" : [ "fun", "build" ],
|
||||
"ignore" :
|
||||
[
|
||||
"addon.txt",
|
||||
".editorconfig",
|
||||
".git*",
|
||||
"ulx.build",
|
||||
"ulx_readme.txt"
|
||||
],
|
||||
"workshopid": 557962280
|
||||
}
|
11
addon.txt
11
addon.txt
@ -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"
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
if SERVER then
|
||||
include( "ulx/init.lua" )
|
||||
else
|
||||
include( "ulx/cl_init.lua" )
|
||||
end
|
121
lua/ulx/base.lua
121
lua/ulx/base.lua
@ -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
|
@ -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 )
|
@ -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" )
|
343
lua/ulx/data.lua
343
lua/ulx/data.lua
@ -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
|
142
lua/ulx/end.lua
142
lua/ulx/end.lua
@ -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
|
@ -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
|
110
lua/ulx/lib.lua
110
lua/ulx/lib.lua
@ -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
|
515
lua/ulx/log.lua
515
lua/ulx/log.lua
@ -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
|
@ -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
|
@ -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
|
@ -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 )
|
@ -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
@ -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
@ -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
|
@ -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 '|'." )
|
@ -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." )
|
@ -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." )
|
@ -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
|
@ -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 )
|
@ -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." )
|
@ -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
|
@ -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 )
|
@ -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 )
|
@ -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 )
|
@ -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
|
@ -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
|
@ -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" )
|
@ -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" )
|
@ -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
@ -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" )
|
@ -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 )
|
@ -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 )
|
@ -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 )
|
@ -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 )
|
@ -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 )
|
@ -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" )
|
@ -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" )
|
@ -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" )
|
19
ulx_motd.txt
19
ulx_motd.txt
@ -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>
|
450
ulx_readme.txt
450
ulx_readme.txt
@ -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
|
Loading…
Reference in New Issue
Block a user