1#!/usr/bin/python -u
2# Dedicated Control handler script for OpenLieroX
3# (http://openlierox.sourceforge.net)
4
5
6# Needed for sleeping/pausing execution
7import time
8# Needed for directory access
9import os
10import sys
11import traceback
12
13
14def getRawResponse():
15	global EmptySignalsCount
16	ret = sys.stdin.readline().strip()
17	if ret != "":
18		return ret
19	else:
20		sys.stderr.write("Dedicated_control: OLX terminated, exiting\n")
21		sys.exit(1)
22
23def getResponse():
24	ret = []
25	resp = getRawResponse()
26	while resp != ".":
27		if not resp.startswith(':'):
28			sys.stderr.write("Dedicated_control: bad OLX dedicated response: " + resp + "\n")
29		else:
30			ret.append( resp[1:] )
31		resp = getRawResponse()
32	return ret
33
34
35def SendCommand(cmd):
36	print cmd
37	return getResponse()
38
39def getSignal():
40	return SendCommand("nextsignal")
41
42## Sending functions ##
43
44# Set a server variable
45def setvar(what, data):
46	SendCommand( "setvar %s \"%s\"" % (str(what), str(data)) )
47
48def setVar(what, data):
49	setvar(what, data)
50
51def setWormWeapons(wormid, weapon1, weapon2, weapon3, weapon4, weapon5):
52	SendCommand( "setWormWeapons %d \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"" % (wormid, weapon1, weapon2, weapon3, weapon4, weapon5) )
53
54def listVars(prefix = ""):
55	return SendCommand( "listVars %s" % (str(prefix)) )
56
57# Use this to make the server quit
58def Quit():
59	SendCommand( "quit" )
60
61# Use this to force the server into lobby - it will kick all connected worms and restart the server
62def startLobby(port):
63	if port:
64		SendCommand( "startlobby " + str(port) )
65	else:
66		SendCommand( "startlobby" )
67
68# start the game (weapon selections screen)
69def startGame():
70	msgs = SendCommand( "startgame" )
71	if len(msgs) > 0:
72		for m in msgs():
73			messageLog(m, LOG_ERROR)
74		return False
75	else:
76		return True
77
78# Use this to force the server into lobby - it will abort current game but won't kick connected worms
79def gotoLobby():
80	SendCommand( "gotolobby" )
81
82def addBot(worm = None):
83	if worm:
84		SendCommand( "addbot \"%s\"" % str(worm) )
85	else:
86		SendCommand( "addbot" )
87
88def kickBot(msg = None):
89	if msg:
90		SendCommand( "kickbot \"%s\"" % str(msg) )
91	else:
92		SendCommand( "kickbot" )
93
94def kickBots():
95	SendCommand( "kickbots" )
96
97# Suicides all local bots
98def killBots():
99	SendCommand( "killbots" )
100
101# Both kick and ban uses the ingame identification code
102# for kicking/banning.
103def kickWorm(iID, reason = ""):
104	if reason != "":
105		SendCommand( "kickworm %i \"%s\"" % (int(iID), str(reason)) )
106	else:
107		SendCommand( "kickworm %i" % int(iID) )
108
109def banWorm(iID, reason = ""):
110	if reason != "":
111		SendCommand( "banworm %i \"%s\"" % (int(iID), str(reason)) )
112	else:
113		SendCommand( "banworm %i" % int(iID) )
114
115def muteWorm(iID):
116	SendCommand( "muteworm " + str(iID) )
117
118def setWormTeam_io(iID, team):
119	SendCommand( "setwormteam " + str(iID) + " " + str(team) )
120
121
122def setWormTeam(iID, team):
123	import dedicated_control_handler as hnd
124	if iID in hnd.worms.keys() and hnd.worms[iID].iID != -1:
125		hnd.worms[iID].Team = team
126		setWormTeam_io(iID, team)
127	else:
128		messageLog("Worm id %i invalid" % iID ,LOG_ADMIN)
129
130def getWormTeam(iID):
131	return int(SendCommand("getwormteam %i" % int(iID))[0])
132
133def getNumberWormsInTeam(team):
134	import dedicated_control_handler as hnd
135	c = 0
136	for w in hnd.worms.values():
137		if getWormTeam( w.iID ) == team:
138			c = c + 1
139	return c
140
141def getWormName(iID):
142	return SendCommand("getwormname %i" % int(iID))[0]
143
144def authorizeWorm(iID):
145	SendCommand( "authorizeworm " + str(iID) )
146
147def getWormList():
148	return [int(w) for w in SendCommand( "getwormlist" )]
149
150# Use this to get the list of all possible bots.
151def getComputerWormList():
152	return [int(w) for w in SendCommand( "getcomputerwormlist" )]
153
154def getWormIP(iID):
155	ret = SendCommand( "getwormip %i" % int(iID) )
156	if len(ret) == 0:
157		return "0.0.0.0"
158	return ret[0]
159
160def getWormLocationInfo(iID):
161	ret = SendCommand( "getwormlocationinfo %i" % int(iID) )
162	if len(ret) == 0:
163		return "Unknown Location"
164	return ret[0]
165
166def getWormPing(iID):
167	ret = SendCommand( "getwormping %i" % int(iID) )
168	if len(ret) == 0:
169		return 0
170	return int(ret[0])
171
172def getWormSkin(iID):
173	ret = SendCommand( "getwormskin %i" % int(iID) )
174	return ( int(ret[0]), ret[1].lower() )
175
176def getVar(var):
177	ret = SendCommand( "getvar %s" % var )
178	if len(ret) == 0: # var does not exist
179		return "" # TODO: or exception?
180	return ret[0]
181
182def getVarHelp(var):
183	ret = SendCommand( "getVarHelp %s" % var )
184	if len(ret) == 0: # var does not exist
185		return ""
186	return ret[0]
187
188def getGameType():
189	return int(getVar("GameOptions.GameInfo.GameType"))
190
191def isTeamGame():
192	gameType = getGameType()
193	return (gameType == 1) or (gameType == 4) or (gameType == 5) or (gameType == 7)
194
195def getFullFileName(fn):
196	return SendCommand( "getfullfilename \"%s\"" % fn )[0]
197
198def getWriteFullFileName(fn):
199	return SendCommand( "getwritefullfilename \"%s\"" % fn )[0]
200
201def listMaps():
202	return SendCommand("listmaps")
203
204def listMods():
205	return SendCommand("listmods")
206
207
208# Use this to write to stdout (standard output)
209def msg(string):
210	SendCommand( "msg \"%s\"" % str(string) )
211
212# Send a chat message
213def chatMsg(string):
214	SendCommand( "chatmsg \"%s\"" % str(string) )
215
216# Send a private chat message
217def privateMsg(iID, string):
218	SendCommand( "privatemsg %i \"%s\"" % ( int(iID), str(string) ) )
219
220
221#Log Severity
222LOG_CRITICAL = 0 # For things that you REALLY need to exit for.
223LOG_ERROR = 1
224LOG_WARN = 2
225LOG_INFO = 3
226# Categories for specific things, perhaps put in a new file?
227# These are not in direct relation to the script.
228LOG_ADMIN = 4
229LOG_USRCMD = 5
230
231def messageLog(message,severity = LOG_INFO):
232	# TODO: Allow setting what loglevels you want logged
233	outline = time.strftime("%Y-%m-%d %H:%M:%S")
234	# Don't clutter the strftime call
235	outline += " -- "
236	if severity == LOG_CRITICAL:
237		outline += "CRITICAL"
238	elif severity == LOG_ERROR:
239		outline += "ERROR"
240	elif severity == LOG_WARN:
241		outline += "WARN"
242	elif severity == LOG_INFO:
243		outline += "INFO"
244	elif severity == LOG_ADMIN: #Log to another file?
245		outline += "ADMIN"
246	elif severity == LOG_USRCMD: #Log to another file?
247		outline += "USERCOMMAND"
248
249	outline += " -- "
250	outline += str(message) #incase we get anything other than string
251	try:
252		f = open(cfg.LOG_FILE,"a")
253		f.write((outline + "\n"))
254		f.close()
255	except IOError:
256		msg("ERROR: Unable to open logfile.")
257
258	#It's possible that we get a broken pipe here, but we can't exit clearly and also display it,
259	# so let python send out the ugly warning.
260	msg(outline)
261
262# Stolen from http://www.linuxjournal.com/article/5821
263def formatExceptionInfo(maxTBlevel=5):
264	cla, exc, trbk = sys.exc_info()
265	excName = cla.__name__
266	try:
267		excArgs = exc.__dict__["args"]
268	except KeyError:
269		excArgs = "<no args>"
270	excTb = traceback.format_tb(trbk, maxTBlevel)
271	return (excName, excArgs, excTb)
272