Android Bug fixes

* Added a UI lock mechanism to avoid render stalls
* Fixed initialization issue due to python init offset for android devices
* Fixed a hang caused by joining threads on android devices
* Fixed a race condition when forcefully stopping threads
This commit is contained in:
LoafyLemon 2023-07-14 23:52:27 +01:00
parent b6c77b1992
commit fc794f969a
7 changed files with 66 additions and 45 deletions

View File

@ -281,13 +281,11 @@ init python:
thread = DollThread(target=_func, args=(self, self._hash))
thread.start()
if settings.get("multithreading"):
@property
def button(self):
@property
def button(self):
if settings.get("multithreading"):
return self._button.get_with_default(self._loading)
else:
@property
def button(self):
else:
return self._build_button(self._hash)
def clear_button_cache(self):

View File

@ -141,35 +141,38 @@ init python:
return Fixed(*sprites, self.emote, fit_first=True)
if settings.get("multithreading"):
def build_image(self):
def build_image(self):
def _func(self, hash):
result = self._build_image(hash)
self._sprite.put(result)
def _func(self, hash):
result = self._build_image(hash)
self._sprite.put(result)
thread = DollThread(target=_func, args=(self, self._hash))
thread.start()
else:
def build_image(self):
self._sprite.put(self._build_image(self._hash))
renpy.restart_interaction()
thread = DollThread(target=_func, args=(self, self._hash))
thread.start()
def _image(self, st, at):
return self._sprite.get_with_default(Null()), None
@property
def image(self):
if settings.get("multithreading"):
if not renpy.is_skipping() and self.is_stale():
self.build_image()
if not renpy.is_skipping() and self.is_stale():
self.build_image()
if renpy.showing(get_character_tag(self.name), layer=self.layer):
self.show()
elif renpy.in_rollback():
self.build_image()
if renpy.showing(get_character_tag(self.name), layer=self.layer):
self.show()
# elif renpy.in_rollback():
# self.build_image()
return DynamicDisplayable(self._image)
return DynamicDisplayable(self._image)
else:
if not renpy.is_skipping() and self.is_stale():
if renpy.showing(get_character_tag(self.name), layer=self.layer):
self.show()
return self._build_image(self._hash)
def equip(self, obj, remove_old=True):
"""Takes DollCloth or DollOutfit object to equip."""

View File

@ -180,13 +180,11 @@ init python:
thread = DollThread(target=_func, args=(self, self._hash, subcat))
thread.start()
if settings.get("multithreading"):
@property
def button(self):
@property
def button(self):
if settings.get("multithreading"):
return self._button.get_with_default(self._loading)
else:
@property
def button(self):
else:
global current_subcategory
return self._build_button(self._hash, current_subcategory)

View File

@ -40,18 +40,24 @@ init python early:
def stop(self):
self._stop.set()
DollThread._instances.remove(self)
DollThread._count -= 1
if self in DollThread._instances:
DollThread._instances.remove(self)
DollThread._count -= 1
if DollThread._count <= 0:
renpy.restart_interaction()
@classmethod
def stop_all(cls):
with cls.__lock:
for thread in cls._instances:
thread.stop()
for thread in cls._instances:
# Allow threads to exit gracefully before forceful termination
for thread in cls._instances:
thread.join()
thread.stop()
# if not renpy.android:
# # Then forcefully terminate the remainders (except on android because that stalls the renderer)
# for thread in cls._instances:
# thread.join()
class DefaultQueue(queue.Queue, NoRollback):
def __init__(self):
@ -89,4 +95,4 @@ init python early:
return (DefaultQueue, ())
def __reduce_ex__(self, protocol):
return DefaultQueue, (), self.__getstate__(), None, iter([])
return DefaultQueue, (), self.__getstate__(), None, iter([])

View File

@ -10,7 +10,7 @@ default preferences.renderer = "auto"
default preferences.gl_powersave = False
default preferences.audio_when_minimized = False
init -5 python:
init python:
settings.default("theme", "auto")
settings.default("text_color_day", "#402313ff")
settings.default("text_color_night", "#341c0fff")

