Skip to content

Commit 4e5f057

Browse files
committed
Added TestPyMySQL to track kills by connected players and bots to a local mysql, config editable.
Every kill it will print killer, victim, the point value (1 for now), and total points the killer has.
1 parent 14b8967 commit 4e5f057

File tree

3 files changed

+280
-9
lines changed

3 files changed

+280
-9
lines changed

PyPlugins/pyplugins.ini

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,26 @@
3636
## python capture 'OnClientAbility2' but not as game event
3737
## python capture 'OnClientUltimate' but not as game event
3838

39-
tests/TestOnAllPluginsLoaded.py
39+
#tests/TestOnAllPluginsLoaded.py
4040
#MenuSystem by Wend4r python interface to CS2Fixes.
41-
##When AllPluginsLoaded, ExecuteObjectMethod OnAllPluginsLoaded and pass a string.
42-
##When a player opens a menu by '!menu' request a list from python and show it in the menu.
41+
##When a player connects UpdatePlayerItems is called by CPP which requests Python to send the players' info
42+
##When a player opens a menu by '!menu' display that info and if stale, update it.
4343

44-
tests/TestEffects.py
44+
tests/TestPyMySQL.py
45+
#Check for Database or Add
46+
#Check for Table or Add
47+
#Check for Connecting Player or Add
48+
#Count kills for Player
49+
#Print killcount
50+
51+
###################tests/TestEffects.py
4552
## Here we go, time to make some nifty effects, pokeball go!
4653
## playsound
4754
## create sprite
4855

4956
##junk below is old work to pull from while making
50-
##'good' working examples above
51-
#SampleEvents.py
52-
#ManyRaces/AdventureTest.py
57+
##better working examples above
58+
###################SampleEvents.py
59+
###################ManyRaces/AdventureTest.py
5360

54-
Adventure/Adventure.py
61+
###################Adventure/Adventure.py

PyPlugins/tests/TestOnAllPluginsLoaded.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ def _teststdstring(self, wrap_func):
3737
alog(str(type(temp)))
3838
alog(str(wrap_func))
3939
alog(str(type(wrap_func)))
40-
#wrap_func("new item") #this works, try more complicated.
4140
wrap_func(temp)
4241
alog("TRY2")
4342
except Exception as e:

