Rework tag acquisition and text conversion

This commit is contained in:
Mc-muffin
2023-05-16 00:05:37 -05:00
parent 75e91359e7
commit a72d1c30d7
3 changed files with 152 additions and 154 deletions

View File

@@ -59,19 +59,13 @@ class ToolsTOR(ToolsTales):
super().__init__("TOR", tbl, "Tales-Of-Rebirth")
with open("../{}/Data/{}/Misc/{}".format(self.repo_name, self.gameName, self.tblFile), encoding="utf-8") as f:
jsonRaw = json.load(f)
self.jsonTblTags ={ k1:{ int(k2,16) if (k1 != "TBL") else k2:v2 for k2,v2 in jsonRaw[k1].items()} for k1,v1 in jsonRaw.items()}
self.itable = dict([[i, struct.pack(">H", int(j))] for j, i in self.jsonTblTags['TBL'].items()])
self.itags = dict([[i, j] for j, i in self.jsonTblTags['TAGS'].items()])
if "NAME" in self.jsonTblTags.keys():
self.inames = dict([[i, j] for j, i in self.jsonTblTags['NAME'].items()])
jsonRaw = json.load(f)
for k, v in jsonRaw.items():
self.jsonTblTags[k] = {int(k2, 16): v2 for k2, v2 in v.items()}
if "COLOR" in self.jsonTblTags.keys():
self.icolors = dict([[i, j] for j, i in self.jsonTblTags['COLOR'].items()])
for k, v in self.jsonTblTags.items():
self.ijsonTblTags[k] = {v2: k2 for k2, v2 in v.items()}
self.id = 1
#byteCode
@@ -479,100 +473,73 @@ class ToolsTOR(ToolsTales):
#Convert a bytes object to text using TAGS and TBL in the json file
def bytes_to_text(self, theirsce: Theirsce, offset=-1, end_strings = b"\x00"):
finalText = ''
TAGS = self.jsonTblTags['TAGS']
finalText = ""
tags = self.jsonTblTags['TAGS']
chars = self.jsonTblTags['TBL']
if (offset > 0):
theirsce.seek(offset, 0)
pos = theirsce.tell()
b = theirsce.read(1)
while b != end_strings:
#print(hex(fileRead.tell()))
b = ord(b)
if (b >= 0x99 and b <= 0x9F) or (b >= 0xE0 and b <= 0xEB):
c = (b << 8) + ord(theirsce.read(1))
# if str(c) not in json_data.keys():
# json_data[str(c)] = char_index[decode(c)]
try:
finalText += (self.jsonTblTags['TBL'][str(c)])
except KeyError:
b_u = (c >> 8) & 0xff
b_l = c & 0xff
finalText += ("{%02X}" % b_u)
finalText += ("{%02X}" % b_l)
elif b == 0x1:
finalText += ("\n")
elif b in (0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xB, 0xC, 0xD, 0xE, 0xF):
b2 = struct.unpack("<L", theirsce.read(4))[0]
if b in TAGS:
tag_name = TAGS.get(b)
tag_param = None
tag_search = tag_name.upper()
if (tag_search in self.jsonTblTags.keys()):
tags2 = self.jsonTblTags[tag_search]
tag_param = tags2.get(b2, None)
if tag_param != None:
finalText += tag_param
else:
#Pad the tag to be even number of characters
hex_value = self.hex2(b2)
if len(hex_value) < 4 and tag_name not in ['icon','speed']:
hex_value = "0"*(4-len(hex_value)) + hex_value
finalText += '<{}:{}>'.format(tag_name, hex_value)
#finalText += ("<%s:%08X>" % (tag_name, b2))
else:
finalText += "<%02X:%08X>" % (b, b2)
elif chr(b) in self.PRINTABLE_CHARS:
finalText += chr(b)
elif b >= 0xA1 and b < 0xE0:
finalText += struct.pack("B", b).decode("cp932")
elif b in (0x13, 0x17, 0x1A):
tag_name = f"Unk{b:02X}"
hex_value = ""
while theirsce.read(1) != b"\x80":
theirsce.seek(theirsce.tell()-1)
mark = theirsce.read(1)
hex_value += mark.hex()
if mark == "\x38":
hex_value += f"{struct.unpack('<H', theirsce.read(2))[0]:04X}"
finalText += '<{}:{}>'.format(tag_name, hex_value)
elif b in (0x18, 0x19):
tag_name = f"Unk{b:02X}"
hex_value = ""
while theirsce.read(1) != b"\x80":
theirsce.seek(theirsce.tell()-1)
hex_value += theirsce.read(1).hex()
finalText += '<{}:{}>'.format(tag_name, hex_value)
elif b == 0x81:
b = theirsce.read(1)
while True:
b = theirsce.read(1)
if b == end_strings: break
b = ord(b)
# Custom Encoded Text
if (0x99 <= b <= 0x9F) or (0xE0 <= b <= 0xEB):
c = (b << 8) | theirsce.read_uint8()
finalText += chars.get(c, "{%02X}{%02X}" % (c >> 8, c & 0xFF))
continue
if b == 0x1:
finalText += ("\n")
continue
# ASCII text
if chr(b) in self.PRINTABLE_CHARS:
finalText += chr(b)
continue
# cp932 text
if 0xA0 < b < 0xE0:
finalText += struct.pack("B", b).decode("cp932")
continue
if b == 0x81:
next_b = theirsce.read(1)
if next_b == b"\x40":
finalText += " "
else:
finalText += "{%02X}" % b
finalText += "{%02X}" % ord(next_b)
else:
finalText += "{%02X}" % b
b = theirsce.read(1)
continue
# Simple Tags
if 0x3 <= b <= 0xF:
parameter = theirsce.read_uint32()
tag_name = tags.get(b, f"{b:02X}")
tag_param = self.jsonTblTags.get(tag_name.upper(), {}).get(parameter, None)
if tag_param is not None:
finalText += tag_param
else:
finalText += f"<{tag_name}:{self.hex2(parameter)}>"
continue
# Variable tags (same as above but using rsce bytecode as parameter)
if 0x13 <= b <= 0x1A:
tag_name = f"unk{b:02X}"
parameter = "".join([f"{c:02X}" for c in theirsce.read_tag_bytes()])
finalText += f"<{tag_name}:{parameter}>"
continue
# None of the above
finalText += "{%02X}" % b
end = theirsce.tell()
size = theirsce.tell() - pos - 1
theirsce.seek(pos)
hex_string = theirsce.read(size).hex()
hex_values = ' '.join(a+b for a,b in zip(hex_string[::2], hex_string[1::2]))
theirsce.seek(end)
#return finalText, hex_values
return finalText
def get_Node_Bytes(self, entry_node):

