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+ \ 
69+ \ 
70+ \ 
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