ladm: initial groundwork, refs #181
This commit is contained in:
parent
0b7ba47861
commit
278fc49025
|
@ -30,3 +30,8 @@ Lua scripts for the Legacy mod
|
||||||
* message is sent to the first matched player name
|
* message is sent to the first matched player name
|
||||||
* player name is a colour and case-insensitive pattern, e.g. ton will match player /-^321ToN-/
|
* player name is a colour and case-insensitive pattern, e.g. ton will match player /-^321ToN-/
|
||||||
* usage: pm player Hello, how are you?
|
* usage: pm player Hello, how are you?
|
||||||
|
|
||||||
|
## ladm - lightweight administration suite
|
||||||
|
|
||||||
|
* NOTE: not even alpha state. Do not use.
|
||||||
|
* manage users on your server
|
|
@ -0,0 +1,88 @@
|
||||||
|
luasql = {} -- sql driver
|
||||||
|
env = {} -- environment object
|
||||||
|
con = {} -- database connection
|
||||||
|
cur = {} -- cursor
|
||||||
|
|
||||||
|
dofile("ladm.cfg")
|
||||||
|
|
||||||
|
-- 1) load the chosen driver
|
||||||
|
-- 2) create environement object
|
||||||
|
-- 3) connect to database
|
||||||
|
function db_init ( )
|
||||||
|
print ( "Connecting to " .. dbdriver .. " database..." )
|
||||||
|
|
||||||
|
if ( dbdriver == "mysql" ) then
|
||||||
|
luasql = require "luasql.mysql"
|
||||||
|
env = assert ( luasql.mysql() )
|
||||||
|
con = assert ( env:connect( dbdatabase, dbuser, dbpassword, dbhost, dbport ) )
|
||||||
|
elseif ( dbdriver == "sqlite" or dbdriver == "sqlite3") then
|
||||||
|
luasql = require "luasql.sqlite3"
|
||||||
|
env = assert ( luasql.sqlite3() )
|
||||||
|
con = assert ( env:connect( dbdatabase .. ".sqlite" ) )
|
||||||
|
end
|
||||||
|
|
||||||
|
if not installed then db_create() end
|
||||||
|
|
||||||
|
cur = assert ( con:execute ( string.format ( "SELECT COUNT(*) FROM %susers", dbprefix ) ) )
|
||||||
|
print("There are " .. tonumber(cur:fetch(row, 'a')) .. " users in the database.\n")
|
||||||
|
|
||||||
|
cur = assert ( con:execute ( string.format ( "SELECT COUNT(*) FROM %svariables", dbprefix ) ) )
|
||||||
|
print("There are " .. tonumber(cur:fetch(row, 'a')) .. " variables in the database.\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- database helper function
|
||||||
|
-- returns database rows matching sql_statement
|
||||||
|
function db_rows ( connection, sql_statement )
|
||||||
|
local cursor = assert (connection:execute (sql_statement))
|
||||||
|
return function ()
|
||||||
|
return cursor:fetch()
|
||||||
|
end
|
||||||
|
end -- rows
|
||||||
|
|
||||||
|
function db_create ()
|
||||||
|
print ( "INSTALLING DATABASE RECORDS" )
|
||||||
|
--cur = assert (con:execute( "DROP TABLE users" ))
|
||||||
|
|
||||||
|
cur = assert ( con:execute ( string.format ( [[
|
||||||
|
CREATE TABLE IF NOT EXISTS %susers(
|
||||||
|
id INT(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
guid VARCHAR(64),
|
||||||
|
first_seen VARCHAR(64),
|
||||||
|
last_seen VARCHAR(64),
|
||||||
|
|
||||||
|
xp_battlesense REAL,
|
||||||
|
xp_engineering REAL,
|
||||||
|
xp_medic REAL,
|
||||||
|
xp_fieldops REAL,
|
||||||
|
xp_lightweapons REAL,
|
||||||
|
xp_heavyweapons REAL,
|
||||||
|
xp_covertops REAL,
|
||||||
|
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE (guid)
|
||||||
|
);
|
||||||
|
]], dbprefix ) ) )
|
||||||
|
|
||||||
|
cur = assert ( con:execute ( string.format ( [[
|
||||||
|
CREATE TABLE IF NOT EXISTS %svariables(
|
||||||
|
id INT(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
type VARCHAR(128) NOT NULL,
|
||||||
|
name VARCHAR(128) NOT NULL,
|
||||||
|
value VARCHAR(128) NOT NULL,
|
||||||
|
description TEXT NOT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY name (name)
|
||||||
|
);
|
||||||
|
]], dbprefix ) ) )
|
||||||
|
|
||||||
|
local configfile = io.open ( "ladm.cfg", "a" )
|
||||||
|
configfile:write ( "\ninstalled = true\n" )
|
||||||
|
configfile:close()
|
||||||
|
--print ( "Done. Please remember to change the 'installed' variable in the ladm.cfg file to 'false'." )
|
||||||
|
|
||||||
|
--et.G_Print ("^4List of users in XP Save database:\n")
|
||||||
|
--for guid, date in rows (con, "SELECT * FROM users") do
|
||||||
|
-- et.G_Print (string.format ("\tGUID %s was last seen on %s\n", guid, date))
|
||||||
|
--end
|
||||||
|
end
|
|
@ -0,0 +1,73 @@
|
||||||
|
|
||||||
|
-- skill identifiers
|
||||||
|
local BATTLESENSE = 0
|
||||||
|
local ENGINEERING = 1
|
||||||
|
local MEDIC = 2
|
||||||
|
local FIELDOPS = 3
|
||||||
|
local LIGHTWEAPONS = 4
|
||||||
|
local HEAVYWEAPONS = 5
|
||||||
|
local COVERTOPS = 6
|
||||||
|
|
||||||
|
local skills = {}
|
||||||
|
skills[BATTLESENSE] = "Battlesense"
|
||||||
|
skills[ENGINEERING] = "Engineering"
|
||||||
|
skills[MEDIC] = "Medic"
|
||||||
|
skills[FIELDOPS] = "Field ops"
|
||||||
|
skills[LIGHTWEAPONS] = "Light weapons"
|
||||||
|
skills[HEAVYWEAPONS] = "Heavy weapons"
|
||||||
|
skills[COVERTOPS] = "Covert ops"
|
||||||
|
|
||||||
|
-- con:prepare with bind_names should be used to prevent sql injections
|
||||||
|
-- but it doesn't work on my version of luasql
|
||||||
|
function validateGUID(cno, guid)
|
||||||
|
-- allow only alphanumeric characters in guid
|
||||||
|
if(string.match(guid, "%W")) then
|
||||||
|
-- Invalid characters detected. We should probably drop this client
|
||||||
|
et.G_Print("^3WARNING: (XP Save) user with id " .. cno .. " has an invalid GUID: " .. guid .. "\n")
|
||||||
|
et.trap_SendServerCommand (cno, "cpm \"" .. "Your XP won't be saved because you have an invalid cl_guid.\n\"")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- saves XP values of a player with id 'cno' into sqlite database
|
||||||
|
function saveXP(cno)
|
||||||
|
local name = et.Info_ValueForKey( et.trap_GetUserinfo( cno ), "name" )
|
||||||
|
local guid = et.Info_ValueForKey( et.trap_GetUserinfo( cno ), "cl_guid" )
|
||||||
|
|
||||||
|
if not validateGUID(cno, guid) then return end
|
||||||
|
|
||||||
|
cur = assert (con:execute(string.format("SELECT * FROM users WHERE guid='%s' LIMIT 1", guid)))
|
||||||
|
local player = cur:fetch({}, 'a')
|
||||||
|
|
||||||
|
if not player then
|
||||||
|
-- This should not happen
|
||||||
|
et.G_Print ("^1ERROR: (XP Save) user was not found in the database!\n")
|
||||||
|
return
|
||||||
|
else
|
||||||
|
et.trap_SendServerCommand (cno, "cpm \"" .. "See you again soon, " .. name .. "\n\"")
|
||||||
|
--for id, name in pairs(skills) do et.G_Print (name .. ": " .. et.gentity_get (cno, "sess.skillpoints", id) .. " XP\n") end
|
||||||
|
|
||||||
|
cur = assert (con:execute(string.format([[UPDATE users SET
|
||||||
|
last_seen='%s',
|
||||||
|
xp_battlesense='%s',
|
||||||
|
xp_engineering='%s',
|
||||||
|
xp_medic='%s',
|
||||||
|
xp_fieldops='%s',
|
||||||
|
xp_lightweapons='%s',
|
||||||
|
xp_heavyweapons='%s',
|
||||||
|
xp_covertops='%s'
|
||||||
|
WHERE guid='%s']],
|
||||||
|
os.date("%Y-%m-%d %H:%M:%S"),
|
||||||
|
et.gentity_get (cno, "sess.skillpoints", BATTLESENSE),
|
||||||
|
et.gentity_get (cno, "sess.skillpoints", ENGINEERING),
|
||||||
|
et.gentity_get (cno, "sess.skillpoints", MEDIC),
|
||||||
|
et.gentity_get (cno, "sess.skillpoints", FIELDOPS),
|
||||||
|
et.gentity_get (cno, "sess.skillpoints", LIGHTWEAPONS),
|
||||||
|
et.gentity_get (cno, "sess.skillpoints", HEAVYWEAPONS),
|
||||||
|
et.gentity_get (cno, "sess.skillpoints", COVERTOPS),
|
||||||
|
guid
|
||||||
|
)))
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,14 @@
|
||||||
|
--
|
||||||
|
-- Configuration file for Legacy Admin Mod
|
||||||
|
--
|
||||||
|
|
||||||
|
debug = false
|
||||||
|
|
||||||
|
-- Database
|
||||||
|
dbdriver = "mysql"
|
||||||
|
dbport = 3306
|
||||||
|
dbhost = "localhost"
|
||||||
|
dbdatabase = "legacy_server"
|
||||||
|
dbprefix = "legacy_"
|
||||||
|
dbuser = "legacy_user"
|
||||||
|
dbpassword = "test"
|
|
@ -0,0 +1,84 @@
|
||||||
|
--[[
|
||||||
|
Author: Jan Šimek [Radegast]
|
||||||
|
Version 0.1
|
||||||
|
License: MIT
|
||||||
|
Released on 09.02.2014
|
||||||
|
Website: http://www.etlegacy.com
|
||||||
|
Mod: intended for the Legacy mod
|
||||||
|
|
||||||
|
Description: lightweight user administration suite
|
||||||
|
]]--
|
||||||
|
|
||||||
|
-- load the config file
|
||||||
|
dofile "ladm.cfg"
|
||||||
|
|
||||||
|
require "core/db"
|
||||||
|
|
||||||
|
db_init()
|
||||||
|
|
||||||
|
function et_InitGame(levelTime, randomSeed, restart)
|
||||||
|
-- name of this module
|
||||||
|
et.RegisterModname ( "Lightweight administration suite for the Legacy mod" )
|
||||||
|
|
||||||
|
-- init db on game start
|
||||||
|
|
||||||
|
|
||||||
|
end -- et_InitGame
|
||||||
|
|
||||||
|
function et_ShutdownGame(restart)
|
||||||
|
local cno = 0
|
||||||
|
local maxclients = tonumber(et.trap_Cvar_Get("sv_maxclients"))
|
||||||
|
|
||||||
|
-- iterate through clients and save their XP
|
||||||
|
while cno < maxclients do
|
||||||
|
local cs = et.trap_GetConfigstring(et.CS_PLAYERS + cno)
|
||||||
|
|
||||||
|
if not cs or cs == "" then break end
|
||||||
|
|
||||||
|
saveXP(cno)
|
||||||
|
cno = cno + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
-- clean up
|
||||||
|
cur:close()
|
||||||
|
con:close()
|
||||||
|
env:close()
|
||||||
|
end -- et_ShutdownGame
|
||||||
|
|
||||||
|
-- called when a client enters the game world
|
||||||
|
function et_ClientBegin(cno)
|
||||||
|
local name = et.Info_ValueForKey( et.trap_GetUserinfo( cno ), "name" )
|
||||||
|
local guid = et.Info_ValueForKey( et.trap_GetUserinfo( cno ), "cl_guid" )
|
||||||
|
|
||||||
|
if not validateGUID(cno, guid) then return end
|
||||||
|
|
||||||
|
cur = assert (con:execute(string.format("SELECT * FROM users WHERE guid='%s'", guid)))
|
||||||
|
local player = cur:fetch({}, 'a')
|
||||||
|
|
||||||
|
if not player then
|
||||||
|
-- First time we see this player
|
||||||
|
et.trap_SendServerCommand (cno, "cpm \"" .. "Welcome, " .. name .. "^7! You are playing on an XP save server.\n\"")
|
||||||
|
cur = assert (con:execute(string.format("INSERT INTO users VALUES ('%s', '%s', '%s', 0, 0, 0, 0, 0, 0, 0)", guid, os.date("%Y-%m-%d %H:%M:%S"), os.date("%Y-%m-%d %H:%M:%S"))))
|
||||||
|
else
|
||||||
|
et.trap_SendServerCommand (cno, "cpm \"" .. "Welcome back, " .. name .. "^7! Your last connection was on " .. player.last_seen .. "\n\"") -- in db: player.name
|
||||||
|
|
||||||
|
--et.G_Print ("Loading XP from database: " .. player.xp_battlesense .. " | " .. player.xp_engineering .. " | " .. player.xp_medic .. " | " .. player.xp_fieldops .. " | " .. player.xp_lightweapons .. " | " .. player.xp_heavyweapons .. " | " .. player.xp_covertops .. "\n\n")
|
||||||
|
|
||||||
|
et.G_XP_Set (cno, player.xp_battlesense, BATTLESENSE, 0)
|
||||||
|
et.G_XP_Set (cno, player.xp_engineering, ENGINEERING, 0)
|
||||||
|
et.G_XP_Set (cno, player.xp_medic, MEDIC, 0)
|
||||||
|
et.G_XP_Set (cno, player.xp_fieldops, FIELDOPS, 0)
|
||||||
|
et.G_XP_Set (cno, player.xp_lightweapons, LIGHTWEAPONS, 0)
|
||||||
|
et.G_XP_Set (cno, player.xp_heavyweapons, HEAVYWEAPONS, 0)
|
||||||
|
et.G_XP_Set (cno, player.xp_covertops, COVERTOPS, 0)
|
||||||
|
|
||||||
|
et.G_Print (name .. "'s current XP levels:\n")
|
||||||
|
for id, skill in pairs(skills) do
|
||||||
|
et.G_Print ("\t" .. skill .. ": " .. et.gentity_get (cno, "sess.skillpoints", id) .. " XP\n")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end -- et_ClientBegin
|
||||||
|
|
||||||
|
function et_ClientDisconnect(cno)
|
||||||
|
saveXP(cno)
|
||||||
|
end -- et_ClientDisconnect
|
Binary file not shown.
Loading…
Reference in New Issue