User:Major Zeman
From WolfWiki
| Major Zeman can be currently (= for about last 3 years) found at forums.acidrainclan.com. |
Contents |
LUA Code fragments
During my first adventure into the world of LUA+ETPro, I ran into several problems. Here are a few functions/code fragments that I think are worth mentioning or could be useful to someone in future:
Get client's GUID
A simple function that gives you guid of the player in given slot. The function performs some checks and converts the guid to uppercase for exact matches.
Note: the function returns short version of guid and should NOT be used for authentication purposes!
-- gets user's guid
-- returns nil if not applicable to entity number
function getguid(targetID)
if (targetID == nil) or (targetID > tonumber(et.trap_Cvar_Get("sv_maxclients"))) or (not et.gentity_get(targetID,"inuse")) then
return nil
end
local userinfo = et.trap_GetUserinfo( targetID )
local guid = et.Info_ValueForKey( userinfo, "cl_guid" )
-- upcase for exact matches
guid = string.upper(guid)
return guid
end
Get client's IP
Anoter simple function, this one returns IP of the player in given slot.
Note: the IP, too, can be spoofed. Use ReyalP's userinfocheck.lua or better his combinedfixes.lua mod on your server to at least lower this risk.
-- gets target's IP without port
function getIP(target)
if (target == nil) then
return nil
end
local userinfo = et.trap_GetUserinfo(target)
local ip = et.Info_ValueForKey(userinfo, "ip")
-- strip port
ip = string.sub(ip,string.find(ip,"(%d+%.%d+%.%d+%.%d+)"))
return ip
end
Get client's ref status
Third function is used to check whether the target client is logged in as referee.
Note: It's not very well known fact that there are actually three levels of referee status: client can either not be referee at all, or be a referee that was voted in or made referee by another referee, and a referee that logged in using referee password. This function however only discriminates between the ordinary levels of "not referee" - "referee" (e.g. doesn't make difference between the two types of referees).
-- returns referee status of target
function getRefStatus(target)
local isref = et.Info_ValueForKey(et.trap_GetConfigstring(et.CS_PLAYERS + target), "ref")
if isref ~= "0" then
return true
else
return false
end
end
Player's Position
This one was actually quite hard to make for me, involved some research in meanings of different items in entity info.
As long as the player is on one of the teams and alive, it's easy:
et.gentity_get(clientID, "origin")
However, when you count in spectators too, it becomes much more complex. Spectator's position isn't stored in "origin" but in "s.origin". And the trickiest part is when spectator choses to follow other player - his entity stops moving at all and his position is given by the position of player they're spectating. All together:
-- get client's position
function playerpos(clientID)
if et.gentity_get(clientID, "sess.sessionTeam") == 3 then
-- spectator
if et.gentity_get(clientID, "sess.spectatorState") == 2 then
-- spectator thats following someone
local spectatedID = et.gentity_get(clientID, "sess.spectatorClient")
return et.gentity_get(spectatedID, "origin")
else -- spectatorstate == 1
-- free spectator
return et.gentity_get(clientID, "s.origin")
end
else
-- regular player
return et.gentity_get(clientID, "origin")
end
end
Indent
Another simple function. This one is useful if you need to print a list of basically anything and want the text to be arranged in columns.
-- makes a string at least <length> characters long, adding spaces behind the original string if needed
function indent(str, length)
local len
len = math.min(string.len(str), length)
str = str .. string.rep(" ", length - len)
return str
end
Note that it never shortens the text so you might end up with a garbled table anyways, but if you set the length to a reasonable number (e.g. 15 for IP - it's max length IPv4 can have), you should be fine.
Read content of a text file on server
This function reads contents of a given file and returns an array of its lines. It can handle all line endings (win|unix|mac). As a price for that though, it will eat up any empty lines.
-- reads file and returns string array of rows (indexed from 1) and number of rows
function readFile(filename)
local fd, len
local rows = {}
fd, len = et.trap_FS_FOpenFile(filename, et.FS_READ)
if len == -1 then
return rows, 0
else
--read it all
local filestr = et.trap_FS_Read(fd, len)
local rowcount = 0
for line in string.gfind(filestr, "[^\r\n]+") do
rowcount = rowcount + 1
rows[rowcount] = line
end
et.trap_FS_FCloseFile(fd)
return rows, rowcount
end
end
Print message to console
This is actually a very useful little function. First, it lets you ignore the differences between printing text to a client's console and into server console, and second, it makes implementation of other functions easier.
-- print message to either client's console or (if clientID == nil) to server console
function printmsg(message, clientID)
if not message then
return
end
-- replace "s in message with 's
local dummy
message, dummy = string.gsub(message, "\"", "'")
if clientID then
et.trap_SendServerCommand(clientID, "print \"".. message .."^7\n\"")
else
et.G_Print(message .."^7\n")
end
end
The way it works is it gets a message and eventually client number. If it got client number, it prints the message to that client, if it got null as client number, it prints to server console. Combined with the way LUA handles function call parameters, the use looks like this: printmsg("Hello", 2) prints "Hello" into console of client #2; printmsg("Hello") prints "Hello" into server console.
The second reason why I found it useful is, you can easily make functions that can be called through both server and client console and need to print some output - just give them clientID parameter, when calling it from server console put clientID = null and let the printmsg function handle it. Example of such function is the next one.
Player ID from name
This is an altered version of function posted on etpro forums by Im2good4u and Deus. I added some more parameter checks, error prints (using the above function, so it can be used both for server and client commands), made it accept slot numbers and partial name matches too.
-- returns clientslot for given name, or nil if no match found (accepts first (partial) match)
-- added color stripping
-- if clientID is filled, reports errors to clientID; else prints them to server console
function getPlayerId(name, clientID)
local i
-- if it's nil, return nil and throw error
if (name == "") then
printmsg("Not enough parameters.", clientID)
return nil
end
-- if it's a number, interpret as slot number
local clientnum = tonumber(name)
if clientnum then
if (clientnum <= tonumber(et.trap_Cvar_Get("sv_maxclients"))) and et.gentity_get(clientnum,"inuse") then
return clientnum
else
printmsg("Slot "..clientnum.." not in use.", clientID)
return nil
end
end
-- exact match first
for i=0,et.trap_Cvar_Get("sv_maxclients"),1 do
playeri = et.gentity_get(i,"pers.netname")
if playeri then
if et.Q_CleanStr( playeri ) == et.Q_CleanStr( name ) then
return i
end
end
end
-- partial match
for i=0,et.trap_Cvar_Get("sv_maxclients"),1 do
playeri = et.gentity_get(i,"pers.netname")
if playeri then
if (string.find(string.lower(et.Q_CleanStr( playeri )), string.lower(et.Q_CleanStr( name )), 1, true)) then
return i
end
end
end
printmsg("No name match found for '"..name.."'.", clientID)
return nil
end
Printing server LUA commans output to semiadmin console
Warning - it works, but it's a very dirty trick.
Unfortunately, there's no normal way to print output of semiadmin commands back to the semiadmin's console. I found a trick that allows you to get around this limitation at least for LUA custom commands. It's quite complex tho, and as I wrote, very nasty. Here it goes:
- first we need to declare a global variable (yeah trouble starts here) - it will actually store client number of last client who ran a /semiadmin or /sa command
-- a terrible hack to enable console output back to semiadmin lastcallerID = nil
- now we'll alter the printmsg function shown above a bit (yeah another advantage of that function heh)
-- print message to either client's console or (if clientID == nil) to server console
function printmsg(message, clientID)
if not message then
return
end
-- replace "s in message with 's
local dummy
message, dummy = string.gsub(message, "\"", "'")
if clientID then
et.trap_SendServerCommand(clientID, "print \"".. message .."^7\n\"")
else
if lastcallerID then
et.trap_SendServerCommand(lastcallerID, "print \"".. message .."^7\n\"")
else
et.G_Print(message .."^7\n")
end
end
end
- fortunately, /sa and /semiadmin are ordinary commands and can be intercepted in CleintCommand trap:
function et_ClientCommand( clientNum, command )
-- lowercase
command = string.lower(command)
-- hack - console output to semiadmin
if (command == "sa") or (command == "semiadmin") then
lastcallerID = clientNum
end
...
end
- now we are basically set, all that remains is to clean up the mess after the party :S
- we need to erase the client ID from the variable so it won't affect someone else's calls; the second setting is after a command was executed already, the first one is for case no custom command was executed and we'll passing the command to ET
function et_ConsoleCommand()
if (string.lower(et.trap_Argv(0))=="...")
... -- all custom console commands go here
else
lastcallerID = nil -- hack to allow console output to semiadmin
return 0
end
lastcallerID = nil -- hack to allow console output to semiadmin
return 1
end
- and finally, we need to make sure semiadmin calling disallowed command will be handled correctly, too - for that I used console print trap as I haven't found any other way to detect that situation:
function et_Print(text)
if string.find(string.lower(et.Q_CleanStr( text )), ") invalid command [", 1, true) then
lastcallerID = nil
end
end
MZ's TJ mod
version: 1.7 (changelog is inside lua script)
released: 20.5.2007
[download zip | lua]
Description
Yet another /save /load mod - this one should be useful for learning and teaching how to trickjump, for pro TJ servers it's probably rather useless.
The mod is based on Kyoko's HSP_TJmod, with fragments of code (sometimes big fragments eh) from ==FF==im2good4u, Furion and robably also from ReyalP. Feengur's ZeN mod was a source of inspiration for me, too.
Key features (as found in Kyoko's TJmod)
- /save and /load - stores your possition on map for each team separately and allows you to teleport back
- /gotohell - server console command, gibs player
- /goto and /iwant - server console commands, teleport one person to another
- /goback - if the person was teleported using /iwant, this server console command moves them back to original location
New features (differences from original mod)
- some code cleanup and formating, parameter checks blah blah blah etc.
- /save2 and /load2 - second save slot. This one is common for both teams and you can /save2 and /load2 also as spectator
- easy jump skipping using /save2 as spectator (here you'll have to decide whether this mod is good or bad for your server)
- some more administrative commands: /rmsaves, /sdisable, /senable (inspired by ZeN)
- all commands allow partial name match as player identification in parameters (altered code from im2good4u)
- saves and /sdisable are persistent across player's reconnects (as long as the script is not reloaded by loading other map etc. the saves persist - the save slots are indexed by guid not player slot)
- /iwant and /goback print explanatory script to target
- /gotohell (and alias /gib) play a sound (again a bit of code from im2good4u) and print a message to everyone
- /disarm command strips a player off all weapons except syringes, knife, binocs and pliers (maybe some more but no shooting weapons) - either for current life or permanently (again altered im2good4u's code)
- /dist gives you distance from others - rather useless but fun command that I found has one practical use after all - you can see who specs you
- /realsay and /realvsay - sends message only to players close to you - this sounds pretty weird but it's useful if you want to explain a trickjump in one room and don't want to confuse those at other jumps
- /TJplayers server console command gives admins overview of info held about the connected players
- /TJhelp gives overview of client commands, /rcon TJhelp gives help for server console commands
- all server commands behave properly and print their output back to caller's console even if used through SemiAdmin command (found a workaround :)
Drawbacks
- no support for etadmin - never worked with that and don't know how it works
- tried to make users stop on load and failed just like all before me did :D
- the workaround to print output back to semiadmin is a bit messy and uses et_Print callback (possible server performance decrease)
- not good for pro TJ servers and seevers without active admins - you can really skip jumps easily and eventually end maps in no time
Thank you
Kyoko / Kotoko
im2good4u
Furion
ReyalP
Feengur
All the guys who wrote LUA API description and code examples here
RefMon
version: 0.2
released: 8.5.2007
[download zip | lua (requires etconst.lua)]
Description
Referee Monitor mod - a lua script that logs all ref commands to a separate, easy to read log.
Function
Referee monitor writes a log record for any ref command issued by either client or server console. The log contains these columns:
- date and time (in server's timezone)
- IP of the client who issued the command (empty for server commands, note that IP can be spoofed)
- name of the client who issued the command (or [console])
- flag - for easy orientation in the log, R means the player was logged in as ref, C means console command, empty otherwise
- command issued
Server console command
- /reflog [optional line number] - prints part of the log to console. The behaviour is similar to !showbans in pub - without parameter, it returns last rows in file, positive number gives you rows starting at that index, negative gives you rows starting at index (-number) from end. Number of rows returned at once is determined by PRINT_ROWS constant (20 by default).
Example log file
2007-05-06 14:51:57 127.0.0.1 {AR}Major Zeman ref
2007-05-06 14:52:01 127.0.0.1 {AR}Major Zeman ref badpassword
2007-05-06 14:52:05 127.0.0.1 {AR}Major Zeman ref goodpassword
2007-05-06 14:52:09 127.0.0.1 {AR}Major Zeman R ref somecommand
2007-05-06 14:52:12 127.0.0.1 {AR}Major Zeman R ref logout
2007-05-06 14:52:16 127.0.0.1 {AR}Major Zeman ref somecommand
2007-05-06 14:52:24 --- [console] C ref referee 0
2007-05-06 14:52:27 127.0.0.1 {AR}Major Zeman R ref somecommand
Files
The zip contains two files:
- refmon.lua - script itself, needed
- etconst.lua - ReyalP's header file, needed
Rules
version: 0.1
released: 14.9.2007
[rules.lua (you'll need to create rules.txt file yourself in the server's etpro directory)
Description
This simple mod just prints contents of a textfile to a client who types in /rules command
Function
Whenever a client issues the /rules command, the mod will print back the content of rules.txt file on server to the client's console. Note that you'll have to create the rules.txt file in the same directory where rules.lua is. The file may contain color codes. Empty lines get eaten up, so use line with space(s) instead. Any line ednigs (win|unix|mac) should get parsed correctly.
Client console command
- /rules - prints the rules file content to the client.
