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 = DollThread(target=_func, args=(self, self._hash))
thread.start() thread.start()
if settings.get("multithreading"): @property
@property def button(self):
def button(self): if settings.get("multithreading"):
return self._button.get_with_default(self._loading) return self._button.get_with_default(self._loading)
else: else:
@property
def button(self):
return self._build_button(self._hash) return self._build_button(self._hash)
def clear_button_cache(self): def clear_button_cache(self):

View File

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

View File

@ -40,18 +40,24 @@ init python early:
def stop(self): def stop(self):
self._stop.set() 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 @classmethod
def stop_all(cls): def stop_all(cls):
with cls.__lock: for thread in cls._instances:
for thread in cls._instances:
thread.stop()
# Allow threads to exit gracefully before forceful termination # Allow threads to exit gracefully before forceful termination
for thread in cls._instances: thread.stop()
thread.join()
# 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): class DefaultQueue(queue.Queue, NoRollback):
def __init__(self): def __init__(self):

View File

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

View File

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

View File

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