Attrib rewrite

This commit is contained in:
Emily 2019-03-13 09:55:17 +01:00
parent 2b418c27c1
commit 204aed6b06
3 changed files with 73 additions and 44 deletions

View File

@ -39,33 +39,33 @@ def lzma_compress(data):
]) ])
class Replay: class Replay:
mode = Serializable(osuModes.STANDARD, TYPE_BYTE) _mode = Serializable(osuModes.STANDARD, TYPE_BYTE)
osu_version = Serializable(20131216, TYPE_INT) _osu_version = Serializable(20131216, TYPE_INT)
beatmap_hash = Serializable(b"d41d8cd98f00b204e9800998ecf8427e", TYPE_STRING) _beatmap_hash = Serializable(b"d41d8cd98f00b204e9800998ecf8427e", TYPE_STRING)
player_name = Serializable(b"osu!", TYPE_STRING) _player_name = Serializable(b"osu!", TYPE_STRING)
score_hash = Serializable(b"d41d8cd98f00b204e9800998ecf8427e", TYPE_STRING) _score_hash = Serializable(b"d41d8cd98f00b204e9800998ecf8427e", TYPE_STRING)
score_300s = Serializable(0, TYPE_USHORT) _score_300s = Serializable(0, TYPE_USHORT)
score_100s = Serializable(0, TYPE_USHORT) _score_100s = Serializable(0, TYPE_USHORT)
score_50s = Serializable(0, TYPE_USHORT) _score_50s = Serializable(0, TYPE_USHORT)
score_gekis = Serializable(0, TYPE_USHORT) _score_gekis = Serializable(0, TYPE_USHORT)
score_katus = Serializable(0, TYPE_USHORT) _score_katus = Serializable(0, TYPE_USHORT)
score_miss = Serializable(0, TYPE_USHORT) _score_miss = Serializable(0, TYPE_USHORT)
score = Serializable(0, TYPE_INT) _score = Serializable(0, TYPE_INT)
combo = Serializable(0, TYPE_USHORT) _combo = Serializable(0, TYPE_USHORT)
perfect = Serializable(True, TYPE_BOOL) _perfect = Serializable(True, TYPE_BOOL)
mods = Serializable(osuMods.NOMOD, TYPE_INT) _mods = Serializable(osuMods.NOMOD, TYPE_INT)
lifebar_graph = Serializable(b"0|1,", TYPE_STRING) _lifebar_graph = Serializable(b"0|1,", TYPE_STRING)
timestamp = Serializable(0, TYPE_ULLONG) _timestamp = Serializable(0, TYPE_ULLONG)
replay_data = Serializable(b"", TYPE_BYTESTREAM, post = lzma_compress) _replay_data = Serializable(b"", TYPE_BYTESTREAM, post = lzma_compress)
online_score_id = Serializable(0, TYPE_ULLONG) _online_score_id= Serializable(0, TYPE_ULLONG)
# Marker (Only used as attribute section marker for auto-serializing) # Marker (Only used as attribute section marker for auto-serializing)
end_of_attributes = None _end_of_attributes = None
def __init__(self, **kwargs): def __init__(self, **kwargs):
allowed_kwargs = { allowed_kwargs = {
@ -79,56 +79,85 @@ class Replay:
if k in allowed_kwargs.keys(): if k in allowed_kwargs.keys():
allowed_kwargs[k](v) # Run callback func allowed_kwargs[k](v) # Run callback func
# --------------------------------------------------------------------------
# Set validators ----------------------------------------------------------- # Set validators -----------------------------------------------------------
def set_mode(self, mode): def set_mode(self, mode):
if mode > 3 or mode < 0: if mode > 3 or mode < 0:
raise Exception("Invalid mode") raise Exception("Invalid mode")
self.mode.value = mode self._mode.value = mode
def set_osu_version(self, osu_version): def set_osu_version(self, osu_version):
if type(osu_version) is not int: if type(osu_version) is not int:
raise Exception("osu! version must be an int") raise Exception("osu! version must be an int")
self.osu_version.value = osu_version self._osu_version.value = osu_version
def set_beatmap_hash(self, md5_hash): def set_beatmap_hash(self, md5_hash):
if len(md5_hash) != 32 or len([x for x in md5_hash if x in string.hexdigits]) != 32: if len(md5_hash) != 32 or len([x for x in md5_hash if x in string.hexdigits]) != 32:
raise Exception("Invalid beatmap hash") raise Exception("Invalid beatmap hash")
self.beatmap_hash.value = md5_hash self._beatmap_hash.value = md5_hash
def set_beatmap(self, filepath): def set_beatmap_file(self, filepath):
if not isfile(filepath): if not isfile(filepath):
raise Exception("Beatmap file not found") raise Exception("Beatmap file not found")
with open(filepath, "rb") as f: with open(filepath, "rb") as f:
self.beatmap_hash.value = md5_file(f) self._beatmap_hash.value = md5_file(f)
def set_player_name(self, player_name): def set_player_name(self, player_name):
self.player_name.value = player_name self._player_name.value = player_name
def set_score_hash(self, md5_hash): def set_score_hash(self, md5_hash):
if type(md5_hash) is bytes: if type(md5_hash) is bytes:
md5_hash = md5_hash.decode() md5_hash = md5_hash.decode()
if len(md5_hash) != 32 or len([x for x in md5_hash if x in string.hexdigits]) != 32: if len(md5_hash) != 32 or len([x for x in md5_hash if x in string.hexdigits]) != 32:
raise Exception("Invalid replay hash") raise Exception("Invalid replay hash")
self.score_hash.value = md5_hash.encode() self._score_hash.value = md5_hash.encode()
def set_score(self, score = None, combo = None, s300 = None, s100 = None, s50 = None, sgekis = None, skatus = None, miss = None):
if type(score) is int: self._score.value = score
if type(combo) is int: self._combo.value = combo
if type(s300) is int: self._score_300s.value = s300
if type(s100) is int: self._score_100s.value = s100
if type(s50) is int: self._score_50s.value = s50
if type(sgekis) is int: self._score_gekis.value = sgekis
if type(skatus) is int: self._score_katus.value = skatus
if type(miss) is int: self._score_miss.value = miss
def set_mods(self, mods): def set_mods(self, mods):
if mods < 0 or mods > (1 << 30) - 1: if mods < 0 or mods > (1 << 30) - 1:
raise Exception("Mods are out of range") raise Exception("Mods are out of range")
self.mods.value = mods self._mods.value = mods
def set_lifebar_graph(self, graph):
t_graph = type(graph)
if t_graph is list:
self._lifebar_graph.value = b"".join(graph)
elif t_graph is str:
self._lifebar_graph.value = graph.encode()
elif t_graph is bytes:
self._lifebar_graph.value = graph
else:
raise Exception("Invalid lifebar data")
def set_timestamp(self, timestamp, use_unix = True):
if use_unix:
timestamp += 62135599380000 # offset
timestamp *= 10 ** 4
self._timestamp.value = timestamp
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
# Update variables --------------------------------------------------------- # Update variables ---------------------------------------------------------
def update_perfect(self): def update_perfect(self):
m = [self.score_100s.value, self.score_50s.value, self.score_katus.value, self.score_miss.value] m = [self._score_100s.value, self._score_50s.value, self._score_katus.value, self._score_miss.value]
self.perfect.value = sum(m) == 0 self._perfect.value = sum(m) == 0
def update_score_hash(self): def update_score_hash(self):
self.set_score_hash( self.set_score_hash(
md5_str("%d%s%s%s%d%d" % ( md5_str("%d%s%s%s%d%d" % (
self.combo.value, "osu", self.player_name.value, self._combo.value, "osu", self._player_name.value,
self.beatmap_hash.value, self.score.value, self.get_rank() self._beatmap_hash.value, self._score.value, self.get_rank()
)) ))
) )
@ -140,27 +169,27 @@ class Replay:
# Get / Helpers ------------------------------------------------------------ # Get / Helpers ------------------------------------------------------------
def get_hits(self): def get_hits(self):
return sum([self.score_300s.value, self.score_100s.value, self.score_50s.value]) return sum([self._score_300s.value, self._score_100s.value, self._score_50s.value])
def get_possible_hits(self): def get_possible_hits(self):
return self.get_hits() + self.score_miss.value return self.get_hits() + self._score_miss.value
def get_rank(self): # We dont give out F ranks around here def get_rank(self): # We dont give out F ranks around here
hits = self.get_possible_hits() hits = self.get_possible_hits()
if hits == 0: if hits == 0:
raise Exception("Can not calculate rank without any score data") raise Exception("Can not calculate rank without any score data")
r300 = self.score_300s.value / hits r300 = self._score_300s.value / hits
r50 = self.score_50s.value / hits r50 = self._score_50s.value / hits
h = osuMods.any_enabled(self.mods.value, osuMods.HIDDEN | osuMods.FLASHLIGHT) h = osuMods.any_enabled(self._mods.value, osuMods.HIDDEN | osuMods.FLASHLIGHT)
if r300 == 1: if r300 == 1:
return osuRanks.SSH if h else osuRanks.SS return osuRanks.SSH if h else osuRanks.SS
if r300 > .9 and r50 <= .01 and self.score_miss.value == 0: if r300 > .9 and r50 <= .01 and self._score_miss.value == 0:
return osuRanks.SH if h else osuRanks.S return osuRanks.SH if h else osuRanks.S
if r300 > .8 and self.score_miss.value == 0 or r300 > .9: if r300 > .8 and self._score_miss.value == 0 or r300 > .9:
return osuRanks.A return osuRanks.A
if r300 > .7 and self.score_miss.value == 0 or r300 > .8: if r300 > .7 and self._score_miss.value == 0 or r300 > .8:
return osuRanks.B return osuRanks.B
if r300 > .6: if r300 > .6:
return osuRanks.C return osuRanks.C
@ -175,7 +204,7 @@ class Replay:
self.write(_frame) self.write(_frame)
return return
self.replay_data.value += bytes(frame) self._replay_data.value += bytes(frame)
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
# IO replay data ----------------------------------------------------------- # IO replay data -----------------------------------------------------------
@ -187,7 +216,7 @@ class Replay:
attribs = [ a for a in self.__dir__() if not a.startswith("__") ] attribs = [ a for a in self.__dir__() if not a.startswith("__") ]
for attrib in attribs: for attrib in attribs:
if attrib == "end_of_attributes": if attrib == "_end_of_attributes":
break break
serializer.add( self.__getattribute__(attrib) ) # Add value to serializer serializer.add( self.__getattribute__(attrib) ) # Add value to serializer

BIN
test.osr

Binary file not shown.

View File

@ -4,7 +4,7 @@ from osuRepy.replay import Replay
replay = Replay() replay = Replay()
replay.write( ReplayFrame(2, 3, 4, 4) ) replay.write( ReplayFrame(2, 3, 4, 4) )
replay.score_300s.value = 20 replay.set_score(s300 = 10)
replay.timestamp.value = 635592412124124124 # Wed Feb 11 2015 09:03:52 GMT+0100 (Central European Standard Time) replay.set_timestamp( 1552466941 )# Wed Feb 11 2015 09:03:52 GMT+0100 (Central European Standard Time)
replay.save("test.osr") replay.save("test.osr")