def test_push1(self): df1 = Dataframe("TEST1", [Car]) df2 = Dataframe("TEST2", [Car], details=df1.details) appname1 = df1.appname appname2 = df2.appname c = Car(0) df2.checkout() df2.add_one(Car, c) c.xvel = 1 df2.sync() version1 = df1.versioned_heap.version_graph.head.current version2 = df2.versioned_heap.version_graph.head.current self.assertEqual(version1, version2) self.assertDictEqual(df1.versioned_heap.state_to_app, { "ROOT": set([appname2]), version1: set([appname2]) }) self.assertDictEqual(df1.versioned_heap.app_to_state, {appname2: version1}) self.assertDictEqual(df2.versioned_heap.state_to_app, { 'ROOT': {appname2}, version1: {'SOCKETPARENT', appname2} }) self.assertDictEqual(df2.versioned_heap.app_to_state, { appname2: version1, "SOCKETPARENT": version1 })
def test_push1(self): df1 = Dataframe("TEST1", [Car]) df2 = Dataframe("TEST2", [Car], details=df1.details) appname1 = df1.appname appname2 = df2.appname c = Car(0) df2.checkout() df2.add_one(Car, c) c.xvel = 1 df2.sync() version1 = df1.versioned_heap.version_graph.head.current version2 = df2.versioned_heap.version_graph.head.current self.assertEqual(version1, version2) self.assertDictEqual( df1.versioned_heap.state_to_app, {"ROOT": set([appname2]), version1: set([appname2])}) self.assertDictEqual( df1.versioned_heap.app_to_state, {appname2: version1}) self.assertDictEqual( df2.versioned_heap.state_to_app, {'ROOT': {appname2}, version1: {'SOCKETPARENT', appname2}}) self.assertDictEqual( df2.versioned_heap.app_to_state, {appname2: version1, "SOCKETPARENT": version1})
def test_basic(self): df = Dataframe("TEST", [Car]) c = Car(0) df.checkout() df.add_one(Car, c) c.xvel = 1 self.assertFalse("xvel" in c.__dict__) self.assertFalse("yvel" in c.__dict__) self.assertFalse("xpos" in c.__dict__) self.assertFalse("ypos" in c.__dict__) self.assertFalse("oid" in c.__dict__) self.assertTrue(hasattr(c, "__r_df__")) self.assertEqual(df.local_heap, c.__r_df__) self.assertEqual(c.xvel, 1) self.assertEqual(c.yvel, 0) self.assertEqual(c.xpos, 0) self.assertEqual(c.ypos, 0) self.assertEqual(c.oid, 0)
def __call__(self, main_func: Callable): # Get the dimensions required for the player dataframe start_time = time() while self.time_out == 0 or (time() - start_time) < self.time_out: try: while True: try: df = Dataframe("dimension_getter", [ServerState], details=(self.host, self.port)) except ConnectionRefusedError as e: if (time() - start_time) > self.time_out: raise e else: break df.pull() df.checkout() if df.read_all(ServerState)[0].server_no_longer_joinable: # This server is from an old game and just hasn't exited yet, wait for a new server. sleep(0.1) continue else: break except (ConnectionResetError, struct.error): sleep(0.1) continue # If we know what game were supposed to be playing, then check to make sure # we match the server environment server_state = df.read_all(ServerState)[0] environment_name = server_state.env_class_name dimension_names: [str] = server_state.env_dimensions if self.server_environment is not None and self.server_environment.__name__ != environment_name: raise ValueError( "Client and Server environment mismatch. We are using: {}. Server is using: {}" .format(self.server_environment.__name__, environment_name)) # Create the correct observation type for our connecting dataframe observation_class = Observation(dimension_names) del df def app(*args, **kwargs): client = Node(client_app, dataframe=(self.host, self.port), Types=[Player, observation_class, ServerState], threading=True) client.start(self, main_func, observation_class, dimension_names, self.host, self.auth_key, *args, **kwargs) return app
def server_df6(send_q, recv_q, server_ready, client_ready): df = Dataframe("SERVER_TEST6", [ClassWithCounter, Counter], resolver={Counter: counter_merge_func}) send_q.put(df.details) client_name = recv_q.get() # The server goes first. df.checkout() c1 = ClassWithCounter(0) df.add_one(Counter, c1.counter) df.add_one(ClassWithCounter, c1) c1.counter.count += 1 # Push record into server. df.commit() # Setting point C1 server_ready.set() # Client # Pull and read the changes. # Waiting at point S1 client_ready.wait() client_ready.clear()
def server_df6(send_q, recv_q, server_ready, client_ready): df = Dataframe("SERVER_TEST6", [ClassWithCounter, Counter]) send_q.put(df.details) client_name = recv_q.get() # The server goes first. df.checkout() c1 = ClassWithCounter(0) df.add_one(Counter, c1.counter) df.add_one(ClassWithCounter, c1) c1.counter.count += 1 # Push record into server. df.commit() # Setting point C1 server_ready.set() # Client # Pull and read the changes. # Waiting at point S1 client_ready.wait() client_ready.clear()
def __call__(self, main_func: Callable): # Get the dimensions required for the player dataframe start_time = time() while self.time_out == 0 or (time() - start_time) < self.time_out: try: while True: try: df = Dataframe("dimension_getter", [ServerState], details=(self.host, self.port)) except ConnectionRefusedError as e: if (time() - start_time) > self.time_out: raise e else: break df.pull() df.checkout() if df.read_all(ServerState)[0].server_no_longer_joinable: # This server is from an old game and just hasn't exited yet, wait for a new server. sleep(0.1) continue else: break except (ConnectionResetError, struct.error): sleep(0.1) continue dimension_names: [str] = df.read_all(ServerState)[0].env_dimensions observation_class = Observation(dimension_names) del df def app(*args, **kwargs): client = Node(client_app, dataframe=(self.host, self.port), Types=[Player, observation_class, ServerState]) client.start(self, main_func, observation_class, dimension_names, self.host, self.auth_key, *args, **kwargs) return app
def client_df6(send_q, recv_q, server_ready, client_ready): server_name = recv_q.get() df = Dataframe("CLIENT_TEST", [ClassWithCounter, Counter], details=server_name, resolver={Counter: counter_merge_func}) send_q.put(df.details) # Waiting at point C1 server_ready.wait() server_ready.clear() # Pull from the server. df.pull() df.checkout() ccs = df.read_all(ClassWithCounter) assert (1 == len(ccs)) c = ccs[0] assert ("counter" not in c.__dict__) assert ("oid" not in c.__dict__) assert (c.counter.oid is 0) assert (c.counter.count is 1) assert (c.oid is 0) df.commit() # Setting point S1 client_ready.set()
def client_df6(send_q, recv_q, server_ready, client_ready): server_name = recv_q.get() df = Dataframe("CLIENT_TEST", [ClassWithCounter, Counter], details=server_name) send_q.put(df.details) # Waiting at point C1 server_ready.wait() server_ready.clear() # Pull from the server. df.pull() df.checkout() ccs = df.read_all(ClassWithCounter) assert (1 == len(ccs)) c = ccs[0] assert ("counter" not in c.__dict__) assert ("oid" not in c.__dict__) assert (c.counter.oid is 0) assert (c.counter.count is 1) assert (c.oid is 0) df.commit() # Setting point S1 client_ready.set()
def client_df7(send_q, recv_q, server_ready, client_ready): server_name = recv_q.get() df = Dataframe("CLIENT_TEST", [Blocker], details=server_name) send_q.put(df.details) #print ("Client at start:", df.versioned_heap.version_graph.nodes.keys()) # Waiting at point C1 #print ("Waiting for C1") server_ready.wait() server_ready.clear() #print ("Client after waiting for server first time.:", df.versioned_heap.version_graph.nodes.keys()) # Pull from the server. df.pull() #print ("Client after first pull:", df.versioned_heap.version_graph.nodes.keys()) df.checkout() blockers = df.read_all(Blocker) assert (1 == len(blockers)) b1 = blockers[0] assert (b1.prop == 1) #print ("Setting S1") # Setting point S1 client_ready.set() b1.prop = 10 assert (b1.prop == 10) df.commit() #print ("Client after first modification:", df.versioned_heap.version_graph.nodes.keys()) # Waiting at point C2 #print ("Waiting for C2") server_ready.wait() server_ready.clear() #print ("Client after waiting for server:", df.versioned_heap.version_graph.nodes.keys()) df.push() #print ("Client after pushing:", df.versioned_heap.version_graph.nodes.keys()) # Setting point S2 #print ("Setting S2") client_ready.set() # Waiting at point c3 #print ("Waiting for C3") server_ready.wait() server_ready.clear() df.pull() #print ("Client after pulling second time:", df.versioned_heap.version_graph.nodes.keys()) df.checkout() assert (b1.prop == 10) b1.prop = 5 df.commit() df.push() # Setting point S3 #print ("Setting S3") client_ready.set() # Waiting at point c4 #print ("Waiting for C4") server_ready.wait() server_ready.clear()
def server_df7(send_q, recv_q, server_ready, client_ready): df = Dataframe("SERVER_TEST7", [Blocker], resolver={Blocker: blocker_merge_func}) send_q.put(df.details) client_name = recv_q.get() # The server goes first. #print ("Server at start:", df.versioned_heap.version_graph.nodes.keys()) df.checkout() #Add Counter to server b1 = Blocker(0) df.add_many(Blocker, [b1]) assert (b1.prop == 0) b1.prop += 1 assert (b1.prop == 1) # Push record into server. df.commit() #print ("Server after adding 2 cars:", df.versioned_heap.version_graph.nodes.keys()) # Setting point C1 #print ("Setting C1") server_ready.set() # Waiting at point S1 #print ("Waiting for S1") client_ready.wait() client_ready.clear() #print ("Server after waiting for client first time:", df.versioned_heap.version_graph.nodes.keys()) #print (df.versioned_heap.state_to_app) df.checkout() assert (b1.prop == 1) b1.prop += 1 assert (b1.prop == 2) df.commit() #print (df.versioned_heap.state_to_app) #print ("Server after modifying once:", df.versioned_heap.version_graph.nodes.keys()) # Setting point C2 #print ("Setting C2") server_ready.set() # Waiting at point S2 #print ("Waiting for S2") client_ready.wait() client_ready.clear() #print ("Server after waiting for client second time.:", df.versioned_heap.version_graph.nodes.keys()) # Check how the merge worked out. df.checkout() assert (b1.prop == 10), b1.prop # Setting point C3 #print ("Setting C3") server_ready.set() # Waiting at point S3 #print ("Waiting for S3") client_ready.wait() client_ready.clear() assert (b1.prop == 10) b1.prop = 20 assert (b1.prop == 20) df.commit() df.checkout() assert (b1.prop == 5) # Setting point C4 #print ("Setting C4") server_ready.set()
def client_df5(send_q, recv_q, server_ready, client_ready): server_name = recv_q.get() df = Dataframe("CLIENT_TEST", [Car], details=server_name) send_q.put(df.details) # Waiting at point C1 server_ready.wait() server_ready.clear() # Pull from the server. df.pull() df.checkout() cars = df.read_all(Car) assert (1 == len(cars)) c = cars[0] assert ("xvel" not in c.__dict__) assert ("yvel" not in c.__dict__) assert ("xpos" not in c.__dict__) assert ("ypos" not in c.__dict__) assert ("oid" not in c.__dict__) assert (c.xvel is 1) assert (c.yvel is 0) assert (c.xpos is 0) assert (c.ypos is 0) assert (c.oid is 0) df.commit() # Setting point S1 client_ready.set() # Waiting at point C2 server_ready.wait() server_ready.clear() df.pull() df.checkout() cars = df.read_all(Car) assert (1 == len(cars)) c = cars[0] assert ("xvel" not in c.__dict__) assert ("yvel" not in c.__dict__) assert ("xpos" not in c.__dict__) assert ("ypos" not in c.__dict__) assert ("oid" not in c.__dict__) assert (c.xvel is 1) assert (c.yvel is 1) assert (c.xpos is 0) assert (c.ypos is 0) assert (c.oid is 0) df.commit() df.checkout() c.xpos = 1 c.ypos = 1 c2 = Car(1) df.add_one(Car, c2) df.commit() df.push() # Setting point S2 client_ready.set() # Waiting at point C3 server_ready.wait() server_ready.clear() df.pull() df.checkout() assert (df.read_one(Car, 1) is None) assert (df.read_one(Car, 2) is None) # Setting point S3 client_ready.set()
def test_basic_delete1(self): df = Dataframe("TEST", [Car]) c = Car(0) df.checkout() df.add_one(Car, c) c.xvel = 1 self.assertFalse("xvel" in c.__dict__) self.assertFalse("yvel" in c.__dict__) self.assertFalse("xpos" in c.__dict__) self.assertFalse("ypos" in c.__dict__) self.assertFalse("oid" in c.__dict__) self.assertTrue(hasattr(c, "__r_df__")) self.assertEqual(df.local_heap, c.__r_df__) self.assertEqual(c.xvel, 1) self.assertEqual(c.yvel, 0) self.assertEqual(c.xpos, 0) self.assertEqual(c.ypos, 0) self.assertEqual(c.oid, 0) df.commit() df.delete_one(Car, c) df.commit() self.assertListEqual(list(), df.read_all(Car)) self.assertFalse("xvel" in c.__dict__) self.assertFalse("yvel" in c.__dict__) self.assertFalse("xpos" in c.__dict__) self.assertFalse("ypos" in c.__dict__) self.assertFalse("oid" in c.__dict__) self.assertTrue(hasattr(c, "__r_df__")) self.assertEqual(None, c.__r_df__) self.assertEqual(c.xvel, 1) self.assertEqual(c.yvel, 0) self.assertEqual(c.xpos, 0) self.assertEqual(c.ypos, 0) self.assertEqual(c.oid, 0)
def server_df2(send_q, recv_q, server_ready, client_ready): df = Dataframe("SERVER_TEST2", [Car]) send_q.put(df.details) client_name = recv_q.get() # The server goes first. #print ("Server at start:", df.versioned_heap.version_graph.nodes.keys()) df.checkout() #Add car to server c1 = Car(0) c2 = Car(1) df.add_many(Car, [c1, c2]) # Modify the car value. c1.xvel = 1 # Push record into server. df.commit() #print ("Server after adding 2 cars:", df.versioned_heap.version_graph.nodes.keys()) # Setting point C1 #print ("Setting C1") server_ready.set() # Waiting at point S1 #print ("Waiting for S1") client_ready.wait() client_ready.clear() #print ("Server after waiting for client first time:", df.versioned_heap.version_graph.nodes.keys()) #print (df.versioned_heap.state_to_app) df.checkout() c1.yvel = 1 df.commit() #print (df.versioned_heap.state_to_app) #print ("Server after modifying once:", df.versioned_heap.version_graph.nodes.keys()) # Setting point C2 #print ("Setting C2") server_ready.set() # Waiting at point S2 #print ("Waiting for S2") client_ready.wait() client_ready.clear() #print ("Server after waiting for client second time.:", df.versioned_heap.version_graph.nodes.keys()) # Check how the merge worked out. df.checkout() c1 = df.read_one(Car, 0) c2 = df.read_one(Car, 1) assert ("xvel" not in c1.__dict__) assert ("yvel" not in c1.__dict__) assert ("xpos" not in c1.__dict__) assert ("ypos" not in c1.__dict__) assert ("oid" not in c1.__dict__) assert (c1.xvel is 1) assert (c1.yvel is 1) assert (c1.xpos is 0) assert (c1.ypos is 0) assert (c1.oid is 0) assert ("xvel" not in c2.__dict__) assert ("yvel" not in c2.__dict__) assert ("xpos" not in c2.__dict__) assert ("ypos" not in c2.__dict__) assert ("oid" not in c2.__dict__) assert (c2.xvel is 0) assert (c2.yvel is 1), c2.yvel assert (c2.xpos is 0) assert (c2.ypos is 0) assert (c2.oid is 1) # Setting point C3 #print ("Setting C3") server_ready.set() # Waiting at point S3 #print ("Waiting for S3") client_ready.wait() client_ready.clear()
def connect(self, username: str, timeout: Optional[float] = None) -> int: """ Connect to the remote server and wait for the game to start. Parameters ---------- username: str Your desired Player Name. timeout: float Optional timout for how long to wait before abandoning connection Returns ------- player_number: int The assigned player number in the global game. Raises ------ ConnectionError If we could not connect to the game server successfully. Notes ----- This is your absolute player number that will be used for interpreting the full server state and the winners after the end of the game. """ # Add this player to the game. self.pull_dataframe() self._player: Player = Player(name=username, auth_key=self._auth_key) self.player_df.add_one(Player, self._player) self.push_dataframe() # Check to see if adding our Player object to the dataframe worked. self.pull_dataframe() if timeout: self.fr.start_timeout(timeout) while True: if self.tick() and timeout: self._player = None raise ConnectionError("Timed out connecting to server.") # The server should remove our player object if it doesnt want us to connect. if self.player_df.read_one(Player, self._player.pid) is None: self._player = None raise ConnectionError("Server rejected adding your player.") # If the game start timed out, then we break out now. if self._server_state.terminal: self._player = None raise ConnectionError("Server could not successfully start game.") # If we have been given a player number, it means the server is ready for a game to start. if self._player.number >= 0: break self.pull_dataframe() # Connect to observation dataframe, and get the initial observation. assert self._player.observation_port > 0, "Server failed to create an observation dataframe." self.observation_df = Dataframe("{}_observation_df".format(self._player.name), [self._observation_class], details=(self._host, self._player.observation_port)) # Receive the first observation and ensure correct game self.pull_dataframe() self._observation = self.observation_df.read_all(self._observation_class)[0] assert all([hasattr(self._observation, dimension) for dimension in self.dimensions]), \ "Mismatch in game between server and client." # Let the server know that we are ready to start. self._player.ready_for_start = True self.push_dataframe() self.connected = True return self._player.number
def server_df5(send_q, recv_q, server_ready, client_ready): df = Dataframe("SERVER_TEST5", [Car]) send_q.put(df.details) client_name = recv_q.get() # The server goes first. df.checkout() #Add car to server c1 = Car(0) df.add_one(Car, c1) # Modify the car value. c1.xvel = 1 # Push record into server. df.commit() # Setting point C1 server_ready.set() # Client # Pull and read the changes. # Waiting at point S1 client_ready.wait() client_ready.clear() # modify the object. df.checkout() c2 = Car(1) df.add_one(Car, c2) df.commit() df.checkout() df.delete_one(Car, c2) c1.yvel = 1 df.commit() # Setting point C2 server_ready.set() # Waiting at point S2 client_ready.wait() client_ready.clear() df.checkout() assert ("xvel" not in c1.__dict__) assert ("yvel" not in c1.__dict__) assert ("xpos" not in c1.__dict__) assert ("ypos" not in c1.__dict__) assert ("oid" not in c1.__dict__) assert (c1.xvel is 1) assert (c1.yvel is 1) assert (c1.xpos is 1) assert (c1.ypos is 1) assert (c1.oid is 0) c2 = df.read_one(Car, 1) assert ("xvel" not in c2.__dict__) assert ("yvel" not in c2.__dict__) assert ("xpos" not in c2.__dict__) assert ("ypos" not in c2.__dict__) assert ("oid" not in c2.__dict__) assert (c2.xvel is 0) assert (c2.yvel is 0) assert (c2.xpos is 0) assert (c2.ypos is 0) assert (c2.oid is 1) df.commit() # Going for delete. df.checkout() c3 = Car(2) df.add_one(Car, c3) c4 = df.read_one(Car, 2) assert (c3.xvel is c4.xvel) assert (c3.yvel is c4.yvel) assert (c3.xpos is c4.xpos) assert (c3.ypos is c4.ypos) assert (c3.oid is c4.oid) c2.yvel = 1 c2.xvel = 1 df.delete_one(Car, c2) assert (df.read_one(Car, 1) is None) assert (c2.__r_df__ is None) assert (c2.xvel == 1) assert (c2.yvel == 1) c2.xvel = 2 c2.yvel = 2 assert (c2.xvel == 2) assert (c2.yvel == 2) assert (Car.__r_table__.object_table[1] == { "oid": { "type": Datatype.INTEGER, "value": 1 }, "xvel": { "type": Datatype.INTEGER, "value": 2 }, "yvel": { "type": Datatype.INTEGER, "value": 2 }, "xpos": { "type": Datatype.INTEGER, "value": 0 }, "ypos": { "type": Datatype.INTEGER, "value": 0 } }) df.delete_one(Car, c3) assert (df.read_one(Car, 2) is None) df.commit() assert (set(df.local_heap.data[Car.__r_meta__.name].keys()) == set([0])) # Setting point C3 server_ready.set() # Waiting for S3 client_ready.wait()
def server_df7(send_q, recv_q, server_ready, client_ready): df = Dataframe("SERVER_TEST7", [Blocker]) send_q.put(df.details) client_name = recv_q.get() # The server goes first. #print ("Server at start:", df.versioned_heap.version_graph.nodes.keys()) df.checkout() #Add Counter to server b1 = Blocker(0) df.add_many(Blocker, [b1]) assert (b1.prop == 0) b1.prop += 1 assert (b1.prop == 1) # Push record into server. df.commit() #print ("Server after adding 2 cars:", df.versioned_heap.version_graph.nodes.keys()) # Setting point C1 #print ("Setting C1") server_ready.set() # Waiting at point S1 #print ("Waiting for S1") client_ready.wait() client_ready.clear() #print ("Server after waiting for client first time:", df.versioned_heap.version_graph.nodes.keys()) #print (df.versioned_heap.state_to_app) df.checkout() assert (b1.prop == 1) b1.prop += 1 assert (b1.prop == 2) df.commit() #print (df.versioned_heap.state_to_app) #print ("Server after modifying once:", df.versioned_heap.version_graph.nodes.keys()) # Setting point C2 #print ("Setting C2") server_ready.set() # Waiting at point S2 #print ("Waiting for S2") client_ready.wait() client_ready.clear() #print ("Server after waiting for client second time.:", df.versioned_heap.version_graph.nodes.keys()) # Check how the merge worked out. df.checkout() assert (b1.prop == 10), b1.prop # Setting point C3 #print ("Setting C3") server_ready.set() # Waiting at point S3 #print ("Waiting for S3") client_ready.wait() client_ready.clear() assert (b1.prop == 10) b1.prop = 20 assert (b1.prop == 20) df.commit() df.checkout() assert (b1.prop == 5) # Setting point C4 #print ("Setting C4") server_ready.set()
def server_df4(send_q, recv_q, server_ready, client_ready): df = Dataframe("SERVER_TEST4", [Car, Counter], resolver={Counter: counter_merge_func}) send_q.put(df.details) client_name = recv_q.get() # The server goes first. #print ("Server at start:", df.versioned_heap.version_graph.nodes.keys()) df.checkout() #Add Counter to server c1 = Counter(0) car1 = Car(0) df.add_many(Counter, [c1]) df.add_many(Car, [car1]) assert (c1.count == 0) # Modify the counter value. c1.count += 1 assert (c1.count == 1) # Push record into server. df.commit() #print ("Server after adding 2 cars:", df.versioned_heap.version_graph.nodes.keys()) # Setting point C1 #print ("Setting C1") server_ready.set() # Waiting at point S1 #print ("Waiting for S1") client_ready.wait() client_ready.clear() #print ("Server after waiting for client first time:", df.versioned_heap.version_graph.nodes.keys()) #print (df.versioned_heap.state_to_app) df.checkout() assert (c1.count == 1) c1.count += 1 assert (c1.count == 2) df.commit() #print (df.versioned_heap.state_to_app) #print ("Server after modifying once:", df.versioned_heap.version_graph.nodes.keys()) # Setting point C2 #print ("Setting C2") server_ready.set() # Waiting at point S2 #print ("Waiting for S2") client_ready.wait() client_ready.clear() #print ("Server after waiting for client second time.:", df.versioned_heap.version_graph.nodes.keys()) # Check how the merge worked out. df.checkout() assert (c1.count == 3) # Setting point C3 #print ("Setting C3") server_ready.set() # Waiting at point S3 #print ("Waiting for S3") client_ready.wait() client_ready.clear()
def test_basic_delete2(self): df = Dataframe("TEST", [Car]) c = Car(0) df.checkout() df.add_one(Car, c) c.xvel = 1 self.assertFalse("xvel" in c.__dict__) self.assertFalse("yvel" in c.__dict__) self.assertFalse("xpos" in c.__dict__) self.assertFalse("ypos" in c.__dict__) self.assertFalse("oid" in c.__dict__) self.assertTrue(hasattr(c, "__r_df__")) self.assertEqual(df.local_heap, c.__r_df__) self.assertEqual(c.xvel, 1) self.assertEqual(c.yvel, 0) self.assertEqual(c.xpos, 0) self.assertEqual(c.ypos, 0) self.assertEqual(c.oid, 0) df.commit() df.push_call_back( "TEST2", [df.versioned_heap.version_graph.head.current, "NEXT"], { Car.__r_meta__.name: { 0: { "types": { Car.__r_meta__.name: Event.Delete } } } }) df.checkout() self.assertListEqual(list(), df.read_all(Car)) self.assertFalse("xvel" in c.__dict__) self.assertFalse("yvel" in c.__dict__) self.assertFalse("xpos" in c.__dict__) self.assertFalse("ypos" in c.__dict__) self.assertFalse("oid" in c.__dict__) self.assertTrue(hasattr(c, "__r_df__")) self.assertEqual(None, c.__r_df__) self.assertEqual(c.xvel, 1) self.assertEqual(c.yvel, 0) self.assertEqual(c.xpos, 0) self.assertEqual(c.ypos, 0) self.assertEqual(c.oid, 0)
def client_df2(send_q, recv_q, server_ready, client_ready): server_name = recv_q.get() df = Dataframe("CLIENT_TEST", [Car], details=server_name) send_q.put(df.details) #print ("Client at start:", df.versioned_heap.version_graph.nodes.keys()) # Waiting at point C1 #print ("Waiting for C1") server_ready.wait() server_ready.clear() #print ("Client after waiting for server first time.:", df.versioned_heap.version_graph.nodes.keys()) # Pull from the server. df.pull() #print ("Client after first pull:", df.versioned_heap.version_graph.nodes.keys()) df.checkout() cars = df.read_all(Car) assert (2 == len(cars)) c1, c2 = cars #print ("Setting S1") # Setting point S1 client_ready.set() c2.yvel = 1 df.commit() #print ("Client after first modification:", df.versioned_heap.version_graph.nodes.keys()) # Waiting at point C2 #print ("Waiting for C2") server_ready.wait() server_ready.clear() #print ("Client after waiting for server:", df.versioned_heap.version_graph.nodes.keys()) df.push() #print ("Client after pushing:", df.versioned_heap.version_graph.nodes.keys()) # Setting point S2 #print ("Setting S2") client_ready.set() # Waiting at point c3 #print ("Waiting for C3") server_ready.wait() server_ready.clear() df.pull() #print ("Client after pulling second time:", df.versioned_heap.version_graph.nodes.keys()) df.checkout() c1 = df.read_one(Car, 0) c2 = df.read_one(Car, 1) assert ("xvel" not in c1.__dict__) assert ("yvel" not in c1.__dict__) assert ("xpos" not in c1.__dict__) assert ("ypos" not in c1.__dict__) assert ("oid" not in c1.__dict__) assert (c1.xvel is 1) assert (c1.yvel is 1) assert (c1.xpos is 0) assert (c1.ypos is 0) assert (c1.oid is 0) assert ("xvel" not in c2.__dict__) assert ("yvel" not in c2.__dict__) assert ("xpos" not in c2.__dict__) assert ("ypos" not in c2.__dict__) assert ("oid" not in c2.__dict__) assert (c2.xvel is 0) assert (c2.yvel is 1) assert (c2.xpos is 0) assert (c2.ypos is 0) assert (c2.oid is 1) # Setting point S3 #print ("Setting S3") client_ready.set()
def client_df7(send_q, recv_q, server_ready, client_ready): server_name = recv_q.get() df = Dataframe("CLIENT_TEST", [Blocker], details=server_name, resolver={Blocker: blocker_merge_func}) send_q.put(df.details) #print ("Client at start:", df.versioned_heap.version_graph.nodes.keys()) # Waiting at point C1 #print ("Waiting for C1") server_ready.wait() server_ready.clear() #print ("Client after waiting for server first time.:", df.versioned_heap.version_graph.nodes.keys()) # Pull from the server. df.pull() #print ("Client after first pull:", df.versioned_heap.version_graph.nodes.keys()) df.checkout() blockers = df.read_all(Blocker) assert (1 == len(blockers)) b1 = blockers[0] assert (b1.prop == 1) #print ("Setting S1") # Setting point S1 client_ready.set() b1.prop = 10 assert (b1.prop == 10) df.commit() #print ("Client after first modification:", df.versioned_heap.version_graph.nodes.keys()) # Waiting at point C2 #print ("Waiting for C2") server_ready.wait() server_ready.clear() #print ("Client after waiting for server:", df.versioned_heap.version_graph.nodes.keys()) df.push() #print ("Client after pushing:", df.versioned_heap.version_graph.nodes.keys()) # Setting point S2 #print ("Setting S2") client_ready.set() # Waiting at point c3 #print ("Waiting for C3") server_ready.wait() server_ready.clear() df.pull() #print ("Client after pulling second time:", df.versioned_heap.version_graph.nodes.keys()) df.checkout() assert (b1.prop == 10) b1.prop = 5 df.commit() df.push() # Setting point S3 #print ("Setting S3") client_ready.set() # Waiting at point c4 #print ("Waiting for C4") server_ready.wait() server_ready.clear()
def test_one_df_subset(self): df = Dataframe("test", [Car, ActiveCar]) car = Car(0, "BLUE") df.add_one(Car, car) df.commit() self.assertEqual(1, len(df.read_all(Car))) self.assertEqual(0, len(df.read_all(ActiveCar))) car.start((10, 10)) self.assertEqual(1, len(df.read_all(Car))) self.assertEqual(1, len(df.read_all(ActiveCar))) acar = df.read_one(ActiveCar, 0) self.assertEqual(acar.details, (0, 10, 10, 0, 0, "BLUE")) self.assertIsInstance(acar, ActiveCar) df.commit() self.assertEqual(1, len(df.read_all(Car))) self.assertEqual(1, len(df.read_all(ActiveCar))) self.assertEqual(acar.details, (0, 10, 10, 0, 0, "BLUE")) self.assertIsInstance(acar, ActiveCar)
class ClientEnvironment: """ Basic client environment that will work with any server environment and handles most of the connection and playing capabilities. """ _TickRate = 60 def __init__(self, dataframe: Dataframe, dimensions: List[str], observation_class: Type[Observation], host: str, server_environment: Optional[Type[BaseEnvironment]] = None, auth_key: str = ''): """ The primary class for interacting with the environment as a remote client. Parameters ---------- dataframe : Dataframe The spacetime dataframe connected to the game server. dimensions : List[str] The names of the observation dimensions observation_class : Type[Observation] The base class of observations in the dataframe. host : str The hostname of the game server server_environment : Optional[Type[BaseEnvironment]] The full server environment if we have access to it. auth_key : str Your authorization key for entering the game if the server has a whitelist. """ self.player_df: Dataframe = dataframe self.observation_df: Optional[Dataframe] = None self._server_state: ServerState = self.player_df.read_all(ServerState)[0] assert self._server_state.terminal is False, "Connecting to a server with no active game." assert self._server_state.server_no_longer_joinable is False, "Server is not accepting new connection." self._player: Optional[Player] = None self._dimensions: List[str] = dimensions self._observation: Observation = None self._observation_class: Type[Observation] = observation_class self._host: str = host self._auth_key: str = auth_key self._server_environment: Optional[BaseEnvironment] = None if server_environment is not None: self._server_environment = server_environment(self._server_state.env_config) self.fr: FrameRateKeeper = FrameRateKeeper(self._TickRate) self.connected: bool = False def pull_dataframe(self) -> None: """ Helper function to update all dataframes for this environment. """ self.player_df.pull() self.player_df.checkout() if self.observation_df is not None: self.observation_df.pull() self.observation_df.checkout() def push_dataframe(self) -> None: """ Helper function to push all dataframes for this environment. """ self.player_df.commit() self.player_df.push() def check_connection(self) -> None: """ Helper function to error out if we are not yet connected to a game server. Raises ------ ConnectionError If connect() has not been called yet. """ if not self.connected: raise ConnectionError("Not connected to game server.") def tick(self) -> bool: """ Helper function to wait for a tick of the framerate. Returns ------- bool Whether or not the framerate keeper has raised a timeout. """ return self.fr.tick() @property def observation(self) -> Dict[str, np.ndarray]: """ Get the current observation present for this agent. Returns ------- Dict[str, np.ndarray] The observation dictionary for this environment. """ self.check_connection() return {dimension: getattr(self._observation, dimension) for dimension in self.dimensions} @property def terminal(self) -> bool: """ Check if the game has ended for us or not. Returns ------- bool Whether or not the game has reached a terminal state. Raises ------ ConnectionError If connect() has not been called yet. """ self.check_connection() return self._server_state.terminal @property def winners(self) -> Optional[List[int]]: """ Get the current list of winners for the game. Returns ------- List[int] The list of player numbers of the winners. Raises ------ ConnectionError If connect() has not been called yet. ValueError If the game is not over yet. """ if not self.terminal: raise ValueError("Game has not ended yet.") return dill.loads(self._server_state.winners) @property def server_environment(self) -> Optional[BaseEnvironment]: """ Get the full server environment object if we have it available. Returns ------- BaseEnvironment Server environment or None is not available. """ return self._server_environment @property def dimensions(self) -> List[str]: """ Get all of the observations that we recieve from the server. Returns ------- List[str] The keys in the observation dictionary. """ return self._dimensions @property def full_state(self): """ Full server state for the game if the environment and the server support it. Returns ------- object Current server state Raises ------ ConnectionError If connect() has not been called yet. ValueError If we do not have access to the full state. """ self.check_connection() if not self.server_environment.serializable(): raise ValueError("Current Environment does not support full state for clients.") return self.server_environment.deserialize_state(self._server_state.serialized_state) def connect(self, username: str, timeout: Optional[float] = None) -> int: """ Connect to the remote server and wait for the game to start. Parameters ---------- username: str Your desired Player Name. timeout: float Optional timout for how long to wait before abandoning connection Returns ------- player_number: int The assigned player number in the global game. Raises ------ ConnectionError If we could not connect to the game server successfully. Notes ----- This is your absolute player number that will be used for interpreting the full server state and the winners after the end of the game. """ # Add this player to the game. self.pull_dataframe() self._player: Player = Player(name=username, auth_key=self._auth_key) self.player_df.add_one(Player, self._player) self.push_dataframe() # Check to see if adding our Player object to the dataframe worked. self.pull_dataframe() if timeout: self.fr.start_timeout(timeout) while True: if self.tick() and timeout: self._player = None raise ConnectionError("Timed out connecting to server.") # The server should remove our player object if it doesnt want us to connect. if self.player_df.read_one(Player, self._player.pid) is None: self._player = None raise ConnectionError("Server rejected adding your player.") # If the game start timed out, then we break out now. if self._server_state.terminal: self._player = None raise ConnectionError("Server could not successfully start game.") # If we have been given a player number, it means the server is ready for a game to start. if self._player.number >= 0: break self.pull_dataframe() # Connect to observation dataframe, and get the initial observation. assert self._player.observation_port > 0, "Server failed to create an observation dataframe." self.observation_df = Dataframe("{}_observation_df".format(self._player.name), [self._observation_class], details=(self._host, self._player.observation_port)) # Receive the first observation and ensure correct game self.pull_dataframe() self._observation = self.observation_df.read_all(self._observation_class)[0] assert all([hasattr(self._observation, dimension) for dimension in self.dimensions]), \ "Mismatch in game between server and client." # Let the server know that we are ready to start. self._player.ready_for_start = True self.push_dataframe() self.connected = True return self._player.number def wait_for_turn(self, timeout: Optional[float] = None): """ Block until it is your turn. This is usually only used in the beginning of the game. Parameters ---------- timeout: float An optional hard timeout on waiting for the game to start. Returns ------- observation: The player's observation once its turn has arrived. """ assert self.connected, "Not connected to game server." if timeout: self.fr.start_timeout(timeout) while not self._player.turn: if self.terminal: raise ConnectionError("Server finished game while we were waiting.") if self.tick() and timeout: raise ConnectionError("Timed out waiting for a game.") self.pull_dataframe() return self.observation def reset(self): self.wait_for_start() return self.observation def wait_for_start(self, timeout: Optional[float] = None): """ Secondary name for to be clearer when starting game. """ self.wait_for_turn(timeout) def valid_actions(self): """ Get a list of all valid moves for the current state. Raises ------ NotImplementedError If the client environment does not have access to all of your available moves. Returns ------- moves: list[str] """ if self._server_environment is not None: return self._server_environment.valid_actions(self.full_state, self._player.number) else: raise NotImplementedError("No valid_action is implemented in this client and " "we do not have access to the full server environment") def step(self, action: str) -> Tuple[Dict[str, np.ndarray], float, bool, Optional[List[int]]]: """ Perform an action and send it to the server. This wil block until it is your turn again. Parameters ---------- action: str Your action string. Returns ------- observation : Dict[str, np.ndarray] The new observation dictionary for the new state. reward : float The reward for the previous action. terminal : bool Whether or not the game has ended. winners : Optional[List[int]] If terminal is true, this will be a list of the player numbers that have won If terminal is false, this will be None """ if not self.terminal: self._player.action = action self._player.ready_for_action_to_be_taken = True self.push_dataframe() while not self._player.turn or self._player.ready_for_action_to_be_taken: self.tick() self.pull_dataframe() reward = self._player.reward_from_last_turn terminal = self.terminal winners = None if terminal: winners = dill.loads(self._server_state.winners) self._player.acknowledges_game_over = True self.push_dataframe() return self.observation, reward, terminal, winners
def server_df4(send_q, recv_q, server_ready, client_ready): df = Dataframe("SERVER_TEST4", [Car, Counter]) send_q.put(df.details) client_name = recv_q.get() # The server goes first. #print ("Server at start:", df.versioned_heap.version_graph.nodes.keys()) df.checkout() #Add Counter to server c1 = Counter(0) car1 = Car(0) df.add_many(Counter, [c1]) df.add_many(Car, [car1]) assert (c1.count == 0) # Modify the counter value. c1.count += 1 assert (c1.count == 1) # Push record into server. df.commit() #print ("Server after adding 2 cars:", df.versioned_heap.version_graph.nodes.keys()) # Setting point C1 #print ("Setting C1") server_ready.set() # Waiting at point S1 #print ("Waiting for S1") client_ready.wait() client_ready.clear() #print ("Server after waiting for client first time:", df.versioned_heap.version_graph.nodes.keys()) #print (df.versioned_heap.state_to_app) df.checkout() assert (c1.count == 1) c1.count += 1 assert (c1.count == 2) df.commit() #print (df.versioned_heap.state_to_app) #print ("Server after modifying once:", df.versioned_heap.version_graph.nodes.keys()) # Setting point C2 #print ("Setting C2") server_ready.set() # Waiting at point S2 #print ("Waiting for S2") client_ready.wait() client_ready.clear() #print ("Server after waiting for client second time.:", df.versioned_heap.version_graph.nodes.keys()) # Check how the merge worked out. df.checkout() assert (c1.count == 3) # Setting point C3 #print ("Setting C3") server_ready.set() # Waiting at point S3 #print ("Waiting for S3") client_ready.wait() client_ready.clear()
def client_df1(send_q, recv_q, server_ready, client_ready): server_name = recv_q.get() df = Dataframe("CLIENT_TEST", [Car], details=server_name) send_q.put(df.details) # Waiting at point C1 server_ready.wait() server_ready.clear() # Pull from the server. df.pull() df.checkout() cars = df.read_all(Car) assert (1 == len(cars)) c = cars[0] assert ("xvel" not in c.__dict__) assert ("yvel" not in c.__dict__) assert ("xpos" not in c.__dict__) assert ("ypos" not in c.__dict__) assert ("oid" not in c.__dict__) assert (c.xvel is 1) assert (c.yvel is 0) assert (c.xpos is 0) assert (c.ypos is 0) assert (c.oid is 0) df.commit() # Setting point S1 client_ready.set() # Waiting at point C2 server_ready.wait() server_ready.clear() df.pull() df.checkout() cars = df.read_all(Car) assert (1 == len(cars)) c = cars[0] assert ("xvel" not in c.__dict__) assert ("yvel" not in c.__dict__) assert ("xpos" not in c.__dict__) assert ("ypos" not in c.__dict__) assert ("oid" not in c.__dict__) assert (c.xvel is 1) assert (c.yvel is 1) assert (c.xpos is 0) assert (c.ypos is 0) assert (c.oid is 0) df.commit() df.checkout() c.xpos = 1 c.ypos = 1 c2 = Car(1) df.add_one(Car, c2) df.commit() df.push() # Setting point S2 client_ready.set() # Waiting at point C3 server_ready.wait() server_ready.clear() df.pull() df.checkout() assert (df.read_one(Car, 1) is None) assert (df.read_one(Car, 2) is None) # This does not work yet. Have to figure it out. # limitation of making it a framework rather than # a programming language itself. # Cannot invalidate old references without holding the # reference itself. #assert ("xvel" not in c2.__dict__) #assert ("yvel" not in c2.__dict__) #assert ("xpos" not in c2.__dict__) #assert ("ypos" not in c2.__dict__) #assert ("oid" not in c2.__dict__) #assert (c2.xvel is 0) #assert (c2.yvel is 0) #assert (c2.xpos is 0) #assert (c2.ypos is 0) #assert (c2.oid is 1) #assert (c2.__r_df__ is None) #assert (Car.__r_table__.object_table[1] == { # "oid": {"type": Datatype.INTEGER, "value": 0}, # "xvel": {"type": Datatype.INTEGER, "value": 0}, # "yvel": {"type": Datatype.INTEGER, "value": 0}, # "xpos": {"type": Datatype.INTEGER, "value": 0}, # "ypos": {"type": Datatype.INTEGER, "value": 0} # }) # Setting point S3 client_ready.set()
def client_df4(send_q, recv_q, server_ready, client_ready): server_name = recv_q.get() df = Dataframe("CLIENT_TEST", [Counter], details=server_name) send_q.put(df.details) #print ("Client at start:", df.versioned_heap.version_graph.nodes.keys()) # Waiting at point C1 #print ("Waiting for C1") server_ready.wait() server_ready.clear() #print ("Client after waiting for server first time.:", df.versioned_heap.version_graph.nodes.keys()) # Pull from the server. df.pull() #print ("Client after first pull:", df.versioned_heap.version_graph.nodes.keys()) df.checkout() counters = df.read_all(Counter) cars = df.read_all(Car) assert (1 == len(counters)) assert (0 == len(cars)) c1 = counters[0] assert (c1.count == 1) #print ("Setting S1") # Setting point S1 client_ready.set() c1.count += 1 assert (c1.count == 2) df.commit() #print ("Client after first modification:", df.versioned_heap.version_graph.nodes.keys()) # Waiting at point C2 #print ("Waiting for C2") server_ready.wait() server_ready.clear() #print ("Client after waiting for server:", df.versioned_heap.version_graph.nodes.keys()) df.push() #print ("Client after pushing:", df.versioned_heap.version_graph.nodes.keys()) # Setting point S2 #print ("Setting S2") client_ready.set() # Waiting at point c3 #print ("Waiting for C3") server_ready.wait() server_ready.clear() df.pull() #print ("Client after pulling second time:", df.versioned_heap.version_graph.nodes.keys()) df.checkout() assert (c1.count == 3) # Setting point S3 #print ("Setting S3") client_ready.set()
def server_df5(send_q, recv_q, server_ready, client_ready): df = Dataframe("SERVER_TEST5", [Car]) send_q.put(df.details) client_name = recv_q.get() # The server goes first. df.checkout() #Add car to server c1 = Car(0) df.add_one(Car, c1) # Modify the car value. c1.xvel = 1 # Push record into server. df.commit() # Setting point C1 server_ready.set() # Client # Pull and read the changes. # Waiting at point S1 client_ready.wait() client_ready.clear() # modify the object. df.checkout() c2 = Car(1) df.add_one(Car, c2) df.commit() df.checkout() df.delete_one(Car, c2) c1.yvel = 1 df.commit() # Setting point C2 server_ready.set() # Waiting at point S2 client_ready.wait() client_ready.clear() df.checkout() assert ("xvel" not in c1.__dict__) assert ("yvel" not in c1.__dict__) assert ("xpos" not in c1.__dict__) assert ("ypos" not in c1.__dict__) assert ("oid" not in c1.__dict__) assert (c1.xvel is 1) assert (c1.yvel is 1) assert (c1.xpos is 1) assert (c1.ypos is 1) assert (c1.oid is 0) c2 = df.read_one(Car, 1) assert ("xvel" not in c2.__dict__) assert ("yvel" not in c2.__dict__) assert ("xpos" not in c2.__dict__) assert ("ypos" not in c2.__dict__) assert ("oid" not in c2.__dict__) assert (c2.xvel is 0) assert (c2.yvel is 0) assert (c2.xpos is 0) assert (c2.ypos is 0) assert (c2.oid is 1) df.commit() # Going for delete. df.checkout() c3 = Car(2) df.add_one(Car, c3) c4 = df.read_one(Car, 2) assert (c3.xvel is c4.xvel) assert (c3.yvel is c4.yvel) assert (c3.xpos is c4.xpos) assert (c3.ypos is c4.ypos) assert (c3.oid is c4.oid) c2.yvel = 1 c2.xvel = 1 df.delete_one(Car, c2) assert (df.read_one(Car, 1) is None) assert (c2.__r_df__ is None) assert (c2.xvel == 1) assert (c2.yvel == 1) c2.xvel = 2 c2.yvel = 2 assert (c2.xvel == 2) assert (c2.yvel == 2) assert (Car.__r_table__.object_table[1] == { "oid": {"type": Datatype.INTEGER, "value": 1}, "xvel": {"type": Datatype.INTEGER, "value": 2}, "yvel": {"type": Datatype.INTEGER, "value": 2}, "xpos": {"type": Datatype.INTEGER, "value": 0}, "ypos": {"type": Datatype.INTEGER, "value": 0} }) df.delete_one(Car, c3) assert (df.read_one(Car, 2) is None) df.commit() assert (set(df.local_heap.data[Car.__r_meta__.name].keys()) == set([0])) # Setting point C3 server_ready.set() # Waiting for S3 client_ready.wait()
def client_df4(send_q, recv_q, server_ready, client_ready): server_name = recv_q.get() df = Dataframe("CLIENT_TEST", [Counter], details=server_name, resolver={Counter: counter_merge_func}) send_q.put(df.details) #print ("Client at start:", df.versioned_heap.version_graph.nodes.keys()) # Waiting at point C1 #print ("Waiting for C1") server_ready.wait() server_ready.clear() #print ("Client after waiting for server first time.:", df.versioned_heap.version_graph.nodes.keys()) # Pull from the server. df.pull() #print ("Client after first pull:", df.versioned_heap.version_graph.nodes.keys()) df.checkout() counters = df.read_all(Counter) cars = df.read_all(Car) assert (1 == len(counters)) assert (0 == len(cars)) c1 = counters[0] assert (c1.count == 1) #print ("Setting S1") # Setting point S1 client_ready.set() c1.count += 1 assert (c1.count == 2) df.commit() #print ("Client after first modification:", df.versioned_heap.version_graph.nodes.keys()) # Waiting at point C2 #print ("Waiting for C2") server_ready.wait() server_ready.clear() #print ("Client after waiting for server:", df.versioned_heap.version_graph.nodes.keys()) df.push() #print ("Client after pushing:", df.versioned_heap.version_graph.nodes.keys()) # Setting point S2 #print ("Setting S2") client_ready.set() # Waiting at point c3 #print ("Waiting for C3") server_ready.wait() server_ready.clear() df.pull() #print ("Client after pulling second time:", df.versioned_heap.version_graph.nodes.keys()) df.checkout() assert (c1.count == 3) # Setting point S3 #print ("Setting S3") client_ready.set()
def server_app(dataframe: Dataframe, env_class: Type[BaseEnvironment], observation_type: Type, args: dict, whitelist: list = None, ready_event: Event = None): timeout = Timeout() fr: FrameRateKeeper = FrameRateKeeper(max_frame_rate=args['tick_rate']) # Keep track of each player and their associated observations observation_dataframes: Dict[int, Dataframe] = {} observations: Dict[int, _Observation] = {} players: Dict[int, Player] = {} # Function to help push all observations def push_observations(): for df in observation_dataframes.values(): df.commit() # Add the server state to the master dataframe server_state = ServerState(env_class.__name__, args["config"], env_class.observation_names()) dataframe.add_one(ServerState, server_state) dataframe.commit() # Function to help clean up server if it ever needs to shutdown def close_server(message: str): server_state.terminal = True logger.error(message) dataframe.commit() sleep(5) # Create the environment and start the server env: BaseEnvironment = env_class(args["config"]) logger.info("Waiting for enough players to join ({} required)...".format(env.min_players)) # Add whitelist support, players will be rejected if their key does not match the expected keys whitelist = [] if whitelist is None else whitelist whitelist_used = len(whitelist) > 0 whitelist_connected = {key: False for key in whitelist} # If we were created by some server manager, inform them we are ready for players if ready_event is not None: ready_event.set() # ----------------------------------------------------------------------------------------------- # Wait for all players to connect # ----------------------------------------------------------------------------------------------- fr.start_timeout(timeout.connect) while len(players) < env.min_players: if fr.tick(): close_server("Game could not find enough players. Shutting down game server.") return 1 dataframe.sync() new_players: Dict[int, Player] = dict((p.pid, p) for p in dataframe.read_all(Player)) # Any players that have connected by have not been acknowledged yet for new_id in new_players.keys() - players.keys(): name = new_players[new_id].name auth_key = new_players[new_id].authentication_key if whitelist_used and auth_key not in whitelist_connected: logger.info("Player tried to join with invalid authentication_key: {}".format(name)) dataframe.delete_one(Player, new_id) del new_players[new_id] continue if whitelist_used and whitelist_connected[auth_key]: logger.info("Player tried to join twice with the same authentication_key: {}".format(name)) dataframe.delete_one(Player, new_id) del new_players[new_id] continue logger.info("New player joined with name: {}".format(name)) # Create new observation dataframe for the new player obs_df = Dataframe("{}_observation".format(name), [observation_type]) obs = observation_type(new_id) obs_df.add_one(observation_type, obs) # Add the dataframes to the database observation_dataframes[new_id] = obs_df observations[new_id] = obs whitelist_connected[auth_key] = True # If any players that we have added before have dropped out for remove_id in players.keys() - new_players.keys(): logger.info("Player {} has left.".format(players[remove_id].name)) auth_key = players[remove_id].authentication_key whitelist_connected[auth_key] = False del observations[remove_id] del observation_dataframes[remove_id] players = new_players # ----------------------------------------------------------------------------------------------- # Create all of the player data and wait for the game to begin # ----------------------------------------------------------------------------------------------- logger.info("Finalizing players and setting up new environment.") server_state.server_no_longer_joinable = True # Create the initial state for the environment and push it if enabled state, player_turns = env.new_state(num_players=len(players)) if not args["observations_only"] and env.serializable(): server_state.serialized_state = env.serialize_state(state) # Set up each player for i, (pid, player) in enumerate(players.items()): # Add the initial observation to each player observations[pid].set_observation(env.state_to_observation(state=state, player=i)) # Finalize each player by giving it a player number and a port for the dataframe player.finalize_player(number=i, observation_port=observation_dataframes[pid].details[1]) if i in player_turns: player.turn = True # Push all of the results to the player players_by_number: Dict[int, Player] = dict((p.number, p) for p in players.values()) push_observations() dataframe.sync() # Wait for all players to be ready fr.start_timeout(timeout.start) while not all(player.ready_for_start for player in players.values()): if fr.tick(): close_server("Players have dropped out between entering the game and starting the game.") return 2 dataframe.checkout() # ----------------------------------------------------------------------------------------------- # Primary game loop # ----------------------------------------------------------------------------------------------- logger.info("Game started...") terminal = False winners = None dataframe.commit() fr.start_timeout(timeout.move) while not terminal: # Wait for a frame to tick move_timeout = fr.tick() # Get new data dataframe.checkout() # Get the player dataframes of the players who's turn it is right now current_players: List[Player] = [p for p in players.values() if p.number in player_turns] current_actions: List[str] = [] ready = args['realtime'] or move_timeout or all(p.ready_for_action_to_be_taken for p in current_players) if not ready: continue # Queue up each players action if it is legal # If the player failed to respond in time, we will simply execute the previous action # If it is invalid, we will pass in a blank string for player in current_players: if player.action == '' or env.is_valid_action(state=state, player=player.number, action=player.action): current_actions.append(player.action) else: logger.info("Player #{}, {}'s, action of {} was invalid, passing empty string as action" .format(player.number, player.name, player.action)) current_actions.append('') # Execute the current move state, player_turns, rewards, terminal, winners = ( env.next_state(state=state, players=player_turns, actions=current_actions) ) # Update true state if enabled if not args["observations_only"] and env.serializable(): server_state.serialized_state = env.serialize_state(state) # Update the player data from the previous move. for player, reward in zip(current_players, rewards): player.reward_from_last_turn = float(reward) player.ready_for_action_to_be_taken = False player.turn = False # Tell the new players that its their turn and provide observation for player_number in player_turns: player = players_by_number[player_number] observations[player.pid].set_observation(env.state_to_observation(state=state, player=player_number)) player.turn = True if terminal: server_state.terminal = True server_state.winners = dill.dumps(winners) for player_number in winners: players_by_number[player_number].winner = True logger.info("Player: {} won the game.".format(winners)) push_observations() dataframe.commit() fr.start_timeout(timeout.move) # ----------------------------------------------------------------------------------------------- # Clean up after game # ----------------------------------------------------------------------------------------------- for player in players.values(): player.turn = True dataframe.commit() dataframe.push() # TODO| The code below attempts to ensure that the players have the final state of the game before the server quits. # TODO| However, an error is thrown when players disconnect during the checkout. If this snippet was removed, # TODO| players would have a similar error when the server would quit while they are pulling. # TODO| May need to talk to Rohan about cleanly exiting this kind of situation. # TODO| It would also be great if we could instead properly confirm that recipients got a message. fr.start_timeout(timeout.end) for player in players.values(): while not player.acknowledges_game_over and not fr.tick(): dataframe.checkout() rankings = env.compute_ranking(state, list(range(len(players))), winners) ranking_dict = {players_by_number[number].name: ranking for number, ranking in rankings.items()} logger.info("Game has ended. Player {} is the winner.".format([key for key, value in ranking_dict.items() if value == 0])) return ranking_dict
def test_multiple_types(self): df1 = Dataframe("TEST1", [Car, Counter], version_by=VersionBy.TYPE) df2 = Dataframe("TEST2", [Car], details=df1.details, version_by=VersionBy.TYPE) appname1 = df1.appname appname2 = df2.appname c = Car(0) count = Counter(0) df2.checkout() df2.add_one(Car, c) c.xvel = 1 df2.commit() df1.checkout() df1.add_one(Counter, count) df1.commit() df2.sync() df1.checkout() self.assertEqual(1, len(df1.read_all(Car))) self.assertListEqual(list(), df2.read_all(Counter))