First commit 🎉
This commit is contained in:
commit
43ea213f9b
728 changed files with 37080 additions and 0 deletions
208
addons/popochiu/migration/helpers/popochiu_migration_helper.gd
Normal file
208
addons/popochiu/migration/helpers/popochiu_migration_helper.gd
Normal file
|
@ -0,0 +1,208 @@
|
|||
@tool
|
||||
class_name PopochiuMigrationHelper
|
||||
extends Node
|
||||
## Helper class to assist migrating Popochiu Projects to newer versions
|
||||
|
||||
const MIGRATIONS_PATH = "res://addons/popochiu/migration/migrations/"
|
||||
const MIGRATION_SECTION = "last_migration"
|
||||
const MIGRATION_KEY = "version"
|
||||
const POPOCHIU_PATH = "res://popochiu/"
|
||||
|
||||
static var old_settings_file := PopochiuResources.GAME_PATH.path_join("popochiu_settings.tres")
|
||||
|
||||
|
||||
#region Public #####################################################################################
|
||||
static func get_migrations_count() -> int:
|
||||
return DirAccess.get_files_at(MIGRATIONS_PATH).size()
|
||||
|
||||
|
||||
## Returns the game folder path. If this returns [member POPOCHIU_PATH], then the project is from
|
||||
## Popochiu 1.x or Popochiu 2.0.0-AlphaX.
|
||||
static func get_game_path() -> String:
|
||||
if (
|
||||
DirAccess.dir_exists_absolute(PopochiuResources.GAME_PATH)
|
||||
and DirAccess.dir_exists_absolute(POPOCHIU_PATH)
|
||||
):
|
||||
return POPOCHIU_PATH
|
||||
elif DirAccess.dir_exists_absolute(PopochiuResources.GAME_PATH):
|
||||
return PopochiuResources.GAME_PATH
|
||||
else: # Error cannot access the game folders
|
||||
return ""
|
||||
|
||||
|
||||
## Returns the user project migration version from the "res://game/popochiu_data.cfg" file.
|
||||
## If the Popochiu Migration Version is greater than the user project migration version
|
||||
## then a migration needs to be done.
|
||||
## If -1 gets returned then an error has occurred.
|
||||
static func get_user_migration_version() -> int:
|
||||
# popochiu_data.cfg config file could not be loaded, return error
|
||||
if PopochiuResources.get_data_cfg() == null:
|
||||
PopochiuUtils.print_error("Can't load [code]popochiu_data.cfg[/code] file.")
|
||||
return -1
|
||||
|
||||
if PopochiuResources.has_data_value(MIGRATION_SECTION, MIGRATION_KEY):
|
||||
# Return the migration version in the popochiu_data.cfg file
|
||||
return PopochiuResources.get_data_value(MIGRATION_SECTION, MIGRATION_KEY, 1)
|
||||
else:
|
||||
# Run Migration 1 and so on
|
||||
return 0
|
||||
|
||||
|
||||
## Returns [code]true[/code] if this is an empty project: no rooms, no characters, no inventory
|
||||
## items, no dialogues, and no audio files.
|
||||
static func is_empty_project() -> bool:
|
||||
return (
|
||||
get_game_path() == PopochiuResources.GAME_PATH
|
||||
and PopochiuResources.get_section_keys("rooms").is_empty()
|
||||
and PopochiuResources.get_section_keys("characters").is_empty()
|
||||
and PopochiuResources.get_section_keys("inventory_items").is_empty()
|
||||
and PopochiuResources.get_section_keys("dialogs").is_empty()
|
||||
and PopochiuResources.get_section_keys("audio").is_empty()
|
||||
)
|
||||
|
||||
|
||||
## Returns [true] if the current Popochiu migration version is newer than the user's migration
|
||||
## version, which means a migration is needed.
|
||||
static func is_migration_needed() -> bool:
|
||||
return get_migrations_count() > get_user_migration_version()
|
||||
|
||||
|
||||
## Updates [code]res://game/popochiu_data.cfg[/code] migration version to [param version].
|
||||
static func update_user_migration_version(new_version: int) -> void:
|
||||
if PopochiuResources.set_data_value(MIGRATION_SECTION, MIGRATION_KEY, new_version) != OK:
|
||||
PopochiuUtils.print_error(
|
||||
"Couldn't update the Migration version from [b]%d[/b] to [b]%d[/b] in Data file." % [
|
||||
get_migrations_count(), new_version
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
## Executes the [param steps] in [param migration] one by one and returns [code]true[/code] if
|
||||
## all finished without failing. It stops execution if a step fails.
|
||||
static func execute_migration_steps(migration: PopochiuMigration, steps: Array) -> bool:
|
||||
if steps.is_empty():
|
||||
PopochiuUtils.print_error(
|
||||
"No steps to execute for Migration %d" % migration.get_version()
|
||||
)
|
||||
await PopochiuEditorHelper.frame_processed()
|
||||
return false
|
||||
|
||||
var idx := 0
|
||||
for step: Callable in steps:
|
||||
# Update the migration step interface to show a loader
|
||||
migration.start_step(idx)
|
||||
# Run the actual step
|
||||
var completion_type: PopochiuMigration.Completion = await step.call()
|
||||
if completion_type in [
|
||||
PopochiuMigration.Completion.DONE, PopochiuMigration.Completion.IGNORED
|
||||
]:
|
||||
# Update the interface, no more loader
|
||||
await migration.step_finished(idx, completion_type)
|
||||
else:
|
||||
return false
|
||||
|
||||
idx += 1
|
||||
|
||||
return true
|
||||
|
||||
|
||||
## Helper function to recursively scan the directory in [param path] and return an [Array] of
|
||||
## absolute file paths with the specified extension.
|
||||
static func get_absolute_file_paths_for_file_extensions(
|
||||
path: String, file_extensions: Array[String], folders_to_ignore: Array[String] = []
|
||||
) -> Array:
|
||||
var file_paths := []
|
||||
var dir: DirAccess = DirAccess.open(path)
|
||||
|
||||
if not dir.dir_exists(path):
|
||||
return file_paths
|
||||
|
||||
dir.list_dir_begin()
|
||||
var element_name = dir.get_next()
|
||||
while not element_name.is_empty():
|
||||
var file_path := path.path_join(element_name)
|
||||
if dir.current_is_dir():
|
||||
if element_name in folders_to_ignore:
|
||||
element_name = dir.get_next()
|
||||
continue
|
||||
|
||||
# Recurse into subdirectories
|
||||
file_paths += get_absolute_file_paths_for_file_extensions(
|
||||
file_path, file_extensions, folders_to_ignore
|
||||
)
|
||||
elif file_extensions.is_empty() or file_path.get_extension() in file_extensions:
|
||||
# Add files with the specified extension to the [file_paths] array
|
||||
file_paths.append(file_path)
|
||||
|
||||
element_name = dir.get_next()
|
||||
dir.list_dir_end()
|
||||
|
||||
return file_paths
|
||||
|
||||
|
||||
## Looks in the text of each file in [param file_paths] for coincidences of [param from], and
|
||||
## replace them by [param to]. If any replacement was done, returns [code]true[/code].
|
||||
static func replace_text_in_files(from: String, to: String, file_paths: Array) -> bool:
|
||||
return PopochiuUtils.any_exhaustive(
|
||||
file_paths,
|
||||
func (file_path: String) -> bool:
|
||||
if not FileAccess.file_exists(file_path):
|
||||
return true
|
||||
|
||||
var file_read := FileAccess.open(file_path, FileAccess.READ)
|
||||
var text := file_read.get_as_text()
|
||||
file_read.close()
|
||||
|
||||
if not from in text:
|
||||
return false
|
||||
|
||||
var file_write := FileAccess.open(file_path, FileAccess.WRITE)
|
||||
text = text.replace(from, to)
|
||||
file_write.store_string(text)
|
||||
file_write.close()
|
||||
return true
|
||||
)
|
||||
|
||||
|
||||
## Returns [true] if the game is checked as pixel-art based on the value in
|
||||
## [code]popochiu/pixel/pixel_art_textures[/code] or in the old [code]popochiu_settings.tres[/code]
|
||||
## file in versions prior to [i]2.0.0-beta3[/i].
|
||||
static func is_pixel_art_game() -> bool:
|
||||
var is_pixel_art := PopochiuConfig.is_pixel_art_textures()
|
||||
|
||||
if FileAccess.file_exists(old_settings_file):
|
||||
var old_settings := load(old_settings_file)
|
||||
if old_settings.get("is_pixel_art_game") != null:
|
||||
is_pixel_art = old_settings.is_pixel_art_game
|
||||
|
||||
return is_pixel_art
|
||||
|
||||
|
||||
## Checks if [param text] exists in the text of the file at [param file_path].
|
||||
static func is_text_in_file(text: String, file_path: String) -> bool:
|
||||
var file_read := FileAccess.open(file_path, FileAccess.READ)
|
||||
var file_text := file_read.get_as_text()
|
||||
file_read.close()
|
||||
|
||||
return text in file_text
|
||||
|
||||
|
||||
## Replaces all text matches in all scripts of the game with the [param replacements].
|
||||
## [param replacements] is an [Array] of [Dictionary] with the keys [code]from[/code] and
|
||||
## [code]to[/code] to replace in the scripts. The [param folders_to_ignore] is an [Array] of
|
||||
## folder names that should be ignored when searching for scripts.
|
||||
static func replace_in_scripts(
|
||||
replacements: Array[Dictionary], folders_to_ignore: Array[String] = []
|
||||
) -> bool:
|
||||
var scripts_paths := get_absolute_file_paths_for_file_extensions(
|
||||
PopochiuResources.GAME_PATH, ["gd"], folders_to_ignore
|
||||
)
|
||||
|
||||
var replaced_matches := 0
|
||||
for dic: Dictionary in replacements:
|
||||
replaced_matches += 1 if replace_text_in_files(dic.from, dic.to, scripts_paths) else 0
|
||||
|
||||
return replaced_matches > 0
|
||||
|
||||
|
||||
#endregion
|
|
@ -0,0 +1 @@
|
|||
uid://dtq44ju6115st
|
128
addons/popochiu/migration/migration/popochiu_migration.gd
Normal file
128
addons/popochiu/migration/migration/popochiu_migration.gd
Normal file
|
@ -0,0 +1,128 @@
|
|||
@tool
|
||||
class_name PopochiuMigration
|
||||
extends Node
|
||||
## This provides the core features needed to do a migration.
|
||||
##
|
||||
## Migration files in [code]res://addons/popochiu/migration/migrations/*.gd[/code] should
|
||||
## extend this class.
|
||||
|
||||
enum Completion {
|
||||
FAILED,
|
||||
DONE,
|
||||
IGNORED,
|
||||
}
|
||||
|
||||
signal step_started(migration: PopochiuMigration, idx: int)
|
||||
signal step_completed(migration: PopochiuMigration)
|
||||
|
||||
var _version := -1
|
||||
var _reload_needed := false
|
||||
|
||||
## [Array] of completed steps
|
||||
var completed := []
|
||||
## [Array] of ignored steps
|
||||
var ignored := []
|
||||
|
||||
|
||||
#region Godot ######################################################################################
|
||||
func _init() -> void:
|
||||
set_migration_version(get("VERSION"))
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Virtual ####################################################################################
|
||||
func _do_migration() -> bool:
|
||||
return false
|
||||
|
||||
|
||||
func _is_reload_required() -> bool:
|
||||
return _reload_needed
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public #####################################################################################
|
||||
## Sets [param version] as the migration version for the migration script.
|
||||
func set_migration_version(version: int) -> void:
|
||||
_version = version
|
||||
|
||||
|
||||
## Returns the [member _version] of this migration.
|
||||
func get_version() -> int:
|
||||
return _version
|
||||
|
||||
|
||||
func get_migration_name() -> String:
|
||||
return "Migration %d" % _version
|
||||
|
||||
|
||||
## Returns [true] if the current Popochiu migration version is newer than the user's migration
|
||||
## version, which means a migration is needed.
|
||||
func is_migration_needed() -> bool:
|
||||
return _version > PopochiuMigrationHelper.get_user_migration_version()
|
||||
|
||||
|
||||
## A helper function to display an error message in the [b]Output[/b] if there is an error doing
|
||||
## the migration, or a message if it is successful. This updates the [code]popochiu_data.cfg[/code]
|
||||
## file to have a new migration version if successful. [param migration] is an instantiated
|
||||
## [PopochiuMigration] from [code]res://addons/popochiu/migration/migrations/*.gd[/code].
|
||||
## [param version] is an integer for the migration version being run. This is intended to be called
|
||||
## [DoMigration].
|
||||
static func run_migration(migration: PopochiuMigration, version: int) -> bool:
|
||||
if not await migration.do_migration():
|
||||
PopochiuUtils.print_error("Migration %d failed" % version)
|
||||
return false
|
||||
else:
|
||||
PopochiuMigrationHelper.update_user_migration_version(version)
|
||||
PopochiuUtils.print_normal("Migration %d completed" % version)
|
||||
return true
|
||||
|
||||
|
||||
## Attempts to do the migration. Returns [code]true[/code] if successful.
|
||||
func do_migration() -> bool:
|
||||
# Make sure the user migration version is less then this migration version
|
||||
if not can_do_migration():
|
||||
return false
|
||||
|
||||
PopochiuUtils.print_normal("Performing Migration %s: %s" % [
|
||||
str(get("VERSION")), get("DESCRIPTION")
|
||||
])
|
||||
|
||||
return await _do_migration()
|
||||
|
||||
|
||||
## Makes sure that the user migration version is less than the current migration version and the
|
||||
## [_version] variable has been set to a value. Returns [code]true[/code] if migration can be done.
|
||||
func can_do_migration() -> bool:
|
||||
# If the user migration version is equal to, or higher than [_version], ignore the migration.
|
||||
# If [_version] is less than 0, then version has not been set so do not do the migration
|
||||
return PopochiuMigrationHelper.get_user_migration_version() < _version and _version >= 0
|
||||
|
||||
|
||||
## Emits [signal step_started] sending the [param idx], which is the index of the migration step
|
||||
## that just started.
|
||||
func start_step(idx: int) -> void:
|
||||
step_started.emit(self, idx)
|
||||
|
||||
|
||||
## Add the migration step ([param idx]) to its corresponding array depending on whether it was
|
||||
## completed ([param type] == [constant Completion.DONE]) or ignored
|
||||
## ([param type] == [constant Completion.IGNORED]). Then emits [signal step_completed] so the GUI
|
||||
## provides feedback to the developer.
|
||||
func step_finished(idx: int, type: Completion) -> void:
|
||||
match type:
|
||||
Completion.DONE:
|
||||
completed.append(idx)
|
||||
Completion.IGNORED:
|
||||
ignored.append(idx)
|
||||
|
||||
step_completed.emit(self)
|
||||
|
||||
|
||||
## Returns [code]true[/code] if this migration needs an Engine restart once applied.
|
||||
func is_reload_required() -> bool:
|
||||
return _is_reload_required()
|
||||
|
||||
|
||||
#endregion
|
|
@ -0,0 +1 @@
|
|||
uid://bs70bq5h5iqqj
|
|
@ -0,0 +1,39 @@
|
|||
@tool
|
||||
class_name PopochiuMigrationX # Change X to be the correct version number for migration
|
||||
extends PopochiuMigration
|
||||
|
||||
# Update constant values to be correct for your migration
|
||||
const VERSION = -1
|
||||
const DESCRIPTION = "short description of migration goes here"
|
||||
const STEPS = [
|
||||
# Include a short description of each step here
|
||||
#"Step 1"
|
||||
]
|
||||
|
||||
|
||||
|
||||
#region Virtual ####################################################################################
|
||||
## This is code specific for this migration. This should return [code]true[/code] if the migration
|
||||
## is successful. This is called from [method do_migration] which checks to make sure the migration
|
||||
## should be done before calling this.
|
||||
func _do_migration() -> bool:
|
||||
return await PopochiuMigrationHelper.execute_migration_steps(
|
||||
self,
|
||||
[
|
||||
# Include the function names for each step here
|
||||
#_step1
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
func _is_reload_required() -> bool:
|
||||
return false
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private ####################################################################################
|
||||
#func _step1() -> Completion:
|
||||
#return Completion.DONE
|
||||
|
||||
#endregion
|
|
@ -0,0 +1 @@
|
|||
uid://txtektgrauyw
|
449
addons/popochiu/migration/migrations/popochiu_migration_1.gd
Normal file
449
addons/popochiu/migration/migrations/popochiu_migration_1.gd
Normal file
|
@ -0,0 +1,449 @@
|
|||
@tool
|
||||
class_name PopochiuMigration1
|
||||
extends PopochiuMigration
|
||||
## Migrates projects from Alpha to Beta.
|
||||
|
||||
const VERSION = 1
|
||||
const DESCRIPTION = "Migrate project structure from alpha-x to beta"
|
||||
const STEPS = [
|
||||
"Delete [b]res://popochiu/autoloads/[/b].",
|
||||
"Move folders in [b]res://popochiu/[/b] to [b]res://game/[/b]. (pre [i]beta 1[/i])",
|
||||
"Rename folders and files to snake_case. (pre [i]alpha 2[/i])",
|
||||
#"Select the default GUI template. (pre [i]beta 1[/i])",
|
||||
"Update paths in [b]res://game/popochiu_data.cfg[/b]. (pre [i]beta 1[/i])",
|
||||
"Rename [b]res://popochiu/[/b] references to [b]res://game/[/b]. (pre [i]beta 1[/i])",
|
||||
"Rename [b]item_xxx[/b] to [b]inventory_item_xxx[/b] for inventory items. (pre [i]beta 1[/i])",
|
||||
"Update [b]PopochiuCharacter[/b]s. (pre [i]beta 1[/i])",
|
||||
"Replace deprecated method calls. (pre [i]beta 1[/i])",
|
||||
]
|
||||
const DEFAULT_GUI_TEMPLATE = "SimpleClick"
|
||||
const PopochiuGuiTemplatesHelper = preload(
|
||||
"res://addons/popochiu/editor/helpers/popochiu_gui_templates_helper.gd"
|
||||
)
|
||||
|
||||
var _snake_renamed := []
|
||||
|
||||
|
||||
#region Virtual ####################################################################################
|
||||
## This is code specific for this migration. This should return [code]true[/code] if the migration
|
||||
## is successful. This is called from [method do_migration] which checks to make sure the migration
|
||||
## should be done before calling this.
|
||||
func _do_migration() -> bool:
|
||||
return await PopochiuMigrationHelper.execute_migration_steps(
|
||||
self,
|
||||
[
|
||||
_delete_popochiu_folder_autoloads,
|
||||
_move_game_data,
|
||||
_rename_files_and_folders_to_snake_case,
|
||||
#_select_gui_template,
|
||||
_rebuild_popochiu_data_file,
|
||||
_rename_game_folder_references,
|
||||
_update_inventory_items,
|
||||
_update_characters,
|
||||
_replace_deprecated_method_calls,
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public #####################################################################################
|
||||
func is_migration_needed() -> bool:
|
||||
return super() and !_ignore_popochiu_folder_step()
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private ####################################################################################
|
||||
## Checks if the folder where the game is stored is the one used since Beta 1. This means the
|
||||
## [code]res://popochiu/[/code] folder doesn't exists in the project
|
||||
func _ignore_popochiu_folder_step() -> bool:
|
||||
return PopochiuMigrationHelper.get_game_path() == PopochiuResources.GAME_PATH
|
||||
|
||||
|
||||
## Delete the [constant PopochiuMigrationHelper.POPOCHIU_PATH] autoloads directory if it exists.
|
||||
func _delete_popochiu_folder_autoloads() -> Completion:
|
||||
if _ignore_popochiu_folder_step():
|
||||
return Completion.IGNORED
|
||||
|
||||
# No need to move the autoloads directory as Popochiu 2 creates them automatically. This will
|
||||
# also fix the issue related with using [preload()] in old [A] autoload.
|
||||
var all_done := false
|
||||
var autoloads_path := PopochiuMigrationHelper.POPOCHIU_PATH.path_join("Autoloads")
|
||||
|
||||
if DirAccess.dir_exists_absolute(autoloads_path):
|
||||
all_done = PopochiuEditorHelper.remove_recursive(autoloads_path)
|
||||
elif DirAccess.dir_exists_absolute(autoloads_path.to_lower()):
|
||||
all_done = PopochiuEditorHelper.remove_recursive(autoloads_path.to_lower())
|
||||
|
||||
_reload_needed = true
|
||||
return Completion.DONE if all_done else Completion.FAILED
|
||||
|
||||
|
||||
## Moves game data from [constant PopochiuMigrationHelper.POPOCHIU_PATH] to
|
||||
## [constant PopochiuResources.GAME_PATH].
|
||||
func _move_game_data() -> Completion:
|
||||
if _ignore_popochiu_folder_step():
|
||||
return Completion.IGNORED
|
||||
|
||||
var folders := DirAccess.get_directories_at(PopochiuMigrationHelper.POPOCHIU_PATH)
|
||||
var files := DirAccess.get_files_at(PopochiuMigrationHelper.POPOCHIU_PATH)
|
||||
|
||||
# Move files from PopochiuMigrationHelper.POPOCHIU_PATH to PopochiuResources.GAME_PATH
|
||||
for file in files:
|
||||
var src := PopochiuMigrationHelper.POPOCHIU_PATH.path_join(file)
|
||||
var dest := PopochiuResources.GAME_PATH.path_join(file.to_snake_case())
|
||||
|
||||
var err := DirAccess.rename_absolute(src, dest)
|
||||
if err != OK:
|
||||
PopochiuUtils.print_error("Couldn't move %s to %s: %d" % [src, dest, err])
|
||||
return Completion.FAILED
|
||||
|
||||
# Move folders from PopochiuMigrationHelper.POPOCHIU_PATH to PopochiuResources.GAME_PATH
|
||||
for folder in folders:
|
||||
var src := PopochiuMigrationHelper.POPOCHIU_PATH.path_join(folder)
|
||||
var dest := PopochiuResources.GAME_PATH.path_join(folder.to_snake_case())
|
||||
|
||||
DirAccess.remove_absolute(dest)
|
||||
|
||||
var err := DirAccess.rename_absolute(src, dest)
|
||||
if err != OK:
|
||||
PopochiuUtils.print_error("Couldn't move %s to %s: %d" % [src, dest, err])
|
||||
return Completion.FAILED
|
||||
|
||||
# All files/folders moved to PopochiuResources.GAME_PATH so delete the
|
||||
# PopochiuMigrationHelper.POPOCHIU_PATH directory
|
||||
_reload_needed = true
|
||||
return (
|
||||
Completion.DONE if DirAccess.remove_absolute(PopochiuMigrationHelper.POPOCHIU_PATH) == OK
|
||||
else Completion.FAILED
|
||||
)
|
||||
|
||||
|
||||
## Rename [constant PopochiuResources.GAME_PATH] files and folders to snake case.
|
||||
func _rename_files_and_folders_to_snake_case() -> Completion:
|
||||
var any_renamed := PopochiuUtils.any_exhaustive(
|
||||
PopochiuEditorHelper.get_absolute_directory_paths_at(PopochiuResources.GAME_PATH),
|
||||
func (folder: String) -> bool:
|
||||
var any_file_renamed := _rename_files_to_snake_case(folder)
|
||||
var any_folder_renamed := _rename_folders_to_snake_case(folder)
|
||||
|
||||
return any_file_renamed or any_folder_renamed
|
||||
)
|
||||
|
||||
if any_renamed:
|
||||
# Go over .gd, .tscn, .tres, and .cfg files to update their references to snake renamed
|
||||
# files and folders
|
||||
var files := PopochiuMigrationHelper.get_absolute_file_paths_for_file_extensions(
|
||||
PopochiuResources.GAME_PATH, ["gd", "tscn", "tres", "cfg"], ["autoloads"]
|
||||
)
|
||||
for names_pair: Dictionary in _snake_renamed:
|
||||
PopochiuMigrationHelper.replace_text_in_files(names_pair.old, names_pair.new, files)
|
||||
|
||||
_reload_needed = true
|
||||
return Completion.DONE if any_renamed else Completion.IGNORED
|
||||
|
||||
|
||||
## Renames all the folders and files in [param folder_path] to snake_case.
|
||||
func _rename_files_to_snake_case(folder_path: String) -> bool:
|
||||
return PopochiuUtils.any_exhaustive(
|
||||
Array(DirAccess.get_files_at(folder_path)),
|
||||
func (file: String) -> bool:
|
||||
var src := folder_path.path_join(file)
|
||||
var dest := folder_path.path_join(file.to_snake_case())
|
||||
|
||||
if src != dest:
|
||||
_snake_renamed.append({
|
||||
old = src.get_file(),
|
||||
new = dest.get_file()
|
||||
})
|
||||
|
||||
DirAccess.rename_absolute(src, dest)
|
||||
return true
|
||||
return false
|
||||
)
|
||||
|
||||
|
||||
## Rename [param path] folders and the content in the folders recursively to snake_case
|
||||
func _rename_folders_to_snake_case(path: String) -> bool:
|
||||
return PopochiuUtils.any_exhaustive(
|
||||
PopochiuEditorHelper.get_absolute_directory_paths_at(path),
|
||||
func (sub_folder: String) -> bool:
|
||||
# recursively rename files/folders to snake_case
|
||||
var any_subfolder_renamed = _rename_folders_to_snake_case(sub_folder)
|
||||
var any_file_renamed := _rename_files_to_snake_case(sub_folder)
|
||||
var snake_case_name := sub_folder.to_snake_case()
|
||||
var folder_renamed := sub_folder != snake_case_name
|
||||
|
||||
if folder_renamed:
|
||||
_snake_renamed.append({
|
||||
old = sub_folder.replace(PopochiuResources.GAME_PATH, ""),
|
||||
new = snake_case_name.replace(PopochiuResources.GAME_PATH, ""),
|
||||
})
|
||||
|
||||
DirAccess.rename_absolute(sub_folder, snake_case_name)
|
||||
folder_renamed = true
|
||||
|
||||
return any_subfolder_renamed or any_file_renamed or folder_renamed
|
||||
)
|
||||
|
||||
|
||||
## Copies the 2-click Context-sensitive GUI to [code]res://game/gui/[/code] if there
|
||||
## is no GUI template selected.
|
||||
func _select_gui_template() -> Completion:
|
||||
if PopochiuResources.get_data_value("ui", "template", "").is_empty():
|
||||
# Assume the project is from Popochiu 1.x or Popochiu 2 - Alpha X and assign the SimpleClick
|
||||
# GUI template
|
||||
await PopochiuGuiTemplatesHelper.copy_gui_template(
|
||||
DEFAULT_GUI_TEMPLATE,
|
||||
func (_progress: int, _msg: String) -> void: return,
|
||||
func () -> void: return,
|
||||
)
|
||||
return Completion.DONE
|
||||
else:
|
||||
await PopochiuEditorHelper.frame_processed()
|
||||
return Completion.IGNORED
|
||||
|
||||
|
||||
## Updates the paths to rooms, characters, inventory items and dialogs so they point to
|
||||
## [code]res://game/[/code] (for cases where the project still used [code]res://popochiu/[/code]).
|
||||
func _rebuild_popochiu_data_file() -> bool:
|
||||
if PopochiuMigrationHelper.is_text_in_file(
|
||||
PopochiuMigrationHelper.POPOCHIU_PATH, PopochiuResources.DATA
|
||||
):
|
||||
_rebuild_popochiu_data_section(PopochiuResources.GAME_PATH, "rooms")
|
||||
_rebuild_popochiu_data_section(PopochiuResources.GAME_PATH, "characters")
|
||||
_rebuild_popochiu_data_section(PopochiuResources.GAME_PATH, "inventory_items")
|
||||
_rebuild_popochiu_data_section(PopochiuResources.GAME_PATH, "dialogs")
|
||||
|
||||
return (
|
||||
Completion.DONE if PopochiuResources.set_data_value("setup", "done", true) == OK
|
||||
else Completion.FAILED
|
||||
)
|
||||
|
||||
return Completion.IGNORED
|
||||
|
||||
|
||||
## Updates the path to [param game_path] for each value in the [param data_section] in the
|
||||
## [code]popochiu_data.cfg[/code] ([ConfigFile]) file.
|
||||
func _rebuild_popochiu_data_section(game_path: String, data_section: String) -> void:
|
||||
var data_path := game_path.path_join(data_section)
|
||||
var section_name := data_section
|
||||
|
||||
# Make sure the section name does not have an "s" character at the end
|
||||
if section_name.length() > 0 and section_name[-1] == "s":
|
||||
section_name = section_name.rstrip("s")
|
||||
|
||||
# Add the keys and tres files for each directory in the data section
|
||||
for folder: String in DirAccess.get_directories_at(data_path):
|
||||
var key_name := folder.to_pascal_case()
|
||||
var tres_file := "%s_%s.tres" % [section_name, folder]
|
||||
var key_value := game_path.path_join("%s/%s/%s" % [data_section, folder, tres_file])
|
||||
|
||||
PopochiuResources.set_data_value(data_section, key_name, key_value)
|
||||
|
||||
|
||||
## Renames uses of [b]res://popochiu/[/b] to [b]res://game/[/b] in [code].tscn[/code],
|
||||
## [code].tres[/code], and [code].gd[/code] files.
|
||||
func _rename_game_folder_references() -> Completion:
|
||||
var changes_done := false
|
||||
|
||||
# Update the path to the main scene in Project Settings
|
||||
var main_scene_path := ProjectSettings.get_setting(PopochiuResources.MAIN_SCENE, "")
|
||||
|
||||
if PopochiuMigrationHelper.POPOCHIU_PATH in main_scene_path:
|
||||
changes_done = true
|
||||
ProjectSettings.set_setting(PopochiuResources.MAIN_SCENE, main_scene_path.replace(
|
||||
PopochiuMigrationHelper.POPOCHIU_PATH, PopochiuResources.GAME_PATH
|
||||
))
|
||||
ProjectSettings.save()
|
||||
|
||||
# Go over gd, tscn, and tres files to update their references to res://popochiu/ by res://game/
|
||||
var files := PopochiuMigrationHelper.get_absolute_file_paths_for_file_extensions(
|
||||
PopochiuResources.GAME_PATH, ["gd", "tscn", "tres", "cfg"], ["autoloads"]
|
||||
)
|
||||
|
||||
if PopochiuMigrationHelper.replace_text_in_files(
|
||||
PopochiuMigrationHelper.POPOCHIU_PATH, PopochiuResources.GAME_PATH, files
|
||||
):
|
||||
changes_done = true
|
||||
|
||||
_reload_needed = changes_done
|
||||
return Completion.DONE if changes_done else Completion.IGNORED
|
||||
|
||||
|
||||
## Updates all inventory items in the project so:[br]
|
||||
## - Their files (.tscn, .gd, and .tres) match the naming defined since beta-1 (inventory_item_*.*).
|
||||
## - All the paths inside those files point to the new file.
|
||||
## - Fixes a naming issue from alpha-1 where the root node name was set wrong. And also applies the
|
||||
## [constant CanvasItem.TEXTURE_FILTER_NEAREST] to each node in case the project is marked as
|
||||
## Pixel-art game.
|
||||
func _update_inventory_items() -> Completion:
|
||||
var inventory_item_files := PopochiuMigrationHelper.get_absolute_file_paths_for_file_extensions(
|
||||
PopochiuResources.INVENTORY_ITEMS_PATH,
|
||||
["tscn", "gd", "tres"]
|
||||
)
|
||||
|
||||
# Get all the inventory item file paths that were previously called item_*.*
|
||||
var scene_files := []
|
||||
var files_to_update := inventory_item_files.filter(
|
||||
func (file_path: String) -> bool:
|
||||
if file_path.get_extension() == "tscn":
|
||||
scene_files.append(file_path)
|
||||
return "/item_" in file_path
|
||||
)
|
||||
|
||||
if files_to_update.is_empty():
|
||||
return Completion.IGNORED
|
||||
|
||||
var update_done := scene_files.all(_update_root_name_and_texture_filter)
|
||||
if update_done:
|
||||
update_done = files_to_update.all(_rename_inventory_item_files_name)
|
||||
|
||||
if update_done and PopochiuMigrationHelper.is_text_in_file("/item_", PopochiuResources.I_SNGL):
|
||||
update_done = PopochiuMigrationHelper.replace_text_in_files(
|
||||
"/item_", "/inventory_item_", [PopochiuResources.I_SNGL]
|
||||
)
|
||||
|
||||
_reload_needed = update_done
|
||||
return Completion.DONE if update_done else Completion.FAILED
|
||||
|
||||
|
||||
## Loads the [PopochiuInventoryItem] in [param scene_file_path] and updates its root node name
|
||||
## and makes its [member CanvasItem.texture_filter] to [constant CanvasItem.TEXTURE_FILTER_NEAREST]
|
||||
## if this is a Pixel-art game.
|
||||
func _update_root_name_and_texture_filter(scene_file_path: String) -> bool:
|
||||
# Update root node name to PascalCase
|
||||
var scene: PopochiuInventoryItem = (load(scene_file_path) as PackedScene).instantiate()
|
||||
scene.name = "Item%s" % scene.script_name.to_pascal_case()
|
||||
|
||||
# Update the texture_filter if needed
|
||||
if PopochiuMigrationHelper.is_pixel_art_game():
|
||||
scene.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
|
||||
|
||||
if PopochiuEditorHelper.pack_scene(scene, scene_file_path) != OK:
|
||||
PopochiuUtils.print_error(
|
||||
"Couldn't update root node name for inventory item: [b]%s[/b]" % scene.script_name
|
||||
)
|
||||
return false
|
||||
return true
|
||||
|
||||
|
||||
## For each [PopochiuInventoryItem] in [param files_paths], updates the root node name to PascalCase,
|
||||
## renames the files to inventory_item_*.*, and updates the internal paths to match the new path.
|
||||
func _rename_inventory_item_files_name(file_path: String) -> bool:
|
||||
var old_file_name := file_path.get_file().get_basename()
|
||||
var new_file_name := old_file_name.replace("item_", "inventory_item_")
|
||||
PopochiuMigrationHelper.replace_text_in_files(old_file_name, new_file_name, [file_path])
|
||||
DirAccess.rename_absolute(file_path, file_path.replace("/item_", "/inventory_item_"))
|
||||
return true
|
||||
|
||||
|
||||
## For each [PopochiuCharacter] updates the way its voices are set to the structure defined in
|
||||
## alpha-3. It also adds new required nodes like an [AnimationPlayer] and a [CollisionPolygon2D] for
|
||||
## the [code]ScalingPolygon[/code].
|
||||
func _update_characters() -> Completion:
|
||||
# Get the characters' .tscn files
|
||||
var file_paths := PopochiuMigrationHelper.get_absolute_file_paths_for_file_extensions(
|
||||
PopochiuResources.CHARACTERS_PATH,
|
||||
["tscn"]
|
||||
)
|
||||
var any_character_updated := PopochiuUtils.any_exhaustive(file_paths, _update_character)
|
||||
return Completion.DONE if any_character_updated else Completion.IGNORED
|
||||
|
||||
|
||||
## Loads the [PopochiuCharacter] in [param scene_path] and:[br]
|
||||
## - Updates its [member PopochiuCharacter.voices] so they match the structure defined in alpha-3.
|
||||
## - Makes its [member CanvasItem.texture_filter] to [constant CanvasItem.TEXTURE_FILTER_NEAREST] if
|
||||
## this is a Pixel-art game.
|
||||
## - Adds [AnimationPlayer] and [CollisionPolygon2D] nodes if necessary.
|
||||
func _update_character(scene_path: String) -> bool:
|
||||
var popochiu_character: PopochiuCharacter = (load(scene_path) as PackedScene).instantiate()
|
||||
var was_scene_updated := false
|
||||
|
||||
# ---- Check if updating the voices [Dictionary] is needed -------------------------------------
|
||||
if not popochiu_character.voices.is_empty() and popochiu_character.voices[0].has("cue"):
|
||||
was_scene_updated = true
|
||||
var voices: Array = PopochiuResources.get_data_value("audio", "vo_cues", [])
|
||||
popochiu_character.voices = popochiu_character.voices.map(_map_voices.bind(voices))
|
||||
|
||||
# ---- Update the texture_filter if needed -----------------------------------------------------
|
||||
if PopochiuMigrationHelper.is_pixel_art_game():
|
||||
was_scene_updated = true
|
||||
popochiu_character.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
|
||||
|
||||
if not popochiu_character.has_node("AnimationPlayer"):
|
||||
# ---- Add an [AnimationPlayer] node if needed ---------------------------------------------
|
||||
was_scene_updated = true
|
||||
var animation_player := AnimationPlayer.new()
|
||||
animation_player.name = "AnimationPlayer"
|
||||
popochiu_character.add_child(animation_player)
|
||||
animation_player.owner = popochiu_character
|
||||
else:
|
||||
# ---- Or remove the texture track if it exists (prior Beta 1)------------------------------
|
||||
var animation_player: AnimationPlayer = popochiu_character.get_node("AnimationPlayer")
|
||||
for anim_name: String in animation_player.get_animation_list():
|
||||
var animation: Animation = animation_player.get_animation(anim_name)
|
||||
var texture_path: String = "%s:%s" % [
|
||||
popochiu_character.get_path_to(popochiu_character.get_node("Sprite2D")),
|
||||
"texture"
|
||||
]
|
||||
var texture_track: int = animation.find_track(texture_path, Animation.TYPE_VALUE)
|
||||
if texture_track > -1:
|
||||
animation.remove_track(texture_track)
|
||||
was_scene_updated = true
|
||||
|
||||
if was_scene_updated and PopochiuEditorHelper.pack_scene(popochiu_character, scene_path) != OK:
|
||||
PopochiuUtils.print_error("Couldn't update [b]%s[/b]." % popochiu_character.script_name)
|
||||
|
||||
return was_scene_updated
|
||||
|
||||
|
||||
## Maps the data [param emotion_dic] to a new [Dictionary] with the new format defined for
|
||||
## [member PopochiuCharacter.voices]. The [param voices] array is used to get the path to the
|
||||
## [PopochiuAudioCue] file that should be used in each voice variation.
|
||||
func _map_voices(emotion_dic: Dictionary, voices: Array) -> Dictionary:
|
||||
var arr: Array[AudioCueSound] = []
|
||||
var new_emotion_dic := {
|
||||
emotion = emotion_dic.emotion,
|
||||
variations = arr
|
||||
}
|
||||
|
||||
for num: int in emotion_dic.variations:
|
||||
var cue_name := "%s_%s" % [emotion_dic.cue, str(num + 1).pad_zeros(2)]
|
||||
var cue_path: String = voices.filter(
|
||||
func (cue_path: String) -> bool:
|
||||
return cue_name in cue_path
|
||||
)[0]
|
||||
|
||||
var popochiu_audio_cue: AudioCueSound = load(cue_path)
|
||||
new_emotion_dic.variations.append(popochiu_audio_cue)
|
||||
|
||||
return new_emotion_dic
|
||||
|
||||
|
||||
## Replace calls to old methods ignoring the [code]res://game/gui/[/code] folder:
|
||||
## - [code]R.get_point[/code] by [code]R.get_marker[/code].
|
||||
## - [code]G.display[/code] to [code]G.show_system_text[/code].
|
||||
## - Methods with [code]_now[/code] suffix.
|
||||
## - [code]super.on_click() | super.on_right_click() | super.on_item_used(item)[/code] by
|
||||
## [code]E.command_fallback()[/code]
|
||||
## - [code]super(item)[/code] to [code]E.command_fallback()[/code].
|
||||
func _replace_deprecated_method_calls() -> Completion:
|
||||
return Completion.DONE if PopochiuMigrationHelper.replace_in_scripts([
|
||||
{from = "R.get_point", to = "R.get_marker"},
|
||||
{from = "G.display", to = "G.show_system_text"},
|
||||
{from = "disable_now()", to = "disable()"},
|
||||
{from = "enable_now()", to = "enable()"},
|
||||
{from = "change_frame_now(", to = "change_frame("},
|
||||
{from = "super.on_click()", to = "E.command_fallback()"},
|
||||
{from = "super.on_right_click()", to = "E.command_fallback()"},
|
||||
{from = "super.on_item_used(item)", to = "E.command_fallback()"},
|
||||
{from = "super(item)", to = "E.command_fallback()"},
|
||||
# TODO: Include the following replacement. But for this one, the change should only be done
|
||||
# in scripts which have the default method implementation.
|
||||
#{from = "func _on_item_used(item", to = "func _on_item_used(_item"},
|
||||
], ["gui"]) else Completion.IGNORED
|
||||
|
||||
|
||||
#endregion
|
|
@ -0,0 +1 @@
|
|||
uid://bedsab8wkbwcb
|
671
addons/popochiu/migration/migrations/popochiu_migration_2.gd
Normal file
671
addons/popochiu/migration/migrations/popochiu_migration_2.gd
Normal file
|
@ -0,0 +1,671 @@
|
|||
@tool
|
||||
class_name PopochiuMigration2
|
||||
extends PopochiuMigration
|
||||
## Migrates projects from Beta to Release.
|
||||
|
||||
const VERSION = 2
|
||||
const DESCRIPTION = "Make changes from beta-x to 2.0.0 release"
|
||||
const STEPS = [
|
||||
"Update external scenes and assign scripts that didn't exist before. (pre [i]release[/i])",
|
||||
"Add a [b]ScalingPolygon[/b] node to each [b]PopochiuCharacter[/b]. (pre [i]beta 1[/i])",
|
||||
"Move popochiu_settings.tres to ProjectSettings. (pre [i]beta 3[/i])",
|
||||
#"Update the DialogMenu GUI component. (pre [i]beta 3[/i])",
|
||||
#"(Optional) Update SettingsBar in 2-click Context-sensitive GUI template. (pre [i]beta 3[/i])",
|
||||
"Remove [b]BaselineHelper[/b] and [b]WalkToHelper[/b] nodes in [b]PopochiuClickable[/b]s." \
|
||||
+ " Also remove [b]DialogPos[/b] node in [b]PopochiuCharacter[/b]s. (pre [i]release[/i])",
|
||||
"Update uses of deprecated properties and methods. (pre [i]release[/i])",
|
||||
"Update rooms sizes",
|
||||
]
|
||||
const RESET_CHILDREN_OWNER = "reset_children_owner"
|
||||
const GAME_INVENTORY_BAR_PATH =\
|
||||
"res://game/gui/components/inventory_bar/inventory_bar.tscn"
|
||||
const GAME_SETTINGS_BAR_PATH =\
|
||||
"res://game/gui/components/settings_bar/settings_bar.tscn"
|
||||
const GAME_DIALOG_MENU_PATH = "res://game/gui/components/dialog_menu/dialog_menu.tscn"
|
||||
const GAME_DIALOG_MENU_OPTION_PATH =\
|
||||
"res://game/gui/components/dialog_menu/dialog_menu_option/"
|
||||
const ADDON_DIALOG_MENU_PATH =\
|
||||
"res://addons/popochiu/engine/objects/gui/components/dialog_menu/dialog_menu.tscn"
|
||||
const TextSpeedOption = preload(
|
||||
PopochiuResources.GUI_ADDON_FOLDER + "components/settings_bar/resources/text_speed_option.gd"
|
||||
)
|
||||
|
||||
var _gui_templates_helper := preload(
|
||||
"res://addons/popochiu/editor/helpers/popochiu_gui_templates_helper.gd"
|
||||
)
|
||||
|
||||
|
||||
#region Virtual ####################################################################################
|
||||
## This is code specific for this migration. This should return [code]true[/code] if the migration
|
||||
## is successful. This is called from [method do_migration] which checks to make sure the migration
|
||||
## should be done before calling this.
|
||||
func _do_migration() -> bool:
|
||||
return await PopochiuMigrationHelper.execute_migration_steps(
|
||||
self,
|
||||
[
|
||||
_update_objects_in_rooms,
|
||||
_add_scaling_polygon_to_characters,
|
||||
_move_settings_to_project_settings,
|
||||
#_update_dialog_menu,
|
||||
#_update_simple_click_settings_bar,
|
||||
_remove_helper_nodes,
|
||||
_replace_deprecated,
|
||||
_update_rooms_sizes,
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private ####################################################################################
|
||||
## Update external prop scenes and assign missing scripts for each prop, hotspot, region, and
|
||||
## walkable area that didn't exist prior [i]beta 1[/i].
|
||||
func _update_objects_in_rooms() -> Completion:
|
||||
var any_room_updated := PopochiuUtils.any_exhaustive(
|
||||
PopochiuEditorHelper.get_rooms(), _update_room
|
||||
)
|
||||
|
||||
_reload_needed = any_room_updated
|
||||
return Completion.DONE if any_room_updated else Completion.IGNORED
|
||||
|
||||
|
||||
## Update the children of the different groups in [param popochiu_room] so the use instances of the
|
||||
## new objects: [PopochiuProp], [PopochiuHotspot], [PopochiuRegion], and [PopochiuWalkableArea].
|
||||
func _update_room(popochiu_room: PopochiuRoom) -> bool:
|
||||
var room_objects_to_add := []
|
||||
var room_objects_to_check := []
|
||||
PopochiuUtils.any_exhaustive([
|
||||
PopochiuPropFactory.new(),
|
||||
PopochiuHotspotFactory.new(),
|
||||
PopochiuRegionFactory.new(),
|
||||
PopochiuWalkableAreaFactory.new(),
|
||||
PopochiuMarkerFactory.new(),
|
||||
], _create_new_room_objects.bind(popochiu_room, room_objects_to_add, room_objects_to_check))
|
||||
|
||||
for group: Dictionary in room_objects_to_add:
|
||||
group.objects.all(
|
||||
func (new_obj) -> bool:
|
||||
# Set the owner of the new object and do the same for its children (those that
|
||||
# were marked as PopochiuRoomObjFactory.CHILD_VISIBLE_IN_ROOM_META)
|
||||
new_obj.owner = popochiu_room
|
||||
|
||||
for child: Node in new_obj.get_meta(RESET_CHILDREN_OWNER):
|
||||
child.owner = popochiu_room
|
||||
new_obj.remove_meta(RESET_CHILDREN_OWNER)
|
||||
|
||||
return true
|
||||
)
|
||||
|
||||
if PopochiuEditorHelper.pack_scene(popochiu_room) != OK:
|
||||
PopochiuUtils.print_error(
|
||||
"Migration 2: Couldn't update [b]%s[/b] after adding new nodes." %
|
||||
popochiu_room.script_name
|
||||
)
|
||||
|
||||
var room_object_updated := false
|
||||
for obj: Node2D in room_objects_to_check:
|
||||
# Check if the node's scene has all the expected nodes based on its base scene
|
||||
var added_nodes := _add_lacking_nodes(obj)
|
||||
if added_nodes and not room_object_updated:
|
||||
room_object_updated = added_nodes
|
||||
|
||||
if room_object_updated and PopochiuEditorHelper.pack_scene(popochiu_room) != OK:
|
||||
PopochiuUtils.print_error(
|
||||
"Migration 2: Couldn't update [b]%s[/b] after adding lacking nodes." %
|
||||
popochiu_room.script_name
|
||||
)
|
||||
|
||||
return !room_objects_to_add.is_empty() or room_object_updated
|
||||
|
||||
|
||||
## Create a new scene of the [param factory] type. The scene will be placed in its corresponding
|
||||
## folder inside the [param popochiu_room] folder. Created [Node]s will be stored in
|
||||
## [param room_objects_to_add] so they are added to the room later.
|
||||
func _create_new_room_objects(
|
||||
factory: PopochiuRoomObjFactory,
|
||||
popochiu_room: PopochiuRoom,
|
||||
room_objects_to_add := [],
|
||||
room_objects_to_check := []
|
||||
) -> bool:
|
||||
var created_objects := []
|
||||
for obj in _get_room_objects(
|
||||
popochiu_room.get_node(factory.get_group()),
|
||||
[],
|
||||
factory.get_type_method()
|
||||
):
|
||||
# Copy the points of the polygons that were previously a node visible in the Room tree, but
|
||||
# now are only properties
|
||||
if (
|
||||
(obj is PopochiuProp or obj is PopochiuHotspot or obj is PopochiuRegion)
|
||||
and (obj.has_node("InteractionPolygon") or obj.has_node("InteractionPolygon2"))
|
||||
):
|
||||
var interaction_polygon: CollisionPolygon2D = obj.get_node("InteractionPolygon")
|
||||
if obj.has_node("InteractionPolygon2"):
|
||||
interaction_polygon = obj.get_node("InteractionPolygon2")
|
||||
|
||||
if interaction_polygon.owner == popochiu_room:
|
||||
# Store the polygon vectors into the new @export variable
|
||||
obj.interaction_polygon = interaction_polygon.polygon
|
||||
obj.interaction_polygon_position = interaction_polygon.position
|
||||
# Delete the CollisionPolygon2D node that in previous versions was attached to the
|
||||
# room
|
||||
interaction_polygon.owner = null
|
||||
interaction_polygon.free()
|
||||
elif (
|
||||
obj is PopochiuWalkableArea
|
||||
and (obj.has_node("Perimeter") or obj.has_node("Perimeter2"))
|
||||
):
|
||||
var perimeter: NavigationRegion2D = obj.get_node("Perimeter")
|
||||
if obj.has_node("Perimeter2"):
|
||||
perimeter = obj.get_node("Perimeter2")
|
||||
|
||||
if perimeter.owner == popochiu_room:
|
||||
# Store the navigation polygon vectors into the new @export variable
|
||||
obj.map_navigation_polygon(perimeter)
|
||||
# Delete the NavigationRegion2D node that in previous versions was attached to the
|
||||
# room
|
||||
perimeter.owner = null
|
||||
perimeter.free()
|
||||
|
||||
# If the object already has its own scene and a script that is not inside Popochiu's folder,
|
||||
# then just check if there are lacking nodes inside its scene
|
||||
if (
|
||||
not obj.scene_file_path.is_empty()
|
||||
and not "addons" in obj.scene_file_path
|
||||
and not "addons" in obj.get_script().resource_path
|
||||
):
|
||||
room_objects_to_check.append(obj)
|
||||
continue
|
||||
|
||||
# Create the new scene (and script if needed) of the [obj]
|
||||
var obj_factory: PopochiuRoomObjFactory = factory.get_new_instance()
|
||||
if obj_factory.create_from(obj, popochiu_room) != ResultCodes.SUCCESS:
|
||||
continue
|
||||
|
||||
# Map the properties of the [obj] to its new instance
|
||||
created_objects.append(_create_new_room_obj(obj_factory, obj, popochiu_room))
|
||||
|
||||
if created_objects.is_empty():
|
||||
return false
|
||||
|
||||
room_objects_to_add.append({
|
||||
factory = factory,
|
||||
objects = created_objects
|
||||
})
|
||||
|
||||
return true
|
||||
|
||||
|
||||
## Recursively search for nodes of a specific type in the [param parent] and its children. The nodes
|
||||
## found are added to the [param objects] array. The [param type_method] is used to determine if a
|
||||
## node is the desired type.
|
||||
func _get_room_objects(parent: Node, objects: Array, type_method: Callable) -> Array:
|
||||
for child: Node in parent.get_children():
|
||||
if type_method.call(child):
|
||||
objects.append(child)
|
||||
else:
|
||||
# If the child is a Node containing other nodes, go deeper in the tree looking for room
|
||||
# object nodes
|
||||
_get_room_objects(child, objects, type_method)
|
||||
|
||||
return objects
|
||||
|
||||
|
||||
## Maps the properties (and nodes if needed) of [param source] to a new instance of itself created
|
||||
## from [param obj_factory]. This assures that objects coming from versions prior to [i]beta 1[/i]
|
||||
## will have the corresponding structure of new Popochiu versions.
|
||||
func _create_new_room_obj(
|
||||
obj_factory: PopochiuRoomObjFactory, source: Node, room: PopochiuRoom
|
||||
) -> Node:
|
||||
var new_obj: Node = (ResourceLoader.load(
|
||||
obj_factory.get_scene_path()
|
||||
) as PackedScene).instantiate(PackedScene.GEN_EDIT_STATE_INSTANCE)
|
||||
new_obj.set_meta(RESET_CHILDREN_OWNER, [])
|
||||
|
||||
source.name += "_"
|
||||
source.get_parent().add_child(new_obj)
|
||||
source.get_parent().move_child(new_obj, source.get_index())
|
||||
|
||||
# Check if the original object has a script attached (different from the default one)
|
||||
if (
|
||||
source.get_script()
|
||||
and not "addons" in source.get_script().resource_path
|
||||
and source.get_script().resource_path != new_obj.get_script().resource_path
|
||||
):
|
||||
# Change the default script by the one attached to the original object
|
||||
new_obj.set_script(load(source.get_script().resource_path))
|
||||
|
||||
# Copy its extra properties (those declared as vars in the script) to the new instance
|
||||
PopochiuResources.copy_popochiu_object_properties(
|
||||
new_obj, source, PopochiuResources[
|
||||
"%s_IGNORE" % obj_factory.get_group().to_snake_case().to_upper()
|
||||
]
|
||||
)
|
||||
|
||||
new_obj.position = source.position
|
||||
new_obj.scale = source.scale
|
||||
new_obj.z_index = source.z_index
|
||||
|
||||
if new_obj is PopochiuProp or new_obj is PopochiuHotspot:
|
||||
new_obj.baseline = source.baseline
|
||||
new_obj.walk_to_point = source.walk_to_point
|
||||
|
||||
if new_obj is PopochiuProp:
|
||||
new_obj.texture = source.texture
|
||||
new_obj.frames = source.frames
|
||||
new_obj.v_frames = source.v_frames
|
||||
new_obj.link_to_item = source.link_to_item
|
||||
new_obj.interaction_polygon = source.interaction_polygon
|
||||
new_obj.interaction_polygon_position = source.interaction_polygon_position
|
||||
|
||||
if obj_factory.get_snake_name() in ["bg", "background"]:
|
||||
new_obj.z_index = -1
|
||||
|
||||
if new_obj is PopochiuRegion:
|
||||
new_obj.interaction_polygon = source.interaction_polygon
|
||||
new_obj.interaction_polygon_position = source.interaction_polygon_position
|
||||
|
||||
if new_obj is PopochiuWalkableArea:
|
||||
new_obj.interaction_polygon = source.interaction_polygon
|
||||
new_obj.interaction_polygon_position = source.interaction_polygon_position
|
||||
|
||||
# Remove the old [source] node from the room
|
||||
source.free()
|
||||
|
||||
return new_obj
|
||||
|
||||
|
||||
## Checks the [code].tscn[/code] file of [param source] for lacking nodes based on its type. If
|
||||
## there are any, then it will add them so the structure of the scene matches the one of the object
|
||||
## it inherits from.
|
||||
func _add_lacking_nodes(source: Node) -> bool:
|
||||
var obj_scene: Node2D = ResourceLoader.load(source.scene_file_path).instantiate()
|
||||
var was_updated := false
|
||||
|
||||
if (
|
||||
PopochiuEditorHelper.is_prop(obj_scene)
|
||||
or PopochiuEditorHelper.is_hotspot(obj_scene)
|
||||
or PopochiuEditorHelper.is_region(obj_scene)
|
||||
) and not obj_scene.has_node("InteractionPolygon"):
|
||||
var interaction_polygon := CollisionPolygon2D.new()
|
||||
interaction_polygon.name = "InteractionPolygon"
|
||||
interaction_polygon.polygon = PackedVector2Array([
|
||||
Vector2(-10, -10), Vector2(10, -10), Vector2(10, 10), Vector2(-10, 10)
|
||||
])
|
||||
obj_scene.add_child(interaction_polygon)
|
||||
obj_scene.move_child(interaction_polygon, 0)
|
||||
interaction_polygon.owner = obj_scene
|
||||
was_updated = true
|
||||
elif PopochiuEditorHelper.is_walkable_area(obj_scene) and not obj_scene.has_node("Perimeter"):
|
||||
var perimeter := NavigationRegion2D.new()
|
||||
perimeter.name = "Perimeter"
|
||||
var polygon := NavigationPolygon.new()
|
||||
polygon.agent_radius = 0.0
|
||||
perimeter.navigation_polygon = polygon
|
||||
obj_scene.add_child(perimeter)
|
||||
perimeter.owner = obj_scene
|
||||
obj_scene.interaction_polygon = source.interaction_polygon
|
||||
obj_scene.clear_and_bake(perimeter.navigation_polygon)
|
||||
was_updated = true
|
||||
|
||||
if PopochiuEditorHelper.is_prop(obj_scene) and not obj_scene.has_node("AnimationPlayer"):
|
||||
var animation_player := AnimationPlayer.new()
|
||||
obj_scene.add_child(animation_player)
|
||||
animation_player.owner = obj_scene
|
||||
was_updated = true
|
||||
|
||||
if was_updated:
|
||||
PopochiuEditorHelper.pack_scene(obj_scene)
|
||||
|
||||
return was_updated
|
||||
|
||||
|
||||
## Add a [CollisionPolygon2D] node named "ScalingPolygon" to each [PopochiuCharacter] that doesn't
|
||||
## have it. Returns [code]Completion.DONE[/code] if any character is updated,
|
||||
## [code]Completion.IGNORED[/code] otherwise.
|
||||
func _add_scaling_polygon_to_characters() -> Completion:
|
||||
# Get the characters' .tscn files
|
||||
var file_paths := PopochiuMigrationHelper.get_absolute_file_paths_for_file_extensions(
|
||||
PopochiuResources.CHARACTERS_PATH,
|
||||
["tscn"]
|
||||
)
|
||||
var any_character_updated := PopochiuUtils.any_exhaustive(file_paths, _add_scaling_polygon_to)
|
||||
return Completion.DONE if any_character_updated else Completion.IGNORED
|
||||
|
||||
|
||||
## Loads the [PopochiuCharacter] in [param scene_path] and add a [CollisionPolygon2D] node if it
|
||||
## doesn't has a [code]ScalingPolygon[/code] child.
|
||||
func _add_scaling_polygon_to(scene_path: String) -> bool:
|
||||
var popochiu_character: PopochiuCharacter = (load(scene_path) as PackedScene).instantiate()
|
||||
var was_scene_updated := false
|
||||
|
||||
# ---- Add the ScalingPolygon node if needed ---------------------------------------------------
|
||||
if not popochiu_character.has_node("ScalingPolygon"):
|
||||
was_scene_updated = true
|
||||
var scaling_polygon := CollisionPolygon2D.new()
|
||||
scaling_polygon.name = "ScalingPolygon"
|
||||
scaling_polygon.polygon = PackedVector2Array([
|
||||
Vector2(-5, -5), Vector2(5, -5), Vector2(5, 5), Vector2(-5, 5)
|
||||
])
|
||||
popochiu_character.add_child(scaling_polygon)
|
||||
popochiu_character.move_child(scaling_polygon, 1)
|
||||
scaling_polygon.owner = popochiu_character
|
||||
|
||||
if was_scene_updated and PopochiuEditorHelper.pack_scene(popochiu_character) != OK:
|
||||
PopochiuUtils.print_error(
|
||||
"Couldn't update [b]%s[/b] with new voices array." % popochiu_character.script_name
|
||||
)
|
||||
|
||||
return was_scene_updated
|
||||
|
||||
|
||||
## Move the values from the old [code]popochiu_settings.tres[/code] file to the new
|
||||
## [code]Project Settings > Popochiu[/code] section. Returns [constant Completion.DONE] if the values
|
||||
## are moved, [constant Completion.IGNORED] if the file doesn't exist, [constant Completion.FAILED]
|
||||
## otherwise.
|
||||
func _move_settings_to_project_settings() -> Completion:
|
||||
var old_settings_file := PopochiuMigrationHelper.old_settings_file
|
||||
|
||||
if not FileAccess.file_exists(old_settings_file):
|
||||
return Completion.IGNORED
|
||||
|
||||
# Move custom defined values in the old [popochiu_settings.tres] file to Project Settings
|
||||
var old_settings: PopochiuSettings = load(old_settings_file)
|
||||
var settings_map := {
|
||||
# ---- GUI ---------------------------------------------------------------------------------
|
||||
"SCALE_GUI": "",
|
||||
"FADE_COLOR": "",
|
||||
"SKIP_CUTSCENE_TIME": "",
|
||||
# ---- Dialogs -----------------------------------------------------------------------------
|
||||
"TEXT_SPEED": old_settings.text_speeds[old_settings.default_text_speed],
|
||||
"AUTO_CONTINUE_TEXT": "",
|
||||
"USE_TRANSLATIONS": "",
|
||||
# ---- Inventory ---------------------------------------------------------------------------
|
||||
"INVENTORY_LIMIT": "",
|
||||
# ---- Pixel game --------------------------------------------------------------------------
|
||||
"PIXEL_ART_TEXTURES": "is_pixel_art_game",
|
||||
"PIXEL_PERFECT": "is_pixel_perfect",
|
||||
}
|
||||
|
||||
for key: String in settings_map:
|
||||
PopochiuConfig.set_project_setting(
|
||||
key,
|
||||
old_settings[key.to_lower()] if key.is_empty() else settings_map[key]
|
||||
)
|
||||
|
||||
for item_name: StringName in old_settings.items_on_start:
|
||||
var items_on_start := PopochiuConfig.get_inventory_items_on_start()
|
||||
items_on_start.append(str(item_name))
|
||||
PopochiuConfig.set_inventory_items_on_start(items_on_start)
|
||||
|
||||
# Move custom defined values in the old [popochiu_settings.tres] to their corresponding GUI
|
||||
# components
|
||||
if FileAccess.file_exists(GAME_INVENTORY_BAR_PATH):
|
||||
var inventory_bar: Control = load(GAME_INVENTORY_BAR_PATH).instantiate()
|
||||
inventory_bar.always_visible = old_settings.inventory_always_visible
|
||||
PopochiuEditorHelper.pack_scene(inventory_bar)
|
||||
|
||||
if FileAccess.file_exists(GAME_SETTINGS_BAR_PATH):
|
||||
var settings_bar: PanelContainer = load(GAME_SETTINGS_BAR_PATH).instantiate()
|
||||
settings_bar.always_visible = old_settings.toolbar_always_visible
|
||||
PopochiuEditorHelper.pack_scene(settings_bar)
|
||||
|
||||
# Remove the old [popochiu_settings.tres]
|
||||
if DirAccess.remove_absolute(old_settings_file) != OK:
|
||||
PopochiuUtils.print_error("Couldn't delete [code]%s[/code]." % old_settings_file)
|
||||
return Completion.FAILED
|
||||
|
||||
return Completion.DONE
|
||||
|
||||
|
||||
## Update the [code]DialogMenu[/code] GUI component to use the new [code]DialogMenuOption[/code].
|
||||
## Returns [constant Completion.DONE] if the component is updated, [constant Completion.IGNORED] if
|
||||
## the game's GUI is not using the [code]DialogMenu[/code] component or is already using the new
|
||||
## version, [constant Completion.FAILED] otherwise.
|
||||
func _update_dialog_menu() -> Completion:
|
||||
if (
|
||||
not FileAccess.file_exists(GAME_DIALOG_MENU_PATH)
|
||||
or DirAccess.dir_exists_absolute(GAME_DIALOG_MENU_OPTION_PATH)
|
||||
):
|
||||
# The game's GUI is not using the DialogMenu GUI component or is already using its beta-3
|
||||
# version
|
||||
return Completion.IGNORED
|
||||
|
||||
# Copy the new [PopochiuDialogMenuOption] component to the game's GUI components folder
|
||||
await _gui_templates_helper.copy_components(ADDON_DIALOG_MENU_PATH)
|
||||
|
||||
# Store the scene of the new [PopochiuDialogMenuOption] in the game's graphic interface folder
|
||||
var game_dialog_menu_option: PackedScene = load(PopochiuResources.GUI_GAME_FOLDER.path_join(
|
||||
"components/dialog_menu/dialog_menu_option/dialog_menu_option.tscn"
|
||||
))
|
||||
|
||||
# Assign the new [PopochiuDialogMenuOption] to the game's GUI dialog menu component and delete
|
||||
# any option inside its DialogOptionsContainer child
|
||||
var game_dialog_menu: PopochiuDialogMenu = load(GAME_DIALOG_MENU_PATH).instantiate()
|
||||
game_dialog_menu.option_scene = game_dialog_menu_option
|
||||
for opt in game_dialog_menu.get_node("ScrollContainer/DialogOptionsContainer").get_children():
|
||||
opt.owner = null
|
||||
opt.free()
|
||||
|
||||
var done := PopochiuEditorHelper.pack_scene(game_dialog_menu)
|
||||
if done != OK:
|
||||
PopochiuUtils.print_error(
|
||||
"Couldn't update PopochiuDialogMenuOption reference in PopochiuDialogMenu"
|
||||
)
|
||||
return Completion.FAILED
|
||||
|
||||
# Update the dependency to [PopochiuDialogMenuOption] in the game's graphic interface scene
|
||||
var game_gui: PopochiuGraphicInterface = load(PopochiuResources.GUI_GAME_SCENE).instantiate()
|
||||
game_gui.get_node("DialogMenu").option_scene = game_dialog_menu_option
|
||||
done = PopochiuEditorHelper.pack_scene(game_gui)
|
||||
if done != OK:
|
||||
PopochiuUtils.print_error(
|
||||
"Couldn't update PopochiuDialogMenuOption reference in PopochiuGraphicInterface"
|
||||
)
|
||||
return Completion.FAILED
|
||||
|
||||
# Delete the old [dialog_menu_option.tscn] file
|
||||
done = DirAccess.remove_absolute(
|
||||
"res://game/gui/components/dialog_menu/dialog_menu_option.tscn"
|
||||
)
|
||||
if done != OK:
|
||||
PopochiuUtils.print_error(
|
||||
"Couldn't update PopochiuDialogMenuOption reference in PopochiuDialogMenu"
|
||||
)
|
||||
return Completion.FAILED
|
||||
|
||||
return Completion.DONE
|
||||
|
||||
|
||||
## Update the [code]SettingsBar[/code] GUI component in the 2-click Context-sensitive GUI template.
|
||||
## Returns [constant Completion.DONE] if the component is updated, [constant Completion.IGNORED] if
|
||||
## the game's GUI does not use the [code]SettingsBar[/code] GUI component or is already using the
|
||||
## new version, [constant Completion.FAILED] otherwise.
|
||||
func _update_simple_click_settings_bar() -> Completion:
|
||||
if not FileAccess.file_exists(GAME_SETTINGS_BAR_PATH):
|
||||
# The game's GUI does not use the SettingsBar GUI component
|
||||
return Completion.IGNORED
|
||||
|
||||
var game_settings_bar: PanelContainer = load(GAME_SETTINGS_BAR_PATH).instantiate()
|
||||
var dialog_speed_button: TextureButton = game_settings_bar.get_node("Box/BtnDialogSpeed")
|
||||
|
||||
if not dialog_speed_button.speed_options.is_empty():
|
||||
# The component is up to date with the beta-3 version
|
||||
return Completion.IGNORED
|
||||
|
||||
var addons_settings_bar: PanelContainer = load(PopochiuResources.GUI_TEMPLATES_FOLDER.path_join(
|
||||
"simple_click/components/settings_bar/settings_bar.tscn"
|
||||
)).instantiate()
|
||||
|
||||
# Store the speed options defined in the original component
|
||||
var speed_options := []
|
||||
for opt: TextSpeedOption in addons_settings_bar.get_node("Box/BtnDialogSpeed").speed_options:
|
||||
var option := TextSpeedOption.new()
|
||||
option.resource_name = opt.resource_name
|
||||
option.speed = opt.speed
|
||||
option.description = opt.description
|
||||
option.icon = load(opt.icon.resource_path.replace(
|
||||
PopochiuResources.GUI_TEMPLATES_FOLDER.path_join(
|
||||
"simple_click/components/settings_bar/sprites/"
|
||||
),
|
||||
"res://game/gui/components/settings_bar/sprites/"
|
||||
))
|
||||
|
||||
speed_options.append(option)
|
||||
|
||||
# Assign the options to the component in the game's graphic interface component and save the
|
||||
# SettingsBat scene
|
||||
dialog_speed_button.speed_options = speed_options
|
||||
var scene_updated := PopochiuEditorHelper.pack_scene(game_settings_bar)
|
||||
|
||||
return Completion.DONE if scene_updated == OK else Completion.FAILED
|
||||
|
||||
|
||||
## Remove visual helper nodes in all [PopochiuProp]s, [PopochiuHotspot]s, and [PopochiuCharacter]s.
|
||||
func _remove_helper_nodes() -> Completion:
|
||||
var characters_paths := PopochiuMigrationHelper.get_absolute_file_paths_for_file_extensions(
|
||||
PopochiuResources.CHARACTERS_PATH,
|
||||
["tscn"]
|
||||
)
|
||||
var props_and_hotspots_paths :=\
|
||||
PopochiuMigrationHelper.get_absolute_file_paths_for_file_extensions(
|
||||
PopochiuResources.ROOMS_PATH,
|
||||
["tscn"],
|
||||
["markers", "regions", "walkable_areas"]
|
||||
).filter(
|
||||
func (file_path: String) -> bool:
|
||||
return not "room_" in file_path
|
||||
)
|
||||
var popochiu_clickables := characters_paths + props_and_hotspots_paths
|
||||
var any_updated := PopochiuUtils.any_exhaustive(popochiu_clickables, _remove_helper_nodes_in)
|
||||
|
||||
return Completion.DONE if any_updated else Completion.IGNORED
|
||||
|
||||
|
||||
## Remove the [code]BaselineHelper[/code] and [code]WalkToHelper[/code] nodes in [param scene_path].
|
||||
## Also remove the [code]DialogPos[/code] node if it is a [PopochiuCharacter]. Returns
|
||||
## [constant Completion.DONE] if any node is removed, [constant Completion.IGNORED] otherwise.
|
||||
func _remove_helper_nodes_in(scene_path: String) -> bool:
|
||||
# Load the scene ignoring cache so changes made in previous steps are taken into account
|
||||
var popochiu_clickable: PopochiuClickable = (
|
||||
ResourceLoader.load(scene_path, "", ResourceLoader.CACHE_MODE_IGNORE) as PackedScene
|
||||
).instantiate(PackedScene.GEN_EDIT_STATE_MAIN)
|
||||
|
||||
var was_scene_updated := false
|
||||
|
||||
# ---- Remove the BaselineHelper and WalkToHelper nodes ----------------------------------------
|
||||
if _remove_node(popochiu_clickable, "BaselineHelper"):
|
||||
was_scene_updated = true
|
||||
|
||||
if _remove_node(popochiu_clickable, "WalkToHelper"):
|
||||
was_scene_updated = true
|
||||
|
||||
# ---- Remove the DialogPos node ---------------------------------------------------------------
|
||||
# TODO: Uncomment this once PR #241 is merged
|
||||
if popochiu_clickable is PopochiuCharacter and popochiu_clickable.has_node("DialogPos"):
|
||||
popochiu_clickable.dialog_pos = popochiu_clickable.get_node("DialogPos").position
|
||||
_remove_node(popochiu_clickable, "DialogPos")
|
||||
was_scene_updated = true
|
||||
|
||||
if was_scene_updated and PopochiuEditorHelper.pack_scene(popochiu_clickable, scene_path) != OK:
|
||||
PopochiuUtils.print_error(
|
||||
"Couldn't remove helper nodes in [b]%s[/b]." % popochiu_clickable.script_name
|
||||
)
|
||||
|
||||
return was_scene_updated
|
||||
|
||||
|
||||
## Remove the node in [param parent] with the path [param node_path]. Returns [code]true[/code] if
|
||||
## the node is removed, [code]false[/code] otherwise.
|
||||
func _remove_node(parent: Node, node_path: NodePath) -> bool:
|
||||
if parent.has_node(node_path):
|
||||
var child: Node = parent.get_node(node_path)
|
||||
child.owner = null
|
||||
child.free()
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
## Replace calls to deprecated properties and methods:
|
||||
## - [code]E.current_room[/code] by [code]R.current[/code].
|
||||
## - [code]E.goto_room()[/code] by [code]R.goto_room()[/code].
|
||||
## - [code]E.queue_camera_offset()[/code] by [code]E.camera.queue_change_offset()[/code].
|
||||
## - [code]E.camera_offset()[/code] by [code]E.camera.change_offset()[/code].
|
||||
## - [code]E.queue_camera_shake()[/code] by [code]E.camera.queue_shake()[/code].
|
||||
## - [code]E.camera_shake()[/code] by [code]E.camera.shake()[/code].
|
||||
## - [code]E.queue_camera_shake_bg()[/code] by [code]E.camera.queue_shake_bg()[/code].
|
||||
## - [code]E.camera_shake_bg()[/code] by [code]E.camera.shake_bg()[/code].
|
||||
## - [code]E.queue_camera_zoom()[/code] by [code]E.camera.queue_change_zoom()[/code].
|
||||
## - [code]E.camera_zoom()[/code] by [code]E.camera.change_zoom()[/code].
|
||||
## - [code]E.stop_camera_shake()[/code] by [code]E.camera.stop_shake()[/code].
|
||||
## - [code]return super.get_runtime_room()[/code] by [code]return get_runtime_room()[/code].
|
||||
## - [code]return super.get_runtime_character()[/code] by [code]return get_runtime_character()[/code].
|
||||
## - [code]return super.get_item_instance()[/code] by [code]return get_item_instance()[/code].
|
||||
## - [code]return E.get_dialog()[/code] by [code]return get_instance()[/code].
|
||||
## Returns [constant Completion.DONE] if any replacement is done, [constant Completion.IGNORED]
|
||||
## otherwise.
|
||||
func _replace_deprecated() -> Completion:
|
||||
return Completion.DONE if PopochiuMigrationHelper.replace_in_scripts([
|
||||
{from = "E.current_room", to = "R.current"},
|
||||
{from = "E.goto_room(", to = "R.goto_room("},
|
||||
{from = "E.queue_camera_offset(", to = "E.camera.queue_change_offset("},
|
||||
{from = "E.camera_offset(", to = "E.camera.change_offset("},
|
||||
{from = "E.queue_camera_shake(", to = "E.camera.queue_shake("},
|
||||
{from = "E.camera_shake(", to = "E.camera.shake("},
|
||||
{from = "E.queue_camera_shake_bg(", to = "E.camera.queue_shake_bg("},
|
||||
{from = "E.camera_shake_bg(", to = "E.camera.shake_bg("},
|
||||
{from = "E.queue_camera_zoom(", to = "E.camera.queue_change_zoom("},
|
||||
{from = "E.camera_zoom(", to = "E.camera.change_zoom("},
|
||||
{from = "E.stop_camera_shake()", to = "E.camera.stop_shake()"},
|
||||
# autoloads
|
||||
{from = "return super.get_runtime_room(", to = "return get_runtime_room("},
|
||||
{from = "return super.get_runtime_character(", to = "return get_runtime_character("},
|
||||
{from = "return super.get_item_instance(", to = "return get_item_instance("},
|
||||
{from = "return E.get_dialog(", to = "return get_instance("},
|
||||
]) else Completion.IGNORED
|
||||
|
||||
|
||||
## Update camera limit calculations for each room to utilize the new [member PopochiuRoom.width]
|
||||
## and [member PopochiuRoom.height] properties.
|
||||
func _update_rooms_sizes() -> Completion:
|
||||
var any_room_updated := PopochiuUtils.any_exhaustive(
|
||||
PopochiuEditorHelper.get_rooms(), _update_room_size
|
||||
)
|
||||
|
||||
_reload_needed = any_room_updated
|
||||
return Completion.DONE if any_room_updated else Completion.IGNORED
|
||||
|
||||
|
||||
## Updates the values of [member PopochiuRoom.width] and [member PopochiuRoom.height] in
|
||||
## [param popochiu_room] based on the values of the deprecated camera limits properties.
|
||||
func _update_room_size(popochiu_room: PopochiuRoom) -> bool:
|
||||
var viewport_width := ProjectSettings.get_setting(PopochiuResources.DISPLAY_WIDTH)
|
||||
var viewport_height := ProjectSettings.get_setting(PopochiuResources.DISPLAY_HEIGHT)
|
||||
|
||||
# Calculate the width based on the camera limits
|
||||
var left := 0.0 if is_inf(popochiu_room.limit_left) else popochiu_room.limit_left
|
||||
var right := 0.0 if is_inf(popochiu_room.limit_right) else popochiu_room.limit_right
|
||||
var width: int = viewport_width - int(left)
|
||||
width += int(right) - viewport_width
|
||||
|
||||
popochiu_room.width = maxi(width, viewport_width)
|
||||
|
||||
# Calculate the height based on the camera limits
|
||||
var top := 0.0 if is_inf(popochiu_room.limit_top) else popochiu_room.limit_top
|
||||
var bottom := 0.0 if is_inf(popochiu_room.limit_bottom) else popochiu_room.limit_bottom
|
||||
var height: int = viewport_height - int(top)
|
||||
height += int(bottom) - viewport_height
|
||||
|
||||
popochiu_room.height = maxi(height, viewport_height)
|
||||
|
||||
if PopochiuEditorHelper.pack_scene(popochiu_room) != OK:
|
||||
PopochiuUtils.print_error(
|
||||
"Migration 2: Couldn't update the [code]width[/code] and [code]height[/code] of" +\
|
||||
" [b]%s[/b] room." % popochiu_room.script_name
|
||||
)
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
|
||||
#endregion
|
|
@ -0,0 +1 @@
|
|||
uid://bdfle6xwae3o5
|
71
addons/popochiu/migration/migrations/popochiu_migration_3.gd
Normal file
71
addons/popochiu/migration/migrations/popochiu_migration_3.gd
Normal file
|
@ -0,0 +1,71 @@
|
|||
@tool
|
||||
class_name PopochiuMigration3
|
||||
extends PopochiuMigration
|
||||
|
||||
const VERSION = 3
|
||||
const DESCRIPTION = "Update clickables to set look_at_point property"
|
||||
const STEPS = [
|
||||
"Update all clickables in rooms",
|
||||
]
|
||||
const LOOK_AT_POINT_OFFSET = Vector2(-10, -10)
|
||||
|
||||
|
||||
#region Virtual ####################################################################################
|
||||
## This is code specific for this migration. This should return [code]true[/code] if the migration
|
||||
## is successful. This is called from [method do_migration] which checks to make sure the migration
|
||||
## should be done before calling this.
|
||||
func _do_migration() -> bool:
|
||||
return await PopochiuMigrationHelper.execute_migration_steps(
|
||||
self,
|
||||
[
|
||||
_update_objects_in_rooms
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private ####################################################################################
|
||||
## Update all rooms clickables to set a default value for the look_at_point property.
|
||||
func _update_objects_in_rooms() -> Completion:
|
||||
var any_room_updated := PopochiuUtils.any_exhaustive(
|
||||
PopochiuEditorHelper.get_rooms(), _update_room
|
||||
)
|
||||
|
||||
_reload_needed = any_room_updated
|
||||
return Completion.DONE if any_room_updated else Completion.IGNORED
|
||||
|
||||
|
||||
func _update_popochiu_clickable(popochiu_room: PopochiuRoom, clickable_type: String) -> bool:
|
||||
if not popochiu_room.has_node(clickable_type):
|
||||
return false
|
||||
|
||||
var changed = false
|
||||
|
||||
for obj: Node in popochiu_room.find_child(clickable_type).get_children():
|
||||
if PopochiuEditorHelper.is_popochiu_clickable(obj):
|
||||
obj.look_at_point = obj.walk_to_point + LOOK_AT_POINT_OFFSET
|
||||
changed = true
|
||||
PopochiuUtils.print_normal(
|
||||
"Migration %d: %s: updated %s look_at_point." %
|
||||
[VERSION, clickable_type, obj.script_name]
|
||||
)
|
||||
|
||||
return changed
|
||||
|
||||
|
||||
func _update_room(popochiu_room: PopochiuRoom) -> bool:
|
||||
var room_updated = _update_popochiu_clickable(popochiu_room, "Characters")
|
||||
room_updated = _update_popochiu_clickable(popochiu_room, "Props") or room_updated
|
||||
room_updated = _update_popochiu_clickable(popochiu_room, "Hotspots") or room_updated
|
||||
|
||||
if room_updated and PopochiuEditorHelper.pack_scene(popochiu_room) != OK:
|
||||
PopochiuUtils.print_error(
|
||||
"Migration %d: Couldn't update [b]%s[/b] after updating clickables." %
|
||||
[VERSION, popochiu_room.script_name]
|
||||
)
|
||||
|
||||
return room_updated
|
||||
|
||||
|
||||
#endregion
|
|
@ -0,0 +1 @@
|
|||
uid://bgqmyaindph57
|
99
addons/popochiu/migration/migrations_manager.gd
Normal file
99
addons/popochiu/migration/migrations_manager.gd
Normal file
|
@ -0,0 +1,99 @@
|
|||
@tool
|
||||
class_name MigrationsManager
|
||||
extends Node
|
||||
|
||||
static var migrations_to_execute := []
|
||||
static var migrations_panel: PopochiuEditorHelper.MigrationsPanel
|
||||
static var migrations_popup: AcceptDialog
|
||||
|
||||
|
||||
#region Public #####################################################################################
|
||||
## If there are migrations available with a higher number then the last one
|
||||
## applied to the project, apply them all in order.
|
||||
static func do_migrations() -> void:
|
||||
if PopochiuMigrationHelper.is_empty_project():
|
||||
PopochiuMigrationHelper.update_user_migration_version(
|
||||
PopochiuMigrationHelper.get_migrations_count()
|
||||
)
|
||||
await PopochiuEditorHelper.frame_processed()
|
||||
return
|
||||
|
||||
if not PopochiuMigrationHelper.is_migration_needed():
|
||||
await PopochiuEditorHelper.frame_processed()
|
||||
return
|
||||
|
||||
migrations_panel = PopochiuEditorHelper.MIGRATIONS_PANEL_SCENE.instantiate()
|
||||
migrations_popup = await PopochiuEditorHelper.show_migrations(migrations_panel)
|
||||
migrations_popup.hide()
|
||||
|
||||
# Get the list of migrations to apply
|
||||
for idx: int in PopochiuMigrationHelper.get_migrations_count():
|
||||
# Migration classes are located at "res://addons/popochiu/migration/migrations/*.gd"
|
||||
var migration: PopochiuMigration = load(
|
||||
PopochiuMigrationHelper.MIGRATIONS_PATH.path_join("popochiu_migration_%d.gd" % (idx + 1))
|
||||
).new()
|
||||
|
||||
if not migration.is_migration_needed():
|
||||
continue
|
||||
|
||||
migrations_to_execute.append(migration)
|
||||
await migrations_panel.add_migration(migration)
|
||||
|
||||
migration.step_started.connect(migrations_panel.start_step)
|
||||
migration.step_completed.connect(migrations_panel.update_steps)
|
||||
|
||||
if migrations_to_execute.is_empty():
|
||||
migrations_popup.free()
|
||||
return
|
||||
|
||||
migrations_popup.get_ok_button().text = "Run migrations"
|
||||
migrations_popup.confirmed.connect(_run_migrations)
|
||||
migrations_popup.canceled.connect(
|
||||
func () -> void:
|
||||
PopochiuEditorHelper.signal_bus.migrations_done.emit()
|
||||
migrations_popup.queue_free()
|
||||
)
|
||||
migrations_popup.show()
|
||||
|
||||
await PopochiuEditorHelper.signal_bus.migrations_done
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private ####################################################################################
|
||||
static func _run_migrations() -> void:
|
||||
migrations_popup.confirmed.disconnect(_run_migrations)
|
||||
migrations_popup.get_ok_button().text = "OK"
|
||||
migrations_popup.get_ok_button().disabled = true
|
||||
# Make the popup visible again so devs can see the progress on the migrations' steps
|
||||
migrations_popup.popup()
|
||||
|
||||
PopochiuUtils.print_normal("Processing Popochiu Migrations")
|
||||
var should_reload := false
|
||||
for migration: PopochiuMigration in migrations_to_execute:
|
||||
var user_migration_version := PopochiuMigrationHelper.get_user_migration_version()
|
||||
# adding 1 to user migration version to match with the migration that needs to be done
|
||||
var migration_version := user_migration_version + 1
|
||||
if not await PopochiuMigration.run_migration(migration, migration_version):
|
||||
PopochiuUtils.print_error(
|
||||
"Something went wrong while executing Migration %d" % migration_version
|
||||
)
|
||||
break
|
||||
should_reload = should_reload or migration.is_reload_required()
|
||||
await migrations_popup.get_tree().create_timer(1.0).timeout
|
||||
|
||||
if should_reload:
|
||||
migrations_panel.reload_label.show()
|
||||
|
||||
migrations_popup.get_ok_button().disabled = false
|
||||
migrations_popup.confirmed.connect(
|
||||
func () -> void:
|
||||
if should_reload:
|
||||
EditorInterface.restart_editor(false)
|
||||
else:
|
||||
PopochiuEditorHelper.signal_bus.migrations_done.emit()
|
||||
migrations_popup.queue_free()
|
||||
)
|
||||
|
||||
|
||||
#endregion
|
1
addons/popochiu/migration/migrations_manager.gd.uid
Normal file
1
addons/popochiu/migration/migrations_manager.gd.uid
Normal file
|
@ -0,0 +1 @@
|
|||
uid://bjw4alle5xg72
|
Loading…
Add table
Add a link
Reference in a new issue