LoafyLemon
4c98cbe669
* Implemented new DollThread method with thread-safe locking mechanism and pickling support for thread event queues * Added memoization for wardrobe elements * Added threading for various wardrobe-related methods * Added lazyloading (to avoid render stalls) * Added button generation for DollCloth and DollOutfit instances * Significantly reduced code repetition inside the wardrobe loop * Added new methods for the Doll, and improved others. * Fixed viewport adjustment values resetting on interaction * Fixed character chit-chats performance issues * Updated saves compatibility patch
92 lines
3.0 KiB
Plaintext
92 lines
3.0 KiB
Plaintext
init python early:
|
|
import threading
|
|
import queue
|
|
|
|
class DollThread(threading.Thread, NoRollback):
|
|
__lock = threading.RLock()
|
|
_count = 0
|
|
_instances = _list()
|
|
_interval = 0.05 if renpy.android else 0.025
|
|
|
|
def __init__(self, interval=None, group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None):
|
|
threading.Thread.__init__(self, group, target, name, args, kwargs, daemon=daemon)
|
|
|
|
self._return = None
|
|
self.interval = interval or self._interval
|
|
self._delay = threading.Timer(self.interval, self._execute)
|
|
self._stop = threading.Event()
|
|
|
|
def start(self):
|
|
DollThread._instances.append(self)
|
|
DollThread._count += 1
|
|
super().start()
|
|
|
|
def run(self):
|
|
with DollThread.__lock:
|
|
self._delay.start()
|
|
self._delay.join()
|
|
self.stop()
|
|
|
|
def _execute(self):
|
|
while not self._stop.is_set():
|
|
if self._target is not None:
|
|
self._return = self._target(*self._args, **self._kwargs)
|
|
renpy.restart_interaction()
|
|
break
|
|
|
|
def join(self, timeout=None):
|
|
super().join(timeout=timeout)
|
|
return self._return
|
|
|
|
def stop(self):
|
|
self._stop.set()
|
|
DollThread._instances.remove(self)
|
|
DollThread._count -= 1
|
|
|
|
@classmethod
|
|
def stop_all(cls):
|
|
with cls.__lock:
|
|
for thread in cls._instances:
|
|
thread.stop()
|
|
|
|
# Allow threads to exit gracefully before forceful termination
|
|
for thread in cls._instances:
|
|
thread.join()
|
|
|
|
class DefaultQueue(queue.Queue, NoRollback):
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.last_item = None
|
|
|
|
def put(self, item, block=True, timeout=None):
|
|
super().put(item, block, timeout)
|
|
self.last_item = item
|
|
|
|
def get_with_default(self, default):
|
|
try:
|
|
return self.get(block=False)
|
|
except queue.Empty:
|
|
return self.last_item or default
|
|
|
|
def __getstate__(self):
|
|
state = self.__dict__.copy()
|
|
del state['last_item']
|
|
del state['mutex']
|
|
del state['not_empty']
|
|
del state['not_full']
|
|
del state['all_tasks_done']
|
|
return state
|
|
|
|
def __setstate__(self, state):
|
|
self.__dict__.update(state)
|
|
self.last_item = None
|
|
self.mutex = threading.Lock()
|
|
self.not_empty = threading.Condition(self.mutex)
|
|
self.not_full = threading.Condition(self.mutex)
|
|
self.all_tasks_done = threading.Condition(self.mutex)
|
|
|
|
def __reduce__(self):
|
|
return (DefaultQueue, ())
|
|
|
|
def __reduce_ex__(self, protocol):
|
|
return DefaultQueue, (), self.__getstate__(), None, iter([]) |