PyPlugins/tests/TestPyMySQL.py

Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
import Source2Py
2+
GameEvent = Source2Py.GameEvent
3+
GameEventKeySymbol_t = Source2Py.GameEventKeySymbol_t
4+
ADVPlayer = Source2Py.ADVPlayer
5+
6+
import logging, inspect, traceback
7+
import pymysql
8+
9+
TestDBConfig = {
10+
'host': 'localhost',
11+
'port': 3306,
12+
'user': 'TestPyMySQL',
13+
'password': 'TestPassword',
14+
'database': 'testkilllog', #mysql uses lowercase only, python cares about case difference
15+
'table': 'testtable'
16+
}
17+
18+
logging.basicConfig(filename='tests/TestPyMySQL.log', encoding='utf-8', level=logging.DEBUG, format='[%(asctime)s]%(message)s', datefmt='%H:%M:%S')
19+
log = logging
20+
21+
def alog(message: str, callername: bool = True):
22+
caller = str("")
23+
if (callername):
24+
caller = "[" + str(inspect.stack()[1].function) + "] "
25+
Source2Py.ServerPrint("[TestPyMySQL]" + caller + str(message))
26+
log.info(msg=("[TestPyMySQL]" + caller + str(message)))
27+
pass
28+
29+
default_player_dict = dict({
30+
"loaded": False,
31+
"name": "default",
32+
"steamid": "-1",
33+
"fake": None,
34+
"kills": 0
35+
})
36+
37+
class TestPyMySQL:
38+
players = dict({})
39+
def _CreateConnections(self):
40+
try:
41+
#self.conn = pymysql.connector.connect(
42+
self.conn = pymysql.connect(
43+
user=TestDBConfig['user'],
44+
password=TestDBConfig['password'],
45+
host=TestDBConfig['host']) #,
46+
#buffered=True)
47+
self.conn.autocommit(True)
48+
self.cursor = self.conn.cursor()
49+
except Exception as e:
50+
alog(e)
51+
alog(traceback.format_exc())
52+
pass
53+
def _CreateDatabase(self):
54+
try:
55+
db = TestDBConfig['database']
56+
query = "CREATE DATABASE IF NOT EXISTS " + db
57+
self.cursor.execute(query)
58+
self.conn.select_db(db)
59+
except Exception as e:
60+
alog(e)
61+
alog(traceback.format_exc())
62+
pass
63+
def _CreateTable(self):
64+
try:
65+
table = TestDBConfig['table']
66+
query = "CREATE TABLE IF NOT EXISTS " + table + \
67+
" ( \
68+
steamid VARCHAR(255) NOT NULL, \
69+
PRIMARY KEY (steamid), \
70+
kills INT DEFAULT 0 \
71+
)"
72+
self.cursor.execute(query)
73+
except Exception as e:
74+
alog(e)
75+
alog(traceback.format_exc())
76+
pass
77+
def OnPluginLoad(self):
78+
try:
79+
self._CreateConnections(self)
80+
self._CreateDatabase(self)
81+
self._CreateTable(self)
82+
except Exception as e:
83+
alog(e)
84+
alog(traceback.format_exc())
85+
pass
86+
def _CloseConnections(self):
87+
self.cursor.close()
88+
self.conn.close()
89+
pass
90+
def OnPluginUnload():
91+
self._CloseConnections(self)
92+
pass
93+
def _SQLAddPlayer(self, key: str):
94+
try:
95+
table = TestDBConfig['table']
96+
97+
query = str("INSERT INTO " + table + " (steamid, kills) values (\"" + key + "\", 0)")
98+
self.cursor.execute(query)
99+
self.conn.commit()
100+
101+
result = self.cursor.rowcount
102+
return bool(result)
103+
except Exception as e:
104+
alog(e)
105+
return False
106+
pass
107+
def _SQLCheckPlayer(self, slot: int, key: str):
108+
try:
109+
table = TestDBConfig['table']
110+
query = str("SELECT kills FROM " + table + " WHERE steamid = '" + key + "' LIMIT 1")
111+
self.cursor.execute(query)
112+
result = self.cursor.fetchone()
113+
if result:
114+
self.players[slot]['kills'] = int(result[0])
115+
self.players[slot]['loaded'] = True
116+
else:
117+
#no match, no player, so no kills.
118+
result = self._SQLAddPlayer(self, key)
119+
self.players[slot]['loaded'] = bool(result)
120+
except Exception as e:
121+
self.players[slot]['loaded'] = False
122+
alog(e)
123+
alog(traceback.format_exc())
124+
pass
125+
def _AddPlayer(self, _slot, _name, _fake, _xuid):
126+
#without .copy() this would have been making a pointer to the default_player_dict
127+
#meaning the default_player_dict would be overwritten with the last joining players
128+
#information. Pointers, man.
129+
self.players[_slot] = default_player_dict.copy()
130+
try:
131+
self.players[_slot]['name'] = _name
132+
self.players[_slot]['fake'] = _fake
133+
134+
if _fake:
135+
self.players[_slot]['steamid'] = _name
136+
else:
137+
self.players[_slot]['steamid'] = str(_xuid)
138+
139+
key = self.players[_slot]['steamid']
140+
self._SQLCheckPlayer(self, _slot, key)
141+
except Exception as e:
142+
alog(e)
143+
alog(traceback.format_exc())
144+
pass
145+
def OnClientPutInServer(self,
146+
_slot: int, #slot on server
147+
_name: str, #player name
148+
_type: int, #0=player, 1=bot, 2=???
149+
_xuid: int):
150+
try:
151+
if _type in [0, 1]:
152+
self._AddPlayer(self, _slot, _name, _type, _xuid)
153+
else: #type was not 0 or 1!
154+
alog("_type=" + str(_type))
155+
pass
156+
except Exception as e:
157+
alog(e)
158+
alog(traceback.format_exc())
159+
pass
160+
def OnClientConnected(self,
161+
_slot: int, #slot on server
162+
_name: str, #player name
163+
_xuid: int, #steam id
164+
_networkID: str, #ip address with port, ex "127.0.0.1:27015"
165+
_ipAddress: str, #ip address only, ex "127.0.0.1"
166+
_fake: bool): #client is a bot
167+
try:
168+
self._AddPlayer(self, _slot, _name, _fake, _xuid)
169+
except Exception as e:
170+
alog(e)
171+
alog(traceback.format_exc())
172+
pass
173+
def _AddKill(self, slot: int):
174+
try:
175+
if self.players[slot]['loaded']:
176+
table = TestDBConfig['table']
177+
steamid = self.players[slot]['steamid']
178+
179+
kills = self.players[slot]['kills'] + 1
180+
self.players[slot]['kills'] = kills
181+
182+
query = str(
183+
" UPDATE " + table + \
184+
" SET kills = " + str(kills) + \
185+
" WHERE steamid = \"" + steamid + "\"")
186+
self.cursor.execute(query)
187+
self.conn.commit()
188+
else:
189+
key = self.players[slot]['steamid']
190+
self._SQLCheckPlayer(self, slot, key)
191+
except Exception as e:
192+
alog(e)
193+
alog(traceback.format_exc())
194+
pass
195+
def OnPlayerDeath(self, event: GameEvent):
196+
try:
197+
geks = GameEventKeySymbol_t("attacker")
198+
aslot = event.GetPlayerSlot(geks).Get()
199+
if aslot < 0:
200+
#bomb kill / server / etc
201+
pass
202+
else:
203+
self._AddKill(self, aslot)
204+
205+
#can get name through here or
206+
#ap = ADVPlayer(aslot)
207+
#aname = ap.GetName()
208+
aname = self.players[aslot]['name']
209+
akills = self.players[aslot]['kills']
210+
211+
geks = GameEventKeySymbol_t("userid")
212+
vslot = event.GetPlayerSlot(geks).Get()
213+
vname = self.players[vslot]['name']
214+
215+
alog(str(aname) + " has killed " + str(vname) + " for 1 point and now has " + str(akills) + " point(s).")
216+
except Exception as e:
217+
alog(e)
218+
alog(traceback.format_exc())
219+
pass
220+
221+
222+
'''
223+
"player_death":dict({
224+
"userid":"playercontroller",
225+
"userid_pawn":"strict_ehandle",
226+
"attacker":"playercontroller",
227+
"attacker_pawn":"strict_ehandle",
228+
"assister":"playercontroller",
229+
"assister_pawn":"strict_ehandle",
230+
"assistedflash":"bool",
231+
"weapon":"string",
232+
"weapon_itemid":"string",
233+
"weapon_fauxitemid":"string",
234+
"weapon_originalowner_xuid":"string",
235+
"headshot":"bool",
236+
"dominated":"short",
237+
"revenge":"short",
238+
"wipe":"short",
239+
"penetrated":"short",
240+
"noreplay":"bool",
241+
"noscope":"bool",
242+
"thrusmoke":"bool",
243+
"attackerblind":"bool",
244+
"distance":"float",
245+
"dmg_health":"short",
246+
"dmg_armor":"byte",
247+
"hitgroup":"byte",
248+
"attackerinair":"bool",
249+
}),
250+
"other_death":dict({
251+
"otherid":"short",
252+
"othertype":"string",
253+
"attacker":"short",
254+
"weapon":"string",
255+
"weapon_itemid":"string",
256+
"weapon_fauxitemid":"string",
257+
"weapon_originalowner_xuid":"string",
258+
"headshot":"bool",
259+
"penetrated":"short",
260+
"noscope":"bool",
261+
"thrusmoke":"bool",
262+
"attackerblind":"bool",
263+
}),
264+
265+
'''

0 commit comments

Comments
 (0)