Fixed replay length (it is not ULEB)

This commit is contained in:
Emily 2019-03-17 02:57:48 +01:00
parent fc5bd5dc00
commit 15c80aae66
5 changed files with 43 additions and 24 deletions

View File

@ -24,8 +24,17 @@ class ReplayFrame:
raise Exception("Buttons are out of range") raise Exception("Buttons are out of range")
self.buttons = buttons self.buttons = buttons
@staticmethod
def _float_convert(f):
if f % 1 == 0:
return repr(int(f))
return repr(round(f, 1))
def __str__(self): def __str__(self):
return "%d|%s|%s|%d," % (self.delta, repr(self.x), repr(self.y), self.buttons) return "%d|%s|%s|%d," % (self.delta,
self._float_convert(self.x),
self._float_convert(self.y),
self.buttons)
def __bytes__(self): def __bytes__(self):
return str(self).encode() return str(self).encode()

View File

@ -1,10 +1,9 @@
SSH = 0 SSH = b"XH"
SH = 1 SH = b"SH"
SS = 2 SS = b"X"
S = 3 S = b"S"
A = 4 A = b"A"
B = 5 B = b"B"
C = 6 C = b"C"
D = 7 D = b"D"
F = 8 F = b"F"
N = 9

View File

@ -105,6 +105,7 @@ class Serializable:
def pack(self, byte_order = BYTEORDER_LITTLE): def pack(self, byte_order = BYTEORDER_LITTLE):
struct_fmt = byte_order + self.get_struct_fmt() struct_fmt = byte_order + self.get_struct_fmt()
#print(struct_fmt, self.get_value())
return struct.pack(struct_fmt, *self.get_value()) return struct.pack(struct_fmt, *self.get_value())
class Serializer: class Serializer:

View File

@ -1,6 +1,7 @@
import struct import struct
import string import string
import lzma #import lzma
import pylzma # Required cause pythons standard library lzma has missing support
from .frame import ReplayFrame from .frame import ReplayFrame
@ -14,9 +15,13 @@ from io import BufferedReader
from os.path import isfile from os.path import isfile
from hashlib import md5 as _md5 from hashlib import md5 as _md5
import traceback
def md5_str(data): def md5_str(data):
print(data)
if type(data) is str: if type(data) is str:
data = data.encode("ascii") data = data.encode("ascii")
print(_md5(data).hexdigest().encode())
return _md5(data).hexdigest().encode() return _md5(data).hexdigest().encode()
def md5_file(file): def md5_file(file):
@ -31,14 +36,13 @@ def md5_file(file):
hash.update(chunk) hash.update(chunk)
return hash.hexdigest() return hash.hexdigest()
def append_and_compress(data):
return lzma_compress(data + b"-12345|0|0|1337,")
def lzma_compress(data): def lzma_compress(data):
return encode_uleb(len(data)) + lzma.compress(data + b"-12345|0|0|1337,", format = lzma.FORMAT_ALONE, filters = [ comp = pylzma.compress(data, dictionary = 21, fastBytes = 255, eos = False)
{ comp = comp[:5] + struct.pack(b"<Q", len(data)) + comp[5:] # Append uncompressed length
"id": lzma.FILTER_LZMA1, return struct.pack("<I", len(comp)) + comp # For some odd ass reason this doesnt use ULEB
"preset": lzma.PRESET_DEFAULT,
"dict_size": 1 << 21
}
])
class Replay: class Replay:
_mode = Serializable(osuModes.STANDARD, TYPE_BYTE) _mode = Serializable(osuModes.STANDARD, TYPE_BYTE)
@ -61,9 +65,10 @@ class Replay:
_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)
_online_score_id= Serializable(0, TYPE_ULLONG)
_replay_data = Serializable(b"", TYPE_BYTESTREAM, post = lzma_compress) _replay_data = Serializable(b"", TYPE_BYTESTREAM, post = append_and_compress)
_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
@ -109,6 +114,8 @@ class Replay:
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):
if type(player_name) is str:
player_name = player_name.encode()
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):
@ -151,6 +158,9 @@ class Replay:
self._timestamp.value = timestamp self._timestamp.value = timestamp
def set_online_score_id(self, online_score_id):
self._online_score_id.value = online_score_id
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
# Update variables --------------------------------------------------------- # Update variables ---------------------------------------------------------
@ -160,8 +170,8 @@ class Replay:
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(b"%d%b%b%b%d%b" % (
self._combo.value, "osu", self._player_name.value, self._combo.value, b"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()
)) ))
) )

View File

@ -14,6 +14,6 @@ replay.set_score(score = 29284624,
combo = 358) # Set score info combo = 358) # Set score info
replay.set_mods(osuMods.HIDDEN | osuMods.DOUBLETIME) # Enable HDDT mods replay.set_mods(osuMods.HIDDEN | osuMods.DOUBLETIME) # Enable HDDT mods
replay.set_timestamp(1552466941) # Set unix timestamp replay.set_timestamp(636880715111611126, False)
replay.save("myReplay.osr") # Export replay to file replay.save("myReplay.osr") # Export replay to file