Optimisations, SlottedObjects, and bug fixes

* Implemented SlottedObject with rollback support,
* Fixed poses not rolling back correctly (see above)
* Fixed character re-showing during cg scenes
This commit is contained in:
LoafyLemon 2023-04-20 19:59:55 +01:00
parent 93909e5862
commit aa29c72e84
8 changed files with 97 additions and 4 deletions

View File

@ -8,6 +8,8 @@ init python:
"zorder": None,
}
__slots__ = ("char", "hue", "zorder", "_hash")
def __init__(self, obj):
self.char = obj
self.hue = HueMatrix(0)

View File

@ -1,5 +1,5 @@
init python:
class DollCloth(DollMethods, SlottedNoRollback):
class DollCloth(DollMethods):
layer_types = {
"mask": "-1",
"skin": 10,
@ -15,6 +15,8 @@ init python:
"zorder": None,
}
__slots__ = ("name", "categories", "type", "id", "color", "unlocked", "level", "blacklist", "modpath", "parent", "char", "color_default", "zorder", "seen", "_hash")
def __init__(self, name, categories, type, id, color, zorder=None, unlocked=False, level=0, blacklist=[], modpath=None, parent=None):
self.name = name
self.categories = categories

View File

@ -48,8 +48,9 @@ init -1 python:
def visit(self):
return []
class DollMethods(object):
class DollMethods(SlottedObject):
"""Container class for commonly used methods and attributes"""
_image = Null()
_image_cached = False
blacklist_toggles = ("hair", "glasses", "pubes", "piercing", "makeup", "tattoo", "earrings")

View File

@ -12,6 +12,8 @@ init python:
"zorder": None,
}
__slots__ = ("char", "_cum", "_hash")
def __init__(self, obj):
self.char = obj
self._cum = {k: None for k in (self.char.clothing_layers | self.char.face_layers).keys()}

View File

@ -10,6 +10,8 @@ init python:
"zorder": None,
}
__slots__ = ("char", "_cum", "_hash")
def __init__(self, obj):
self.char = obj
self._face = {k: None for k in self.char.face_layers.keys()}

View File

@ -44,6 +44,9 @@ init python:
"headgear": 281
}
__slots__ = ("wardrobe", "wardrobe_list", "blacklist", "outfits", "name", "states", "face", "body", "cum", \
"pose", "emote", "_hash", "zorder", "layer", "animation", "tag", "pos", "zoom", "xzoom", "align", "modpath")
def __init__(self, name, modpath=None):
self.wardrobe = {}
self.wardrobe_list = []
@ -84,7 +87,7 @@ init python:
return hash(salt)
def show(self):
if renpy.get_screen(("wardrobe", "animatedCG", "studio")):
if renpy.get_screen(("wardrobe", "animatedCG", "studio")) or renpy.showing("cg"):
return
base_transform = doll_transform(self.pos, self.zoom, self.xzoom)

View File

@ -1,7 +1,9 @@
init python:
class DollOutfit(DollMethods, SlottedNoRollback):
class DollOutfit(DollMethods):
default_schedule = {"day": False, "night": False, "cloudy": False, "rainy": False, "snowy": False}
__slots__ = ("group", "name", "desc", "price", "char", "unlocked", "schedule", "temp", "hidden", "addons", "_hash")
def __init__(self, group, unlocked=False, name="", desc="", price=0, temp=False, schedule={}, hidden=False, addons=[]):
self.group = [x.clone() if not x.parent else x for x in group]
self.name = name

View File

@ -123,3 +123,82 @@ python early hide:
renpy.display.focus.set_focused = set_focused
init -100 python:
# Due to the sheer number of Doll-type objects we create and keep per each character,
# we have to use each and every optimization technique we can get our hands on.
# The below code implements revertable __slots__ support, which reduces memory,
# without losing any functionality relevant to the objects that are using it.
#
# The code is taken from a PR proposed by Andykl:
# https://github.com/renpy/renpy/pull/3282
class _RevertableObject(_object):
# Reimplementation of the Ren'py class,
# but with slots support.
def __new__(cls, *args, **kwargs):
self = super(_RevertableObject, cls).__new__(cls)
log = renpy.game.log
if log is not None:
log.mutated[id(self)] = None
return self
def __init__(self, *args, **kwargs):
if (args or kwargs) and renpy.config.developer:
raise TypeError("object() takes no parameters.")
__setattr__ = renpy.revertable.mutator(object.__setattr__) # type: ignore
__delattr__ = renpy.revertable.mutator(object.__delattr__) # type: ignore
def _clean(self):
return None
def _compress(self, clean):
return clean
def _rollback(self, compressed):
pass
class SlottedObject(_RevertableObject):
__slots__ = ()
def __init_subclass__(cls):
if renpy.config.developer:
if hasattr(cls, "__getstate__"):
raise TypeError("slotted_object subclasses can't have "
"__getstate__ method. Use __reduce__ instead.")
for slot in cls.__dict__.get("__slots__", ()):
if slot.startswith("__") and not slot.endswith("__"):
raise ValueError("slotted_object __slots__ can not be mangled. "
"If you need it, mangle it by yourself.")
def _clean(self):
rv = object.__reduce_ex__(self, 2)[2]
# We need to make a copy of __dict__ to avoid its futher mutations.
# No attributes are set
if rv is None:
rv = { }
# Only __dict__ have attributes
elif isinstance(rv, dict):
rv = rv.copy()
# Only __slots__ have attributes
elif rv[0] is None:
rv = rv[1]
# Otherwise it is (__dict__, __slots__), so merge it together
else:
rv = dict(rv[0], **rv[1])
return rv
def _rollback(self, compressed):
if hasattr(self, "__dict__"):
self.__dict__.clear()
for k, v in compressed.items():
setattr(self, k, v)