Commit | Line | Data |
---|---|---|
8ee66edd FC |
1 | from os import pardir # pardir is .. (parent directory) |
2 | from os.path import dirname, abspath, join | |
3 | from sys import modules | |
4 | from direct.task import Task | |
5 | from direct.interval.IntervalGlobal import ivalMgr | |
6 | from lib.gameobject import GameObject | |
7 | ||
8 | ||
9 | class TaskDec: | |
10 | ||
11 | paused_taskchain = 'paused tasks' | |
12 | ||
13 | def __init__(self, tsk): | |
14 | self.tsk = tsk | |
15 | path = dirname(modules[Task.__name__].__file__) | |
16 | self.__direct_dir = abspath(join(path, pardir)) # path of direct.* | |
17 | ||
18 | def process(self): | |
19 | func = self.tsk.get_function() # ordinary tasks | |
20 | mod = func.__module__ | |
21 | modfile = '' | |
22 | if "from '" in str(modules[mod]): | |
23 | modfile = str(modules[mod]).split("from '")[1][:-2] | |
24 | sys_mod = modfile.find(self.__direct_dir) < 0 | |
25 | actor_ival = False | |
26 | if hasattr(func, 'im_class'): | |
27 | actor_ival = func.im_class.__name__ == 'ActorInterval' | |
28 | if mod.find('direct.interval') == 0 and not actor_ival: | |
29 | self.tsk.interval.pause() # python-based intervals | |
30 | return self.tsk | |
31 | if mod not in modules or sys_mod: return self.tsk | |
32 | return None | |
33 | ||
34 | def pause(self): | |
35 | tsk = self.tsk | |
36 | has_args = hasattr(tsk, 'getArgs') | |
37 | tsk.stored_extraArgs = tsk.get_args() if has_args else None | |
38 | if hasattr(tsk, 'getFunction'): tsk.stored_call = tsk.get_function() | |
39 | has_p = hasattr(tsk, '_priority') | |
40 | tsk.stored_priority = tsk._priority if has_p else tsk.get_sort() | |
41 | if hasattr(tsk, 'remainingTime'): tsk.remove() # do_later tasks | |
42 | else: # ordinary tasks | |
43 | tsk.lastactivetime = -tsk.time if hasattr(tsk, 'time') else 0 | |
44 | tsk.setTaskChain(TaskDec.paused_taskchain) | |
45 | ||
46 | def __resume_do_later(self): | |
47 | tsk = self.tsk | |
48 | d_t = globalClock.get_real_time() - globalClock.get_frame_time() | |
49 | tmp_delay = tsk.remainingTime - d_t | |
50 | upon_death = tsk.uponDeath if hasattr(tsk, 'uponDeath') else None | |
51 | new_task = taskMgr.doMethodLater( | |
52 | tmp_delay, tsk.stored_call, tsk.name, uponDeath=upon_death, | |
53 | priority=tsk.stored_priority, extraArgs=tsk.stored_extraArgs) | |
54 | if hasattr(tsk, 'remainingTime'): new_task.delayTime = tsk.delayTime | |
55 | ||
56 | def resume(self): | |
57 | tsk = self.tsk | |
58 | if hasattr(tsk, 'interval'): | |
59 | tsk.interval.resume() | |
60 | if hasattr(tsk, 'stored_call'): tsk.set_function(tsk.stored_call) | |
61 | return | |
62 | if hasattr(tsk, 'remainingTime'): | |
63 | self.__resume_do_later() | |
64 | return | |
65 | tsk.set_delay(tsk.lastactivetime) # ordinary tasks | |
66 | tsk.set_task_chain('default') | |
67 | tsk.clear_delay() # to avoid assertion error on resume | |
68 | ||
69 | ||
70 | class P3dPause(GameObject): | |
71 | ||
72 | def __init__(self): | |
73 | GameObject.__init__(self) | |
74 | taskMgr.setupTaskChain(TaskDec.paused_taskchain, frameBudget=0) | |
75 | self.__paused_ivals = [] | |
76 | self.__paused_tasks = [] | |
77 | ||
78 | @property | |
79 | def paused(self): | |
80 | tsk = taskMgr.getTasksNamed('__on_frame')[0] | |
81 | return tsk.getTaskChain() == TaskDec.paused_taskchain | |
82 | ||
83 | def pause_tasks(self): | |
84 | is_tsk = lambda tsk: tsk and hasattr(tsk, 'getFunction') | |
85 | tasks = [TaskDec(tsk) for tsk in taskMgr.getTasks() if is_tsk(tsk)] | |
86 | tasks = [tsk for tsk in tasks | |
87 | if tsk.tsk.get_task_chain() != 'unpausable'] | |
88 | namefilter = ['igLoop', 'dataLoop', 'ivalLoop', 'collisionLoop', | |
89 | 'garbageCollectStates', 'audioLoop', | |
90 | 'resetPrevTransform', 'eventManager'] | |
91 | tasks = [tsk for tsk in tasks | |
92 | if tsk.tsk.get_name_prefix() not in namefilter] | |
93 | not_none = lambda tsk: tsk is not None | |
94 | paused_tasks = list(filter(not_none, [tsk.process() for tsk in tasks])) | |
95 | self.__paused_tasks = list(map(TaskDec, paused_tasks)) | |
96 | for tsk in list(filter(is_tsk, taskMgr.getDoLaters())): | |
97 | self.__paused_tasks += [TaskDec(tsk)] | |
98 | tsk.remainingTime = tsk.wakeTime - globalClock.get_frame_time() | |
99 | list(map(lambda tsk: tsk.pause(), self.__paused_tasks)) | |
100 | ||
101 | def remove_task(self, tsk): | |
102 | list(map(self.__paused_tasks.remove, [ptsk for ptsk in self.__paused_tasks if ptsk.tsk == tsk])) | |
103 | ||
104 | def pause(self): | |
105 | self.__paused_ivals = ivalMgr.getIntervalsMatching('*') | |
106 | self.pause_tasks() | |
107 | return self.paused | |
108 | ||
109 | def resume(self): | |
110 | list(map(lambda ival: ival.resume(), self.__paused_ivals)) | |
111 | list(map(lambda tsk: tsk.resume(), self.__paused_tasks)) | |
112 | return self.paused | |
113 | ||
114 | def destroy(self): GameObject.destroy(self) |