NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

video.py (8503B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\heronotification\video.py
      2 import abc
      3 import math
      4 import eveui
      5 import gametime
      6 import signals
      7 import trinity
      8 import uthread2
      9 from carbonui import uiconst
     10 from carbonui.primitives.sprite import StreamingVideoSprite
     11 from carbonui.uianimations import animations
     12 from eve.client.script.ui.heronotification.cancel import Cancelled
     13 from stacklesslib.locks import NLCondition
     14 
     15 class LoopPolicy(object):
     16     __metaclass__ = abc.ABCMeta
     17 
     18     @abc.abstractmethod
     19     def should_stop(self):
     20         pass
     21 
     22     def on_start_looping(self):
     23         pass
     24 
     25     def on_loop_finished(self):
     26         pass
     27 
     28     def dispose(self):
     29         pass
     30 
     31 
     32 class LoopCountPolicy(LoopPolicy):
     33 
     34     def __init__(self, loop_count):
     35         self._loop_count = loop_count
     36         self._finished_loops = 0
     37 
     38     def should_stop(self):
     39         return self._finished_loops >= self._loop_count
     40 
     41     def on_loop_finished(self):
     42         self._finished_loops += 1
     43 
     44 
     45 class LoopTimerPolicy(LoopPolicy):
     46 
     47     def __init__(self, duration):
     48         self._duration = duration
     49         self._loop_start = None
     50 
     51     def should_stop(self):
     52         return self._loop_start is not None and gametime.now() - self._loop_start >= self._duration
     53 
     54     def on_start_looping(self):
     55         self._loop_start = gametime.now()
     56 
     57 
     58 class SegmentedVideoHeroNotification(object):
     59 
     60     def __init__(self, video_width, video_height, video_intro_path, video_loop_path, video_outro_path, loop_policy, allow_cancel_intro = False, allow_cancel_loop = False):
     61         self._allow_cancel_intro = allow_cancel_intro
     62         self._allow_cancel_loop = allow_cancel_loop
     63         self._cancellation_token = None
     64         self._loop_policy = loop_policy
     65         self._state = State.INIT
     66         self._video_height = video_height
     67         self._video_intro_path = video_intro_path
     68         self._video_loop_path = video_loop_path
     69         self._video_outro_path = video_outro_path
     70         self._video_sprite_intro = None
     71         self._video_sprite_loop = None
     72         self._video_sprite_outro = None
     73         self._video_width = video_width
     74         self.on_intro_start = signals.Signal()
     75         self.on_loop_start = signals.Signal()
     76         self.on_outro_start = signals.Signal()
     77         self._on_intro_start_condition = NLCondition()
     78         self._on_loop_start_condition = NLCondition()
     79         self._on_outro_start_condition = NLCondition()
     80         self._is_killed_gracefully = False
     81 
     82     def play(self, parent, cancellation_token):
     83         if self._state != State.INIT:
     84             raise RuntimeError('The video is already playing')
     85         self._cancellation_token = cancellation_token
     86         try:
     87             self._setup(parent)
     88             self._wait_for_intro()
     89         except Cancelled:
     90             self._hard_outro()
     91         else:
     92             self._wait_for_loops()
     93             self._play_outro()
     94             self._wait_for_outro()
     95         finally:
     96             self._cleanup()
     97 
     98     def wait_for_intro_start(self):
     99         if self._state < State.INTRO:
    100             self._on_intro_start_condition.wait()
    101 
    102     def wait_for_loop_start(self):
    103         if self._state < State.LOOP:
    104             self._on_loop_start_condition.wait()
    105 
    106     def wait_for_outro_start(self):
    107         if self._state < State.OUTRO:
    108             self._on_outro_start_condition.wait()
    109 
    110     def _setup(self, parent):
    111         self._state = State.SETUP
    112         self._video_sprite_intro = self._create_video_sprite(parent=parent, video_path=self._video_intro_path, auto_play=True, on_finished=self._on_intro_finished)
    113         self._video_sprite_loop = self._create_video_sprite(parent=parent, video_path=self._video_loop_path, loop=True, display=False)
    114         self._video_sprite_outro = self._create_video_sprite(parent=parent, video_path=self._video_outro_path, display=False)
    115         self._state = State.INTRO
    116         self.on_intro_start()
    117         self._on_intro_start_condition.notify_all()
    118 
    119     def _create_video_sprite(self, parent, video_path, loop = False, auto_play = False, on_finished = None, display = True):
    120         sprite = StreamingVideoSprite(parent=parent, align=uiconst.CENTER, state=uiconst.UI_DISABLED, width=self._video_width, height=self._video_height, videoPath=video_path, disableAudio=True, videoLoop=loop, videoAutoPlay=auto_play, blendMode=trinity.TR2_SBM_ADD, spriteEffect=trinity.TR2_SFX_COPY)
    121         sprite.display = display
    122         if on_finished is not None:
    123             sprite.OnVideoFinished = on_finished
    124         return sprite
    125 
    126     def _on_intro_finished(self):
    127         if self._state == State.INTRO:
    128             self._play_loop()
    129 
    130     def _wait_for_intro(self):
    131         while self._state == State.INTRO:
    132             should_continue = self._wait_for_next_frame()
    133             if not should_continue:
    134                 return
    135             if self._allow_cancel_intro:
    136                 self._cancellation_token.check_cancelled()
    137 
    138     def _play_loop(self):
    139         self._state = State.LOOP
    140         self._video_sprite_loop.display = True
    141         self._video_sprite_intro.display = False
    142         self._video_sprite_loop.Play()
    143         self._loop_policy.on_start_looping()
    144         self.on_loop_start()
    145         self._on_loop_start_condition.notify_all()
    146 
    147     def _wait_for_loops(self):
    148         last_loop = self._get_video_loops()
    149         while not self._loop_policy.should_stop():
    150             if self._allow_cancel_loop and self._cancellation_token.cancelled:
    151                 while self._get_video_loops() == last_loop:
    152                     should_continue = self._wait_for_next_frame()
    153                     if not should_continue:
    154                         return
    155                     return
    156 
    157             should_continue = self._wait_for_next_frame()
    158             if not should_continue:
    159                 return
    160             loop = self._get_video_loops()
    161             while last_loop < loop:
    162                 last_loop += 1
    163                 self._loop_policy.on_loop_finished()
    164 
    165     def _get_video_loops(self):
    166         if not self._video_sprite_loop.duration:
    167             return 0
    168         return int(math.floor(self._video_sprite_loop.mediaTime / float(self._video_sprite_loop.duration)))
    169 
    170     def _play_outro(self):
    171         self._state = State.OUTRO
    172         self._video_sprite_outro.display = True
    173         self._video_sprite_loop.display = False
    174         self._video_sprite_loop.Pause()
    175         self._video_sprite_outro.Play()
    176         self.on_outro_start()
    177         self._on_outro_start_condition.notify_all()
    178 
    179     def _wait_for_outro(self):
    180         while self._state == State.OUTRO:
    181             if self._video_sprite_outro.isFinished:
    182                 break
    183             should_continue = self._wait_for_next_frame()
    184             if not should_continue:
    185                 return
    186 
    187     def _hard_outro(self):
    188         for sprite in (self._video_sprite_intro, self._video_sprite_loop, self._video_sprite_outro):
    189             if sprite is not None and not sprite.destroyed:
    190                 animations.FadeOut(sprite, duration=0.5)
    191 
    192         uthread2.sleep(0.5)
    193         self._state = State.FINISHED
    194 
    195     def _wait_for_next_frame(self):
    196         eveui.wait_for_next_frame()
    197         if self.is_killed_gracefully:
    198             return False
    199         self._check_destroyed()
    200         return True
    201 
    202     def _check_destroyed(self):
    203         for element in (self._video_sprite_intro, self._video_sprite_loop, self._video_sprite_outro):
    204             if element is None or element.destroyed:
    205                 raise HeroNotificationDestroyed()
    206 
    207     @property
    208     def is_killed_gracefully(self):
    209         return self._is_killed_gracefully
    210 
    211     def kill(self):
    212         self._is_killed_gracefully = True
    213 
    214     def _cleanup(self):
    215         self._loop_policy.dispose()
    216         for element in (self._video_sprite_intro, self._video_sprite_loop, self._video_sprite_outro):
    217             if element is not None:
    218                 element.Close()
    219 
    220         self._video_sprite_intro = None
    221         self._video_sprite_loop = None
    222         self._video_sprite_outro = None
    223         self._cancellation_token = None
    224         self._state = State.FINISHED
    225         self._on_intro_start_condition.notify_all()
    226         self._on_loop_start_condition.notify_all()
    227         self._on_outro_start_condition.notify_all()
    228 
    229     def __call__(self, parent, cancellation_token):
    230         self.play(parent, cancellation_token)
    231 
    232 
    233 class State(object):
    234     INIT = 1
    235     SETUP = 2
    236     INTRO = 3
    237     LOOP = 4
    238     OUTRO = 5
    239     FINISHED = 6
    240 
    241 
    242 class HeroNotificationDestroyed(Exception):
    243     pass