View File

@ -6,7 +6,7 @@ init offset = -10
default persistent.custom_settings = {}
default persistent.custom_settings_default = {}
init -10 python in settings:
init python in settings:
from store import persistent, Action, DictEquality
not_set = object()

View File

@ -35,10 +35,19 @@ init python:
_lock = False
def rebuild_wardrobe_icons(items, subcat):
if not settings.get("multithreading"):
return
if subcat == "import":
return
for i in items.get(subcat, []):
i.build_button(subcat)
def lock_wardrobe_icon(icon):
if not settings.get("multithreading"):
return icon
lock = bool(DollThread._count)
return gray_tint(icon) if lock else icon
@ -629,9 +638,10 @@ screen wardrobe_menu(xx, yy):
button:
focus_mask None
xysize (72, 72)
background icon
background lock_wardrobe_icon(icon)
activate_sound "sounds/scroll.ogg"
tooltip category
sensitive (not bool(DollThread._count))
action Return(["category", category])
if current_category == category:
xoffset icon_xoffset
@ -646,8 +656,9 @@ screen wardrobe_menu(xx, yy):
button:
focus_mask None
xysize (72, 72)
background Fixed(icon_bg, Transform("interface/wardrobe/icons/categories/outfits.webp", zoom=0.45, anchor=(0.5, 0.5), align=(0.5, 0.5)), icon_frame)
background lock_wardrobe_icon(Fixed(icon_bg, Transform("interface/wardrobe/icons/categories/outfits.webp", zoom=0.45, anchor=(0.5, 0.5), align=(0.5, 0.5)), icon_frame))
tooltip "Outfits Manager"
sensitive (not bool(DollThread._count))
action Return(["category", "outfits"])
if current_category == "outfits":
yoffset icon_yoffset
@ -758,7 +769,7 @@ screen wardrobe_menuitem(xx, yy):
pos (12, 108)
for subcategory in category_items.keys():
$ icon = "interface/wardrobe/icons/{}.webp".format(subcategory)
$ icon = lock_wardrobe_icon("interface/wardrobe/icons/{}.webp".format(subcategory))
button:
focus_mask None
@ -767,6 +778,7 @@ screen wardrobe_menuitem(xx, yy):
selected_background Transform(icon, size=(72, 72), fit="contain", )
selected (subcategory == current_subcategory)
tooltip subcategory
sensitive (not bool(DollThread._count))
action Return(["subcategory", subcategory])
# # Item icons
@ -810,7 +822,7 @@ screen wardrobe_outfit_menuitem(xx, yy):
pos (8, 108)
for subcategory in category_items.keys():
$ icon = "interface/wardrobe/icons/{}.webp".format(subcategory)
$ icon = lock_wardrobe_icon("interface/wardrobe/icons/{}.webp".format(subcategory))
$ action = Return(["subcategory", subcategory])
if subcategory == "schedule" and not get_character_scheduling(states.active_girl):
@ -823,6 +835,7 @@ screen wardrobe_outfit_menuitem(xx, yy):
background Transform(icon, alpha=0.65, xsize=72, fit="contain")
selected_background Transform(icon, xsize=72, fit="contain")
selected (subcategory == current_subcategory)
sensitive (not bool(DollThread._count))
tooltip subcategory
action action
@ -846,8 +859,10 @@ screen wardrobe_outfit_menuitem(xx, yy):
textbutton "Save":
focus_mask None
xysize icon_size
insensitive_background "#0000001A"
idle_background "#00000033"
text_align (0.5, 0.5)
sensitive (not bool(DollThread._count))
action Return(["addoutfit", None])
if current_subcategory == "import":
@ -895,6 +910,7 @@ style wardrobe_button is empty:
style wardrobe_button_text:
color "#fff"
insensitive_color "#808080"
size 20
outlines [ (2, "#000", 0, 0) ]