From 1ed08d6a583726af250ee17c05bb9e0e717dceb8 Mon Sep 17 00:00:00 2001 From: Marco Date: Mon, 24 Feb 2025 15:30:19 +0100 Subject: [PATCH] Build script --- .gitignore | 3 +- Cirno.csproj | 1 + CreateIcon.gd | 274 ++++++++++++++++++ CreateIcon.gd.uid | 1 + Export.ps1 | 1 + ReplaceIcon.gd | 212 ++++++++++++++ ReplaceIcon.gd.uid | 1 + Sprites/Actors/Cirno.aseprite | 4 +- Sprites/Icon.ico | Bin 0 -> 51262 bytes addons/scene_palette/save_data/save_data.tres | 7 + export_presets.cfg | 4 +- project.godot | 2 +- 12 files changed, 505 insertions(+), 5 deletions(-) create mode 100644 CreateIcon.gd create mode 100644 CreateIcon.gd.uid create mode 100644 Export.ps1 create mode 100644 ReplaceIcon.gd create mode 100644 ReplaceIcon.gd.uid create mode 100644 Sprites/Icon.ico create mode 100644 addons/scene_palette/save_data/save_data.tres diff --git a/.gitignore b/.gitignore index f89d046b..2bf14b32 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ # Godot 4+ specific ignores .godot/ -.vscode/ \ No newline at end of file +.vscode/ +build/** \ No newline at end of file diff --git a/Cirno.csproj b/Cirno.csproj index 493468ac..91540dd0 100644 --- a/Cirno.csproj +++ b/Cirno.csproj @@ -4,6 +4,7 @@ true + \ No newline at end of file diff --git a/CreateIcon.gd b/CreateIcon.gd new file mode 100644 index 00000000..ff511c47 --- /dev/null +++ b/CreateIcon.gd @@ -0,0 +1,274 @@ +class_name CreateIcon +extends SceneTree + +var error_callable: Callable + + +func _init() -> void: + var arguments = OS.get_cmdline_args() + if arguments.size() != 4 and arguments.size() != 9: + print( + "Usage:\n godot -s CreateIcon.gd name ...\n", + "\n", + "Creates uncompressed windows ico file.\n", + "Add --headless to hide Godot console.\n", + "\n", + "Arguments:\n", + " godot path to Godot 4 beta2+ executable\n", + " name path to created icon\n", + " provide one or six files. If one provided it will be scaled for all\n", + " icon resolutions. Multiple files should be 16x16, 32x32, 48x48, 64x64,\n", + " 128x128\n and 256x256 pixels big." + ) + quit() + return + var images := [] + if arguments.size() == 9: + var names := [arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8]] + var check_names := {} + for name in names: + if check_names.has(name): + printerr("File ", name, " was added more than once") + return + check_names[name] = true + images = load_images(names) + else: + images = prepare_images(arguments[3]) + if not images.is_empty(): + save_icon(arguments[2], images) + quit() + + +func load_images(paths: PackedStringArray) -> Array: + var images := [] + for path in paths: + var image := Image.new() + var error = image.load(path) + if error: + print_error(str("Could not load image: ", path)) + return [] + image.convert(Image.FORMAT_RGBA8) + images.append(image) + images.sort_custom(sort_images_by_size) + var index := 0 + for size in [16, 32, 48, 64, 128, 256]: + var image: Image = images[index] + if image.get_width() != size: + print_error(str("Image has incorrect width: ", image.get_width(), " expected: ", size)) + return [] + if image.get_height() != size: + print_error(str("Image has incorrect height: ", image.get_height(), " expected: ", size)) + return [] + index += 1 + return images + + +func prepare_images(path: String) -> Array: + var images := [] + for size in [16, 32, 48, 64, 128, 256]: + var image := Image.new() + var error = image.load(path) + if error: + print_error(str("Could not load image: ", path)) + return [] + image.convert(Image.FORMAT_RGBA8) + image.resize(size, size) + images.append(image) + return images + + +func save_icon(destination_path: String, images: Array) -> void: + var file = FileAccess.open(destination_path, FileAccess.WRITE) + if not file: + print_error(str("Could not open file for writing!\n", FileAccess.get_open_error())) + return + var icon_creator := IconCreator.new() + file.store_buffer(icon_creator.generate_icon(images)) + + +func print_error(error_message: String) -> void: + printerr(error_message) + if error_callable: + error_callable.call(error_message) + + +static func sort_images_by_size(a: Image, b: Image) -> bool: + return a.get_width() < b.get_width() + + +class IconCreator: + const ADLER_MOD := 65521 + const ZLIB_BLOCK_SIZE := 16384 + const CRC_TABLE_SIZE := 256 + const ICON_ENTRY_SIZE := 16 + var PNG_SIGNATURE := PackedByteArray([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0a]) + var IHDR_SIGNATURE := PackedByteArray([0x49, 0x48, 0x44, 0x52]) + var IDAT_SIGNATURE := PackedByteArray([0x49, 0x44, 0x41, 0x54]) + var IEND_SIGNATURE := PackedByteArray([0x49, 0x45, 0x4e, 0x44]) + + var crc_table: Array + + + func _init() -> void: + crc_table = generate_crc_table() + + + func generate_icon(images: Array) -> PackedByteArray: + var result := PackedByteArray() + result.append_array(generate_icon_header(images.size())) + var offset := result.size() + images.size() * ICON_ENTRY_SIZE + var pngs := [] + for image in images: + assert(image.get_format() == Image.FORMAT_RGBA8) + var png := generate_png(image) + pngs.append(png) + var icon_entry := generate_icon_entry(image, png.size(), offset) + result.append_array(icon_entry) + offset += png.size() + for png in pngs: + result.append_array(png) + return result + + + func generate_icon_header(size: int) -> PackedByteArray: + var result := PackedByteArray() + result.append_array(lsb_first(0x0, 2)) # reserved + result.append_array(lsb_first(0x1, 2)) # icon type + result.append_array(lsb_first(size, 2)) # image count + return result + + + func generate_icon_entry(image: Image, size: int, offset: int) -> PackedByteArray: + var result := PackedByteArray() + result.append(image.get_width()) # width + result.append(image.get_height()) # height + result.append(0x0) # size of color palette + result.append(0x0) # reserved + result.append_array(lsb_first(0, 2)) # no color planes + result.append_array(lsb_first(32, 2)) # bits per pixel + result.append_array(lsb_first(size)) # size of embedded png + result.append_array(lsb_first(offset)) + return result + + + func generate_png(image: Image) -> PackedByteArray: + var result := PackedByteArray() + var header_chunk := generate_header_chunk(image.get_width(), image.get_height()) + var data_chunk := generate_data_chunk(image) + var end_chunk := generate_end_chunk() + result.append_array(PNG_SIGNATURE) + result.append_array(generate_chunk(header_chunk)) + result.append_array(generate_chunk(data_chunk)) + result.append_array(generate_chunk(end_chunk)) + return result + + + func generate_chunk(chunk: PackedByteArray) -> PackedByteArray: + var result := PackedByteArray() + result.append_array(msb_first(chunk.size() - 4)) + result.append_array(chunk) + result.append_array(msb_first(crc(chunk))) + return result + + + func generate_header_chunk(width: int, height: int) -> PackedByteArray: + var result = PackedByteArray() + result.append_array(IHDR_SIGNATURE) + result.append_array(msb_first(width)) + result.append_array(msb_first(height)) + result.append(0x8) # bit depth + result.append(0x6) # color type 32bit RGBA + result.append(0x0) # compression method + result.append(0x0) # filter method + result.append(0x0) # interlace method + return result + + + func generate_data_chunk(image: Image) -> PackedByteArray: + @warning_ignore("shadowed_variable") + var filtered_pixels := filtered_pixels(image.get_width(), image.get_height(), image.get_data()) + @warning_ignore("integer_division") + var zlib_block_count := filtered_pixels.size() / ZLIB_BLOCK_SIZE + (1 if filtered_pixels.size() % ZLIB_BLOCK_SIZE else 0) + var result := PackedByteArray() + result.append_array(IDAT_SIGNATURE) + result.append(0x78) # CMF + result.append(0x1) # FLG + for i in range(zlib_block_count): + var last_block := i == zlib_block_count - 1 + result.append(0x1 if last_block else 0x0) + @warning_ignore("shadowed_variable") + var block_size := filtered_pixels.size() % ZLIB_BLOCK_SIZE if last_block else ZLIB_BLOCK_SIZE + result.append_array(block_size(block_size)) + for b in range(block_size): + result.append(filtered_pixels[i * ZLIB_BLOCK_SIZE + b]) + result.append_array(msb_first(adler(filtered_pixels))) + return result + + + func generate_end_chunk() -> PackedByteArray: + return IEND_SIGNATURE + + + func filtered_pixels(width: int, height: int, pixels: PackedByteArray) -> PackedByteArray: + var result = PackedByteArray() + for row in range(height): + result.append(0x0) + for column in range(width * 4): + result.append(pixels[row * width * 4 + column]) + return result + + + func generate_crc_table() -> Array: + var result = [] + var c: int + for n in range(CRC_TABLE_SIZE): + c = n + for _i in range(8): + if (c & 1) != 0: + c = 0xedb88320 ^ (c >> 1) + else: + c = c >> 1 + result.append(c) + return result + + + func crc(bytes: PackedByteArray) -> int: + var c := 0xffffffff + for i in range(bytes.size()): + c = crc_table[(c ^ bytes[i]) & 0xff] ^ (c >> 8) + return c ^ 0xffffffff + + + func adler(bytes: PackedByteArray) -> int: + var a := 1 + var b := 0 + for byte in bytes: + a = (a + byte) % ADLER_MOD + b = (a + b) % ADLER_MOD + return b << 16 | a + + + func msb_first(i: int) -> PackedByteArray: + var result := PackedByteArray() + result.append((i >> 24) & 0xff) + result.append((i >> 16) & 0xff) + result.append((i >> 8) & 0xff) + result.append(i & 0xff) + return result + + + func lsb_first(i: int, size = 4) -> PackedByteArray: + var result := PackedByteArray() + for _s in range(size): + result.append(i & 0xff) + i = i >> 8 + return result + + + func block_size(i: int) -> PackedByteArray: + var result := PackedByteArray() + result.append(i & 0xff) + result.append((i >> 8) & 0xff) + result.append((i & 0xff) ^ 0xff) + result.append(((i >> 8) & 0xff) ^ 0xff) + return result diff --git a/CreateIcon.gd.uid b/CreateIcon.gd.uid new file mode 100644 index 00000000..4f2ebb9a --- /dev/null +++ b/CreateIcon.gd.uid @@ -0,0 +1 @@ +uid://bb0n1dj2k22gl diff --git a/Export.ps1 b/Export.ps1 new file mode 100644 index 00000000..9788c52a --- /dev/null +++ b/Export.ps1 @@ -0,0 +1 @@ +F:\Apps\Godot_v4.4\Godot_v4.4-rc1_mono_win64.exe --headless --export-release "Windows Desktop" .\build\Cirno_No_Reason.exe \ No newline at end of file diff --git a/ReplaceIcon.gd b/ReplaceIcon.gd new file mode 100644 index 00000000..3cfef3af --- /dev/null +++ b/ReplaceIcon.gd @@ -0,0 +1,212 @@ +class_name ReplaceIcon +extends SceneTree + +const ICON_SIZE := 359559 + +var error_callable: Callable + + +func _init() -> void: + var arguments = OS.get_cmdline_args() + if arguments.size() != 4: + print( + "Usage:\n", + " godot -s ReplaceIcon.gd icon name\n", + "\n", + "Replaces ico file in windows PE32+ executable.\n", + "Add --headless to hide Godot console.\n", + "\n", + "Arguments:\n", + " godot path to Godot 4 beta2+ executable\n", + " icon path to new icon\n", + " name path to modified PE32+ executable\n" + ) + quit() + return + replace_icon(arguments[3], arguments[2]) + quit() + + +func replace_icon(executable_path: String, icon_path: String) -> void: + var icon_replacer := IconReplacer.new() + + var images := get_images(icon_path) + + var executable_file := FileAccess.open(executable_path, FileAccess.READ_WRITE) + if not executable_file: + print_error("Could not open executable file!") + return + var headers := executable_file.get_buffer(2048) + var resources_section_entry := icon_replacer.find_resources_section_entry(headers) + if not resources_section_entry: + return + if resources_section_entry.size_of_raw_data < 359559: + print_error("Could not find icons in executable. Wrong template?") + return + + executable_file.seek(resources_section_entry.pointer_to_raw_data) + var resources := executable_file.get_buffer(resources_section_entry.size_of_raw_data) + + resources = icon_replacer.replace_icons(resources, resources_section_entry.virtual_address, images) + if not resources.is_empty(): + executable_file.seek(resources_section_entry.pointer_to_raw_data) + executable_file.store_buffer(resources) + + +func get_images(icon_path: String) -> Dictionary: + var file := FileAccess.open(icon_path, FileAccess.READ) + if not file: + print_error(str("Could not open icon file!\n", FileAccess.get_open_error())) + return {} + return Icon.new(file.get_buffer(ICON_SIZE)).images + + +func print_error(error_message: String) -> void: + printerr(error_message) + if error_callable: + error_callable.call(error_message) + + +class IconReplacer: + enum ImageType {PE32 = 0x10b, PE32_PLUS = 0x20b} + + const PE_HEADER_ADDRESS_OFFSET := 0x3c + const NUMBER_OF_SECTIONS_OFFSET := 0x6 + const SIZE_OF_OPTIONAL_HEADER_OFFSET := 0x14 + const MAGIC_OFFSET := 0x18 + const COFF_HEADER_SIZE := 24 + const SECTION_SIZE := 40 + const SIZE_OF_RAW_DATA_OFFSET := 0x10 + const POINTER_TO_RAW_DATA_OFFSET := 0x14 + const DATA_ENTRY_SIZE := 16 + + var error_callable: Callable + + + func replace_icons(resources: PackedByteArray, rva_offset: int, images: Dictionary) -> PackedByteArray: + var data_entries := find_data_entries(resources) + for data_size in images.keys(): + var icon_offset := find_icon_offset(data_entries, data_size, rva_offset) + if resources.slice(icon_offset + 1, icon_offset + 4).get_string_from_ascii() != "PNG": + print_error("Wrong icon type, PNG signature missing") + return PackedByteArray() + resources = IconReplacer.replace(resources, images[data_size], icon_offset) + return resources + + + func find_icon_offset(data_entries: Array, data_size: int, rva_offset: int) -> int: + for data_entry in data_entries: + if data_entry.size == data_size: + return data_entry.rva - rva_offset + return -1 + + + func find_resources_section_entry(headers: PackedByteArray) -> SectionEntry: + var header_offset := IconReplacer.lsb_first(headers, PE_HEADER_ADDRESS_OFFSET, 2) + var image_type := IconReplacer.lsb_first(headers, header_offset + MAGIC_OFFSET, 2) + if not image_type == ImageType.PE32_PLUS: + print_error("Only PE32+ executables are handled.") + return null + var sections_size := IconReplacer.lsb_first(headers, header_offset + NUMBER_OF_SECTIONS_OFFSET, 2) + var size_of_optional_header := IconReplacer.lsb_first(headers, header_offset + SIZE_OF_OPTIONAL_HEADER_OFFSET, 2) + var sections_offset := header_offset + COFF_HEADER_SIZE + size_of_optional_header + for _i in range(sections_size): + var section_name = headers.slice(sections_offset, sections_offset + 8).get_string_from_ascii() + if section_name == ".rsrc": + return SectionEntry.new(headers.slice(sections_offset, sections_offset + SECTION_SIZE)) + sections_offset += SECTION_SIZE + return null + + + func find_data_entries(resources: PackedByteArray) -> Array: + var result := [] + parse_table(resources, 0, result) + return result + + + func parse_table(resources: PackedByteArray, offset: int, data_entries: Array) -> void: + var entry_count := IconReplacer.lsb_first(resources, offset + 14, 2) + offset += 16 + for _i in range(entry_count): + parse_entry(resources, offset, data_entries) + offset += 8 + + + func parse_entry(resources: PackedByteArray, offset: int, data_entries: Array) -> void: + var entry_offset := IconReplacer.lsb_first(resources, offset + 4) + if entry_offset & 0x80000000: + parse_table(resources, entry_offset & 0x7fffffff, data_entries) + else: + parse_data_entry(resources, entry_offset, data_entries) + + + func parse_data_entry(resources: PackedByteArray, offset: int, data_entries: Array) -> void: + data_entries.append(DataEntry.new(resources.slice(offset, offset + DATA_ENTRY_SIZE))) + + + func print_error(error_message: String) -> void: + printerr(error_message) + if error_callable: + error_callable.call(error_message) + + + static func lsb_first(bytes: PackedByteArray, offset: int, byte_count = 4) -> int: + var result := 0 + for i in range(byte_count, 0, -1): + result = (result << 8) + bytes[offset + i - 1] + return result + + + static func replace(bytes: PackedByteArray, replacement: PackedByteArray, index: int) -> PackedByteArray: + for i in range(replacement.size()): + bytes.set(index + i, replacement[i]) + return bytes + + +class SectionEntry: + const VIRTUAL_ADDRESS_OFFSET := 0x0c + const SIZE_OF_RAW_DATA_OFFSET = 0x10 + const POINTER_TO_RAW_DATA_OFFSET = 0x14 + + var virtual_address: int + var pointer_to_raw_data: int + var size_of_raw_data: int + + + func _init(bytes: PackedByteArray) -> void: + virtual_address = IconReplacer.lsb_first(bytes, VIRTUAL_ADDRESS_OFFSET) + size_of_raw_data = IconReplacer.lsb_first(bytes, SIZE_OF_RAW_DATA_OFFSET) + pointer_to_raw_data = IconReplacer.lsb_first(bytes, POINTER_TO_RAW_DATA_OFFSET) + + +class DataEntry: + const RVA_OFFSET := 0 + const SIZE_OFFSET := 4 + + var rva: int + var size: int + + + func _init(bytes: PackedByteArray) -> void: + rva = IconReplacer.lsb_first(bytes, RVA_OFFSET) + size = IconReplacer.lsb_first(bytes, SIZE_OFFSET) + + +class Icon: + const IMAGE_COUNT_OFFSET := 0x4 + const IMAGES_OFFSET := 0x6 + const ICON_ENTRY_SIZE := 16 + const SIZE_OFFSET := 0x8 + const DATA_OFFSET := 0xc + + var images := {} + + + func _init(bytes: PackedByteArray) -> void: + var image_count := IconReplacer.lsb_first(bytes, IMAGE_COUNT_OFFSET, 2) + var offset := IMAGES_OFFSET + for i in image_count: + var size := IconReplacer.lsb_first(bytes, offset + SIZE_OFFSET) + var data_offset := IconReplacer.lsb_first(bytes, offset + DATA_OFFSET) + images[size] = bytes.slice(data_offset, data_offset + size) + offset += ICON_ENTRY_SIZE diff --git a/ReplaceIcon.gd.uid b/ReplaceIcon.gd.uid new file mode 100644 index 00000000..fb1844db --- /dev/null +++ b/ReplaceIcon.gd.uid @@ -0,0 +1 @@ +uid://cdbkovbleadx1 diff --git a/Sprites/Actors/Cirno.aseprite b/Sprites/Actors/Cirno.aseprite index 8b940359..886aad11 100644 --- a/Sprites/Actors/Cirno.aseprite +++ b/Sprites/Actors/Cirno.aseprite @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9bc3fdd9abed06ce91a678e656d33723778614600e2ae691e2403dfb9ccf5094 -size 4029 +oid sha256:25d9f61ebdb413dd604f8f13db73225ae033f7ba822e41c5ae419f4d5f3a608b +size 4439 diff --git a/Sprites/Icon.ico b/Sprites/Icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..9d108eef993d3468abd2e9d443d7f53697142ae5 GIT binary patch literal 51262 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 Y*c)B$0~PW@$xi&t=>IVKqP7$GA1N7&AOHXW literal 0 HcmV?d00001 diff --git a/addons/scene_palette/save_data/save_data.tres b/addons/scene_palette/save_data/save_data.tres new file mode 100644 index 00000000..b30374ee --- /dev/null +++ b/addons/scene_palette/save_data/save_data.tres @@ -0,0 +1,7 @@ +[gd_resource type="Resource" script_class="PalettePluginSaveData" load_steps=2 format=3 uid="uid://c6r8j36esb764"] + +[ext_resource type="Script" uid="uid://d2vskl7301jhr" path="res://addons/scene_palette/resources/rsc_pallete_plugin_save_data.gd" id="1_tuhxn"] + +[resource] +script = ExtResource("1_tuhxn") +favorites = {} diff --git a/export_presets.cfg b/export_presets.cfg index 5c9554ea..c6e4e99b 100644 --- a/export_presets.cfg +++ b/export_presets.cfg @@ -10,8 +10,10 @@ export_filter="all_resources" include_filter="" exclude_filter="" export_path="../builds/cirnoreason.exe" +patches=PackedStringArray() encryption_include_filters="" encryption_exclude_filters="" +seed=0 encrypt_pck=false encrypt_directory=false script_export_mode=2 @@ -32,7 +34,7 @@ codesign/digest_algorithm=1 codesign/description="" codesign/custom_options=PackedStringArray() application/modify_resources=true -application/icon="" +application/icon="uid://dicat7qqa0a7o" application/console_wrapper_icon="" application/icon_interpolation=4 application/file_version="" diff --git a/project.godot b/project.godot index b98c82ba..22c17b3b 100644 --- a/project.godot +++ b/project.godot @@ -100,7 +100,7 @@ project/assembly_name="Cirno" [editor_plugins] -enabled=PackedStringArray("res://addons/DebugGUI/plugin.cfg", "res://addons/dialogic/plugin.cfg", "res://addons/smoothing/plugin.cfg") +enabled=PackedStringArray("res://addons/DebugGUI/plugin.cfg", "res://addons/dialogic/plugin.cfg", "res://addons/scene_palette/plugin.cfg", "res://addons/smoothing/plugin.cfg") [global_group]