|  | @@ -1,4 +1,5 @@
 | 
	
		
			
			| 1 | 1 |  # coding: utf-8
 | 
	
		
			
			|  | 2 | +import os
 | 
	
		
			
			| 2 | 3 |  import typing
 | 
	
		
			
			| 3 | 4 |  
 | 
	
		
			
			| 4 | 5 |  import time
 | 
	
	
		
			
			|  | @@ -52,6 +53,7 @@ class BaseActor(Actor):
 | 
	
		
			
			| 52 | 53 |      ) -> None:
 | 
	
		
			
			| 53 | 54 |          self._mode = MODE_MAN_STAND_UP
 | 
	
		
			
			| 54 | 55 |          self.weapon_image_applier = WeaponImageApplier(config, self)
 | 
	
		
			
			|  | 56 | +        self.firing_texture_cache = {}  # type: typing.Dict[str, typing.Dict[typing.List[pyglet.image.TextureRegion]]  # nopep8
 | 
	
		
			
			| 55 | 57 |          super().__init__(image_path, subject=subject, config=config)
 | 
	
		
			
			| 56 | 58 |  
 | 
	
		
			
			| 57 | 59 |          # Firing
 | 
	
	
		
			
			|  | @@ -95,6 +97,10 @@ class BaseActor(Actor):
 | 
	
		
			
			| 95 | 97 |      def weapons(self) -> typing.List[str]:
 | 
	
		
			
			| 96 | 98 |          return []
 | 
	
		
			
			| 97 | 99 |  
 | 
	
		
			
			|  | 100 | +    def build_textures_cache(self) -> None:
 | 
	
		
			
			|  | 101 | +        super().build_textures_cache()
 | 
	
		
			
			|  | 102 | +        self.build_firing_texture_cache()
 | 
	
		
			
			|  | 103 | +
 | 
	
		
			
			| 98 | 104 |      def get_default_appliable_images(self) -> typing.List[Image.Image]:
 | 
	
		
			
			| 99 | 105 |          if not self.weapons:
 | 
	
		
			
			| 100 | 106 |              return []
 | 
	
	
		
			
			|  | @@ -127,6 +133,29 @@ class BaseActor(Actor):
 | 
	
		
			
			| 127 | 133 |          except UnknownWeapon:
 | 
	
		
			
			| 128 | 134 |              return []
 | 
	
		
			
			| 129 | 135 |  
 | 
	
		
			
			|  | 136 | +    def build_firing_texture_cache(self) -> None:
 | 
	
		
			
			|  | 137 | +        cache_dir = self.config.resolve('global.cache_dir_path')
 | 
	
		
			
			|  | 138 | +        for mode in self.get_modes():
 | 
	
		
			
			|  | 139 | +            for weapon in self.weapons:
 | 
	
		
			
			|  | 140 | +                firing_images = self.image_cache_manager.firing_cache.get_list(
 | 
	
		
			
			|  | 141 | +                    mode,
 | 
	
		
			
			|  | 142 | +                    weapon,
 | 
	
		
			
			|  | 143 | +                )
 | 
	
		
			
			|  | 144 | +                for i, firing_image in enumerate(firing_images):
 | 
	
		
			
			|  | 145 | +                    image_name = '{}_firing_{}_{}_{}.png'.format(
 | 
	
		
			
			|  | 146 | +                        str(self.subject.id),
 | 
	
		
			
			|  | 147 | +                        mode,
 | 
	
		
			
			|  | 148 | +                        weapon,
 | 
	
		
			
			|  | 149 | +                        i,
 | 
	
		
			
			|  | 150 | +                    )
 | 
	
		
			
			|  | 151 | +                    cache_image_path = os.path.join(cache_dir, image_name)
 | 
	
		
			
			|  | 152 | +                    firing_image.save(cache_image_path)
 | 
	
		
			
			|  | 153 | +
 | 
	
		
			
			|  | 154 | +                    self.firing_texture_cache\
 | 
	
		
			
			|  | 155 | +                        .setdefault(mode, {})\
 | 
	
		
			
			|  | 156 | +                        .setdefault(weapon, [])\
 | 
	
		
			
			|  | 157 | +                        .append(pyglet.image.load(cache_image_path))
 | 
	
		
			
			|  | 158 | +
 | 
	
		
			
			| 130 | 159 |      def firing(self, firing: 'GuiFiringEvent') -> None:
 | 
	
		
			
			| 131 | 160 |          # FIXME: move some code ?
 | 
	
		
			
			| 132 | 161 |          now = time.time()
 | 
	
	
		
			
			|  | @@ -135,35 +164,29 @@ class BaseActor(Actor):
 | 
	
		
			
			| 135 | 164 |              firing.increment_animation_index()
 | 
	
		
			
			| 136 | 165 |  
 | 
	
		
			
			| 137 | 166 |              try:
 | 
	
		
			
			| 138 |  | -                image = self.image_cache_manager.firing_cache.get(
 | 
	
		
			
			| 139 |  | -                    mode=self.mode,
 | 
	
		
			
			| 140 |  | -                    weapon=firing.weapon,
 | 
	
		
			
			| 141 |  | -                    position=firing.animation_index,
 | 
	
		
			
			| 142 |  | -                )
 | 
	
		
			
			| 143 |  | -            except UnknownAnimationIndex:
 | 
	
		
			
			| 144 |  | -                image = self.image_cache_manager.firing_cache.get(
 | 
	
		
			
			| 145 |  | -                    mode=self.mode,
 | 
	
		
			
			| 146 |  | -                    weapon=firing.weapon,
 | 
	
		
			
			| 147 |  | -                    position=0,
 | 
	
		
			
			| 148 |  | -                )
 | 
	
		
			
			| 149 |  | -                firing.reset_animation_index()
 | 
	
		
			
			| 150 |  | -            except UnknownFiringAnimation as exc:
 | 
	
		
			
			|  | 167 | +                texture = self.firing_texture_cache\
 | 
	
		
			
			|  | 168 | +                    [self.mode]\
 | 
	
		
			
			|  | 169 | +                    [firing.weapon]\
 | 
	
		
			
			|  | 170 | +                    [firing.animation_index]
 | 
	
		
			
			|  | 171 | +            except KeyError:
 | 
	
		
			
			| 151 | 172 |                  self.logger.error(
 | 
	
		
			
			| 152 |  | -                    'No firing animation for actor {}({}): {}'.format(
 | 
	
		
			
			|  | 173 | +                    'No firing animation for actor {}({}) for mode "{}"'
 | 
	
		
			
			|  | 174 | +                    ' and weapon "{}"'.format(
 | 
	
		
			
			| 153 | 175 |                          self.__class__.__name__,
 | 
	
		
			
			| 154 | 176 |                          str(self.subject.id),
 | 
	
		
			
			| 155 |  | -                        str(exc),
 | 
	
		
			
			|  | 177 | +                        self.mode,
 | 
	
		
			
			|  | 178 | +                        firing.weapon,
 | 
	
		
			
			| 156 | 179 |                      )
 | 
	
		
			
			| 157 | 180 |                  )
 | 
	
		
			
			| 158 | 181 |                  return  # There is no firing animation defined
 | 
	
		
			
			|  | 182 | +            except IndexError:
 | 
	
		
			
			|  | 183 | +                texture = self.firing_texture_cache\
 | 
	
		
			
			|  | 184 | +                    [self.mode]\
 | 
	
		
			
			|  | 185 | +                    [firing.weapon]\
 | 
	
		
			
			|  | 186 | +                    [0]
 | 
	
		
			
			|  | 187 | +                firing.reset_animation_index()
 | 
	
		
			
			| 159 | 188 |  
 | 
	
		
			
			| 160 |  | -            # FIXME cache: prepare before firing
 | 
	
		
			
			| 161 |  | -            import uuid
 | 
	
		
			
			| 162 |  | -            tmp_path = '/tmp/{}.png'.format(str(uuid.uuid4()))
 | 
	
		
			
			| 163 |  | -            image.save(tmp_path)
 | 
	
		
			
			| 164 |  | -            pyglet_image = pyglet.image.load(tmp_path)
 | 
	
		
			
			| 165 |  | -
 | 
	
		
			
			| 166 |  | -            self.update_image(pyglet_image.get_texture())
 | 
	
		
			
			|  | 189 | +            self.update_image(texture)
 | 
	
		
			
			| 167 | 190 |  
 | 
	
		
			
			| 168 | 191 |  
 | 
	
		
			
			| 169 | 192 |  class Man(BaseActor):
 |