home · contact · privacy
Multi-process FOV generation on send_gamestate.
authorChristian Heller <c.heller@plomlompom.de>
Sat, 5 Dec 2020 01:46:53 +0000 (02:46 +0100)
committerChristian Heller <c.heller@plomlompom.de>
Sat, 5 Dec 2020 01:46:53 +0000 (02:46 +0100)
plomrogue/game.py
plomrogue/mapping.py
plomrogue/things.py

index 453ee30dd84f968b6f3555b09f6d428722bb31c3..ff761556e0da3f4299411ad0ae27051db7957a3f 100755 (executable)
@@ -203,7 +203,23 @@ class Game(GameBase):
         """Send out game state data relevant to clients."""
 
         self.io.send('TURN ' + str(self.turn))
-        for c_id in self.sessions:
+        from plomrogue.mapping import FovMap
+        import multiprocessing
+        pool = multiprocessing.Pool()
+        players = []
+        c_ids = [c_id for c_id in self.sessions]
+        for c_id in c_ids:
+            players += [self.get_player(c_id)]
+        player_fovs = []
+        for player in players:
+            player.prepare_multiprocessible_fov_stencil()
+            player_fovs += [player._fov]
+        new_fovs = pool.map(FovMap.init_terrain, [fov for fov in player_fovs])
+        for i in range(len(players)):
+            players[i]._fov = new_fovs[i]
+        pool.close()
+        pool.join()
+        for c_id in c_ids:
             player = self.get_player(c_id)
             visible_terrain = player.fov_stencil_map()
             self.io.send('FOV %s' % quote(player.fov_stencil.terrain), c_id)
index d1fc9fb91457f6358698f855070e1c259ae88e62..e806ef70f8c721386bf9cdeada5733fc57eea176 100644 (file)
@@ -210,7 +210,6 @@ class Map():
 class SourcedMap(Map):
 
     def __init__(self, things, source_maps, source_center, radius, get_map):
-        self.source_maps = source_maps
         self.radius = radius
         example_map = get_map(YX(0, 0))
         self.source_geometry = example_map.geometry
@@ -233,7 +232,7 @@ class SourcedMap(Map):
             if big_yx in obstacles and little_yx in obstacles[big_yx]:
                 self.source_map_segment += 'X'
             else:
-                self.source_map_segment += self.source_maps[big_yx][little_yx]
+                self.source_map_segment += source_maps[big_yx][little_yx]
 
     def source_yxyx(self, yx):
         absolute_yx = yx + self.offset
@@ -294,7 +293,14 @@ class FovMap(SourcedMap):
         self.terrain = '?' * self.size_i
         self[self.center] = '.'
         self.shadow_cones = []
+        #self.circle_out(self.center, self.shadow_process)
+
+    def init_terrain(self):
+        # we outsource this to allow multiprocessing some stab at it,
+        # and return it since multiprocessing does not modify its
+        # processing sources
         self.circle_out(self.center, self.shadow_process)
+        return self
 
     def throws_shadow(self, yx):
         return self.source_map_segment[self.get_position_index(yx)] == 'X'
index a5d38897205282e51fb29ba23333c72fded7b02a..9edfa68ca85871557aeb396075c37ed68475011d 100644 (file)
@@ -329,16 +329,28 @@ class ThingAnimate(Thing):
             self.game.changed = True
             self.task = self.get_next_task()
 
+    def prepare_multiprocessible_fov_stencil(self):
+        fov_map_class = self.game.map_geometry.fov_map_class
+        fov_radius = 3 if self.drunk > 0 else 12
+        self._fov = fov_map_class(self.game.things, self.game.maps,
+                                  self.position, fov_radius, self.game.get_map)
+
+    def multiprocessible_fov_stencil(self):
+        self._fov.init_terrain()
+
     @property
     def fov_stencil(self):
         if self._fov:
             return self._fov
-        fov_map_class = self.game.map_geometry.fov_map_class
-        fov_radius = 3 if self.drunk > 0 else 12
-        self._fov = fov_map_class(self.game.things, self.game.maps, self.position,
-                                  fov_radius, self.game.get_map)
+        # due to the pre-multiprocessing in game.send_gamestate,
+        # the following should actually never be called
+        self.prepare_multiprocessible_fov_stencil()
+        self.multiprocessible_fov_stencil()
         return self._fov
 
+    def fov_stencil_make(self):
+        self._fov.make()
+
     def fov_test(self, big_yx, little_yx):
         test_position = self.fov_stencil.target_yx(big_yx, little_yx)
         if self.fov_stencil.inside(test_position):