mirror of
https://github.com/JHDev2006/Super-Mario-Bros.-Remastered-Public.git
synced 2025-10-22 15:38:14 +00:00
added the game
This commit is contained in:
307
Scripts/UI/RomAssetEditor.gd
Normal file
307
Scripts/UI/RomAssetEditor.gd
Normal file
@@ -0,0 +1,307 @@
|
||||
class_name AssetEditor
|
||||
extends AssetRipper
|
||||
|
||||
const CUR_SPRITE_TEXT: String = "Current Sprite:\n%s"
|
||||
|
||||
var list_index: int = 0
|
||||
var sprite_list: Array
|
||||
var cached_sprites: Dictionary[String, Dictionary]
|
||||
|
||||
var tile_atlas: Texture
|
||||
var rom_provided: bool
|
||||
|
||||
var source_path: String
|
||||
var tile_index: int = 0
|
||||
var columns: int = 4
|
||||
var sheet_size := Vector2i(16, 16)
|
||||
|
||||
var palette_base: String = "Tile"
|
||||
var palettes: Dictionary
|
||||
var tiles: Dictionary
|
||||
|
||||
@onready var rom_required: Label = %RomRequired
|
||||
@onready var file_dialog: FileDialog = %FileDialog
|
||||
|
||||
@onready var image_preview: TextureRect = %ImagePreview
|
||||
@onready var green_preview: TextureRect = %GreenPreview
|
||||
@onready var tiles_preview: TextureRect = %TilesPreview
|
||||
@onready var cur_sprite: Label = %CurSprite
|
||||
|
||||
@onready var preview: Sprite2D = %Preview
|
||||
@onready var buttons: HBoxContainer = %Buttons
|
||||
@onready var palette_override: LineEdit = %PaletteOverride
|
||||
|
||||
@onready var scroll_container: ScrollContainer = %ScrollContainer
|
||||
@onready var json_container: VBoxContainer = %JSONContainer
|
||||
@onready var json_edit: TextEdit = %JSONEdit
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
Global.get_node("GameHUD").hide()
|
||||
if Global.rom_path != "":
|
||||
on_file_selected(Global.rom_path)
|
||||
|
||||
func _exit_tree() -> void:
|
||||
Global.get_node("GameHUD").show()
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if not rom_provided:
|
||||
return
|
||||
|
||||
if event is InputEventMouseMotion:
|
||||
var is_snapped = not Input.is_action_pressed("editor_cam_fast")
|
||||
var mouse_pos: Vector2 = event.position + Vector2(
|
||||
scroll_container.scroll_horizontal,
|
||||
scroll_container.scroll_vertical
|
||||
) + Vector2(-4, -8)
|
||||
preview.position = Vector2i(mouse_pos).snappedi(8 if is_snapped else 1)
|
||||
|
||||
preview.visible = true
|
||||
if preview.position.x + 8 > sheet_size.x:
|
||||
preview.visible = false
|
||||
if preview.position.y + 8 > sheet_size.y:
|
||||
preview.visible = false
|
||||
|
||||
if not preview.is_visible_in_tree(): return
|
||||
|
||||
var direction: int = 0
|
||||
if event.is_action_pressed("editor_cam_left"): direction = -1
|
||||
if event.is_action_pressed("editor_cam_right"): direction = 1
|
||||
if event.is_action_pressed("pick_tile"):
|
||||
if tiles.has(preview.position):
|
||||
tile_index = tiles[preview.position].index
|
||||
preview.flip_h = tiles[preview.position].flip_h
|
||||
preview.flip_v = tiles[preview.position].flip_v
|
||||
if Input.is_action_pressed("editor_select"):
|
||||
if tiles[preview.position].has("palette"):
|
||||
palette_override.text = tiles[preview.position]["palette"]
|
||||
else:
|
||||
palette_override.text = ""
|
||||
preview.region_rect = Rect2i(index_to_coords(tile_index, 32) * 8, Vector2i(8, 8))
|
||||
if direction != 0:
|
||||
var multiply = 1 if not Input.is_action_pressed("editor_cam_fast") else 8
|
||||
tile_index = wrapi(tile_index + direction * multiply, 0, 512)
|
||||
preview.region_rect = Rect2i(index_to_coords(tile_index, 32) * 8, Vector2i(8, 8))
|
||||
|
||||
if event.is_action_pressed("jump_0"): preview.flip_h = not preview.flip_h
|
||||
if event.is_action_pressed("run_0"): preview.flip_v = not preview.flip_v
|
||||
|
||||
var left_click: bool = event.is_action_pressed("mb_left")
|
||||
var right_click: bool = event.is_action_pressed("mb_right")
|
||||
if left_click or right_click:
|
||||
if left_click:
|
||||
tiles[preview.position] = {
|
||||
"index": tile_index,
|
||||
"flip_h": preview.flip_h,
|
||||
"flip_v": preview.flip_v
|
||||
}
|
||||
if not palette_override.text.is_empty():
|
||||
tiles[preview.position]["palette"] = palette_override.text
|
||||
else:
|
||||
tiles.erase(preview.position)
|
||||
|
||||
update_edited_image()
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if Input.is_action_pressed("editor_select") == false:
|
||||
return
|
||||
var left_click: bool = Input.is_action_pressed("mb_left")
|
||||
var right_click: bool = Input.is_action_pressed("mb_right")
|
||||
if left_click or right_click:
|
||||
if left_click:
|
||||
tiles[preview.position] = {
|
||||
"index": tile_index,
|
||||
"flip_h": preview.flip_h,
|
||||
"flip_v": preview.flip_v
|
||||
}
|
||||
if not palette_override.text.is_empty():
|
||||
tiles[preview.position]["palette"] = palette_override.text
|
||||
else:
|
||||
tiles.erase(preview.position)
|
||||
|
||||
update_edited_image()
|
||||
|
||||
func update_edited_image() -> void:
|
||||
var tiles_images: Array[Image] = get_tile_images(image_preview.texture.get_image().get_size(), tiles, palettes)
|
||||
tiles_preview.texture = ImageTexture.create_from_image(tiles_images[0])
|
||||
green_preview.texture = ImageTexture.create_from_image(tiles_images[1])
|
||||
|
||||
func get_tile_images(
|
||||
img_size: Vector2i, tile_list: Dictionary, palette_lists: Dictionary
|
||||
) -> Array[Image]:
|
||||
var image := Image.create(img_size.x, img_size.y, false, Image.FORMAT_RGBA8)
|
||||
var green_image := Image.create(img_size.x, img_size.y, false, Image.FORMAT_RGBA8)
|
||||
|
||||
for palette_name in palette_lists.keys():
|
||||
var cur_column: int = 0
|
||||
var offset := Vector2.ZERO
|
||||
|
||||
var pal_json: String = FileAccess.get_file_as_string(
|
||||
PALETTES_FOLDER % [DEFAULT_PALETTE_GROUP, palette_name])
|
||||
var pal_dict: Dictionary = JSON.parse_string(pal_json).palettes
|
||||
|
||||
for palette_id: String in palette_lists[palette_name]:
|
||||
var palette: Array = pal_dict.get(palette_id, PREVIEW_PALETTE)
|
||||
|
||||
for tile_pos: Vector2 in tile_list:
|
||||
var tile_dict: Dictionary = tile_list[tile_pos]
|
||||
var tile_palette: String = tile_dict.get("palette", palette_base)
|
||||
if tile_palette == palette_name:
|
||||
var destination: Vector2 = tile_pos + offset
|
||||
if destination.x < img_size.x and destination.y < img_size.y:
|
||||
draw_green(green_image, destination)
|
||||
draw_tile(
|
||||
false,
|
||||
image,
|
||||
tile_dict.get("index", 0),
|
||||
destination,
|
||||
palette,
|
||||
tile_dict.get("flip_h", false),
|
||||
tile_dict.get("flip_v", false)
|
||||
)
|
||||
cur_column += 1
|
||||
if cur_column >= columns:
|
||||
cur_column = 0
|
||||
offset.x = 0
|
||||
offset.y += sheet_size.y
|
||||
else:
|
||||
offset.x += sheet_size.x
|
||||
return [image, green_image]
|
||||
|
||||
func on_file_selected(path: String) -> void:
|
||||
rom = FileAccess.get_file_as_bytes(path)
|
||||
prg_rom_size = rom[4] * 16384
|
||||
chr_rom = rom.slice(16 + prg_rom_size)
|
||||
|
||||
rom_provided = true
|
||||
rom_required.hide()
|
||||
buttons.show()
|
||||
|
||||
# setup sprite atlas for placing tiles
|
||||
var atlas := Image.create(256, 256, false, Image.FORMAT_RGBA8)
|
||||
for index in range(512):
|
||||
var pos: Vector2i = index_to_coords(index, 32) * 8
|
||||
draw_tile(false, atlas, index, pos, PREVIEW_PALETTE)
|
||||
preview.texture = ImageTexture.create_from_image(atlas)
|
||||
#
|
||||
|
||||
var list_json: String = FileAccess.get_file_as_string(SPRITE_LIST_PATH)
|
||||
var list_dict: Dictionary = JSON.parse_string(list_json)
|
||||
sprite_list = list_dict.get("sprites", [])
|
||||
|
||||
cycle_list(0)
|
||||
|
||||
func load_sprite(sprite_dict: Dictionary) -> void:
|
||||
source_path = sprite_dict.source_path
|
||||
|
||||
if source_path.begins_with("res://"):
|
||||
image_preview.texture = load(source_path)
|
||||
else:
|
||||
var image := Image.load_from_file(source_path)
|
||||
image_preview.texture = ImageTexture.create_from_image(image)
|
||||
cur_sprite.text = CUR_SPRITE_TEXT % source_path.get_file()
|
||||
|
||||
columns = str_to_var(sprite_dict.get("columns", "4"))
|
||||
sheet_size = str_to_var(sprite_dict.get("sheet_size", "Vector2i(16, 16)"))
|
||||
palette_base = sprite_dict.get("palette_base", "Tile")
|
||||
|
||||
var palettes_var: Variant = str_to_var(sprite_dict.get("palettes", var_to_str(get_default_palettes())))
|
||||
if typeof(palettes_var) == TYPE_ARRAY:
|
||||
palettes = {}
|
||||
palettes[palette_base] = palettes_var
|
||||
elif typeof(palettes_var) == TYPE_DICTIONARY:
|
||||
palettes = palettes_var
|
||||
|
||||
tiles = str_to_var(sprite_dict.get("tiles", "{}"))
|
||||
|
||||
update_palettes()
|
||||
update_edited_image()
|
||||
|
||||
func save_sprite() -> void:
|
||||
var sprite_dict: Dictionary = get_as_dict()
|
||||
var destination_path: String = png_path_to_json(sprite_dict.source_path)
|
||||
|
||||
var json_string: String = JSON.stringify(sprite_dict)
|
||||
DirAccess.make_dir_recursive_absolute(destination_path.get_base_dir())
|
||||
var file: FileAccess = FileAccess.open(destination_path, FileAccess.WRITE)
|
||||
file.store_line(json_string)
|
||||
file.close()
|
||||
|
||||
# save green over original image
|
||||
var base_image: Image = image_preview.texture.get_image()
|
||||
var green_image: Image = green_preview.texture.get_image()
|
||||
for y in range(green_image.get_size().y):
|
||||
for x in range(green_image.get_size().x):
|
||||
var found_color: Color = green_image.get_pixel(x, y)
|
||||
if found_color.a > 0:
|
||||
base_image.set_pixel(x, y, found_color)
|
||||
base_image.save_png(sprite_dict.source_path)
|
||||
|
||||
func cycle_list(add_index: int) -> void:
|
||||
if add_index != 0:
|
||||
cached_sprites[sprite_list[list_index]] = get_as_dict()
|
||||
list_index = wrapi(list_index + add_index, 0, sprite_list.size())
|
||||
|
||||
if sprite_list[list_index] in cached_sprites:
|
||||
load_sprite(cached_sprites[sprite_list[list_index]])
|
||||
else:
|
||||
var json_path: String = sprite_list[list_index].replace(
|
||||
"res://Assets/Sprites/", "res://Resources/AssetRipper/Sprites/"
|
||||
).replace(".png", ".json")
|
||||
if FileAccess.file_exists(json_path):
|
||||
var json_string: String = FileAccess.get_file_as_string(json_path)
|
||||
load_sprite(JSON.parse_string(json_string))
|
||||
else:
|
||||
load_sprite({"source_path": sprite_list[list_index]})
|
||||
|
||||
func get_as_dict() -> Dictionary:
|
||||
return {
|
||||
"source_path": source_path,
|
||||
"columns": var_to_str(columns),
|
||||
"sheet_size": var_to_str(sheet_size),
|
||||
"palette_base": palette_base,
|
||||
"palettes": var_to_str(palettes),
|
||||
"tiles": var_to_str(tiles)
|
||||
}
|
||||
|
||||
func get_default_palettes() -> Dictionary:
|
||||
var pal_json: String = FileAccess.get_file_as_string(
|
||||
PALETTES_FOLDER % [DEFAULT_PALETTE_GROUP, palette_base])
|
||||
var pal_dict: Dictionary = JSON.parse_string(pal_json)
|
||||
var default_palettes: Array = pal_dict.get("palettes", []).keys()
|
||||
return {palette_base: default_palettes}
|
||||
|
||||
func update_palettes(load_textedit: bool = false) -> void:
|
||||
if load_textedit:
|
||||
var dict: Dictionary = JSON.parse_string(json_edit.text)
|
||||
columns = dict.get("columns", 1)
|
||||
var size_array: Array = dict.get("sheet_size", [16, 16])
|
||||
sheet_size = Vector2i(size_array[0], size_array[1])
|
||||
palette_base = dict.get("palette_base", "Tile")
|
||||
var pal_var: Variant = dict.get("palettes", get_default_palettes())
|
||||
if typeof(pal_var) == TYPE_ARRAY:
|
||||
palettes = {}
|
||||
palettes[palette_base] = pal_var
|
||||
elif typeof(pal_var) == TYPE_DICTIONARY:
|
||||
palettes = pal_var
|
||||
update_edited_image()
|
||||
|
||||
json_edit.text = JSON.stringify(
|
||||
{
|
||||
"columns": columns,
|
||||
"sheet_size": [sheet_size.x, sheet_size.y],
|
||||
"palette_base": palette_base,
|
||||
"palettes": palettes
|
||||
}, "\t", false)
|
||||
|
||||
func toggle_palettes_view(toggled_on: bool) -> void:
|
||||
json_container.visible = toggled_on
|
||||
scroll_container.visible = not toggled_on
|
||||
|
||||
func draw_green(
|
||||
image: Image,
|
||||
pos: Vector2i
|
||||
) -> void:
|
||||
for y in range(8):
|
||||
for x in range(8):
|
||||
image.set_pixelv(Vector2i(x, y) + pos, Color.GREEN)
|
Reference in New Issue
Block a user