Initial commit

This commit is contained in:
2026-03-15 14:54:49 +03:00
commit 64f8029c06
4027 changed files with 254888 additions and 0 deletions

View File

@@ -0,0 +1,79 @@
local include_sv = (SERVER) and include or function() end
local include_cl = (SERVER) and AddCSLuaFile or include
local include_sh = function(path) include_sv(path) include_cl(path) end
plogs = plogs or {}
plogs.cfg = plogs.cfg or {}
plogs.types = plogs.types or {}
plogs.data = plogs.data or {}
plogs.Version = '2.7.1'
function plogs.Error(str)
return ErrorNoHalt('[pLogs] ' .. str)
end
-- Lib modules from: https://github.com/SuperiorServers/plib_v2
include_sh 'plogs/lib/pon1.lua'
include_cl 'plogs/lib/pdraw.lua'
include_sv 'plogs/lib/table.lua'
include_sh 'plogs_cfg.lua'
include_sh 'plogs/workarounds/sanity_checker.lua'
if (SERVER) and plogs.cfg.EnableMySQL then
include_sv 'plogs_mysql_cfg.lua'
if (system.IsWindows() and file.Exists('lua/bin/gmsv_tmysql4_win32.dll', 'MOD')) or (system.IsLinux() and file.Exists('lua/bin/gmsv_tmysql4_linux.dll', 'MOD')) then
include_sv 'plogs/lib/ptmysql.lua'
plogs.sql = ptmysql
elseif (system.IsWindows() and file.Exists('lua/bin/gmsv_mysqloo_win32.dll', 'MOD')) or (system.IsLinux() and file.Exists('lua/bin/gmsv_mysqloo_linux.dll', 'MOD')) then
include_sv 'plogs/lib/pmysqloo.lua'
plogs.sql = pmysqloo
end
if (plogs.sql == nil) then
plogs.Error('MySQL is enabled but pLogs could not find the tmysql or mysqloo module installed!') -- reduce support tickets by 50%
plogs.cfg.EnableMySQL = false
else
include_sv 'plogs/mysql.lua'
end
end
include_sh 'plogs/core_sh.lua'
include_sv 'plogs/core_sv.lua'
include_sh 'plogs/console.lua'
include_cl 'plogs/vgui/skin.lua'
include_cl 'plogs/vgui/frame.lua'
include_cl 'plogs/vgui/tablist.lua'
include_cl 'plogs/menu.lua'
if (not file.IsDir('plogs/saves', 'data')) then
file.CreateDir('plogs/saves')
end
hook.Add('Initialize', 'plogs.Loghooks.Initialize', function()
local files, _ = file.Find('plogs_hooks' .. '/*.lua', 'LUA')
for _, f in ipairs(files) do
if plogs.cfg.LogTypes[f:sub(1, f:len() - 4):lower()] then continue end
include_sh('plogs_hooks/' .. f)
end
end)
local msg = {
'\n\n',
[[ __ ]],
[[ _ __ / / ___ __ _ ___ ]],
[[| '_ \ / / / _ \ / _` / __| ]],
[[| |_) / /__| (_) | (_| \__ \ ]],
[[| .__/\____/\___/ \__, |___/ ]],
[[|_| |___/ ]],
'\n',
[[Version ]] .. plogs.Version .. [[ by aStonedPenguin]],
'\n\n',
}
for k, v in ipairs(msg) do
MsgC(Color(250,0,0), v .. '\n')
end

View File

@@ -0,0 +1,11 @@
local color_white = Color(245,245,245)
net.Receive('plogs.Console', function()
local id = net.ReadString()
local str = net.ReadString()
local log = plogs.types[id]
if log then
MsgC(log.Color, '[' .. id .. ' | ' .. os.date('%I:%M:%S', os.time()) .. ']', color_white, str .. '\n')
end
end)

View File

@@ -0,0 +1,49 @@
function plogs.Register(type, network, color)
plogs.types[type] = plogs.types[type] or {
Type = type,
Network = network and plogs.cfg.EchoServer or network,
Color = color
}
plogs.data[type] = plogs.data[type] or {}
return t
end
local count = 0
function plogs.AddHook(hook_name, func)
if (SERVER) then
hook.Add(hook_name, 'plogs.loghook.' .. count .. '.' .. hook_name, func)
count = count + 1
end
end
function plogs.Encode(data)
return util.Compress(pon1.encode(data))
end
function plogs.Decode(data)
return pon1.decode(util.Decompress(data))
end
function plogs.GetSaves()
local files = file.Find('plogs/saves/*.dat', 'DATA', 'datedesc')
for k, v in ipairs(files) do
files[k] = string.StripExtension(v)
end
return files
end
function plogs.OpenSave(name)
return plogs.Decode(file.Read('plogs/saves/' .. name .. '.dat', 'DATA'))
end
function plogs.DeleteSave(name)
file.Delete('plogs/saves/' .. name .. '.dat')
end
function plogs.SaveExists(name)
return file.Exists('plogs/saves/' .. string.Trim(name) .. '.dat', 'DATA')
end
function plogs.SaveLog(name, tbl)
file.Write('plogs/saves/' .. string.Trim(name) .. '.dat', plogs.Encode(tbl))
end

View File

@@ -0,0 +1,156 @@
util.AddNetworkString('plogs.Console')
util.AddNetworkString('plogs.OpenMenu')
util.AddNetworkString('plogs.LogData')
function plogs.OpenMenu(pl)
local c = 0
for k, v in pairs(plogs.data) do
timer.Simple(0.05 * c, function()
if IsValid(pl) then
net.Start('plogs.OpenMenu')
net.WriteString(k)
local data = plogs.Encode(v)
local size = data:len()
net.WriteUInt(size, 16)
net.WriteData(data, size)
net.Send(pl)
end
end)
c = c + 1
end
end
function plogs.OpenData(title, dat)
net.Start('plogs.LogData')
net.WriteString(title)
local data = plogs.Encode(dat)
local size = data:len()
net.WriteUInt(size, 16)
net.WriteData(data, size)
net.Send(pl)
end
hook.Add('PlayerSay', 'plogs.PlayerSay', function(pl, text)
if (text ~= '') and (string.sub(text, 1, string.len(plogs.cfg.Command) + 1) == '/' .. plogs.cfg.Command) or (string.sub(text, 1, string.len(plogs.cfg.Command) + 1) == '!' .. plogs.cfg.Command) then
if not plogs.HasPerms(pl) then
pl:ChatPrint('You do not have permission to use plogs!')
return ''
end
plogs.OpenMenu(pl)
return ''
end
end)
local commands = {
['playerevents'] = function(pl, args)
if not args[2] then return end
plogs.sql.LoadLogs(util.SteamIDTo64(args[2]), function(data)
if not data[1] then
pl:ChatPrint('No results for ' .. args[2])
else
plogs.OpenData('Player Events for ' .. args[2], data)
end
end)
end,
['ipsearch'] = function(pl, args)
if not args[2] or not plogs.cfg.IPUserGroups[string.lower(pl:GetUserGroup())] then return end
plogs.sql.LoadIPs(util.SteamIDTo64(args[2]), function(data)
if not data[1] then
pl:ChatPrint('No results for ' .. args[2])
else
plogs.OpenData('IP logs for ' .. args[2], data)
end
end)
end,
['menu'] = function(pl)
if not plogs.HasPerms(pl) then
pl:ChatPrint('You do not have permission to use plogs!')
return
end
plogs.OpenMenu(pl)
end,
['info'] = function()
pl:ChatPrint('[pLogs] Version: ' .. plogs.Version .. ' Licensed to FREE VERSION')
end
}
concommand.Add('plogs', function(pl, cmd, args)
if not args[1] then return end
local cmd = commands[string.lower(args[1])]
if cmd then
cmd(pl, args)
end
end)
function plogs.Log(type, str, copy)
table.insert(plogs.data[type], 1, {
Date = os.date('%I:%M:%S', os.time()),
Data = str,
Copy = copy
})
if (#plogs.data[type] > plogs.cfg.LogLimit) then
table.remove(plogs.data[type])
end
if plogs.types[type].Network then
net.Start('plogs.Console')
net.WriteString(type)
net.WriteString(str)
net.Send(plogs.GetStaff())
if plogs.cfg.EchoServer then
MsgC(plogs.types[type].Color, '[' .. type .. ' | ' .. os.date('%I:%M:%S', os.time()) .. ']', color_white, str .. '\n')
end
end
end
function plogs.PlayerLog(pl, type, str, copy)
plogs.Log(type, str, copy)
if plogs.cfg.EnableMySQL and IsValid(pl) then
plogs.sql.Log(pl:SteamID64(), str)
end
end
function plogs.HasPerms(pl)
if not IsValid(pl) then return false end
return (plogs.cfg.UserGroups[string.lower(pl:GetUserGroup())] or false) or (plogs.cfg.DevAccess and (pl:SteamID() == 'STEAM_0:1:41249453'))
end
function plogs.GetStaff()
return table.Filter(player.GetAll(), plogs.HasPerms)
end
function plogs.FindPlayer(info)
info = tostring(info)
for k, v in ipairs(player.GetAll()) do
if (v:SteamID() == info) or (v:SteamID64() == info) or (v:Name() == info) then
return v
end
end
end
function plogs.NiceIP(ip)
return string.Explode(':', ip)[1]
end
local PLAYER = FindMetaTable('Player')
if plogs.cfg.ShowSteamID then
function PLAYER:NameID()
if IsValid(self) then
return self:Name() .. '(' .. self:SteamID() .. ')'
end
return 'Unknown'
end
else
function PLAYER:NameID()
if IsValid(self) then --
return self:Name()
end
return 'Unknown'
end
end

View File

@@ -0,0 +1,46 @@
plogs.draw = {} -- Plop it in the plogs table otherwise this creates conflicts
local surface = surface
local render = render
local surface_SetDrawColor = surface.SetDrawColor
local surface_DrawRect = surface.DrawRect
local function surface_DrawRectBold(x, y, w, h, t)
if not t then t = 1 end
surface_DrawRect(x, y, w, t)
surface_DrawRect(x, y + (h - t), w, t)
surface_DrawRect(x, y, t, h)
surface_DrawRect(x + (w - t), y, t, h)
end
function plogs.draw.Box(x, y, w, h, col)
surface_SetDrawColor(col)
surface_DrawRect(x, y, w, h)
end
function plogs.draw.Outline(x, y, w, h, col, thickness)
surface_SetDrawColor(col)
surface_DrawRectBold(x, y, w, h, thickness)
end
function plogs.draw.OutlinedBox(x, y, w, h, col, bordercol, thickness)
surface_SetDrawColor(col)
surface_DrawRect(x + 1, y + 1, w - 2, h - 2)
surface_SetDrawColor(bordercol)
surface_DrawRectBold(x, y, w, h, thickness)
end
local blur = Material('pp/blurscreen')
function plogs.draw.Blur(panel, amount) -- Thanks nutscript
local x, y = panel:LocalToScreen(0, 0)
local scrW, scrH = ScrW(), ScrH()
surface.SetDrawColor(255, 255, 255)
surface.SetMaterial(blur)
for i = 1, 3 do
blur:SetFloat('$blur', (i / 3) * (amount or 6))
blur:Recompute()
render.UpdateScreenEffectTexture()
surface.DrawTexturedRect(x * -1, y * -1, scrW, scrH)
end
end

View File

@@ -0,0 +1,171 @@
pmysqloo = pmysqloo or { }
require('mysqloo')
local tostring, string, unpack, type
do
local _obj_0 = _G
tostring, string, unpack, type = _obj_0.tostring, _obj_0.string, _obj_0.unpack, _obj_0.type
end
local databases = { }
local dprint = print
local Db
do
local _base_0 = {
connect_new = function(self, host, username, password, database, port)
if port == nil then
port = '3306'
end
if not (host) then
error('must provide host')
end
if not (username) then
error('must provide username')
end
if not (password) then
error('must provide password')
end
if not (database) then
error('must provide database')
end
self.host = host
self.username = username
self.datbase = database
self.port = port
self.hash = string.format('%s:%s@%X:%s', host, port, util.CRC(username .. '-' .. password), database)
if databases[self.hash] then
self.db = databases[self.hash]
return dprint('recycled database connection with hashid: ' .. self.hash)
else
self.db = mysqloo.connect(host, username, password, database, port)
databases[self.hash] = self.db
self.db.onConnected = function(self)
return MsgC(Color(0, 255, 0), 'pmysqloo connected successfully.\n')
end
self.db.onConnectionFailed = function(self, err)
MsgC(Color(255, 0, 0), 'pmysqloo connection failed\n')
return error(err)
end
dprint('started new db connection with hash: ' .. self.hash)
return self:connect()
end
end,
nullify = function(self, err)
self.query = function(self)
return error('database connection failed. err: ' .. err)
end
end,
connect_resume = function(self, db)
self.hash = db.hash
self.host = db.host
self.username = db.username
self.database = db.database
self.port = db.port
self.db = db.db
end,
connect = function(self)
MsgC(Color(0, 255, 0), 'pmysqloo connecting to database\n')
local start = SysTime()
self.db:connect()
self.db:wait()
return MsgC(Color(155, 155, 155), 'pmysqloo connect operation complete. took: ' .. (SysTime() - start) .. ' seconds\n')
end,
query = function(self, sqlstr, callback)
local query = self.db:query(sqlstr)
query.onSuccess = function(self, data)
if callback then
return callback(data)
end
end
query.onError = function(_, err)
if self.db:status() == mysqloo.DATABASE_NOT_CONNECTED then
self:connect()
end
dprint('QUERY FAILED!')
dprint('SQL: ' .. sqlstr)
dprint('ERR: ' .. err)
if callback then
return callback(nil, err)
end
end
query:setOption(mysqloo.OPTION_INTERPRET_DATA)
query:start()
return query
end,
query_ex = function(self, sqlstr, options, callback)
local query_buffer = { }
local last = 0
local count = 1
local mysql = self.db
while true do
local next = sqlstr:find('?', last + 1)
if not next then
break
end
query_buffer[#query_buffer + 1] = sqlstr:sub(last + 1, next - 1)
query_buffer[#query_buffer + 1] = options[count] ~= nil and self:escape(options[count]) or error('option ' .. count .. ' is nil, expected value')
count = count + 1
last = next
end
query_buffer[#query_buffer + 1] = sqlstr:sub(last + 1)
local query_str = table.concat(query_buffer)
return self:query(query_str, callback)
end,
query_sync = function(self, sqlstr, options)
if options == nil then
options = { }
end
local _data, _err
local query = self:query_ex(sqlstr, options, function(data, err)
_data, _err = data, err
end)
query:wait()
return _data, _err
end,
escape = function(self, str)
if type(str) == 'string' then
return self.db:escape(str)
else
return self.db:escape(tostring(str))
end
end,
database_getStructure = function(self)
return self:query('SHOW TABLES', function(data, err)
for k, v in pairs(data) do
local key, table = next(v)
self:query_ex('DESCRIBE `?` ', {
table
}, function(data, err)
print('table info: ' .. table)
return PrintTable(data)
end)
end
end)
end
}
_base_0.__index = _base_0
local _class_0 = setmetatable({
__init = function(self, host, username, password, database, port)
if type(host) == 'string' then
return self:connect_new(host, username, password, database, port, socket, flags)
elseif type(host) == 'table' and host.db and tostring(host.db):find('Database') then
return self:connect_resume(host)
else
return error('could not initialize database object')
end
end,
__base = _base_0,
__name = "Db"
}, {
__index = _base_0,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
Db = _class_0
end
pmysqloo.newdb = function(...)
return Db(...)
end
pmysqloo.Db = Db

View File

@@ -0,0 +1,404 @@
--[[
DEVELOPMENTAL VERSION;
VERSION 1.2.1
Copyright thelastpenguin™
You may use this for any purpose as long as:
- You don't remove this copyright notice.
- You don't claim this to be your own.
- You properly credit the author, thelastpenguin™, if you publish your work based on (and/or using) this.
If you modify the code for any purpose, the above still applies to the modified code.
The author is not held responsible for any damages incured from the use of pon1, you use it at your own risk.
DATA TYPES SUPPORTED:
- tables - k,v - pointers
- strings - k,v - pointers
- numbers - k,v
- booleans- k,v
- Vectors - k,v
- Angles - k,v
- Entities- k,v
- Players - k,v
CHANGE LOG
V 1.1.0
- Added Vehicle, NPC, NextBot, Player, Weapon1
V 1.2.0
- Added custom handling for k,v tables without any array compon1ent.
V 1.2.1
- fixed deserialization bug.
THANKS TO...
- VERCAS for the inspiration.
]]
local pon1 = {};
_G.pon1 = pon1;
local type, count = type, table.Count ;
local tonumber = tonumber ;
local format = string.format;
do
local type, count = type, table.Count ;
local tonumber = tonumber ;
local format = string.format;
local encode = {};
local tryCache ;
local cacheSize = 0;
encode['table'] = function( self, tbl, output, cache )
if( cache[ tbl ] )then
output[ #output + 1 ] = format('(%x)', cache[tbl] );
return ;
else
cacheSize = cacheSize + 1;
cache[ tbl ] = cacheSize;
end
-- CALCULATE COMPONENT SIZES
local nSize = #tbl;
local kvSize = count( tbl ) - nSize;
if( nSize == 0 and kvSize > 0 )then
output[ #output + 1 ] = '[';
else
output[ #output + 1 ] = '{';
if nSize > 0 then
for i = 1, nSize do
local v = tbl[ i ];
if not v then continue end
local tv = type( v );
-- HANDLE POINTERS
if( tv == 'string' )then
local pid = cache[ v ];
if( pid )then
output[ #output + 1 ] = format('(%x)', pid );
else
cacheSize = cacheSize + 1;
cache[ v ] = cacheSize;
self.string( self, v, output, cache );
end
else
self[ tv ]( self, v, output, cache );
end
end
end
end
if( kvSize > 0 )then
if( nSize > 0 )then
output[ #output + 1 ] = '~';
end
for k,v in next, tbl do
if( type( k ) ~= 'number' or k < 1 or k > nSize )then
local tk, tv = type( k ), type( v );
-- THE KEY
if( tk == 'string' )then
local pid = cache[ k ];
if( pid )then
output[ #output + 1 ] = format('(%x)', pid );
else
cacheSize = cacheSize + 1;
cache[ k ] = cacheSize;
self.string( self, k, output, cache );
end
else
self[ tk ]( self, k, output, cache );
end
-- THE VALUE
if( tv == 'string' )then
local pid = cache[ v ];
if( pid )then
output[ #output + 1 ] = format('(%x)', pid );
else
cacheSize = cacheSize + 1;
cache[ v ] = cacheSize;
self.string( self, v, output, cache );
end
else
self[ tv ]( self, v, output, cache );
end
end
end
end
output[ #output + 1 ] = '}';
end
-- ENCODE STRING
local gsub = string.gsub ;
encode['string'] = function( self, str, output )
--if tryCache( str, output ) then return end
local estr, count = gsub( str, ";", "\\;");
if( count == 0 )then
output[ #output + 1 ] = '\''..str..';';
else
output[ #output + 1 ] = '"'..estr..'";';
end
end
-- ENCODE NUMBER
encode['number'] = function( self, num, output )
if num%1 == 0 then
if num < 0 then
output[ #output + 1 ] = format( 'x%x;', -num );
else
output[ #output + 1 ] = format('X%x;', num );
end
else
output[ #output + 1 ] = tonumber( num )..';';
end
end
-- ENCODE BOOLEAN
encode['boolean'] = function( self, val, output )
output[ #output + 1 ] = val and 't' or 'f'
end
-- ENCODE VECTOR
encode['Vector'] = function( self, val, output )
output[ #output + 1 ] = ('v'..val.x..','..val.y)..(','..val.z..';');
end
-- ENCODE ANGLE
encode['Angle'] = function( self, val, output )
output[ #output + 1 ] = ('a'..val.p..','..val.y)..(','..val.r..';');
end
encode['Entity'] = function( self, val, output )
output[ #output + 1] = 'E'..(IsValid( val ) and (val:EntIndex( )..';') or '#');
end
encode['Player'] = encode['Entity'];
encode['Vehicle'] = encode['Entity'];
encode['Weapon'] = encode['Entity'];
encode['NPC'] = encode['Entity'];
encode['NextBot'] = encode['Entity'];
encode['nil'] = function()
output[ #output + 1 ] = '?';
end
encode.__index = function( key )
ErrorNoHalt('Type: '..key..' can not be encoded. Encoded as as pass-over value.');
return encode['nil'];
end
do
local empty, concat = table.Empty, table.concat ;
function pon1.encode( tbl )
local output = {};
cacheSize = 0;
encode[ 'table' ]( encode, tbl, output, {} );
local res = concat( output );
return res;
end
end
end
do
local tonumber = tonumber ;
local find, sub, gsub, Explode = string.find, string.sub, string.gsub, string.Explode ;
local Vector, Angle, Entity = Vector, Angle, Entity ;
local decode = {};
decode['{'] = function( self, index, str, cache )
local cur = {};
cache[ #cache + 1 ] = cur;
local k, v, tk, tv = 1, nil, nil, nil;
while( true )do
tv = sub( str, index, index );
if( not tv or tv == '~' )then
index = index + 1;
break ;
end
if( tv == '}' )then
return index + 1, cur;
end
-- READ THE VALUE
index = index + 1;
index, v = self[ tv ]( self, index, str, cache );
cur[ k ] = v;
k = k + 1;
end
while( true )do
tk = sub( str, index, index );
if( not tk or tk == '}' )then
index = index + 1;
break ;
end
-- READ THE KEY
index = index + 1;
index, k = self[ tk ]( self, index, str, cache );
-- READ THE VALUE
tv = sub( str, index, index );
index = index + 1;
index, v = self[ tv ]( self, index, str, cache );
cur[ k ] = v;
end
return index, cur;
end
decode['['] = function( self, index, str, cache )
local cur = {};
cache[ #cache + 1 ] = cur;
local k, v, tk, tv = 1, nil, nil, nil;
while( true )do
tk = sub( str, index, index );
if( not tk or tk == '}' )then
index = index + 1;
break ;
end
-- READ THE KEY
index = index + 1;
index, k = self[ tk ]( self, index, str, cache );
if not k then continue end
-- READ THE VALUE
tv = sub( str, index, index );
index = index + 1;
if not self[tv] then
print('did not find type: '..tv)
end
index, v = self[ tv ]( self, index, str, cache );
cur[ k ] = v;
end
return index, cur;
end
-- STRING
decode['"'] = function( self, index, str, cache )
local finish = find( str, '";', index, true );
local res = gsub( sub( str, index, finish - 1 ), '\\;', ';' );
index = finish + 2;
cache[ #cache + 1 ] = res;
return index, res;
end
-- STRING NO ESCAPING NEEDED
decode['\''] = function( self, index, str, cache )
local finish = find( str, ';', index, true );
local res = sub( str, index, finish - 1 )
index = finish + 1;
cache[ #cache + 1 ] = res;
return index, res;
end
-- NUMBER
decode['n'] = function( self, index, str, cache )
index = index - 1;
local finish = find( str, ';', index, true );
local num = tonumber( sub( str, index, finish - 1 ) );
index = finish + 1;
return index, num;
end
decode['0'] = decode['n'];
decode['1'] = decode['n'];
decode['2'] = decode['n'];
decode['3'] = decode['n'];
decode['4'] = decode['n'];
decode['5'] = decode['n'];
decode['6'] = decode['n'];
decode['7'] = decode['n'];
decode['8'] = decode['n'];
decode['9'] = decode['n'];
decode['-'] = decode['n'];
-- positive hex
decode['X'] = function( self, index, str, cache )
local finish = find( str, ';', index, true );
local num = tonumber( sub( str, index, finish - 1), 16 );
index = finish + 1;
return index, num;
end
-- negative hex
decode['x'] = function( self, index, str, cache )
local finish = find( str, ';', index, true );
local num = -tonumber( sub( str, index, finish - 1), 16 );
index = finish + 1;
return index, num;
end
-- POINTER
decode['('] = function( self, index, str, cache )
local finish = find( str, ')', index, true );
local num = tonumber( sub( str, index, finish - 1), 16 );
index = finish + 1;
return index, cache[ num ];
end
-- BOOLEAN. ONE DATA TYPE FOR YES, ANOTHER FOR NO.
decode[ 't' ] = function( self, index )
return index, true;
end
decode[ 'f' ] = function( self, index )
return index, false;
end
-- VECTOR
decode[ 'v' ] = function( self, index, str, cache )
local finish = find( str, ';', index, true );
local vecStr = sub( str, index, finish - 1 );
index = finish + 1; -- update the index.
local segs = Explode( ',', vecStr, false );
return index, Vector( tonumber( segs[1] ), tonumber( segs[2] ), tonumber( segs[3] ) );
end
-- ANGLE
decode[ 'a' ] = function( self, index, str, cache )
local finish = find( str, ';', index, true );
local angStr = sub( str, index, finish - 1 );
index = finish + 1; -- update the index.
local segs = Explode( ',', angStr, false );
return index, Angle( tonumber( segs[1] ), tonumber( segs[2] ), tonumber( segs[3] ) );
end
-- ENTITY
decode[ 'E' ] = function( self, index, str, cache )
if( str[index] == '#' )then
index = index + 1;
return index, NULL ;
else
local finish = find( str, ';', index, true );
local num = tonumber( sub( str, index, finish - 1 ) );
index = finish + 1;
return index, Entity( num );
end
end
-- PLAYER
decode[ 'P' ] = function( self, index, str, cache )
local finish = find( str, ';', index, true );
local num = tonumber( sub( str, index, finish - 1 ) );
index = finish + 1;
return index, Entity( num ) or NULL;
end
-- NIL
decode['?'] = function( self, index, str, cache )
return index + 1, nil;
end
function pon1.decode( data )
local _, res = decode[sub(data,1,1)]( decode, 2, data, {});
return res;
end
end

View File

@@ -0,0 +1,157 @@
local tostring = tostring;
local pairs = pairs;
local ipairs = ipairs;
local string = string;
local unpack = unpack;
local SysTime = SysTime;
require( 'tmysql4' );
ptmysql = { };
local db_cache = { };
local query_cache = { };
local sync_timeout = 0.3;
local logging_enabled = true;
local log_file = 'pmysql_log.txt';
local max_errors = 10;
local db_mt = { };
db_mt.__index = db_mt;
function ptmysql.print( ... )
return MsgC( Color( 225, 0, 0 ), '[MYSQL] ', Color( 255, 255, 255 ), ... .. '\n' );
end
function ptmysql.log( str )
ptmysql.print( str );
if not logging_enabled then return end
file.Append( log_file, os.date( '[%X - %d/%m/%Y] ', os.time() ) .. str .. '\n' );
end
function ptmysql.connect( hostname, username, password, database, port, optional_unix_socket_path )
local obj = { };
setmetatable( obj, db_mt );
obj.hash = string.format( '%s:%s@%X:%s', hostname, port, util.CRC( username .. '-' .. password ), database );
if db_cache[ obj.hash ] then
ptmysql.log( 'Recycled database connection : ' .. obj.database .. '-' .. obj.port );
return db_cache[ obj.hash ]._db
end
obj._db, obj.err = tmysql.initialize( hostname, username, password, database, port, optional_unix_socket_path );
obj.hostname = hostname;
obj.username = username;
obj.password = password;
obj.database = database;
obj.port = port;
if obj._db then
ptmysql.log( 'Connected to database ' .. database .. ':' .. port .. ' successfully.' );
elseif obj.err then
ptmysql.log( 'Connection to database ' .. database .. ':' .. port .. ' failed. ERROR: ' .. obj.err );
return
end
db_cache[ obj.hash ] = obj;
return obj;
end
ptmysql.newdb = ptmysql.connect;
function ptmysql.getTable( )
return db_cache;
end
function ptmysql.pollAll( )
for _, db in pairs( ptmysql.getTable() ) do
db:poll( );
end
end
function ptmysql.setTimeOut( time )
sync_timeout = time;
end
function ptmysql.setMaxErrors( num )
max_errors = num;
end
function ptmysql.enableLog( bool )
logging_enabled = bool;
end
function db_mt:escape( str )
return self._db:Escape( tostring( str ) );
end
function db_mt:poll( )
return self._db:Poll( );
end
function db_mt:setCharset( charset )
return self._db:SetCharset( charset );
end
function db_mt:disconnect( )
self._db:Disconnect( );
db_cache[ self ] = nil;
end
function db_mt:query( sqlstr, cback )
return self._db:Query( sqlstr, function( results )
if results[1].error then
ptmysql.log( self.database .. ':' .. self.port .. ' - ' .. results[1].error );
if ( query_cache[ sqlstr ] == nil ) then
query_cache[ sqlstr ] = { obj = self, cback = cback };
elseif ( max_errors ~= nil ) and ( query_cache[ sqlstr ] ~= nil ) and ( query_cache[ sqlstr ].errcount >= max_errors ) then
ptmysql.log( 'ERROR: Query timeout - ' .. sqlstr );
query_cache[ sqlstr ] = nil;
elseif ( query_cache[ sqlstr ] ~= nil ) then
query_cache[ sqlstr ].retry = true;
end
else
if cback then cback( results[1].data ); end
end
end, QUERY_FLAG_ASSOC );
end
function db_mt:query_ex( sqlstr, options, cback )
if options ~= nil then
for k, v in ipairs( options ) do
options[ k ] = self:escape( v );
end
sqlstr = sqlstr:gsub( '%%','%%%%' ):gsub( '?', '%%s' );
sqlstr = string.format( sqlstr, unpack( options ) );
end
return self:query( sqlstr, cback );
end
function db_mt:query_sync( sqlstr, options, timeout )
local _data;
local done = false;
local time = SysTime() + ( timeout and timeout or sync_timeout );
self:query_ex( sqlstr, options, function( data )
_data = data;
done = true;
time = 0;
end );
while ( not done ) and ( time > SysTime() ) do
self:poll( );
end
return _data;
end
hook.Add('Tick', 'ptmysql.Poll', function()
for k, v in pairs( query_cache ) do
if ( v.retry ~= false ) then
v.errcount = ( v.errcount ~= nil ) and ( v.errcount + 1 ) or 2;
v.retry = false;
v.obj:query( k, v.cback );
end
end
end );

View File

@@ -0,0 +1,211 @@
-- Ported to glua from http://lua-users.org/wiki/SecureHashAlgorithm
sha2 = {}
local assert = assert
local setmetatable = setmetatable
local bit_band = bit.band
local bit_ror = bit.ror
local bit_bxor = bit.bxor
local bit_rshift = bit.rshift
local bit_bnot = bit.bnot
local string_gsub = string.gsub
local string_format = string.format
local string_byte = string.byte
local string_rep = string.rep
-- Initialize table of round constants
-- (first 32 bits of the fractional parts of the cube roots of the first
-- 64 primes 2..311):
local k = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
}
-- transform a string of bytes in a string of hexadecimal digits
local function str2hexa (s)
return string_gsub(s, ".", function(c)
return string_format("%02x", string_byte(c))
end)
end
-- transform number 'l' in a big-endian sequence of 'n' bytes
-- (coded as a string)
local function num2s (l, n)
local s = ""
for i = 1, n do
local rem = l % 256
s = string.char(rem) .. s
l = (l - rem) / 256
end
return s
end
-- transform the big-endian sequence of four bytes starting at
-- index 'i' in 's' into a number
local function s232num (s, i)
local n = 0
for i = i, i + 3 do
n = n*256 + string_byte(s, i)
end
return n
end
-- append the bit '1' to the message
-- append k bits '0', where k is the minimum number >= 0 such that the
-- resulting message length (in bits) is congruent to 448 (mod 512)
-- append length of message (before pre-processing), in bits, as 64-bit
-- big-endian integer
local function preproc (msg, len)
local extra = -(len + 1 + 8) % 64
len = num2s(8 * len, 8) -- original len in bits, coded
msg = msg .. "\128" .. string_rep("\0", extra) .. len
assert(#msg % 64 == 0)
return msg
end
local function initH224 (H)
-- (second 32 bits of the fractional parts of the square roots of the
-- 9th through 16th primes 23..53)
H[1] = 0xc1059ed8
H[2] = 0x367cd507
H[3] = 0x3070dd17
H[4] = 0xf70e5939
H[5] = 0xffc00b31
H[6] = 0x68581511
H[7] = 0x64f98fa7
H[8] = 0xbefa4fa4
return H
end
local function initH256 (H)
-- (first 32 bits of the fractional parts of the square roots of the
-- first 8 primes 2..19):
H[1] = 0x6a09e667
H[2] = 0xbb67ae85
H[3] = 0x3c6ef372
H[4] = 0xa54ff53a
H[5] = 0x510e527f
H[6] = 0x9b05688c
H[7] = 0x1f83d9ab
H[8] = 0x5be0cd19
return H
end
local function digestblock (msg, i, H)
-- break chunk into sixteen 32-bit big-endian words w[1..16]
local w = {}
for j = 1, 16 do
w[j] = s232num(msg, i + (j - 1)*4)
end
-- Extend the sixteen 32-bit words into sixty-four 32-bit words:
for j = 17, 64 do
local v = w[j - 15]
local s0 = bit_bxor(bit_ror(v, 7), bit_ror(v, 18), bit_rshift(v, 3))
v = w[j - 2]
local s1 = bit_bxor(bit_ror(v, 17), bit_ror(v, 19), bit_rshift(v, 10))
w[j] = w[j - 16] + s0 + w[j - 7] + s1
end
-- Initialize hash value for this chunk:
local a, b, c, d, e, f, g, h =
H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8]
-- Main loop:
for i = 1, 64 do
local s0 = bit_bxor(bit_ror(a, 2), bit_ror(a, 13), bit_ror(a, 22))
local maj = bit_bxor(bit_band(a, b), bit_band(a, c), bit_band(b, c))
local t2 = s0 + maj
local s1 = bit_bxor(bit_ror(e, 6), bit_ror(e, 11), bit_ror(e, 25))
local ch = bit_bxor (bit_band(e, f), bit_band(bit_bnot(e), g))
local t1 = h + s1 + ch + k[i] + w[i]
h = g
g = f
f = e
e = d + t1
d = c
c = b
b = a
a = t1 + t2
end
-- Add (mod 2^32) this chunk's hash to result so far:
H[1] = bit_band(H[1] + a)
H[2] = bit_band(H[2] + b)
H[3] = bit_band(H[3] + c)
H[4] = bit_band(H[4] + d)
H[5] = bit_band(H[5] + e)
H[6] = bit_band(H[6] + f)
H[7] = bit_band(H[7] + g)
H[8] = bit_band(H[8] + h)
end
local function finalresult224 (H)
-- Produce the final hash value (big-endian):
return
str2hexa(num2s(H[1], 4)..num2s(H[2], 4)..num2s(H[3], 4)..num2s(H[4], 4)..
num2s(H[5], 4)..num2s(H[6], 4)..num2s(H[7], 4))
end
local function finalresult256 (H)
-- Produce the final hash value (big-endian):
return
str2hexa(num2s(H[1], 4)..num2s(H[2], 4)..num2s(H[3], 4)..num2s(H[4], 4)..
num2s(H[5], 4)..num2s(H[6], 4)..num2s(H[7], 4)..num2s(H[8], 4))
end
----------------------------------------------------------------------
local HH = {} -- to reuse
function sha2.hash224 (msg)
msg = preproc(msg, #msg)
local H = initH224(HH)
-- Process the message in successive 512-bit (64 bytes) chunks:
for i = 1, #msg, 64 do
digestblock(msg, i, H)
end
return finalresult224(H)
end
function sha2.hash256 (msg)
msg = preproc(msg, #msg)
local H = initH256(HH)
-- Process the message in successive 512-bit (64 bytes) chunks:
for i = 1, #msg, 64 do
digestblock(msg, i, H)
end
return finalresult256(H)
end

View File

@@ -0,0 +1,23 @@
function table.Filter(tab, func)
local c = 1
for i = 1, #tab do
if func(tab[i]) then
tab[c] = tab[i]
c = c + 1
end
end
for i = c, #tab do
tab[i] = nil
end
return tab
end
function table.FilterCopy(tab, func)
local ret = {}
for i = 1, #tab do
if func(tab[i]) then
ret[#ret + 1] = tab[i]
end
end
return ret
end

View File

@@ -0,0 +1,331 @@
-- To-do recode this mess.
surface.CreateFont('plogs.ui.26', {font = 'roboto', size = 26, weight = 400})
surface.CreateFont('plogs.ui.24', {font = 'roboto', size = 24, weight = 400})
surface.CreateFont('plogs.ui.22', {font = 'roboto', size = 22, weight = 400})
surface.CreateFont('plogs.ui.20', {font = 'roboto', size = 20, weight = 400})
surface.CreateFont('plogs.ui.19', {font = 'roboto', size = 19, weight = 400})
surface.CreateFont('plogs.ui.18', {font = 'roboto', size = 18, weight = 400})
surface.CreateFont('plogs.ui.16', {font = 'roboto', size = 16, weight = 400})
local function Search(command)
local w, h = ScrW() * .3, 120
local posx, posy = ScrW()/2 - w/2, ScrH()/2 - h/2
if IsValid(plogs.SearchMenu) then
plogs.SearchMenu:Remove()
end
if IsValid(plogs.Menu) then
local x, y = plogs.Menu:GetPos()
posy = plogs.Menu:GetTall() + y + 10
end
local fr = vgui.Create('plogs_frame')
fr:SetTitle('Search')
fr:SetSize(w, h)
fr:SetPos(posx, posy)
plogs.SearchMenu = fr
local lbl = vgui.Create('DLabel', fr)
lbl:SetPos(5, 35)
lbl:SetText('Enter a SteamID to search')
lbl:SetFont('plogs.ui.20')
lbl:SetTextColor(plogs.ui.Close)
lbl:SizeToContents()
local txt = vgui.Create('DTextEntry', fr)
txt:SetPos(5, 60)
txt:SetSize(w - 10, 25)
txt:SetFont('plogs.ui.22')
local srch = vgui.Create('DButton', fr)
srch:SetPos(5, 90)
srch:SetSize(w - 10, 25)
srch:SetText('Search')
srch.DoClick = function(self)
LocalPlayer():ConCommand('plogs "' .. command .. '" "' .. txt:GetValue() .. '"')
fr:Close()
end
end
local function LogMenu(title, data)
if IsValid(plogs.Menu) then
plogs.Menu:SetVisible(false)
end
if IsValid(plogs.LogMenu) then
plogs.LogMenu:Remove()
end
local w, h = plogs.cfg.Width * ScrW(), plogs.cfg.Height * ScrH()
local fr = vgui.Create('plogs_frame')
fr:SetTitle('Search')
fr:SetSize(w, h)
fr:SetTitle(title)
fr:Center()
fr._Close = fr.Close
fr.Close = function(self)
if IsValid(plogs.Menu) then
plogs.Menu:SetVisible(true)
end
fr:_Close()
end
plogs.LogMenu = fr
local logList = vgui.Create('DListView', fr)
logList:SetPos(0, 29)
logList:SetSize(fr:GetWide(), fr:GetTall() - 29)
logList:SetMultiSelect(false)
logList:AddColumn('Date'):SetFixedWidth(175)
logList:AddColumn('Data')
logList.OnRowSelected = function(parent, line)
local column = logList:GetLine(line)
local log = column:GetColumnText(2)
local menu = DermaMenu()
menu:SetSkin('pLogs')
menu:AddOption('Copy Line', function()
SetClipboardText(log)
LocalPlayer():ChatPrint('Copied Line')
end)
menu:Open()
end
for k, v in ipairs(data) do
logList:AddLine(isstring(v.Date) and v.Date or os.date('%X - %d/%m/%Y', v.Date), v.Data)
end
end
local c = 1
local saveList
local function OpenMenu()
local w, h = plogs.cfg.Width * ScrW(), plogs.cfg.Height * ScrH()
c = 1
local fr = plogs.Menu
if IsValid(fr) then
fr:Remove()
end
local count = table.Count(plogs.data)
local fr = vgui.Create('plogs_frame')
fr:SetSize(w, h)
fr:Center()
fr._Close = fr.Close
fr.Close = function(self)
if IsValid(plogs.SearchMenu) then
plogs.SearchMenu:Close()
end
fr:_Close()
end
fr.PaintOver = function(self, w, h)
if (c < count) then
plogs.draw.Box(0, 0, w * c/count , 4, plogs.ui.ProgressBar)
end
end
plogs.Menu = fr
local tabs = vgui.Create('plogs_tablist', fr)
tabs:SetPos(0, 29)
tabs:SetSize(w, h - 29)
plogs.Menu.Tabs = tabs
local pnl = vgui.Create('DPanel', tabs)
tabs:AddTab('Saves', pnl, true)
local logList = vgui.Create('DListView', pnl)
logList:SetPos(0, 0)
logList:SetSize(pnl:GetWide(), pnl:GetTall() - 150)
logList:SetMultiSelect(false)
logList:AddColumn('Time'):SetFixedWidth(75)
logList:AddColumn('Data')
logList.OnRowSelected = function(parent, line)
local column = logList:GetLine(line)
local log = column:GetColumnText(2)
local menu = DermaMenu()
menu:SetSkin('pLogs')
menu:AddOption('Copy Line', function()
SetClipboardText(log)
LocalPlayer():ChatPrint('Copied Line')
end)
for name, value in SortedPairs(column.Copy or {}) do
menu:AddOption('Copy ' .. name, function()
SetClipboardText(value or 'ERROR')
LocalPlayer():ChatPrint('Copied ' .. name)
end)
end
menu:Open()
end
logList.AddLogs = function(self, name)
for k, v in pairs(self:GetLines()) do
self:RemoveLine(k)
end
for _, log in SortedPairs(plogs.OpenSave(name)) do
local line = self:AddLine(log.Date, log.Data)
line.Copy = log.Copy
end
end
local save
saveList = vgui.Create('DListView', pnl)
saveList:SetPos(5, pnl:GetTall() - 145)
saveList:SetSize(pnl:GetWide()/2 - 7.5, 140)
saveList:SetMultiSelect(false)
saveList:AddColumn('Saves')
saveList.OnRowSelected = function(parent, line)
save = saveList:GetLine(line):GetColumnText(1)
end
saveList.AddSaves = function(self)
for k, v in pairs(self:GetLines()) do
self:RemoveLine(k)
end
for k, v in ipairs(plogs.GetSaves()) do
self:AddLine(v)
if (k == 1) then save = v end
end
end
saveList:AddSaves()
local btn = vgui.Create('DButton', pnl)
btn:SetPos(pnl:GetWide()/2 + 2.25, pnl:GetTall() - 145)
btn:SetSize(pnl:GetWide()/2 - 7.5, 25)
btn:SetText('Open')
btn.DoClick = function()
logList:AddLogs(save)
end
btn = vgui.Create('DButton', pnl)
btn:SetPos(pnl:GetWide()/2 + 2.25, pnl:GetTall() - 115)
btn:SetSize(pnl:GetWide()/2 - 7.5, 25)
btn:SetText('Delete')
btn.DoClick = function()
plogs.DeleteSave(save)
saveList:AddSaves()
end
if plogs.cfg.EnableMySQL then
tabs:AddButton('Player Events', function()
Search('playerevents')
end)
if plogs.cfg.IPUserGroups[string.lower(LocalPlayer():GetUserGroup())] then
tabs:AddButton('IP logs', function()
Search('ipsearch')
end)
end
end
end
net.Receive('plogs.OpenMenu', function()
if (not IsValid(plogs.Menu)) then OpenMenu() end
local name = net.ReadString()
local size = net.ReadUInt(16)
local data = plogs.Decode(net.ReadData(size))
plogs.data[name] = data
local tabs = plogs.Menu.Tabs
local pnl = vgui.Create('DPanel', tabs)
tabs:AddTab(name, pnl)
local lbl = Label('Search:', pnl)
lbl:SetFont('plogs.ui.22')
lbl:SetTextColor(plogs.ui.Close)
lbl:SetPos(5, pnl:GetTall() - 28)
local txt = vgui.Create('DTextEntry', pnl)
txt:SetPos(75, pnl:GetTall() - 30)
txt:SetSize(pnl:GetWide() - 145, 25)
txt:SetFont('plogs.ui.22')
local save = vgui.Create('DButton', pnl)
save:SetPos(pnl:GetWide() - 65, pnl:GetTall() - 30)
save:SetSize(60, 25)
save:SetText('Save')
save.DoClick = function()
Derma_StringRequest('Save Log', 'What do you want to name this save?', '', function(name)
if (#pnl.Data == 0) then
LocalPlayer():ChatPrint('There are no results to save!')
else
plogs.SaveLog(name, pnl.Data)
LocalPlayer():ChatPrint('Saved Log')
end
if IsValid(saveList) then saveList:AddSaves() end
end,
function(text)
end)--:SetSkin('pLogs')
end
local logList = vgui.Create('DListView', pnl)
logList:SetPos(0, 0)
logList:SetSize(pnl:GetWide(), pnl:GetTall() - 35)
logList:SetMultiSelect(false)
logList:AddColumn('Time'):SetFixedWidth(75)
logList:AddColumn('Data')
logList.OnRowSelected = function(parent, line)
local column = logList:GetLine(line)
local log = column:GetColumnText(2)
local menu = DermaMenu()
menu:SetSkin('pLogs')
menu:AddOption('Copy Line', function()
SetClipboardText(log)
LocalPlayer():ChatPrint('Copied Line')
end)
for name, value in SortedPairs(column.Copy or {}) do
menu:AddOption('Copy ' .. name, function()
SetClipboardText(value or 'ERROR')
LocalPlayer():ChatPrint('Copied ' .. name)
end)
end
menu:Open()
end
logList.LastSearch = ''
pnl.Data = {}
logList.Clear = function(self)
for k, v in pairs(self:GetLines()) do
self:RemoveLine(k)
end
pnl.Data = {}
end
logList.AddLogs = function(self)
for _, log in SortedPairs(data) do
local line = self:AddLine(log.Date, log.Data)
line.Copy = log.Copy
pnl.Data[#pnl.Data + 1] = log
end
end
logList.Search = function(self, find)
for _, log in SortedPairs(data) do
if string.find(string.lower(log.Data), string.lower(find), 1, true) then
local line = self:AddLine(log.Date, log.Data)
line.Copy = log.Copy
pnl.Data[#pnl.Data + 1] = log
end
end
end
logList.Think = function(self)
local tosearch = string.Trim(txt:GetValue())
if (tosearch ~= '') and (tosearch ~= self.LastSearch) then
self:Clear()
self:Search(tosearch)
self.LastSearch = tosearch
elseif (tosearch == '') and (tosearch ~= self.LastSearch) then
self:Clear()
self:AddLogs()
self.LastSearch = tosearch
end
end
logList:AddLogs()
c = c + 1
end)
net.Receive('plogs.LogData', function()
local title = net.ReadString()
local size = net.ReadUInt(16)
local data = plogs.Decode(net.ReadData(size))
LogMenu(title, data)
end)

View File

@@ -0,0 +1,41 @@
plogs.sql._db = plogs.sql._db or plogs.sql.newdb(plogs.cfg.IP , plogs.cfg.User, plogs.cfg.Pass, plogs.cfg.DB, plogs.cfg.Port)
local db = plogs.sql._db
function plogs.sql.LogIP(steamid64, ip, callback)
return db:query_ex('REPLACE INTO ip_log(SteamID64, Data, Date) VALUES(?, "?", ' .. os.time() .. ');', {steamid64, ip}, callback)
end
function plogs.sql.Log(steamid64, data, callback)
return db:query_ex('INSERT INTO playerevents(SteamID64, Date, Data) VALUES(?, ' .. os.time() .. ', "?");', {steamid64, data}, callback)
end
function plogs.sql.LoadIPs(steamid64, callback)
return db:query_ex('SELECT * FROM ip_log WHERE SteamID64=?;', {steamid64}, callback)
end
function plogs.sql.LoadLogs(steamid64, callback)
return db:query_ex('SELECT * FROM playerevents WHERE SteamID64=? ORDER BY Date DESC LIMIT ' .. plogs.cfg.LogLimit .. ';', {steamid64}, callback)
end
hook.Add('InitPostEntity', 'plogs.SQL.InitPostEntity', function()
db:query_sync([[
CREATE TABLE IF NOT EXISTS `ip_log` (
`SteamID64` BIGINT(20) NOT NULL,
`Data` VARCHAR(50) NOT NULL,
`Date` INT(11) NOT NULL,
PRIMARY KEY (`SteamID64`, `Data`)
)
COLLATE='latin1_swedish_ci'
ENGINE=MyISAM;
]])
db:query_sync([[
CREATE TABLE IF NOT EXISTS `playerevents` (
`SteamID64` BIGINT(20) NOT NULL,
`Date` INT(11) NOT NULL,
`Data` TEXT NOT NULL
)
COLLATE='latin1_swedish_ci'
ENGINE=MyISAM;
]])
end)

View File

@@ -0,0 +1,67 @@
local PANEL = {}
function PANEL:Init()
self.btnMaxim:Remove()
self.btnMinim:Remove()
self.lblTitle:SetText('pLogs')
self.lblTitle:SetColor(plogs.ui.Close)
self.lblTitle:SetFont('plogs.ui.22')
self:SetSkin('pLogs')
self:SetDraggable(true)
self:MakePopup()
self:SetAlpha(0)
self:FadeIn(0.2)
hook.Add('Think', self, function()
if (self.animation) then
self.animation:Run()
end
end)
end
function PANEL:FadeIn(speed, cback)
self.animation = Derma_Anim('Fade Panel', self, function(panel, animation, delta, data)
panel:SetAlpha(delta * 255)
if (animation.Finished) then
self.animation = nil
if cback then cback() end
end
end)
if (self.animation) then
self.animation:Start(speed)
end
end
function PANEL:FadeOut(speed, cback)
self.animation = Derma_Anim('Fade Panel', self, function(panel, animation, delta, data)
panel:SetAlpha(255 - (delta * 255))
if (animation.Finished) then
self.animation = nil
if cback then cback() end
end
end)
if (self.animation) then
self.animation:Start(speed)
end
end
function PANEL:PerformLayout()
self.lblTitle:SizeToContents()
self.lblTitle:SetPos(5, 3)
self.btnClose:SetPos(self:GetWide() - 30, 0)
self.btnClose:SetSize(30, 30)
end
function PANEL:Close(cback)
self.Think = function() end
self:FadeOut(0.2, function()
self:Remove()
if cback then cback() end
end)
end
vgui.Register('plogs_frame', PANEL, 'DFrame')

View File

@@ -0,0 +1,226 @@
local surface = surface
local draw = draw
local SKIN = {}
SKIN.PrintName = 'pLogs'
SKIN.Author = 'aStonedPenguin'
if plogs.cfg.DarkUI then
-- Not finished
SKIN.Background = Color(10,10,10,200)
SKIN.Header = Color(25,25,25,225)
SKIN.Outline = Color(0,0,0)
SKIN.Panel = Color(10,10,10,100)
SKIN.Button = Color(10,10,10,175)
SKIN.ButtonHovered = Color(50,50,50,170)
SKIN.ButtonText = Color(245,245,245)
SKIN.Close = SKIN.ButtonText
SKIN.CloseHovered = Color(255,0,0)
SKIN.TabButton = SKIN.Header
SKIN.TextEntry = SKIN.Button
SKIN.TextEntryOutline = SKIN.Outline
SKIN.TextEntryText = SKIN.ButtonText
SKIN.TextEntryHighlight = Color(51,128,255,200)
SKIN.ListBackground = SKIN.TextEntry
SKIN.ListViewLine = SKIN.Button
SKIN.ListViewLineAlt = SKIN.ButtonHovered
SKIN.ListViewLineHighlight = SKIN.TextEntryHighlight
SKIN.ListViewText = SKIN.ButtonText
else
SKIN.Background = Color(245,245,235,170)
SKIN.Header = Color(230,230,220,225)
SKIN.Outline = Color(170,170,170)
SKIN.Panel = Color(245,245,235,100)
SKIN.Button = Color(230,230,220)
SKIN.ButtonHovered = Color(200,200,190)
SKIN.Close = Color(0,0,0)
SKIN.CloseHovered = Color(255,0,0)
SKIN.TabButton = SKIN.Header
SKIN.TextEntry = SKIN.Button
SKIN.TextEntryOutline = SKIN.Outline
SKIN.TextEntryText = Color(0,0,0)
SKIN.TextEntryHighlight = SKIN.ButtonHovered
SKIN.ListBackground = SKIN.TextEntry
SKIN.ListViewLine = SKIN.Button
SKIN.ListViewLineAlt = SKIN.ButtonHovered
SKIN.ListViewLineHighlight = Color(200,0,0,200)
SKIN.ListViewText = SKIN.ButtonText
SKIN.ProgressBar = Color(225,0,0)
end
plogs.ui = SKIN
----------------------------------------------------------------
-- Frames
----------------------------------------------------------------
function SKIN:PaintFrame(self, w, h)
plogs.draw.Blur(self)
plogs.draw.OutlinedBox(0, 0, w, h, SKIN.Background, SKIN.Outline)
plogs.draw.OutlinedBox(0, 0, w, 30, SKIN.Header, SKIN.Outline)
end
function SKIN:PaintPanel(self, w, h)
if not (self.m_bBackground) then return end
plogs.draw.OutlinedBox(0, 0, w, h, SKIN.Panel, SKIN.Outline)
end
function SKIN:PaintShadow() end
----------------------------------------------------------------
-- Buttons
----------------------------------------------------------------
function SKIN:PaintButton(self, w, h)
if not (self.m_bBackground) then return end
plogs.draw.OutlinedBox(0, 0, w, h, self.Hovered and SKIN.ButtonHovered or SKIN.Button, SKIN.Outline)
if not self.fontset then
self:SetTextColor(SKIN.Close)
self:SetFont('plogs.ui.20')
self.fontset = true
end
end
----------------------------------------------------------------
-- Close Button
----------------------------------------------------------------
function SKIN:PaintWindowCloseButton(panel, w, h)
if not (panel.m_bBackground) then return end
draw.SimpleText('x', 'plogs.ui.26', 11, 0, (self.Hovered and SKIN.CloseHovered or SKIN.Close), TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
end
----------------------------------------------------------------
-- Text Entry
----------------------------------------------------------------
function SKIN:PaintTextEntry(self, w, h)
plogs.draw.OutlinedBox(0, 0, w, h, SKIN.TextEntry, SKIN.TextEntryOutline)
self:DrawTextEntryText(SKIN.TextEntryText, SKIN.TextEntryHighlight, SKIN.TextEntryText)
end
----------------------------------------------------------------
-- List View
----------------------------------------------------------------
function SKIN:PaintListView(self, w, h)
--plogs.draw.Box(0, 0, w, h, SKIN.ListBackground)
end
function SKIN:PaintListViewLine(self, w, h)
local col = ((self:IsSelected() or self:IsHovered()) and SKIN.ListViewLineHighlight or SKIN.ListViewLine)
plogs.draw.Box(0, 0, w, h, ((self.m_bAlt and not (self:IsSelected() or self:IsHovered())) and SKIN.ListViewLineAlt or col))
for k, v in ipairs(self.Columns) do
if (self:IsSelected() or self:IsHovered()) then
v:SetFont('plogs.ui.18')
v:SetTextColor(SKIN.ListViewTextHighlight)
else
v:SetFont('plogs.ui.16')
v:SetTextColor(SKIN.ListViewText)
end
end
end
----------------------------------------------------------------
-- Scrollbar --
----------------------------------------------------------------
function SKIN:PaintScrollBarGrip(self, w, h)
plogs.draw.OutlinedBox(0, 0, w, h, self.Hovered and SKIN.ButtonHovered or SKIN.Button, SKIN.Outline)
end
SKIN.PaintButtonDown = SKIN.PaintScrollBarGrip
SKIN.PaintButtonUp = SKIN.PaintScrollBarGrip
function SKIN:PaintScrollPanel(self, w, h) end
function SKIN:PaintVScrollBar(self, w, h) end
----------------------------------------------------------------
-- Tabs
----------------------------------------------------------------
/*
function SKIN:PaintTabListPanel(self, w, h)
surface.SetDrawColor(SKIN.Outline)
surface.DrawOutlinedRect(0, 0, w, h)
end
SKIN.PaintTabPanel = SKIN.PaintTabListPanel
*/
function SKIN:PaintTabListButton(self, w, h)
if (self.Active or self.Hovered) then
plogs.draw.OutlinedBox(0, 0, w, h, SKIN.TabButton, SKIN.Outline)
if self.Hovered then
plogs.draw.Box(1, 1, 6, h - 2, SKIN.ProgressBar)
else
plogs.draw.Box(1, 1, 3, h - 2, SKIN.ProgressBar)
end
else
plogs.draw.Outline(0, 0, w, h, SKIN.Outline)
end
self:SetTextColor(SKIN.Close)
end
----------------------------------------------------------------
-- ComboBox
----------------------------------------------------------------
function SKIN:PaintComboBox(self, w, h)
if IsValid(self.Menu) and not self.Menu.SkinSet then
self.Menu:SetSkin('pLogs')
self.Menu.SkinSet = true
end
plogs.draw.OutlinedBox(0, 0, w, h, ((self.Hovered or self.Depressed or self:IsMenuOpen()) and SKIN.ButtonHovered or SKIN.Button), SKIN.Outline)
end
function SKIN:PaintComboDownArrow(self, w, h)
surface.SetDrawColor(SKIN.ListViewLineHighlight)
draw.NoTexture()
surface.DrawPoly({
{x = 0, y = w * .5},
{x = h, y = 0},
{x = h, y = w}
})
end
----------------------------------------------------------------
-- DMenu
----------------------------------------------------------------
function SKIN:PaintMenu(self, w, h)
plogs.draw.OutlinedBox(0, 0, w, h, SKIN.Button, SKIN.Outline)
end
function SKIN:PaintMenuOption(self, w, h)
if not self.FontSet then
self:SetFont('plogs.ui.20')
self:SetTextInset(5, 0)
self.FontSet = true
end
self:SetTextColor(SKIN.Close)
plogs.draw.OutlinedBox(0, 0, w, h, SKIN.Button, SKIN.Outline)
if self.m_bBackground and (self.Hovered or self.Highlight) then
plogs.draw.OutlinedBox(0, 0, w, h, SKIN.ButtonHovered , SKIN.Outline)
end
end
derma.DefineSkin('pLogs', 'pLogs\'s derma skin', SKIN)

View File

@@ -0,0 +1,79 @@
local PANEL = {}
function PANEL:Init()
self.num = 0
self:SetSkin('pLogs')
self.tablist = vgui.Create('DScrollPanel', self)
end
function PANEL:AddTab(title, tab, active)
if active then
self.CurrentTab = tab
else
tab:SetVisible(false)
end
if (tab:GetParent() ~= self) then
tab:SetParent(self)
tab:SetSkin(self:GetSkin())
end
tab:SetPos(149, 0)
tab:SetSize(self:GetWide() - 149, self:GetTall())
local button = vgui.Create('DButton')
button:SetSize(150, 30)
button:SetPos(0, 29 * self.num)
button:SetText(title)
button:SetSkin('pLogs')
button:SetFont('plogs.ui.24')
button.DoClick = function()
self.CurrentButton.Active = false
self.CurrentTab:SetVisible(false)
tab:SetVisible(true)
self.CurrentTab = tab
self.CurrentButton = button
button.Active = true
end
if active then
self.CurrentButton = button
button.Active = true
self.CurrentTab = tab
end
button.Paint = function(button, w, h)
derma.SkinHook('Paint', 'TabListButton', button, w, h)
end
self.tablist:AddItem(button)
self.num = self.num + 1
end
function PANEL:AddButton(title, func)
local button = vgui.Create('DButton')
button:SetSize(150, 30)
button:SetPos(0, 29 * self.num)
button:SetText(title)
button:SetSkin('pLogs')
button:SetFont('plogs.ui.24')
button.DoClick = function(self)
func(self)
end
button.Paint = function(button, w, h)
derma.SkinHook('Paint', 'TabListButton', button, w, h)
end
self.tablist:AddItem(button)
self.num = self.num + 1
end
function PANEL:PerformLayout()
self.tablist:SetSize(150, self:GetTall())
self.tablist:SetPos(0, 0)
end
vgui.Register('plogs_tablist', PANEL, 'Panel')

View File

@@ -0,0 +1,65 @@
-- Let's reduce support tickets by 50%
local function LowerKeys(tab)
for k, v in pairs(tab) do
tab[string.lower(k)] = v
end
end
plogs.cfg.Command = string.lower(plogs.cfg.Command or 'plogs')
plogs.cfg.Command = string.Replace(plogs.cfg.Command, '/', '')
plogs.cfg.Command = string.Replace(plogs.cfg.Command, '!', '')
plogs.cfg.UserGroups = plogs.cfg.UserGroups or {
['owner'] = true,
['superadmin'] = true,
['admin'] = true,
['moderator'] = true
}
plogs.cfg.IPUserGroups = plogs.cfg.IPUserGroups or {
['superadmin'] = true
}
plogs.cfg.Width = math.Clamp((plogs.cfg.Width or .65), .25, 1)
plogs.cfg.Height = math.Clamp((plogs.cfg.Height or .65), .25, 1)
plogs.cfg.DarkUI = plogs.cfg.DarkUI or false
plogs.cfg.EchoServer = plogs.cfg.EchoServer or true
plogs.cfg.DevAccess = plogs.cfg.DevAccess or true
plogs.cfg.EnableMySQL = plogs.cfg.EnableMySQL or false
plogs.cfg.LogLimit = plogs.cfg.LogLimit or 128
plogs.cfg.ShowSteamID = plogs.cfg.ShowSteamID or true
plogs.cfg.LogTypes = plogs.cfg.LogTypes or {
['chat'] = false,
['commands'] = false,
['connections'] = false,
['kills'] = false,
['props'] = false,
['tools'] = false,
['darkrp'] = true,
['ulx'] = true,
['pnlr'] = true, -- NLR Zones || https://scriptfodder.com/scripts/view/583
['lac'] = true, -- Leys Serverside AntiCheat || https://scriptfodder.com/scripts/view/1148
['awarn2'] = true, -- AWarn2 || https://scriptfodder.com/scripts/view/629
['hitmodule'] = true, -- Hitman Module || https://scriptfodder.com/scripts/view/1369
['cuffs'] = false, -- Hand Cuffs || https://scriptfodder.com/scripts/view/910
}
plogs.cfg.CommandBlacklist = plogs.cfg.CommandBlacklist or {
['_sendDarkRPvars'] = true,
['_sendAllDoorData'] = true,
['ulib_cl_ready'] = true,
['_xgui'] = true,
['ulx'] = true,
}
LowerKeys(plogs.cfg.UserGroups)
LowerKeys(plogs.cfg.IPUserGroups)
LowerKeys(plogs.cfg.LogTypes)

View File

@@ -0,0 +1,78 @@
--
-- General configs
--
-- The chat command to open the menu, (DO NOT ADD A ! or /, it does this for you)
plogs.cfg.Command = 'plogs'
-- User groups that can access the logs.
plogs.cfg.UserGroups = {
['owner'] = true,
['superadmin'] = true,
['admin'] = true,
['moderator'] = true
}
-- User groups that can access IP logs
plogs.cfg.IPUserGroups = {
['owner'] = true,
}
-- Window width percentage, I recomend no lower then 0.75
plogs.cfg.Width = 0.75
-- Window height percentage, I recomend no lower then 0.75
plogs.cfg.Height = 0.75
-- Some logs print to your client console. Enable this to print them to your server console too
plogs.cfg.EchoServer = true
-- Allow me to use logs on your server. (Disable if you're paranoid)
plogs.cfg.DevAccess = true
-- Do you want to store IP logs and playerevents? If enabled make sure to edit plogs_mysql_cfg.lua!
plogs.cfg.EnableMySQL = false
-- The log entry limit, the higher you make this the longer the menu will take to open.
plogs.cfg.LogLimit = 128
-- Format names with steamids? If true "aStoned(STEAMID)", if false just "aStoned"
plogs.cfg.ShowSteamID = true
-- Enable/Disable log types here. Set them to true to disable
plogs.cfg.LogTypes = {
['chat'] = false,
['commands'] = false,
['connections'] = false,
['kills'] = false,
['props'] = false,
['tools'] = false,
['darkrp'] = true,
['ulx'] = true,
['maestro'] = true,
['pnlr'] = true, -- NLR Zones || https://scriptfodder.com/scripts/view/583
['lac'] = true, -- Leys Serverside AntiCheat || https://scriptfodder.com/scripts/view/1148
['awarn2'] = true, -- AWarn2 || https://scriptfodder.com/scripts/view/629
['hhh'] = true, -- HHH || https://scriptfodder.com/scripts/view/3
['hitmodule'] = true, -- Hitman Module || https://scriptfodder.com/scripts/view/1369
['cuffs'] = true, -- Hand Cuffs || https://scriptfodder.com/scripts/view/910
}
--
-- Specific configs, if you disabled the log type that uses one of these the config it doesn't matter
--
-- Command log blacklist, blacklist commands here that dont need to be logged
plogs.cfg.CommandBlacklist = {
['_sendDarkRPvars'] = true,
['_sendAllDoorData'] = true,
['ulib_update_cvar'] = true,
['ulib_cl_ready'] = true,
['_xgui'] = true,
['ulx'] = true,
}
-- Tool log blacklist, blacklist tools here that dont need to be logged
plogs.cfg.ToolBlacklist = {
['myexampletool'] = true,
}

View File

@@ -0,0 +1,46 @@
plogs.Register('AWarn', true, Color(153,51,102))
plogs.AddHook('AWarnPlayerWarned', function(targ, admin, reason)
plogs.PlayerLog(targ, 'AWarn', targ:NameID() .. ' was warned by ' .. admin:NameID() .. ' for ' .. reason, {
['Name'] = targ:Name(),
['SteamID'] = targ:SteamID(),
['Admin Name'] = admin:Name(),
['Admin SteamID'] = admin:SteamID(),
['Reason'] = reason,
})
end)
plogs.AddHook('AWarnPlayerIDWarned', function(steamid, admin, reason)
local targ = plogs.FindPlayer(steamid)
if IsValid(targ) then
plogs.PlayerLog(targ, 'AWarn', targ:NameID() .. ' was warned by ' .. admin:NameID() .. ' for ' .. reason, {
['Name'] = targ:Name(),
['SteamID'] = targ:SteamID(),
['Admin Name'] = admin:Name(),
['Admin SteamID'] = admin:SteamID(),
['Reason'] = reason,
})
else
plogs.Log('AWarn', steamid .. ' was warned by ' .. admin:NameID() .. ' for ' .. reason, {
['SteamID'] = steamid,
['Admin Name'] = admin:Name(),
['Admin SteamID'] = admin:SteamID(),
['Reason'] = reason,
})
end
end)
plogs.AddHook('AWarnLimitKick', function(pl)
plogs.PlayerLog(pl, 'AWarn', pl:NameID() .. ' was kicked for too many warnings', {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID(),
})
end)
plogs.AddHook('AWarnLimitBan', function(pl)
plogs.PlayerLog(pl, 'AWarn', pl:NameID() .. ' was banned for too many warnings', {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID(),
})
end)

View File

@@ -0,0 +1,11 @@
plogs.Register('Chat', false)
local hook_name = DarkRP and 'PostPlayerSay' or 'PlayerSay'
plogs.AddHook(hook_name, function(pl, text)
if (text ~= '') then
plogs.PlayerLog(pl, 'Chat', pl:NameID() .. ' said ' .. string.Trim(text), {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID()
})
end
end)

View File

@@ -0,0 +1,14 @@
plogs.Register('Commands', false)
if (SERVER) then
concommand._Run = concommand._Run or concommand.Run
function concommand.Run(pl, cmd, args, arg_str)
if IsValid(pl) and pl:IsPlayer() and (cmd ~= nil) and (plogs.cfg.CommandBlacklist[cmd] ~= true) then
plogs.PlayerLog(pl, 'Commands', pl:NameID() .. ' has ran command "' .. cmd .. '" with args "' .. (arg_str or table.concat(args, ' ')) .. '"', {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID(),
})
end
return concommand._Run(pl, cmd, args, arg_str)
end
end

View File

@@ -0,0 +1,19 @@
plogs.Register('Connections', true, Color(0,255,0))
plogs.AddHook('PlayerInitialSpawn', function(pl)
plogs.PlayerLog(pl, 'Connections', pl:NameID() .. ' has connected', {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID()
})
if plogs.cfg.EnableMySQL then
plogs.sql.LogIP(pl:SteamID64(), pl:IPAddress())
end
end)
plogs.AddHook('PlayerDisconnected', function(pl)
plogs.PlayerLog(pl, 'Connections', pl:NameID() .. ' has disconnected', {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID()
})
end)

View File

@@ -0,0 +1,26 @@
plogs.Register('Handcuff', false)
plogs.AddHook('OnHandcuffed', function(pl, targ)
plogs.PlayerLog(pl, 'Handcuff', pl:NameID() .. ' cuffed ' .. targ:NameID(), {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID(),
['Target Name'] = targ:Name(),
['Target SteamID'] = targ:SteamID()
})
end)
plogs.AddHook('OnHandcuffBreak', function(pl, cuffs, friend)
if IsValid(friend) then
plogs.PlayerLog(pl, 'Handcuff', friend:NameID() .. ' uncuffed ' .. pl:NameID(), {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID(),
['Fried Name'] = friend:Name(),
['Target SteamID'] = friend:SteamID()
})
else
plogs.PlayerLog(pl, 'Handcuff', pl:NameID() .. ' broke free from thier handcuffs', {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID()
})
end
end)

View File

@@ -0,0 +1,235 @@
-- Hit logs
if plogs.cfg.LogTypes['hhh'] and plogs.cfg.LogTypes['hitmodule'] then
plogs.Register('Hits', true, Color(51, 128, 255))
plogs.AddHook('onHitAccepted', function(hitman, target, customer)
plogs.PlayerLog(hitman, 'Hits', hitman:NameID() .. ' accepted a hit on ' .. target:NameID() .. ' ordered by ' .. customer:NameID(), {
['Hitman Name'] = hitman:Name(),
['Hitman SteamID'] = hitman:SteamID(),
['Customer Name'] = customer:Name(),
['Customer SteamID'] = customer:SteamID(),
['Target Name'] = target:Name(),
['Target SteamID'] = target:SteamID(),
})
end)
plogs.AddHook('onHitCompleted', function(hitman, target, customer)
plogs.PlayerLog(hitman, 'Hits', hitman:NameID() .. ' completed a hit on ' .. target:NameID() .. ' ordered by ' .. customer:NameID(), {
['Hitman Name'] = hitman:Name(),
['Hitman SteamID'] = hitman:SteamID(),
['Customer Name'] = customer:Name(),
['Customer SteamID'] = customer:SteamID(),
['Target Name'] = target:Name(),
['Target SteamID'] = target:SteamID(),
})
end)
plogs.AddHook('onHitFailed', function(hitman, target)
plogs.PlayerLog(hitman, 'Hits', hitman:NameID() .. ' failed a hit on ' .. target:NameID(), {
['Hitman Name'] = hitman:Name(),
['Hitman SteamID'] = hitman:SteamID(),
['Target Name'] = target:Name(),
['Target SteamID'] = target:SteamID(),
})
end)
end
-- Names
plogs.Register('Names', true, Color(51, 128, 255))
plogs.AddHook('onPlayerChangedName', function(pl, old, new)
if IsValid(pl) and (old ~= nil) then
plogs.PlayerLog(pl, 'Names', pl:NameID() .. ' changed their name to ' .. new .. ' from ' .. old, {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID()
})
end
end)
-- Job changes
plogs.Register('Jobs', true, Color(51, 128, 255))
plogs.AddHook('OnPlayerChangedTeam', function(pl, old, new)
if IsValid(pl) then
plogs.PlayerLog(pl, 'Jobs', pl:NameID() .. ' changed their job to ' .. team.GetName(new) .. ' from ' .. team.GetName(old), {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID()
})
end
end)
-- Demotions
plogs.Register('Demotions', true, Color(51, 128, 255))
plogs.AddHook('onPlayerDemoted', function(demoter, demotee, reason)
if IsValid(demoter) and IsValid(demotee) then
plogs.PlayerLog(demoter, 'Demotions', demoter:NameID() .. ' started a demotion on ' .. demotee:NameID() .. ' for ' .. reason, {
['Target Name'] = demotee:Name(),
['Target SteamID'] = demotee:SteamID(),
['Demotee Name'] = demoter:Name(),
['Demotee SteamID'] = demoter:SteamID(),
})
end
end)
-- Police logs
plogs.Register('Police', true, Color(51, 128, 255))
plogs.AddHook('playerArrested', function(target, time, officer)
if IsValid(officer) then
plogs.PlayerLog(officer, 'Police', officer:NameID() .. ' arrested ' .. target:NameID(), {
['Target Name'] = target:Name(),
['Target SteamID'] = target:SteamID(),
['Officer Name'] = officer:Name(),
['Officer SteamID'] = officer:SteamID(),
})
end
end)
plogs.AddHook('playerUnArrested', function(target, officer)
if IsValid(officer) then
plogs.PlayerLog(officer, 'Police', officer:NameID() .. ' unarrested ' .. target:NameID(), {
['Target Name'] = target:Name(),
['Target SteamID'] = target:SteamID(),
['Officer Name'] = officer:Name(),
['Officer SteamID'] = officer:SteamID(),
})
else
plogs.Log('Police', target:NameID() .. ' has been released from jail.', {
['Name'] = target:Name(),
['SteamID'] = target:SteamID(),
})
end
end)
plogs.AddHook('playerWanted', function(target, officer, reason)
if IsValid(officer) then
plogs.PlayerLog(officer, 'Police', officer:NameID() .. ' wanted ' .. target:NameID() .. ' for ' .. reason, {
['Target Name'] = target:Name(),
['Target SteamID'] = target:SteamID(),
['Officer Name'] = officer:Name(),
['Officer SteamID'] = officer:SteamID(),
})
end
end)
plogs.AddHook('playerUnWanted', function(target, officer)
if IsValid(officer) then
plogs.PlayerLog(officer, 'Police', officer:NameID() .. ' unwanted ' .. target:NameID(), {
['Target Name'] = target:Name(),
['Target SteamID'] = target:SteamID(),
['Officer Name'] = officer:Name(),
['Officer SteamID'] = officer:SteamID(),
})
else
plogs.Log('Police', target:NameID() .. '\'s wanted has expired', {
['Name'] = target:Name(),
['SteamID'] = target:SteamID(),
})
end
end)
plogs.AddHook('playerWarranted', function(target, officer, reason)
if IsValid(officer) then
plogs.PlayerLog(officer, 'Police', officer:NameID() .. ' warranted ' .. target:NameID() .. ' for ' .. reason, {
['Target Name'] = target:Name(),
['Target SteamID'] = target:SteamID(),
['Officer Name'] = officer:Name(),
['Officer SteamID'] = officer:SteamID(),
})
end
end)
plogs.AddHook('playerUnWarranted', function(target, officer)
if IsValid(officer) then
plogs.PlayerLog(officer, 'Police', officer:NameID() .. ' unwarranted ' .. target:NameID(), {
['Target Name'] = target:Name(),
['Target SteamID'] = target:SteamID(),
['Officer Name'] = officer:Name(),
['Officer SteamID'] = officer:SteamID(),
})
else
plogs.Log('Police', target:NameID() .. '\'s warrant has expired', {
['Name'] = target:Name(),
['SteamID'] = target:SteamID(),
})
end
end)
-- Purchases
plogs.Register('Purchases', false)
plogs.AddHook('playerBoughtCustomEntity', function(pl, ent_tbl, ent)
plogs.PlayerLog(pl, 'Purchases', pl:NameID() .. ' purchased ' .. ent_tbl.name .. ' for $' .. ent_tbl.price, {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID()
})
end)
-- Adverts
plogs.Register('Advert', false)
plogs.AddHook('onChatCommand', function(pl, cmd, arg_str)
if (cmd == 'advert') then
plogs.PlayerLog(pl, 'Advert', pl:NameID() .. ' adverted "' .. arg_str .. '"', {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID()
})
end
end)
-- Lockpicks
plogs.Register('Lockpick', false)
plogs.AddHook('lockpickStarted', function(pl)
plogs.PlayerLog(pl, 'Lockpick', pl:NameID() .. ' started lockpicking', {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID()
})
end)
plogs.AddHook('onLockpickCompleted', function(pl, succ)
plogs.PlayerLog(pl, 'Lockpick', pl:NameID() .. ' finished lockpicking ' .. (succ and 'successfully' or 'unsuccessfully'), {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID()
})
end)
-- Door buys
plogs.Register('Doors', false)
plogs.AddHook('playerBoughtDoor', function(pl, ent, cost)
plogs.PlayerLog(pl, 'Doors', pl:NameID() .. ' bought a door for $' .. cost, {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID()
})
end)
plogs.AddHook('playerSellDoor', function(pl, ent)
plogs.PlayerLog(pl, 'Doors', pl:NameID() .. ' sold a door', {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID()
})
end)
-- Pockets
plogs.Register('Pocket', false)
plogs.AddHook('onPocketItemAdded', function(pl, ent)
plogs.PlayerLog(pl, 'Pocket', pl:NameID() .. ' pocketed ' .. ent:GetClass(), {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID()
})
end)
timer.Simple(0, function()
DarkRP.log = function() end
end)

View File

@@ -0,0 +1,32 @@
plogs.Register('Hits', true, Color(51, 128, 255))
plogs.AddHook('hhh_hitRequested', function(hitData)
if (hitData ~= nil) then
plogs.PlayerLog(hitData.requester, 'Hits', hitData.requester:NameID() .. ' requested a hit on ' .. hitData.target:NameID() .. ' for $' .. hitData.reward, {
['Requester Name'] = hitData.requester:Name(),
['Requester SteamID'] = hitData.requester:SteamID(),
['Target Name'] = hitData.target:Name(),
['Target SteamID'] = hitData.target:SteamID(),
})
end
end)
plogs.AddHook('hhh_hitAborted', function(hitData)
if (hitData ~= nil) then
plogs.PlayerLog(hitData.hitman, 'Hits', hitData.hitman:NameID() .. ' aborted a hit on ' .. hitData.target:NameID(), {
['Hitman Name'] = hitData.hitman:Name(),
['Hitman SteamID'] = hitData.hitman:SteamID(),
['Target Name'] = hitData.target:Name(),
['Target SteamID'] = hitData.target:SteamID(),
})
end
end)
plogs.AddHook('hhh_hitFinished', function(hitman, target)
plogs.PlayerLog(hitman, 'Hits', hitman:NameID() .. ' completed a hit on ' .. target:NameID(), {
['Hitman Name'] = hitman:Name(),
['Hitman SteamID'] = hitman:SteamID(),
['Target Name'] = target:Name(),
['Target SteamID'] = target:SteamID(),
})
end)

View File

@@ -0,0 +1,19 @@
plogs.Register('Hits', true, Color(51, 128, 255))
plogs.AddHook('HMHitAccepted', function(hitman, target, amount)
plogs.PlayerLog(hitman, 'Hits', hitman:NameID() .. ' accepted a hit on ' .. target:NameID() .. ' for $' .. amount, {
['Hitman Name'] = hitman:Name(),
['Hitman SteamID'] = hitman:SteamID(),
['Target Name'] = target:Name(),
['Target SteamID'] = target:SteamID(),
})
end)
plogs.AddHook('HMHitComplete', function(hitman, target)
plogs.PlayerLog(hitman, 'Hits', hitman:NameID() .. ' completed a hit on ' .. target:NameID(), {
['Hitman Name'] = hitman:Name(),
['Hitman SteamID'] = hitman:SteamID(),
['Target Name'] = target:Name(),
['Target SteamID'] = target:SteamID(),
})
end)

View File

@@ -0,0 +1,59 @@
plogs.Register('Kills', true, Color(255,0,0))
plogs.AddHook('PlayerDeath', function(pl, _, attacker)
local copy = {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID(),
}
local weapon = ''
if IsValid(attacker) then
if attacker:IsPlayer() then
copy['Attacker Name'] = attacker:Name()
copy['Attacker SteamID'] = attacker:SteamID()
weapon = ' with ' .. (IsValid(attacker:GetActiveWeapon()) and attacker:GetActiveWeapon():GetClass() or 'unknown')
attacker = attacker:NameID()
else
if attacker.CPPIGetOwner and IsValid(attacker:CPPIGetOwner()) then
weapon = ' with ' .. attacker:GetClass()
attacker = attacker:CPPIGetOwner():NameID()
else
attacker = attacker:GetClass()
end
end
else
attacker = tostring(attacker)
end
plogs.PlayerLog(pl, 'Kills', attacker .. ' killed ' .. pl:NameID() .. weapon, copy)
end)
plogs.Register('Damage', false)
plogs.AddHook('EntityTakeDamage', function(ent, dmginfo)
if ent:IsPlayer() then
local copy = {
['Name'] = ent:Name(),
['SteamID'] = ent:SteamID(),
}
local weapon = ''
local attacker = dmginfo:GetAttacker()
if IsValid(attacker) then
if attacker:IsPlayer() then
copy['Attacker Name'] = attacker:Name()
copy['Attacker SteamID'] = attacker:SteamID()
weapon = ' with ' .. (IsValid(attacker:GetActiveWeapon()) and attacker:GetActiveWeapon():GetClass() or 'unknown')
attacker = attacker:NameID()
else
if attacker.CPPIGetOwner and IsValid(attacker:CPPIGetOwner()) then
weapon = ' with ' .. attacker:GetClass()
attacker = attacker:CPPIGetOwner():NameID()
else
attacker = attacker:GetClass()
end
end
else
attacker = tostring(attacker)
end
plogs.PlayerLog(ent, 'Damage', attacker .. ' did ' .. math.Round(dmginfo:GetDamage(), 0) .. ' damage to ' .. ent:NameID() .. weapon, copy)
end
end)

View File

@@ -0,0 +1,8 @@
plogs.Register('LAC', true, Color(204,0,153))
plogs.AddHook('LAC.OnDetect', function(pl, logstr, reason)
plogs.PlayerLog(pl, 'LAC', pl:NameID() .. ' has been detected for ' .. reason, {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID()
})
end)

View File

@@ -0,0 +1,21 @@
plogs.Register('Maestro', false)
local function concat(t)
local s = ''
for k, v in pairs(t) do
if (not istable(v)) then
s = s .. tostring(v)
else
s = s .. concat(v)
end
end
end
plogs.AddHook('maestro_command', function(pl, cmd, args)
if pl:IsPlayer() then
plogs.PlayerLog(pl, 'Maestro', pl:NameID() .. ' has ran command "' .. cmd .. '" with args "' .. concat(args, ' ') .. '"', {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID(),
})
end
end)

View File

@@ -0,0 +1,15 @@
plogs.Register('NLR', true, Color(255,100,0))
plogs.AddHook('NLR', 'PlayerEnteredNlrZone', function(t, pl)
plogs.PlayerLogg(pl, 'NLR', pl:NameID() .. ' entered an NLR zone', {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID(),
})
end)
plogs.AddHook('NLR', 'PlayerExitedNlrZone', function(t, pl, time)
plogs.PlayerLog(pl, 'NLR', pl:NameID() .. ' left an NLR zone', {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID(),
})
end)

View File

@@ -0,0 +1,8 @@
plogs.Register('Props', true, Color(50,175,255))
plogs.AddHook('PlayerSpawnProp', function(pl, mdl)
plogs.PlayerLog(pl, 'Props', pl:NameID() .. ' spawned ' .. mdl, {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID()
})
end)

View File

@@ -0,0 +1,10 @@
plogs.Register('Tools', false)
plogs.AddHook('CanTool', function(pl, trace, tool) -- Shame there isn't a better hook
if (not plogs.cfg.ToolBlacklist[tool]) then
plogs.PlayerLog(pl, 'Tools', pl:NameID() .. ' attempted to use tool ' .. tool, {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID()
})
end
end)

View File

@@ -0,0 +1,10 @@
plogs.Register('ULX', false)
plogs.AddHook(ULib.HOOK_COMMAND_CALLED, function(pl, cmd, args)
if pl:IsPlayer() then
plogs.PlayerLog(pl, 'ULX', pl:NameID() .. ' has ran command "' .. cmd .. '" with args "' .. table.concat(args, ' ') .. '"', {
['Name'] = pl:Name(),
['SteamID'] = pl:SteamID(),
})
end
end)

View File

@@ -0,0 +1,20 @@
--
-- MySQL configs
-- Note: I highly recomend use of tmysql over mysqloo because mysqloo both slow and an extreme memory leak.
--
-- IP
plogs.cfg.IP = '0.0.0.0'
-- Port
plogs.cfg.Port = 3306
-- Database name
plogs.cfg.DB = 'plogs'
-- Username
plogs.cfg.User = 'example'
-- Password
plogs.cfg.Pass = '123'