mirror of
https://github.com/cainan-c/TaikoPythonTools.git
synced 2024-11-27 17:00:50 +01:00
Bug fixes
This commit is contained in:
parent
10fdaa492d
commit
6c72cf631b
@ -4,6 +4,7 @@ import glob
|
|||||||
import concurrent.futures
|
import concurrent.futures
|
||||||
import gzip
|
import gzip
|
||||||
import json
|
import json
|
||||||
|
import numpy as np
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
@ -366,7 +367,7 @@ def update_selection_count(event=None):
|
|||||||
if platform == "PS4":
|
if platform == "PS4":
|
||||||
max_entries = 400
|
max_entries = 400
|
||||||
elif platform == "WIIU3":
|
elif platform == "WIIU3":
|
||||||
max_entries = 199
|
max_entries = 90 # this is due to us using RGBA for textures. High quality = less textures can be added.
|
||||||
elif platform == "NS1":
|
elif platform == "NS1":
|
||||||
max_entries = 600
|
max_entries = 600
|
||||||
elif platform == "PTB":
|
elif platform == "PTB":
|
||||||
@ -1491,10 +1492,6 @@ def generate_wiiu3_texture(id, genreNo, current_unique_id, append_ura, custom_so
|
|||||||
rotated_font_path = 'data/_resource/font/KozGoPr6NRegular.otf'
|
rotated_font_path = 'data/_resource/font/KozGoPr6NRegular.otf'
|
||||||
create_images(data, id, genreNo, font_path, rotated_font_path, current_unique_id, append_ura)
|
create_images(data, id, genreNo, font_path, rotated_font_path, current_unique_id, append_ura)
|
||||||
|
|
||||||
import os
|
|
||||||
from PIL import Image
|
|
||||||
import struct
|
|
||||||
|
|
||||||
class TextureSurface:
|
class TextureSurface:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.mipmaps = []
|
self.mipmaps = []
|
||||||
@ -1517,6 +1514,8 @@ class NutTexture:
|
|||||||
def getNutFormat(self):
|
def getNutFormat(self):
|
||||||
if self.pixelInternalFormat == 'RGBA':
|
if self.pixelInternalFormat == 'RGBA':
|
||||||
return 14
|
return 14
|
||||||
|
elif self.pixelInternalFormat == 'CompressedRgbaS3tcDxt5Ext':
|
||||||
|
return 28 # Example format code for DXT5, adjust as necessary
|
||||||
raise NotImplementedError("Only RGBA format is implemented")
|
raise NotImplementedError("Only RGBA format is implemented")
|
||||||
|
|
||||||
class NUT:
|
class NUT:
|
||||||
@ -1605,6 +1604,77 @@ class NUT:
|
|||||||
with open(output_path, 'wb') as f:
|
with open(output_path, 'wb') as f:
|
||||||
f.write(data)
|
f.write(data)
|
||||||
|
|
||||||
|
def modify_nut_file_dds(self, file_path, output_path):
|
||||||
|
# Set replacement bytes to 00
|
||||||
|
|
||||||
|
with open(file_path, 'rb') as f:
|
||||||
|
data = bytearray(f.read())
|
||||||
|
|
||||||
|
del data[0x0000:0x0280]
|
||||||
|
|
||||||
|
# Given byte string
|
||||||
|
byte_string = "4E 54 50 33 02 00 00 06 00 00 00 00 00 00 00 00 00 00 F0 40 00 00 00 00 00 00 EF D0 00 70 00 00 00 05 00 02 02 D0 00 40 00 00 00 00 00 00 00 00 00 00 02 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 B4 00 00 00 2D 00 00 00 0B 40 00 00 02 D0 00 00 00 C0 00 00 00 00 00 00 00 00 00 00 00 00 65 58 74 00 00 00 00 20 00 00 00 10 00 00 00 00 47 49 44 58 00 00 00 10 00 00 00 00 00 00 00 00 00 01 86 10 00 00 00 00 00 01 85 A0 00 70 00 00 00 05 00 02 02 D0 00 68 00 00 00 00 00 00 00 00 00 00 F1 E0 00 00 00 00 00 00 00 00 00 00 00 00 00 01 24 80 00 00 49 20 00 00 12 50 00 00 04 A0 00 00 01 10 00 00 00 00 00 00 00 00 00 00 00 00 65 58 74 00 00 00 00 20 00 00 00 10 00 00 00 00 47 49 44 58 00 00 00 10 00 00 00 01 00 00 00 00 00 00 F0 40 00 00 00 00 00 00 EF D0 00 70 00 00 00 05 00 02 02 D0 00 40 00 00 00 00 00 00 00 00 00 02 77 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 B4 00 00 00 2D 00 00 00 0B 40 00 00 02 D0 00 00 00 C0 00 00 00 00 00 00 00 00 00 00 00 00 65 58 74 00 00 00 00 20 00 00 00 10 00 00 00 00 47 49 44 58 00 00 00 10 00 00 00 02 00 00 00 00 00 00 C8 50 00 00 00 00 00 00 C7 E0 00 70 00 00 00 05 00 02 00 60 01 90 00 00 00 00 00 00 00 00 00 03 66 70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 96 00 00 00 25 80 00 00 09 60 00 00 02 60 00 00 00 A0 00 00 00 00 00 00 00 00 00 00 00 00 65 58 74 00 00 00 00 20 00 00 00 10 00 00 00 00 47 49 44 58 00 00 00 10 00 00 00 04 00 00 00 00 00 00 74 A0 00 00 00 00 00 00 74 40 00 60 00 00 00 04 00 02 00 38 01 90 00 00 00 00 00 00 00 00 00 04 2D E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 57 80 00 00 15 E0 00 00 05 80 00 00 01 60 65 58 74 00 00 00 00 20 00 00 00 10 00 00 00 00 47 49 44 58 00 00 00 10 00 00 00 04 00 00 00 00 00 00 74 A0 00 00 00 00 00 00 74 40 00 60 00 00 00 04 00 02 00 38 01 90 00 00 00 00 00 00 00 00 00 04 A1 C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 57 80 00 00 15 E0 00 00 05 80 00 00 01 60 65 58 74 00 00 00 00 20 00 00 00 10 00 00 00 00 47 49 44 58 00 00 00 10 00 00 00 05 00 00 00 00"
|
||||||
|
|
||||||
|
# Convert the byte string into bytes
|
||||||
|
bytes_data = bytes.fromhex(byte_string.replace(' ', ''))
|
||||||
|
|
||||||
|
# Concatenate the bytes
|
||||||
|
data = bytes_data + data
|
||||||
|
|
||||||
|
with open(output_path, 'wb') as f:
|
||||||
|
f.write(data)
|
||||||
|
|
||||||
|
def convert_png_to_dds(png_file, dds_file):
|
||||||
|
# Ensure the input PNG file exists
|
||||||
|
if not os.path.isfile(png_file):
|
||||||
|
print(f"Error: {png_file} does not exist.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Construct the command to convert using nvcompress
|
||||||
|
command = [
|
||||||
|
'nvcompress', # Assuming nvcompress is in your PATH
|
||||||
|
'-silent', # Optional: Suppress output from nvcompress
|
||||||
|
'-bc3', # DXT5 compression (BC3 in nvcompress)
|
||||||
|
'-alpha', # Alpha Channel
|
||||||
|
'-highest', # Alpha Channel
|
||||||
|
png_file, # Input PNG file
|
||||||
|
dds_file # Output DDS file
|
||||||
|
]
|
||||||
|
|
||||||
|
# Run the command using subprocess
|
||||||
|
try:
|
||||||
|
subprocess.run(command, check=True)
|
||||||
|
print(f"Conversion successful: {png_file} -> {dds_file}")
|
||||||
|
return True
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print(f"Error during conversion: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def convert_png_files_in_folder(input_folder, output_folder):
|
||||||
|
# Ensure the input folder exists
|
||||||
|
if not os.path.isdir(input_folder):
|
||||||
|
print(f"Error: {input_folder} is not a valid directory.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Create the output folder if it doesn't exist
|
||||||
|
if not os.path.exists(output_folder):
|
||||||
|
os.makedirs(output_folder)
|
||||||
|
|
||||||
|
# Iterate through files in the input folder
|
||||||
|
for filename in os.listdir(input_folder):
|
||||||
|
if filename.endswith(".png"):
|
||||||
|
input_path = os.path.join(input_folder, filename)
|
||||||
|
output_filename = os.path.splitext(filename)[0] + ".dds"
|
||||||
|
output_path = os.path.join(output_folder, output_filename)
|
||||||
|
|
||||||
|
# Convert PNG to DDS
|
||||||
|
success = convert_png_to_dds(input_path, output_path)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
print(f"Conversion successful: {input_path} -> {output_path}")
|
||||||
|
else:
|
||||||
|
print(f"Conversion failed: {input_path}")
|
||||||
|
|
||||||
def load_png_to_texture(filepath):
|
def load_png_to_texture(filepath):
|
||||||
with Image.open(filepath) as img:
|
with Image.open(filepath) as img:
|
||||||
img = img.convert("RGBA")
|
img = img.convert("RGBA")
|
||||||
@ -1614,6 +1684,42 @@ def load_png_to_texture(filepath):
|
|||||||
texture.add_mipmap(mipmap_data)
|
texture.add_mipmap(mipmap_data)
|
||||||
return texture
|
return texture
|
||||||
|
|
||||||
|
def read_dds_to_bytes(dds_file):
|
||||||
|
try:
|
||||||
|
with open(dds_file, "rb") as f:
|
||||||
|
dds_bytes = f.read()
|
||||||
|
return dds_bytes
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"Error: File '{dds_file}' not found.")
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error reading DDS file '{dds_file}': {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def load_dds_to_texture(filepath):
|
||||||
|
with Image.open(filepath) as img:
|
||||||
|
#img = img.convert("RGBA")
|
||||||
|
width, height = img.size
|
||||||
|
mipmap_data = read_dds_to_bytes(filepath)
|
||||||
|
texture = NutTexture(width, height, "CompressedRgbaS3tcDxt5Ext", "CompressedRgbaS3tcDxt5Ext")
|
||||||
|
#texture.add_mipmap(mipmap_data)
|
||||||
|
return texture
|
||||||
|
|
||||||
|
def generate_nut_texture_dds(input_folder, output_file):
|
||||||
|
nut = NUT()
|
||||||
|
convert_png_files_in_folder(input_folder, input_folder)
|
||||||
|
for filename in os.listdir(input_folder):
|
||||||
|
if filename.endswith(".dds"):
|
||||||
|
texture = load_dds_to_texture(os.path.join(input_folder, filename))
|
||||||
|
nut.add_texture(texture)
|
||||||
|
|
||||||
|
# Save the NUT file
|
||||||
|
nut.save(output_file)
|
||||||
|
|
||||||
|
# Modify the saved NUT file
|
||||||
|
#nut.modify_nut_file(output_file, output_file)
|
||||||
|
nut.modify_nut_file_dds(output_file, output_file)
|
||||||
|
|
||||||
def generate_nut_texture(input_folder, output_file):
|
def generate_nut_texture(input_folder, output_file):
|
||||||
nut = NUT()
|
nut = NUT()
|
||||||
for filename in os.listdir(input_folder):
|
for filename in os.listdir(input_folder):
|
||||||
@ -1627,7 +1733,6 @@ def generate_nut_texture(input_folder, output_file):
|
|||||||
# Modify the saved NUT file
|
# Modify the saved NUT file
|
||||||
nut.modify_nut_file(output_file, output_file)
|
nut.modify_nut_file(output_file, output_file)
|
||||||
|
|
||||||
|
|
||||||
# file encryption
|
# file encryption
|
||||||
def encrypt_file_ptb(input_file, output_file):
|
def encrypt_file_ptb(input_file, output_file):
|
||||||
# Generate a random initialization vector (IV)
|
# Generate a random initialization vector (IV)
|
||||||
@ -2349,9 +2454,6 @@ def remove_musicinfo_leftover(directory_path):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error deleting {directory_path}: {e}")
|
print(f"Error deleting {directory_path}: {e}")
|
||||||
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
import glob
|
|
||||||
|
|
||||||
def remove_texture_leftover(texture_output_dir):
|
def remove_texture_leftover(texture_output_dir):
|
||||||
try:
|
try:
|
||||||
@ -2442,44 +2544,6 @@ def export_data():
|
|||||||
audio_output_dir = f"out/content/{formatted_id}/sound"
|
audio_output_dir = f"out/content/{formatted_id}/sound"
|
||||||
texture_output_dir = f"out/content/{formatted_id}/texture"
|
texture_output_dir = f"out/content/{formatted_id}/texture"
|
||||||
|
|
||||||
try:
|
|
||||||
if len(selected_items) > max_entries:
|
|
||||||
messagebox.showerror("Selection Limit Exceeded", f"Maximum {max_entries} entries can be selected for {game_platform}.")
|
|
||||||
return
|
|
||||||
|
|
||||||
# Load preview position data
|
|
||||||
with open(previewpos_path, "r", encoding="utf-8") as previewpos_file:
|
|
||||||
previewpos_data = json.load(previewpos_file)
|
|
||||||
|
|
||||||
if custom_songs:
|
|
||||||
with open(custom_previewpos_path, "r", encoding="utf-8") as custom_previewpos_file:
|
|
||||||
custom_previewpos_data = json.load(custom_previewpos_file)
|
|
||||||
|
|
||||||
# Copy fumen folders for selected songs to output directory
|
|
||||||
for item_id in selected_items:
|
|
||||||
song_id = tree.item(item_id)["values"][1]
|
|
||||||
fumen_folder_path = os.path.join(data_dir, "fumen", str(song_id))
|
|
||||||
if os.path.exists(fumen_folder_path):
|
|
||||||
if game_platform == "WIIU3":
|
|
||||||
#shutil.copytree(fumen_folder_path, os.path.join(fumen_output_dir, f"{song_id}"))
|
|
||||||
print()
|
|
||||||
else:
|
|
||||||
shutil.copytree(fumen_folder_path, os.path.join(fumen_output_dir, f"{song_id}"))
|
|
||||||
song_info = next((item for item in music_info["items"] if item["id"] == song_id), None)
|
|
||||||
|
|
||||||
if custom_songs:
|
|
||||||
for item_id in selected_items:
|
|
||||||
|
|
||||||
song_id = tree.item(item_id)["values"][1]
|
|
||||||
custom_fumen_folder_path = os.path.join(custom_data_dir, "fumen", str(song_id))
|
|
||||||
if os.path.exists(fumen_folder_path):
|
|
||||||
if game_platform == "WIIU3":
|
|
||||||
#shutil.copytree(fumen_folder_path, os.path(fumen_output_dir, f"{song_id}"))
|
|
||||||
print(" ")
|
|
||||||
else:
|
|
||||||
shutil.copytree(fumen_folder_path, os.path.join(fumen_output_dir, f"{song_id}"))
|
|
||||||
song_info = next((item for item in custom_music_info["items"] if item["id"] == song_id), None)
|
|
||||||
|
|
||||||
def copy_fumens_ura():
|
def copy_fumens_ura():
|
||||||
# Copy fumen folders for selected songs to output directory
|
# Copy fumen folders for selected songs to output directory
|
||||||
song_id = tree.item(item_id)["values"][1]
|
song_id = tree.item(item_id)["values"][1]
|
||||||
@ -2535,6 +2599,42 @@ def export_data():
|
|||||||
else:
|
else:
|
||||||
shutil.copytree(fumen_folder_path, os.path.join(fumen_output_dir, f"{song_id}"))
|
shutil.copytree(fumen_folder_path, os.path.join(fumen_output_dir, f"{song_id}"))
|
||||||
|
|
||||||
|
try:
|
||||||
|
if len(selected_items) > max_entries:
|
||||||
|
messagebox.showerror("Selection Limit Exceeded", f"Maximum {max_entries} entries can be selected for {game_platform}.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Load preview position data
|
||||||
|
with open(previewpos_path, "r", encoding="utf-8") as previewpos_file:
|
||||||
|
previewpos_data = json.load(previewpos_file)
|
||||||
|
|
||||||
|
if custom_songs:
|
||||||
|
with open(custom_previewpos_path, "r", encoding="utf-8") as custom_previewpos_file:
|
||||||
|
custom_previewpos_data = json.load(custom_previewpos_file)
|
||||||
|
|
||||||
|
|
||||||
|
# Copy fumen folders for selected songs to output directory
|
||||||
|
if game_platform == "WIIU3":
|
||||||
|
print()
|
||||||
|
else:
|
||||||
|
for item_id in selected_items:
|
||||||
|
song_id = tree.item(item_id)["values"][1]
|
||||||
|
fumen_folder_path = os.path.join(data_dir, "fumen", str(song_id))
|
||||||
|
if os.path.exists(fumen_folder_path):
|
||||||
|
shutil.copytree(fumen_folder_path, os.path.join(fumen_output_dir, f"{song_id}"))
|
||||||
|
|
||||||
|
song_info = next((item for item in music_info["items"] if item["id"] == song_id), None)
|
||||||
|
|
||||||
|
if custom_songs:
|
||||||
|
for item_id in selected_items:
|
||||||
|
|
||||||
|
song_id = tree.item(item_id)["values"][1]
|
||||||
|
custom_fumen_folder_path = os.path.join(custom_data_dir, "fumen", str(song_id))
|
||||||
|
if os.path.exists(custom_fumen_folder_path):
|
||||||
|
shutil.copytree(custom_fumen_folder_path, os.path.join(fumen_output_dir, f"{song_id}"))
|
||||||
|
|
||||||
|
song_info = next((item for item in custom_music_info["items"] if item["id"] == song_id), None)
|
||||||
|
|
||||||
for item_id in selected_items:
|
for item_id in selected_items:
|
||||||
song_id = tree.item(item_id)["values"][1]
|
song_id = tree.item(item_id)["values"][1]
|
||||||
if custom_songs:
|
if custom_songs:
|
||||||
@ -2548,9 +2648,12 @@ def export_data():
|
|||||||
|
|
||||||
# Calculate song_order based on genreNo and current_unique_id
|
# Calculate song_order based on genreNo and current_unique_id
|
||||||
song_order = (int(song_info["genreNo"]) * 1000) + current_unique_id
|
song_order = (int(song_info["genreNo"]) * 1000) + current_unique_id
|
||||||
|
|
||||||
if game_platform == "WIIU3":
|
if game_platform == "WIIU3":
|
||||||
|
|
||||||
if song_info["id"].startswith("cs"):
|
pattern = r"^cs\d{4}$"
|
||||||
|
|
||||||
|
if re.match(pattern, song_info["id"]):
|
||||||
custom_songs == True
|
custom_songs == True
|
||||||
else:
|
else:
|
||||||
custom_songs == False
|
custom_songs == False
|
||||||
@ -2622,7 +2725,7 @@ def export_data():
|
|||||||
|
|
||||||
root.append(wiiu3_song_info_xml)
|
root.append(wiiu3_song_info_xml)
|
||||||
|
|
||||||
if song_info["id"].startswith("cs"):
|
if re.match(pattern, song_info["id"]):
|
||||||
custom_songs == True
|
custom_songs == True
|
||||||
generate_wiiu3_texture(song_info["id"], song_info["genreNo"], current_unique_id, append_ura=False, custom_songs=True)
|
generate_wiiu3_texture(song_info["id"], song_info["genreNo"], current_unique_id, append_ura=False, custom_songs=True)
|
||||||
else:
|
else:
|
||||||
@ -2633,7 +2736,7 @@ def export_data():
|
|||||||
root.set('num', str(db_data_count))
|
root.set('num', str(db_data_count))
|
||||||
save_xml_to_file(root, file_path)
|
save_xml_to_file(root, file_path)
|
||||||
|
|
||||||
if song_info["id"].startswith("cs"):
|
if re.match(pattern, song_info["id"]):
|
||||||
custom_songs == True
|
custom_songs == True
|
||||||
copy_fumens_custom()
|
copy_fumens_custom()
|
||||||
else:
|
else:
|
||||||
@ -2651,7 +2754,7 @@ def export_data():
|
|||||||
output_file = os.path.join(texture_output_dir, f"{song_info['id']}.nut")
|
output_file = os.path.join(texture_output_dir, f"{song_info['id']}.nut")
|
||||||
generate_nut_texture(input_folder, output_file)
|
generate_nut_texture(input_folder, output_file)
|
||||||
|
|
||||||
if song_info["id"].startswith("cs"):
|
if re.match(pattern, song_info["id"]):
|
||||||
custom_songs == True
|
custom_songs == True
|
||||||
convert_song_wiiu(song_id, custom_songs=True)
|
convert_song_wiiu(song_id, custom_songs=True)
|
||||||
else:
|
else:
|
||||||
@ -2683,7 +2786,7 @@ def export_data():
|
|||||||
|
|
||||||
wiiu3_song_info_xml = create_wiiu3_song_info_ura_xml(song_info, current_unique_id, song_order, word_list)
|
wiiu3_song_info_xml = create_wiiu3_song_info_ura_xml(song_info, current_unique_id, song_order, word_list)
|
||||||
root.append(wiiu3_song_info_xml)
|
root.append(wiiu3_song_info_xml)
|
||||||
if song_info["id"].startswith("cs"):
|
if re.match(pattern, song_info["id"]):
|
||||||
custom_songs == True
|
custom_songs == True
|
||||||
generate_wiiu3_texture(song_info["id"], song_info["genreNo"], current_unique_id, append_ura=True, custom_songs=True)
|
generate_wiiu3_texture(song_info["id"], song_info["genreNo"], current_unique_id, append_ura=True, custom_songs=True)
|
||||||
else:
|
else:
|
||||||
@ -2706,7 +2809,7 @@ def export_data():
|
|||||||
output_file = os.path.join(texture_output_dir, f"ex_{song_info['id']}.nut")
|
output_file = os.path.join(texture_output_dir, f"ex_{song_info['id']}.nut")
|
||||||
generate_nut_texture(input_folder, output_file)
|
generate_nut_texture(input_folder, output_file)
|
||||||
|
|
||||||
if song_info["id"].startswith("cs"):
|
if re.match(pattern, song_info["id"]):
|
||||||
custom_songs == True
|
custom_songs == True
|
||||||
convert_song_wiiu(song_id, custom_songs=True)
|
convert_song_wiiu(song_id, custom_songs=True)
|
||||||
else:
|
else:
|
||||||
@ -2719,7 +2822,7 @@ def export_data():
|
|||||||
remove_musicinfo_leftover(output_dir)
|
remove_musicinfo_leftover(output_dir)
|
||||||
remove_texture_leftover(texture_output_dir)
|
remove_texture_leftover(texture_output_dir)
|
||||||
|
|
||||||
if song_info["id"].startswith("cs"):
|
if re.match(pattern, song_info["id"]):
|
||||||
custom_songs == True
|
custom_songs == True
|
||||||
else:
|
else:
|
||||||
custom_songs == False
|
custom_songs == False
|
||||||
|
Loading…
Reference in New Issue
Block a user