client.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. from getpass import getpass
  2. import websocket
  3. import _thread
  4. import json
  5. import time
  6. from cmd import Cmd
  7. class MyPrompt(Cmd):
  8. def __init__(self, ws):
  9. super(MyPrompt, self).__init__()
  10. self.ws = ws
  11. def do_build(self, args):
  12. """Starts the construction of a building."""
  13. send_json(self.ws, {
  14. 'type': "build",
  15. 'name': args,
  16. })
  17. def do_research(self, args):
  18. """Starts the research of a new technology."""
  19. send_json(self.ws, {
  20. 'type': "research",
  21. 'name': args,
  22. })
  23. def do_train(self, args):
  24. """Starts the training of a unit."""
  25. args = args.split(" ")
  26. send_json(self.ws, {
  27. 'type': "train",
  28. 'name': args[0],
  29. 'level': args[1] if len(args) > 1 else 1
  30. })
  31. def do_jobs(self, args):
  32. """List the current running jobs."""
  33. global player_data
  34. global server_config
  35. for job in player_data['jobs']:
  36. product = job['product']
  37. if product['type'] == "building":
  38. print("Upgrading {} to level {}.".format(server_config['building'][product['name']]['name'], player_data['buildings'][product['name']] + 1))
  39. elif product['type'] == "research":
  40. print("Researching {} level {}.".format(server_config['research'][product['name']]['name'], player_data['research'][product['name']] + 1))
  41. elif product['type'] == "unit":
  42. print("Training level {} {}.".format(product['level'], server_config['unit'][product['name']]['name']))
  43. elif product['type'] == "mission":
  44. print("Mission: {}".format(product['mission']['name']))
  45. else:
  46. print("Unknown job: {}".format(job))
  47. bar_width = 20
  48. remaining = job['finish_time'] - time.time()
  49. progress = remaining / job['product']['time']
  50. num_bars = bar_width - int(progress * bar_width)
  51. print("[" + num_bars * "#" + (bar_width - num_bars) * " " + "]" + str(int(remaining)) + "s remaining")
  52. print("-" * (bar_width + 10))
  53. if not player_data['jobs']:
  54. print("No jobs are currently running.")
  55. def do_missions(self, args):
  56. """List available missions."""
  57. global player_data
  58. global server_config
  59. for i, mission in enumerate(player_data['missions']):
  60. print("{}. {}".format(i + 1, mission['name']))
  61. print("Units required:")
  62. for unit, count in mission['units'].items():
  63. print("\t- {} x{}".format(server_config['unit'][unit]['name'], count))
  64. print("Rewards:")
  65. print("\tResources:")
  66. for resource, amount in mission['rewards']['resources'].items():
  67. print("\t- {} x{}".format(resource, amount))
  68. print("-" * 20)
  69. option = 0
  70. opt_len = len(player_data['missions'])
  71. while option not in range(1, opt_len + 1):
  72. print("[1-{}] or 'c' to cancel: ".format(opt_len), end="", flush=True)
  73. try:
  74. option = input()
  75. if option == 'c':
  76. return
  77. else:
  78. option = int(option)
  79. except ValueError:
  80. print("Please enter an integer.")
  81. mission = player_data['missions'][option - 1]
  82. units_required = dict(mission['units'])
  83. units = list()
  84. if mission['type'] == 'gather':
  85. for i, unit in enumerate(player_data['units']):
  86. if unit['type'] in units_required.keys() and units_required[unit['type']] > 0:
  87. units.append(i)
  88. units_required[unit['type']] -= 1
  89. if sum(units_required.values()) == 0:
  90. send_json(self.ws, {
  91. 'type': "mission",
  92. 'index': option - 1,
  93. 'units': units,
  94. })
  95. else:
  96. print("Not enough units.")
  97. def do_logout(self, args):
  98. """Log out."""
  99. self.ws.close()
  100. return True
  101. def do_resources(self, args):
  102. """List available resources."""
  103. global player_data
  104. for resource, amount in player_data['resources'].items():
  105. print("{}: {} / {} ({}/s)".format(
  106. resource.title(),
  107. int(amount),
  108. player_data['resources_max'][resource],
  109. player_data['resources_production'][resource]
  110. ))
  111. def do_buildings(self, args):
  112. """List the buildings of the city and their levels."""
  113. global player_data
  114. global server_config
  115. any_building = False
  116. for name, level in player_data['buildings'].items():
  117. if level > 0:
  118. any_building = True
  119. print("{}, level {}".format(server_config['building'][name]['name'], level))
  120. if not any_building:
  121. print("There are no buildings in this city.")
  122. def do_units(self, args):
  123. """List available units."""
  124. global player_data
  125. global server_config
  126. if player_data['units']:
  127. for unit in player_data['units']:
  128. print("{}, level {}".format(server_config['unit'][unit['type']]['name'], unit['level']))
  129. else:
  130. print("There are no units in this city.")
  131. def do_exit(self, args):
  132. """Exits the program."""
  133. print("Exiting.")
  134. raise SystemExit
  135. def default(self, line):
  136. print("Unknown command: " + line)
  137. def emptyline(self):
  138. pass
  139. prompt = None
  140. def send_json(ws, message):
  141. ws.send(json.dumps(message))
  142. def on_message(ws, message):
  143. global player_data
  144. global server_config
  145. global prompt
  146. data = json.loads(message)
  147. if prompt is None and 'result' in data:
  148. if data['result'] == 0:
  149. prompt = MyPrompt(ws)
  150. prompt.prompt = '> '
  151. prompt.intro = 'Starting prompt...'
  152. _thread.start_new_thread(prompt.cmdloop, ())
  153. return
  154. elif data['result'] == 1:
  155. print("Unknown user/password combination.")
  156. elif data['result'] == 2:
  157. print("Username already taken.")
  158. elif data['result'] == 3:
  159. print("Not logged in.")
  160. ws.close()
  161. if 'username' in data:
  162. player_data = data
  163. elif 'server' in data:
  164. server_config = data
  165. def on_error(ws, error):
  166. print(error)
  167. def on_close(ws):
  168. global prompt
  169. print("### Connection to server closed ###")
  170. prompt = None
  171. connect()
  172. def on_open(username, password, register=False):
  173. def run(ws):
  174. send_json(ws, {
  175. 'type': "register" if register else "login",
  176. 'username': username,
  177. 'password': password,
  178. })
  179. return run
  180. def connect():
  181. ws = websocket.WebSocketApp("ws://localhost:6060",
  182. on_message = on_message,
  183. on_error = on_error,
  184. on_close = on_close)
  185. option = 0
  186. while option not in (1, 2):
  187. print("1. Login")
  188. print("2. Register")
  189. print("> ", end="", flush=True)
  190. try:
  191. option = int(input())
  192. except ValueError:
  193. print("Please enter an integer value.")
  194. continue
  195. print("Username: ", end="", flush=True)
  196. username = input()
  197. password = getpass()
  198. ws.on_open = on_open(username, password, option == 2)
  199. def run(*args):
  200. ws.run_forever()
  201. _thread.start_new_thread(run, ())
  202. def main():
  203. connect()
  204. while True:
  205. time.sleep(1)
  206. if __name__ == "__main__":
  207. main()