38
38
import Utils
39
39
from Utils import version_tuple , restricted_loads , Version , async_start
40
40
from NetUtils import Endpoint , ClientStatus , NetworkItem , decode , encode , NetworkPlayer , Permission , NetworkSlot , \
41
- SlotType
41
+ SlotType , LocationStore
42
42
43
43
min_client_version = Version (0 , 1 , 6 )
44
44
colorama .init ()
@@ -152,7 +152,9 @@ class Context:
152
152
"compatibility" : int }
153
153
# team -> slot id -> list of clients authenticated to slot.
154
154
clients : typing .Dict [int , typing .Dict [int , typing .List [Client ]]]
155
- locations : typing .Dict [int , typing .Dict [int , typing .Tuple [int , int , int ]]]
155
+ locations : LocationStore # typing.Dict[int, typing.Dict[int, typing.Tuple[int, int, int]]]
156
+ location_checks : typing .Dict [typing .Tuple [int , int ], typing .Set [int ]]
157
+ hints_used : typing .Dict [typing .Tuple [int , int ], int ]
156
158
groups : typing .Dict [int , typing .Set [int ]]
157
159
save_version = 2
158
160
stored_data : typing .Dict [str , object ]
@@ -187,8 +189,6 @@ def __init__(self, host: str, port: int, server_password: str, password: str, lo
187
189
self .player_name_lookup : typing .Dict [str , team_slot ] = {}
188
190
self .connect_names = {} # names of slots clients can connect to
189
191
self .allow_releases = {}
190
- # player location_id item_id target_player_id
191
- self .locations = {}
192
192
self .host = host
193
193
self .port = port
194
194
self .server_password = server_password
@@ -284,6 +284,7 @@ async def send_msgs(self, endpoint: Endpoint, msgs: typing.Iterable[dict]) -> bo
284
284
except websockets .ConnectionClosed :
285
285
logging .exception (f"Exception during send_msgs, could not send { msg } " )
286
286
await self .disconnect (endpoint )
287
+ return False
287
288
else :
288
289
if self .log_network :
289
290
logging .info (f"Outgoing message: { msg } " )
@@ -297,6 +298,7 @@ async def send_encoded_msgs(self, endpoint: Endpoint, msg: str) -> bool:
297
298
except websockets .ConnectionClosed :
298
299
logging .exception ("Exception during send_encoded_msgs" )
299
300
await self .disconnect (endpoint )
301
+ return False
300
302
else :
301
303
if self .log_network :
302
304
logging .info (f"Outgoing message: { msg } " )
@@ -311,6 +313,7 @@ async def broadcast_send_encoded_msgs(self, endpoints: typing.Iterable[Endpoint]
311
313
websockets .broadcast (sockets , msg )
312
314
except RuntimeError :
313
315
logging .exception ("Exception during broadcast_send_encoded_msgs" )
316
+ return False
314
317
else :
315
318
if self .log_network :
316
319
logging .info (f"Outgoing broadcast: { msg } " )
@@ -413,7 +416,7 @@ def _load(self, decoded_obj: dict, game_data_packages: typing.Dict[str, typing.A
413
416
self .seed_name = decoded_obj ["seed_name" ]
414
417
self .random .seed (self .seed_name )
415
418
self .connect_names = decoded_obj ['connect_names' ]
416
- self .locations = decoded_obj [ ' locations' ]
419
+ self .locations = LocationStore ( decoded_obj . pop ( " locations" )) # pre-emptively free memory
417
420
self .slot_data = decoded_obj ['slot_data' ]
418
421
for slot , data in self .slot_data .items ():
419
422
self .read_data [f"slot_data_{ slot } " ] = lambda data = data : data
@@ -902,11 +905,7 @@ def release_player(ctx: Context, team: int, slot: int):
902
905
903
906
def collect_player (ctx : Context , team : int , slot : int , is_group : bool = False ):
904
907
"""register any locations that are in the multidata, pointing towards this player"""
905
- all_locations = collections .defaultdict (set )
906
- for source_slot , location_data in ctx .locations .items ():
907
- for location_id , values in location_data .items ():
908
- if values [1 ] == slot :
909
- all_locations [source_slot ].add (location_id )
908
+ all_locations = ctx .locations .get_for_player (slot )
910
909
911
910
ctx .broadcast_text_all ("%s (Team #%d) has collected their items from other worlds."
912
911
% (ctx .player_names [(team , slot )], team + 1 ),
@@ -925,11 +924,7 @@ def collect_player(ctx: Context, team: int, slot: int, is_group: bool = False):
925
924
926
925
927
926
def get_remaining (ctx : Context , team : int , slot : int ) -> typing .List [int ]:
928
- items = []
929
- for location_id in ctx .locations [slot ]:
930
- if location_id not in ctx .location_checks [team , slot ]:
931
- items .append (ctx .locations [slot ][location_id ][0 ]) # item ID
932
- return sorted (items )
927
+ return ctx .locations .get_remaining (ctx .location_checks , team , slot )
933
928
934
929
935
930
def send_items_to (ctx : Context , team : int , target_slot : int , * items : NetworkItem ):
@@ -977,13 +972,12 @@ def collect_hints(ctx: Context, team: int, slot: int, item: typing.Union[int, st
977
972
slots .add (group_id )
978
973
979
974
seeked_item_id = item if isinstance (item , int ) else ctx .item_names_for_game (ctx .games [slot ])[item ]
980
- for finding_player , check_data in ctx .locations .items ():
981
- for location_id , (item_id , receiving_player , item_flags ) in check_data .items ():
982
- if receiving_player in slots and item_id == seeked_item_id :
983
- found = location_id in ctx .location_checks [team , finding_player ]
984
- entrance = ctx .er_hint_data .get (finding_player , {}).get (location_id , "" )
985
- hints .append (NetUtils .Hint (receiving_player , finding_player , location_id , item_id , found , entrance ,
986
- item_flags ))
975
+ for finding_player , location_id , item_id , receiving_player , item_flags \
976
+ in ctx .locations .find_item (slots , seeked_item_id ):
977
+ found = location_id in ctx .location_checks [team , finding_player ]
978
+ entrance = ctx .er_hint_data .get (finding_player , {}).get (location_id , "" )
979
+ hints .append (NetUtils .Hint (receiving_player , finding_player , location_id , item_id , found , entrance ,
980
+ item_flags ))
987
981
988
982
return hints
989
983
@@ -1555,15 +1549,11 @@ def _cmd_hint_location(self, location: str = "") -> bool:
1555
1549
1556
1550
1557
1551
def get_checked_checks (ctx : Context , team : int , slot : int ) -> typing .List [int ]:
1558
- return [location_id for
1559
- location_id in ctx .locations [slot ] if
1560
- location_id in ctx .location_checks [team , slot ]]
1552
+ return ctx .locations .get_checked (ctx .location_checks , team , slot )
1561
1553
1562
1554
1563
1555
def get_missing_checks (ctx : Context , team : int , slot : int ) -> typing .List [int ]:
1564
- return [location_id for
1565
- location_id in ctx .locations [slot ] if
1566
- location_id not in ctx .location_checks [team , slot ]]
1556
+ return ctx .locations .get_missing (ctx .location_checks , team , slot )
1567
1557
1568
1558
1569
1559
def get_client_points (ctx : Context , client : Client ) -> int :
0 commit comments