GithubHelp home page GithubHelp logo

chillavanilla / teeworldseconmod Goto Github PK

View Code? Open in Web Editor NEW
3.0 2.0 1.0 296 KB

A python script which communicates with teeworlds server log as input and econ connection as output.

License: MIT License

Shell 14.97% Python 85.03%
teeworlds-server teeworlds econ-connection python-script vanilla teeworlds-vanilla

teeworldseconmod's Introduction

TeeworldsEconMod

A python script which communicates with teeworlds server log as input and econ connection as output.

Setup

on debian based systems do:

sudo apt install python3 python3-pip git expect
git clone https://github.com/ChillaVanilla/TeeworldsEconMod.git
cd TeeworldsEconMod
pip3 install -r requirements.txt
./start_tem.sh

How to use?

create a tem.settings file and write line by line these configurations:

sh_tw_path=/path/to/your/teeworlds/directory/
sh_tw_binary=name_of_teeworlds_srv
sh_logs_path=/path/to/log/directory/
sh_econ_password=password
sh_econ_port=8203
py_debug=0
py_stats_mode=file
py_file_database=stats/

a sample config could look like:

sh_tw_path=/home/chiller/teeworlds/
sh_tw_binary=teeworlds_srv
sh_logs_path=/home/chiller/logs/
sh_econ_password=7h9had8a9
sh_econ_port=8203
py_debug=1
py_stats_mode=sql
py_sql_database=stats.db

To fire things up execute ./start_tem.sh.

This will start your teeworlds server pipe the output through the python scripts and then respond via netcat connection to the teeworlds econ api.

Dependencies

You need python3 and expect installed. And a teeworlds server with an autoexec.cfg including:

ec_port "port"
ec_password "password"

Advanced config

Additional config variables can be found in

src/global_settings.py

You can also lock names and only allow connections from specific regions. This is to combat player faking and can be used to protect kill/death ratio.

Create a file called locked_names.json that contains an array of locked names in this format:

[
  { "names": ["ChillerDragon", "ChillerDragon.*"], "regions": ["Bavaria"], "ips": ["127.0.0.1"] }
  { "names": ["nameless tee"], "regions": ["Hesse"], "ips": ["8.8.8.8"] }
]

If a player joins with any of the specified in the names array its ip has to be either included in the ips array or the ipinfo lookup has to match one of the regions

Then create a ipinfo account and set the api token in your tem.settings file:

py_ipinfo_token=exampletoken

Testing

To make sure everything runs fine on your system you can try running the tests. It runs tem against a few sample logs.

# install bc which is a dependency of test.sh
# also works without but you get a few warnings
sudo apt install bc
cd test
./test.sh

# for more information check the help page
./test.sh --help

Logs

Currently the logs have some weird binary chunks in it and grep doesn't work well with it.

If you want to convert the logs to text only you could use a command like:

