Added wifi handler for web setup.
Showing
6 changed files
with
258 additions
and
69 deletions
1 | 1 | ||
2 | global_aliases = { | ||
3 | 'n': 'north', | ||
4 | 's': 'south', | ||
5 | 'e': 'east', | ||
6 | 'w': 'west', | ||
7 | 'u': 'up', | ||
8 | 'd': 'down', | ||
9 | 'l': 'look', | ||
10 | } | ||
11 | |||
2 | class CommandHandler(object): | 12 | class CommandHandler(object): |
3 | 13 | ||
4 | def tokenize_params(self): | 14 | def tokenize_params(self): |
... | @@ -45,18 +55,89 @@ class CommandHandler(object): | ... | @@ -45,18 +55,89 @@ class CommandHandler(object): |
45 | 55 | ||
46 | return True | 56 | return True |
47 | 57 | ||
48 | def parse(self, id, cmd, params, room, mud, players): | 58 | def who(self): |
59 | self.mud.send_message(self.id, "") | ||
60 | self.mud.send_message(self.id, "-------- {} Players Currently Online --------".format(len(self.players))) | ||
61 | for pid, player in self.players.items(): | ||
62 | self.mud.send_message(self.id, " " + player["name"]) | ||
63 | self.mud.send_message(self.id, "---------------------------------------------".format(len(self.players))) | ||
64 | self.mud.send_message(self.id, "") | ||
65 | return True | ||
66 | |||
67 | def go(self): | ||
68 | # store the exit name | ||
69 | ex = self.params.lower().strip() | ||
70 | |||
71 | # if the specified exit is found in the room's exits list | ||
72 | if ex in self.room.get_exits(): | ||
73 | # go through all the players in the game | ||
74 | for pid, pl in self.players.items(): | ||
75 | # if player is in the same room and isn't the player | ||
76 | # sending the command | ||
77 | if self.players[pid]["room"] == self.players[self.id]["room"] \ | ||
78 | and pid != self.id: | ||
79 | # send them a message telling them that the player | ||
80 | # left the room | ||
81 | self.mud.send_message(pid, "{} left via exit '{}'".format( | ||
82 | self.players[self.id]["name"], ex)) | ||
83 | |||
84 | # update the player's current room to the one the exit leads to | ||
85 | loaded = self.load_room(self.room.get_exits()[ex]) | ||
86 | if loaded == None: | ||
87 | self.mud.send_message(id, "An invisible force prevents you from going in that direction.") | ||
88 | return True | ||
89 | else: | ||
90 | self.players[self.id]["room"] = self.room.get_exits()[ex] | ||
91 | self.room = loaded | ||
92 | |||
93 | # go through all the players in the game | ||
94 | for pid, pl in self.players.items(): | ||
95 | # if player is in the same (new) room and isn't the player | ||
96 | # sending the command | ||
97 | if self.players[pid]["room"] == self.players[self.id]["room"] \ | ||
98 | and pid != self.id: | ||
99 | # send them a message telling them that the player | ||
100 | # entered the room | ||
101 | self.mud.send_message(pid, | ||
102 | "{} arrived via exit '{}'".format( | ||
103 | self.players[self.id]["name"], ex)) | ||
104 | |||
105 | # send the player a message telling them where they are now | ||
106 | self.mud.send_message(id, "You arrive at '{}'".format(self.room.get_title())) | ||
107 | |||
108 | # the specified exit wasn't found in the current room | ||
109 | else: | ||
110 | # send back an 'unknown exit' message | ||
111 | self.mud.send_message(id, "Unknown exit '{}'".format(ex)) | ||
112 | return True | ||
113 | |||
114 | |||
115 | def alias(self, command): | ||
116 | if command in global_aliases: | ||
117 | return global_aliases[command] | ||
118 | if 'aliases' not in self.players[self.id]: | ||
119 | self.players[self.id]["aliases"] = {} | ||
120 | if command in self.players[self.id]["aliases"]: | ||
121 | return self.players[self.id]["aliases"][command] | ||
122 | return command | ||
123 | |||
124 | def parse(self, id, cmd, params, room, mud, players, load_room): | ||
49 | self.id = id | 125 | self.id = id |
50 | self.cmd = cmd | ||
51 | self.params = params | 126 | self.params = params |
52 | self.tokenize_params() | 127 | self.tokenize_params() |
53 | self.room = room | 128 | self.room = room |
54 | self.mud = mud | 129 | self.mud = mud |
55 | self.players = players | 130 | self.players = players |
131 | self.load_room = load_room | ||
132 | self.cmd = self.alias(cmd) | ||
56 | 133 | ||
57 | try: | 134 | try: |
58 | method = getattr(self, cmd) | 135 | if self.cmd in self.room.get_exits(): |
136 | self.params = self.cmd + " " + self.params | ||
137 | self.cmd = "go" | ||
138 | method = getattr(self, self.cmd) | ||
59 | return method() | 139 | return method() |
60 | except AttributeError: | 140 | except AttributeError: |
141 | mud.send_message(id, "Unknown command '{}'".format(self.cmd)) | ||
61 | return False | 142 | return False |
62 | 143 | ... | ... |
... | @@ -2,5 +2,6 @@ Commands: | ... | @@ -2,5 +2,6 @@ Commands: |
2 | say <message> - Says something out loud, e.g. 'say Hello' | 2 | say <message> - Says something out loud, e.g. 'say Hello' |
3 | look - Examines the surroundings, e.g. 'look' | 3 | look - Examines the surroundings, e.g. 'look' |
4 | go <exit> - Moves through the exit specified, e.g. 'go outside' | 4 | go <exit> - Moves through the exit specified, e.g. 'go outside' |
5 | who - Lists all players currently connected | ||
5 | save - Saves your character | 6 | save - Saves your character |
6 | quit - Saves your character then closes the connection | 7 | quit - Saves your character then closes the connection |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -25,13 +25,15 @@ import time | ... | @@ -25,13 +25,15 @@ import time |
25 | # import datetime | 25 | # import datetime |
26 | #import io | 26 | #import io |
27 | import json | 27 | import json |
28 | 28 | import machine | |
29 | # import the MUD server class | 29 | # import the MUD server class |
30 | from mudserver import MudServer | 30 | from mudserver import MudServer |
31 | from commands import CommandHandler | 31 | from commands import CommandHandler |
32 | 32 | ||
33 | print('STARTING MUD\r\n\r\n\r\n') | 33 | print('STARTING MUD\r\n\r\n\r\n') |
34 | 34 | ||
35 | flash_button = machine.Pin(0, machine.Pin.IN, machine.Pin.PULL_UP) | ||
36 | |||
35 | rooms = {} | 37 | rooms = {} |
36 | 38 | ||
37 | # stores the players in the game | 39 | # stores the players in the game |
... | @@ -62,7 +64,7 @@ def load_room(room_name): | ... | @@ -62,7 +64,7 @@ def load_room(room_name): |
62 | 64 | ||
63 | def save_object_to_file(obj, filename): | 65 | def save_object_to_file(obj, filename): |
64 | with open(filename, 'w', encoding='utf-8') as f: | 66 | with open(filename, 'w', encoding='utf-8') as f: |
65 | f.write(json.dumps(obj, ensure_ascii=False)) | 67 | f.write(json.dumps(obj)) |
66 | 68 | ||
67 | def load_object_from_file(filename): | 69 | def load_object_from_file(filename): |
68 | try: | 70 | try: |
... | @@ -78,7 +80,9 @@ def prompt(pid): | ... | @@ -78,7 +80,9 @@ def prompt(pid): |
78 | 80 | ||
79 | # main game loop. We loop forever (i.e. until the program is terminated) | 81 | # main game loop. We loop forever (i.e. until the program is terminated) |
80 | while True: | 82 | while True: |
81 | 83 | gc.collect() | |
84 | if flash_button.value() == 0: | ||
85 | break | ||
82 | # pause for 1/5 of a second on each loop, so that we don't constantly | 86 | # pause for 1/5 of a second on each loop, so that we don't constantly |
83 | # use 100% CPU time | 87 | # use 100% CPU time |
84 | time.sleep(0.001) | 88 | time.sleep(0.001) |
... | @@ -97,6 +101,8 @@ while True: | ... | @@ -97,6 +101,8 @@ while True: |
97 | # go through any newly connected players | 101 | # go through any newly connected players |
98 | for id in mud.get_new_players(): | 102 | for id in mud.get_new_players(): |
99 | 103 | ||
104 | |||
105 | |||
100 | # add the new player to the dictionary, noting that they've not been | 106 | # add the new player to the dictionary, noting that they've not been |
101 | # named yet. | 107 | # named yet. |
102 | # The dictionary key is the player's id number. We set their room to | 108 | # The dictionary key is the player's id number. We set their room to |
... | @@ -105,8 +111,9 @@ while True: | ... | @@ -105,8 +111,9 @@ while True: |
105 | players[id] = { | 111 | players[id] = { |
106 | "name": None, | 112 | "name": None, |
107 | "room": None, | 113 | "room": None, |
108 | "inventory": None, | 114 | "inventory": {}, |
109 | "prompt": "> ", | 115 | "prompt": "> ", |
116 | "aliases": {}, | ||
110 | } | 117 | } |
111 | 118 | ||
112 | # send the new player a prompt for their name | 119 | # send the new player a prompt for their name |
... | @@ -124,8 +131,11 @@ while True: | ... | @@ -124,8 +131,11 @@ while True: |
124 | for pid, pl in players.items(): | 131 | for pid, pl in players.items(): |
125 | # send each player a message to tell them about the diconnected | 132 | # send each player a message to tell them about the diconnected |
126 | # player | 133 | # player |
127 | mud.send_message(pid, "{} quit the game".format( | 134 | if players[id]["name"] != None: |
135 | mud.send_message(pid, "{} quit the game".format( | ||
128 | players[id]["name"])) | 136 | players[id]["name"])) |
137 | else: | ||
138 | save_object_to_file(players[id], "players/{}.json".format(players[id]["name"])) | ||
129 | 139 | ||
130 | # remove the player's entry in the player dictionary | 140 | # remove the player's entry in the player dictionary |
131 | del(players[id]) | 141 | del(players[id]) |
... | @@ -143,7 +153,9 @@ while True: | ... | @@ -143,7 +153,9 @@ while True: |
143 | # if the player hasn't given their name yet, use this first command as | 153 | # if the player hasn't given their name yet, use this first command as |
144 | # their name and move them to the starting room. | 154 | # their name and move them to the starting room. |
145 | if players[id]["name"] is None: | 155 | if players[id]["name"] is None: |
146 | 156 | if command.strip() == '' or command is None: | |
157 | mud.send_message(id, "Invalid Name") | ||
158 | continue | ||
147 | loaded_player = load_object_from_file("players/{}.json".format(command)) | 159 | loaded_player = load_object_from_file("players/{}.json".format(command)) |
148 | if loaded_player is None: | 160 | if loaded_player is None: |
149 | players[id]["name"] = command | 161 | players[id]["name"] = command |
... | @@ -204,65 +216,12 @@ while True: | ... | @@ -204,65 +216,12 @@ while True: |
204 | players[id]["name"], params)) | 216 | players[id]["name"], params)) |
205 | 217 | ||
206 | # 'look' command | 218 | # 'look' command |
207 | elif cmd_handler.parse(id, command, params, rm, mud, players): | 219 | else: |
208 | |||
209 | pass | ||
210 | |||
211 | # 'go' command | ||
212 | elif command == "go": | ||
213 | |||
214 | # store the exit name | ||
215 | ex = params.lower() | ||
216 | |||
217 | # store the player's current room | ||
218 | rm = load_room(players[id]["room"]) | ||
219 | |||
220 | # if the specified exit is found in the room's exits list | ||
221 | if ex in rm.get_exits(): | ||
222 | |||
223 | # go through all the players in the game | ||
224 | for pid, pl in players.items(): | ||
225 | # if player is in the same room and isn't the player | ||
226 | # sending the command | ||
227 | if players[pid]["room"] == players[id]["room"] \ | ||
228 | and pid != id: | ||
229 | # send them a message telling them that the player | ||
230 | # left the room | ||
231 | mud.send_message(pid, "{} left via exit '{}'".format( | ||
232 | players[id]["name"], ex)) | ||
233 | |||
234 | # update the player's current room to the one the exit leads to | ||
235 | loaded = load_room(rm.get_exits()[ex]) | ||
236 | if loaded == None: | ||
237 | mud.send_message(id, "An invisible force prevents you from going in that direction.") | ||
238 | continue | ||
239 | else: | ||
240 | players[id]["room"] = rm.get_exits()[ex] | ||
241 | rm = loaded | ||
242 | |||
243 | # go through all the players in the game | ||
244 | for pid, pl in players.items(): | ||
245 | # if player is in the same (new) room and isn't the player | ||
246 | # sending the command | ||
247 | if players[pid]["room"] == players[id]["room"] \ | ||
248 | and pid != id: | ||
249 | # send them a message telling them that the player | ||
250 | # entered the room | ||
251 | mud.send_message(pid, | ||
252 | "{} arrived via exit '{}'".format( | ||
253 | players[id]["name"], ex)) | ||
254 | |||
255 | # send the player a message telling them where they are now | ||
256 | mud.send_message(id, "You arrive at '{}'".format(rm.get_title())) | ||
257 | |||
258 | # the specified exit wasn't found in the current room | ||
259 | else: | ||
260 | # send back an 'unknown exit' message | ||
261 | mud.send_message(id, "Unknown exit '{}'".format(ex)) | ||
262 | 220 | ||
221 | handler_results = cmd_handler.parse(id, command, params, rm, mud, players, load_room) | ||
263 | 222 | ||
264 | # some other, unrecognised command | ||
265 | else: | ||
266 | # send back an 'unknown command' message | ||
267 | mud.send_message(id, "Unknown command '{}'".format(command)) | ||
268 | prompt(id) | 223 | prompt(id) |
224 | |||
225 | # Start WIFI Setup | ||
226 | if flash_button.value() == 0: | ||
227 | import wifiweb | ||
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -324,7 +324,8 @@ class MudServer(object): | ... | @@ -324,7 +324,8 @@ class MudServer(object): |
324 | 324 | ||
325 | # if there is a problem reading from the socket (e.g. the client | 325 | # if there is a problem reading from the socket (e.g. the client |
326 | # has disconnected) a socket error will be raised | 326 | # has disconnected) a socket error will be raised |
327 | except socket.error: | 327 | except Exception as e: |
328 | sys.print_exception(e) | ||
328 | self._handle_disconnect(id) | 329 | self._handle_disconnect(id) |
329 | 330 | ||
330 | def _handle_disconnect(self, clid): | 331 | def _handle_disconnect(self, clid): | ... | ... |
rooms/outside.py
0 → 100644
1 | from .baseroom import BaseRoom | ||
2 | |||
3 | class Outside(BaseRoom): | ||
4 | |||
5 | def __init__(self): | ||
6 | |||
7 | title = "Outside the Tavern" | ||
8 | description = "You are standing outside of a simple tavern made of pressed clay and shale roof. \r\nThe door becons you to come in and have a drink." | ||
9 | exits = {"tavern": "Tavern"} | ||
10 | look_items = { | ||
11 | "tavern": "A roughly constructed building.", | ||
12 | } | ||
13 | |||
14 | super(Outside, self).__init__(title, description, exits, look_items) |
wifiweb.py
0 → 100644
1 | |||
2 | import network | ||
3 | import socket | ||
4 | import machine | ||
5 | import time | ||
6 | |||
7 | ap = network.WLAN(network.AP_IF) | ||
8 | ap.active(True) | ||
9 | ap.config(essid='MUD') | ||
10 | ap.config(authmode=1) | ||
11 | |||
12 | class DNSQuery: | ||
13 | def __init__(self, data): | ||
14 | self.data=data | ||
15 | self.dominio='' | ||
16 | |||
17 | print("Reading datagram data...") | ||
18 | m = data[2] # ord(data[2]) | ||
19 | tipo = (m >> 3) & 15 # Opcode bits | ||
20 | if tipo == 0: # Standard query | ||
21 | ini=12 | ||
22 | lon=data[ini] # ord(data[ini]) | ||
23 | while lon != 0: | ||
24 | self.dominio+=data[ini+1:ini+lon+1].decode("utf-8") +'.' | ||
25 | ini+=lon+1 | ||
26 | lon=data[ini] #ord(data[ini]) | ||
27 | |||
28 | def respuesta(self, ip): | ||
29 | packet=b'' | ||
30 | print("Resposta {} == {}".format(self.dominio, ip)) | ||
31 | if self.dominio: | ||
32 | packet+=self.data[:2] + b"\x81\x80" | ||
33 | packet+=self.data[4:6] + self.data[4:6] + b'\x00\x00\x00\x00' # Questions and Answers Counts | ||
34 | packet+=self.data[12:] # Original Domain Name Question | ||
35 | packet+= b'\xc0\x0c' # Pointer to domain name | ||
36 | packet+= b'\x00\x01\x00\x01\x00\x00\x00\x3c\x00\x04' # Response type, ttl and resource data length -> 4 bytes | ||
37 | packet+=bytes(map(int,ip.split('.'))) # 4 bytes of IP | ||
38 | return packet | ||
39 | |||
40 | def accept_conn(listen_sock): | ||
41 | cl, addr = listen_sock.accept() | ||
42 | print('client connected from', addr) | ||
43 | print('Request:') | ||
44 | request = cl.recv(2048) | ||
45 | print(request) | ||
46 | if 'GET /?' in request: | ||
47 | #GET /?network=Volley&networkpass=test | ||
48 | request = str(request) | ||
49 | part = request.split(' ')[1] | ||
50 | params = part.split('?')[1].split('&') | ||
51 | network_param = params[0].split('=')[1] | ||
52 | network_pass_param = params[1].split('=')[1] | ||
53 | |||
54 | sta_if = network.WLAN(network.STA_IF) | ||
55 | sta_if.active(True) | ||
56 | sta_if.connect(network_param, network_pass_param) | ||
57 | while sta_if.isconnected() == False: | ||
58 | time.sleep(1) | ||
59 | cl.send('<html><body>Configuration Saved!<br><br>Network: {} <br>IP Address: {}<br>Password: {}<br><br><br>Restarting Device...</body></html>'.format(network_param, sta_if.ifconfig()[0], network_pass_param)) | ||
60 | cl.close() | ||
61 | time.sleep(20) | ||
62 | machine.reset() | ||
63 | return | ||
64 | print('Getting Network STA_IF') | ||
65 | sta_if = network.WLAN(network.STA_IF) | ||
66 | print('Starting Network Scan...') | ||
67 | avail_networks = sta_if.scan() | ||
68 | print('Network Scan Complete') | ||
69 | endpoint_string = "" | ||
70 | for endpoint in avail_networks: | ||
71 | endpoint_string += "<option value={}>{}</option>".format(endpoint[0].decode('latin1'), endpoint[0].decode('latin1')) | ||
72 | response = """ | ||
73 | <html> | ||
74 | <head> | ||
75 | <title>Mud Setup</title> | ||
76 | </head> | ||
77 | <body margin='10px'> | ||
78 | <h2>Configure Wifi Network</h2> | ||
79 | <form action='/' method='GET'> | ||
80 | Network: <select name='network' id='network'> | ||
81 | {} | ||
82 | </select><br><br> | ||
83 | Password: <input type='text' name='networkpass' id='networkpass'> | ||
84 | <input type="submit"> | ||
85 | </form> | ||
86 | </body> | ||
87 | </html> | ||
88 | \n\n""".format(endpoint_string) | ||
89 | # rows = ['<tr><td>%s</td><td>%d</td></tr>' % (str(p), p.value()) for p in pins] | ||
90 | # response = html % '\n'.join(rows) | ||
91 | print('Sending Response') | ||
92 | cl.send(response) | ||
93 | print('Closing Socket') | ||
94 | time.sleep(0.001) | ||
95 | cl.close() | ||
96 | |||
97 | listen_s = None | ||
98 | |||
99 | port = 80 | ||
100 | |||
101 | s = socket.socket() | ||
102 | |||
103 | ai = socket.getaddrinfo("0.0.0.0", port) | ||
104 | addr = ai[0][4] | ||
105 | |||
106 | s.bind(addr) | ||
107 | s.listen(1) | ||
108 | s.setsockopt(socket.SOL_SOCKET, 20, accept_conn) | ||
109 | iface = network.WLAN(network.AP_IF) | ||
110 | if iface.active(): | ||
111 | print("Web Server daemon started on ws://%s:%d" % (iface.ifconfig()[0], port)) | ||
112 | |||
113 | |||
114 | # def accept_dns(listen_sock): | ||
115 | # cl, addr = listen_sock.accept() | ||
116 | # print('DNS client connected from', addr) | ||
117 | # try: | ||
118 | # data, addr = udps.recvfrom(1024) | ||
119 | # print("incomming datagram...") | ||
120 | # p=DNSQuery(data) | ||
121 | # udps.sendto(p.respuesta(ip), addr) | ||
122 | # print('Replying: {:s} -> {:s}'.format(p.dominio, ip)) | ||
123 | # except: | ||
124 | # print('No dgram') | ||
125 | |||
126 | # # SETUP DNS | ||
127 | # ip=ap.ifconfig()[0] | ||
128 | # print('DNS Server: dom.query. 60 IN A {:s}'.format(ip)) | ||
129 | |||
130 | # udps = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | ||
131 | # udps.setblocking(False) | ||
132 | # udps.bind(('',53)) | ||
133 | # udps.setsockopt(socket.SOL_SOCKET, 20, accept_dns) |
-
Please register or sign in to post a comment