WTS/game/scripts/doll/threading.rpy
LoafyLemon 4c98cbe669 Wardrobe performance improvements and bug fixes
* 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
2023-07-11 22:57:49 +01:00

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([])