for f in logs/*; do echo "[`basename $f`]... (`wc -l $f`)"; strings $f > txt_logs/`basename $f`; done

Bugs

sv_scorelimit 1000 is strongly recommended if scorelimit is lower the wins and looses will be calculated on new round start. So all players who leave during end screen won't be tracked. If the scorelimit is 1000 the wins and looses will be saved instantly on the 10th capture.

Keep in mind the script just parses the logs. So everything messing with the logs can be dangerous. Things like restart and reload are untested and not recommended. Also using the rcon command say to create fake game messages like say 'nameless tee' has left the game is most likely crashing the server.

teeworldseconmod's People

Contributors

chillerdragon avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar

teeworldseconmod's Issues

Discord bridge utf8 bug


line: 0:-2:el pro: ¡VB 89YUOL
Traceback (most recent call last):
  File "./bot.py", line 46, in <module>
    main()
  File "./bot.py", line 38, in main
    HandleData(line)
  File "./bot.py", line 24, in HandleData
    requests.post("https://discordapp.com/api/webhooks/" + token, data={"content": line})
  File "/home/chiller/.local/lib/python3.5/site-packages/requests/api.py", line 116, in post
    return request('post', url, data=data, json=json, **kwargs)
  File "/home/chiller/.local/lib/python3.5/site-packages/requests/api.py", line 60, in request
    return session.request(method=method, url=url, **kwargs)
  File "/home/chiller/.local/lib/python3.5/site-packages/requests/sessions.py", line 519, in request
    prep = self.prepare_request(req)
  File "/home/chiller/.local/lib/python3.5/site-packages/requests/sessions.py", line 462, in prepare_request
    hooks=merge_hooks(request.hooks, self.hooks),
  File "/home/chiller/.local/lib/python3.5/site-packages/requests/models.py", line 316, in prepare
    self.prepare_body(data, files, json)
  File "/home/chiller/.local/lib/python3.5/site-packages/requests/models.py", line 507, in prepare_body
    body = self._encode_params(data)
  File "/home/chiller/.local/lib/python3.5/site-packages/requests/models.py", line 104, in _encode_params
    v.encode('utf-8') if isinstance(v, str) else v))
UnicodeEncodeError: 'utf-8' codec can't encode character '\udcc2' in position 13: surrogates not allowed

Crash: name missmatch p.name='None'

[2020-03-03 21:40:18][game]: kill killer='9:0:EviL' victim='2:1:nameless' weapon=4 special=1
[2020-03-03 21:40:18][game]: pickup player='1:toBsucht' item=3
[2020-03-03 21:40:19][chat]: 4:1:♾: а следующее оружие у тебя на чем? ))
[2020-03-03 21:40:19][game]: flag_return player='7:kroxa' team=0
[2020-03-03 21:40:20][game]: pickup player='3:BITCH' item=1
[2020-03-03 21:40:20][game]: pickup player='2:nameless' item=1
[2020-03-03 21:40:20][game]: pickup player='7:kroxa' item=1
[2020-03-03 21:40:20][game]: pickup player='7:kroxa' item=1
[2020-03-03 21:40:20][game]: pickup player='7:kroxa' item=1
[2020-03-03 21:40:21][game]: pickup player='2:nameless' item=2
[2020-03-03 21:40:23][chat]: 5:1:CHERO: пробел)
[2020-03-03 21:40:23][game]: pickup player='8:tota' item=1
[2020-03-03 21:40:23][game]: pickup player='3:BITCH' item=1
[2020-03-03 21:40:23][game]: pickup player='8:tota' item=1
[2020-03-03 21:40:23][game]: pickup player='3:BITCH' item=1
[2020-03-03 21:40:23][game]: pickup player='8:tota' item=1
[2020-03-03 21:40:23][game]: pickup player='1:toBsucht' item=0
[2020-03-03 21:40:24][game]: pickup player='8:tota' item=0
[2020-03-03 21:40:25][game]: pickup player='5:CHERO' item=1
[2020-03-03 21:40:25][game]: pickup player='5:CHERO' item=1
[2020-03-03 21:40:25][game]: pickup player='5:CHERO' item=1
[2020-03-03 21:40:26][game]: flag_capture player='1:toBsucht' team=0 time=31.74
[2020-03-03 21:40:26][game]: pickup player='8:tota' item=3
[2020-03-03 21:40:26][game]: pickup player='9:EviL' item=0
[2020-03-03 21:40:26][game]: pickup player='9:EviL' item=0
[2020-03-03 21:40:26][game]: pickup player='9:EviL' item=0
[2020-03-03 21:40:26][game]: flag_grab player='3:BITCH' team=1
[2020-03-03 21:40:27][game]: pickup player='2:nameless' item=2
[2020-03-03 21:40:27][game]: pickup player='1:toBsucht' item=2
[2020-03-03 21:40:27][game]: flag_grab player='9:EviL' team=0
[2020-03-03 21:40:27][server]: cid=0 cmd='say "[ERROR] name missmatch p.name='None' name='EviL'"'
[2020-03-03 21:40:27][chat]: *** [ERROR] name missmatch p.name='None' name='EviL'

Warnings spam chat

[2019-11-23 20:01:24][chat]:  2: ФФФФФФФ(invalid utf8)
[2019-11-23 20:01:24][chat]: -1: : *** [WARNING] UnicodeDecodeError! Please contact an admin.

Invalid names are possible that trigger this warning when they use chat. So this can get very annoying. It is probably best idea to move all warnings to the admin console only.

Update flag time instant

Do not wait for disconnect or round end so players can see rank improving while fast capping and nobody can overwrite with worse new highscore.

Add blacklist of vote reasons

Add a config to automatically veto all votes containing given values. Example:

  • No reason given
  • please f3
  • awd
  • dwa
  • (insert insult here)

Unicode crashbug

The crashlog:

[chat]: *** 'leooelisabeth' has left the game
[game]: leave player='9:leooelisabeth'
[chat]: *** The red flag was captured by 'Mr. Teeseeks' (13.06 seconds)
[teamchat]: 3:1:nameless tee: ннннннннннннеееееееееееееккккккккккккккккккккууууууууууууууууууууццццццццццццццццццццйцййцввваааааааааапппппппппппппппÑ
Traceback (most recent call last):
  File "/home/chiller/git/TeeworldsEconMod/src/main.py", line 48, in MainLoop
    line = sys.stdin.readline()
  File "/usr/lib/python3.4/codecs.py", line 313, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd1 in position 276: invalid continuation byte

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/chiller/git/TeeworldsEconMod/src/main.py", line 97, in <module>
    main(sys.argv[1:])
  File "/home/chiller/git/TeeworldsEconMod/src/main.py", line 94, in main
    MainLoop()
  File "/home/chiller/git/TeeworldsEconMod/src/main.py", line 55, in MainLoop
    say("[WARNING] UnicodeDecodeError! Please contact an admin.")
NameError: name 'say' is not defined

Track wins

Keep track of all the caps and count red and blue caps to check on new round who has more flags.
Also create a temporary player variable which holds the current team to reward in win or loose on round end.

Maybe count disconnecting while being in the worse team as loose or what ever. Or do something else agianst disconnect before loose. And also keep in mind that many players leave on deathscreen and the new round message in the server log arrives at the end of the deathscreen. So maybe detect scorelimit somehow or always trigegr game end on 10 flags and warn that lower scorelimits than 1000 might influence winnning stats.

Nicer join stats (maybe global rank)

The kills deaths and spree info is too much for a join message.
Maybe only show kill rank or create a new gloabl rank depending on points calculated by all the ranks mixed somehow.

Update flag time instant

Do not wait for disconnect or round end so players can see rank improving while fast capping and nobody can overwrite with worse new highscore.

Fix players with chatcommand names

if someone uses the name '/help' or '/top5' the command gets executed every time they use chat.
So they can't use the '/rank' command.

Add support for all gametypes

CTF runs kinda fine for now but DM and TDM are pretty untested.
Detect gametype at round start and count kills as score in non CTF gametypes to choose a winner on game end.

Potential performance boost

Currently player objects fetched by iterating over the players array all over the place.
It would probably be smarter to use a Dictionary with the name being the key.

teamchange failed


^@^@[18:37:55][server]: player is ready. ClientID=15 addr=84.XXX.XXX.XXX:58675
^@^@echo "[WARNING] UnicodeDecodeError! Please contact an admin."
[18:37:55][server]: cid=0 cmd='echo "[WARNING] UnicodeDecodeError! Please contact an admin."'
^@^@[18:37:55][Console]: [WARNING] UnicodeDecodeError! Please contact an admin.
^@^@[18:37:55][server]: player has entered the game. ClientID=15 addr=84.82.88.251:58675
^@^@say "[ERROR] teamchange failed id=15 data=[game]: team_join player='15:flappie' team=1"
say "  id=12 name='e6aJloBcblPe'"
say "  id=6 name='Who'"
say "  id=3 name='ChillerDragon'"
say "  id=10 name='Spulae Mulae'"
say "  id=8 name='Whis'"
say "  id=2 name='Cap'tain roc'"
say "  id=0 name='Ponny'"
say "  id=5 name='naamloos tie'"
say "  id=7 name='nameless tee'"
say "  id=11 name='Soleil'"
say "  id=13 name='Swap'"
say "  id=1 name='teeless name'"
say "  id=4 name='Stechus Kaktus'"
say "  id=9 name='martinus magnus'"
[18:37:55][server]: cid=0 cmd='say "[ERROR] teamchange failed id=15 data=[game]: team_join player='15:flappie' team=1"'
^@^@[18:37:55][chat]: *** [ERROR] teamchange failed id=15 data=[game]: team_join player='15:flappie' team=1

Announcement system

Add a new thread that prints every x seconds a random announcement from a file to the chat.
Use this to advertise admin contact.

team_join player='x:(connecting)' crash

[12:26:47][chat]: 2:1:monad: someone joinning red?
[12:27:00][chat]: 1:1:Boycraft: nope
[12:27:21][chat]: 1:1:Boycraft: hooray
[12:27:48][server]: player is ready. ClientID=0 addr=127.XXX.XXX.XXX:15682
[12:27:49][server]: player has entered the game. ClientID=0 addr=127.XXX.XXX.XXX:15682
say "[stats] 'DIVYAM' kills: 261 deaths: 571 killingspree: 5"
[12:27:49][server]: cid=0 cmd='say "[stats] 'DIVYAM' kills: 261 deaths: 571 killingspree: 5"'
[12:27:49][chat]: *** [stats] 'DIVYAM' kills: 261 deaths: 571 killingspree: 5
[12:28:05][server]: player is ready. ClientID=6 addr=5.XXX.XXX.XXX:21605
say "[ERROR] teamchange failed id=6 data=[game]: team_join player='6:(connecting)' team=0->1"
say "  id=3 name='MAHmut'"
say "  id=1 name='Boycraft'"
say "  id=5 name='E=mc^2'"
say "  id=2 name='monad'"
say "  id=4 name='Puldcross'"
say "  id=0 name='DIVYAM'"

Seems like it is possible that a invalid (connecting) player can change the team. Probably caused by balance.

Track auth state of players

Do not trigger discord ping when a admin is authed (bot.py). And block echo commands like !reload_settings for moderators (tem).

Add option to force port

Either as normal tem setting or even as start script argument. Add config to force the port which then gets passed to the teeworlds server as econ port. Also allow the value random.

The use case for this is security through non default/changing ports. And no port jamming during fast restarts (saves nerves and time during development).

sh_force_port=8303
sh_force_port=random

untracked namechange from '(connecting)' to 'foo'

[2020-07-13 12:14:40][server]: player is ready. ClientID=2 addr=XXX.XXX.XXX.XXX:44228
[2020-07-13 12:14:40][game]: Teams are balanced (red=2 blue=1)
[2020-07-13 12:14:40][game]: kill killer='6:1:i3slkiller' victim='6:1:i3slkiller' weapon=-3 special=0
[2020-07-13 12:14:40][game]: team_join player='6:i3slkiller' team=1->0
[2020-07-13 12:14:40][game]: kill killer='1:0:Dillon' victim='1:0:Dillon' weapon=-3 special=0
[2020-07-13 12:14:40][game]: team_join player='1:Dillon' team=0->1
[2020-07-13 12:14:40][game]: team_join player='2:(connecting)' team=0->1
[2020-07-13 12:14:40][server]: player has entered the game. ClientID=2 addr=XXX.XXX.XXX.XXX:44228
[2020-07-13 12:14:40][game]: team_join player='2:zyles' team=1
[2020-07-13 12:14:40][game]: Teams are balanced (red=1 blue=2)
[2020-07-13 12:14:40][server]: cid=0 cmd='say "[stats] '(connecting)' kills: 237 deaths: 238 killingspree: 10"'                                                                                                   
[2020-07-13 12:14:40][chat]: *** [stats] '(connecting)' kills: 237 deaths: 238 killingspree: 10
[2020-07-13 12:14:40][server]: cid=0 cmd='say "[ERROR] untracked namechange from '(connecting)' to 'zyles'"'                                                                                                      
[2020-07-13 12:14:40][chat]: *** [ERROR] untracked namechange from '(connecting)' to 'zyles'

Protect names

After 2 years running in production the first user report came in that complained about fakers destroying the Kill Death Ratio. I always was somehow bothered by it and thus deaths are intentionally hidden in the stats commands.

It would be nice for users that REALLY want this to be able to provide something. I thought about two options:

  • Complete lock of specific names. Could be unlocked by moderators manually. And are autokicked otherwise.

  • Lock names to ip range. If the user has a fixed ip range from his provider or even a static ip this might be an option.

Upgrade '/stats' command

Use new name recognizion techniques and only print stats of one player.
Maybe splitt in global and round stats and remove '/stats_all' from command list.

Filter vanilla names

top5 are full of nameless tee (1)nameless tee and (1)
add atleast an config option to filter them out of the rankings

Unicode again

    4 [5d1e214b][game]: pickup player='3:Niklas 32' item=1/0
     3 [5d1e214c][game]: pickup player='3:Niklas 32' item=1/0
     2 [5d1e214c][chat]: 2:-2:nameless tee: ❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤<de1f>
     1 [5d1e214c][server]: cid=0 cmd='say "[WARNING] UnicodeDecodeError! Please contact an admin."'
897067 [5d1e214c][chat]: *** [WARNING] UnicodeDecodeError! Please contact an admin.

No python error but the server stopped.

Crashbug invalid team

[2019-10-03 16:56:49][game]: pickup player='1:machine' item=1
[2019-10-03 16:56:49][game]: team_join player='0:ChillerDragon' team=0->-1
[2019-10-03 16:56:49][server]: cid=0 cmd='say "[ERROR] invalid team=0->-1"'
[2019-10-03 16:56:49][chat]: *** [ERROR] invalid team=0->-1

Crash: sqlite3.OperationalError: database is locked

^@^@[21:29:59][game]: leave player='3:name'
^@^@Traceback (most recent call last):
  File "./src/main.py", line 126, in <module>
    main(sys.argv[1:])
  File "./src/main.py", line 123, in main
    MainLoop()
  File "./src/main.py", line 88, in MainLoop
    HandleData(line[1:20], line[21:]) # cut off the timestamp
  File "./src/main.py", line 61, in HandleData
    player.HandlePlayerLeave(data[:-1]) # chop of newline
  File "/home/chiller/git/TeeworldsEconMod/src/player.py", line 159, in HandlePlayerLeave
    SaveAndDeletePlayer(player)
  File "/home/chiller/git/TeeworldsEconMod/src/player.py", line 72, in SaveAndDeletePlayer
    SaveStats(player)
  File "/home/chiller/git/TeeworldsEconMod/src/save_stats.py", line 9, in SaveStats
    return SaveStatsSQL(player)
  File "/home/chiller/git/TeeworldsEconMod/src/sql_stats.py", line 192, in SaveStatsSQL
    player.a_haxx0r, player.a_blazeit, player.a_satan, player.a_virgin
sqlite3.OperationalError: database is locked

Add tests for achievements

  File "./src/main.py", line 115, in <module>
    main(sys.argv[1:])
  File "./src/main.py", line 112, in main
    MainLoop()
  File "./src/main.py", line 77, in MainLoop
    HandleData(line[1:20], line[21:]) # cut off the timestamp
  File "./src/main.py", line 66, in HandleData
    game.HandleGame(timestamp, data)
  File "/home/chiller/git/TeeworldsEconMod/src/game.py", line 97, in HandleGame
    flag.HandleFlapCap07(data)
  File "/home/chiller/git/TeeworldsEconMod/src/flag.py", line 75, in HandleFlapCap07
    __HandleFlagCap(p, m.group("time"), flag_color)
  File "/home/chiller/git/TeeworldsEconMod/src/flag.py", line 21, in __HandleFlagCap
    achievements.CheckFlag(player_obj, time)
  File "/home/chiller/git/TeeworldsEconMod/src/achievements.py", line 48, in CheckFlag
    if player.UpdateAchievement(player, "satan"):
AttributeError: 'Player' object has no attribute 'UpdateAchievement'

ban system

just after few commands I got banned. It's bad!

Better round end tracking

Check sv_scorelimit on round start to early track wins and looses not only for 1000.

to fix the bug:

sv_scorelimit 1000 is strongly recommended if scorelimit is lower the wins and looses will be calculated on new round start. So all players who leave during end screen won't be tracked. If the scorelimit is 1000 the wins and looses will be saved instantly on the 10th capture.

Store killing spree in database directly

Make sure a killing spree is never overwritten by a worse highscore compared to a outdated record. Can happen on 0.7 when both tees have the same name or if two servers are running.

It can happen that both players break the killing spree highscore while both are online. If then the player with the better highscore leaves first the other one overwrites it with a worse highscore.

Fix parse injection names

Make sure nothing breaks if a player uses the name ' victim=' or other similar names currently used for parsing.

Better non interactive support

If the script gets started with nohup or by any other non interactive script it should behave differently. It should exit with an error code on invalid log path and not prompt the user to create one.

Add archivements

Funny flag times like:
13.37
4.20
6.66
6.9

Should be announced in chat and showed in '/archivements'
also maybe detect double kills by checking time diff between kills

some config sanitization might help

I'm getting this constructed line, I think trailing slashes should kinda be sanitized with python

config:

sh_tw_path=/home/jxsl13.tw/teeworlds/build/
py_file_database=stats/vanilla_ctf_stats.db

Kinda disturbed by that double slash there.

...
[TEM] No stats/ folder found in your teeworlds directory
[TEM] should be at: /home/jxsl13.tw/teeworlds/build//stats
...

Maybe remove trailing slash from every configuration line that expects a directory and add it manually yourself when constructing the final path.

0.6 uses hex and decimal system for ids

[5da1c1eb][server]: 'foo' -> 'foo'
[5da1c1eb][server]: player has entered the game. ClientID=a addr=185.XXX.XXX.XXX:2073
[5da1c1eb][chat]: *** 'foo' entered and joined the blue team
[5da1c1eb][game]: team_join player='10:foo' team=1
[5da1c1eb][chat]: *** [ERROR] teamchange failed id=10 data=[game]: team_join player='10:foo' team=1

The player is stored with id 'a' and looked up by id 10.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.