View File

@@ -31,7 +31,8 @@ class ToolsTales:
VALID_VOICEID = ['VSM_', 'voice_', 'VCT_']
def __init__(self, gameName, tblFile, repo_name):
self.jsonTblTags = {}
self.ijsonTblTags = {}
self.gameName = gameName
self.repo_name = repo_name
self.basePath = os.getcwd()
@@ -493,67 +494,55 @@ class ToolsTales:
#Convert text to Bytes object to reinsert text into THEIRSCE and other files
def text_to_bytes(self, text):
multi_regex = (self.HEX_TAG + "|" + self.COMMON_TAG + r"|(\n)")
tokens = [sh for sh in re.split(multi_regex, text) if sh]
unames = []
splitLineBreak = text.split('\x0A')
nb = len(splitLineBreak)
bytesFinal = b''
i=0
for line in splitLineBreak:
string_hex = re.split(self.HEX_TAG, line)
string_hex = [sh for sh in string_hex if sh]
#print(string_hex)
for s in string_hex:
if re.match(self.HEX_TAG, s):
bytesFinal += struct.pack("B", int(s[1:3], 16))
output = b''
for t in tokens:
# Hex literals
if re.match(self.HEX_TAG, t):
output += struct.pack("B", int(t[1:3], 16))
# Tags
elif re.match(self.COMMON_TAG, t):
tag, param, *_ = t[3][1:-1].split(":") + [None]
if param is not None:
output += struct.pack("B", self.ijsonTblTags["TAGS"].get(tag, int(tag, 16)))
# FIXME
if tag.lower() in ("unk13", "unk17", "unk1a"):
splat = re.findall("..", param)
i = 0
while i < len(splat):
if splat[i] == "38" and i + 2 < len(splat):
output += bytes.fromhex(splat[i])
output += bytes.fromhex(splat[i + 2])
output += bytes.fromhex(splat[i + 1])
i += 3
else:
output += bytes.fromhex(splat[i])
i += 1
output += bytes.fromhex("80")
elif "unk" in tag.lower:
output += bytes.fromhex(param + "80")
else:
output += struct.pack("<I", param)
else:
s_com = re.split(self.COMMON_TAG, s)
s_com = [sc for sc in s_com if sc]
for c in s_com:
if re.match(self.COMMON_TAG, c):
if ":" in c:
split = c.split(":")
tag = split[0][1:]
print(split)
if tag in self.itags.keys():
bytesFinal += struct.pack("B", self.itags[tag])
for k, v in self.ijsonTblTags:
if tag in v:
output += struct.pack("B", self.ijsonTblTags["TAGS"][k.lower()])
output += struct.pack("<I", v[tag])
break
if tag in ['Unk13', 'Unk17', 'Unk18', 'Unk19', 'Unk1A']:
right_part = split[1][0:-1]
nb = len(right_part) / 2.0
bytesFinal += int(right_part, 16).to_bytes(int(nb), 'big')
else:
bytesFinal += int(split[1][0:-1], 16).to_bytes(4, 'little')
# Actual text
elif t == "\n":
output += b"\x01"
else:
for c in t:
output += self.ijsonTblTags["TBL"].get(c, c.encode("cp932"))
else:
bytesFinal += struct.pack("B", int(split[0][1:], 16))
bytesFinal += struct.pack("<I", int(split[1][:8], 16))
if c in self.inames:
bytesFinal += struct.pack("B", 0xB)
bytesFinal += struct.pack("<I", self.inames[c])
if c in self.icolors:
bytesFinal += struct.pack("B", 0x5)
bytesFinal += struct.pack("<I", self.icolors[c])
else:
for c2 in c:
if c2 in self.itable.keys():
bytesFinal += self.itable[c2]
else:
bytesFinal += c2.encode("cp932")
i=i+1
if (nb >=2 and i<nb):
bytesFinal += b'\x01'
return bytesFinal
return output
def search_all_files(self, japanese_text):

View File

@@ -67,6 +67,48 @@ class Theirsce(FileIO):
yield opcode
self.seek(pos)
def read_tag_bytes(self):
data = b""
while self.read_uint8_at(self.tell() + 1) != 0x80:
data += self.read(1)
opcode = data[-1]
if opcode < 0x80:
if opcode & 8 != 0:
data += self.read(2)
else:
data += self.read(1)
elif opcode < 0xE0:
size_mask = (opcode >> 3) & 3
if size_mask == 1: data += self.read(1)
elif size_mask == 2: data += self.read(2)
elif size_mask == 3: data += self.read(4)
elif opcode < 0xF0:
data += self.read(1)
elif opcode < 0xF8:
if (0xF2 <= opcode < 0xF5) or opcode == 0xF7:
data += self.read(2)
elif opcode == 0xF5:
data += self.read(4)
elif opcode == 0xF6:
data += self.read(1)
for _ in range(data[-1]):
if ord(data[-1]) & 8 != 0:
data += self.read(2)
else:
data += self.read(3)
elif opcode < 0xFC:
data += self.read(2)
self.read(1)
return data
def read_opcode(self):
pos = self.tell()
opcode = self.read_uint8()