Big refactor: Fix plugin issues when disabling/reenabling plugins (#598)

Co-authored-by: balloonpopper <5151242+balloonpopper@users.noreply.github.com>
Co-authored-by: Duncan Brown <duncan@prometheussoftware.ca>
This commit is contained in:
Julian Murgia
2022-07-10 20:40:08 +02:00
committed by GitHub
parent dfbceadd1c
commit ad79aa69d1
113 changed files with 2977 additions and 2072 deletions

View File

@@ -3,166 +3,98 @@ tool
extends Node
class_name Escoria
# Signal sent when Escoria is paused
signal paused
# Signal sent when Escoria is resumed from pause
signal resumed
# Signal sent when pause menu has to be displayed
signal request_pause_menu
# Current game state
# * DEFAULT: Common game function
# * DIALOG: Game is playing a dialog
# * WAIT: Game is waiting
enum GAME_STATE {
DEFAULT,
DIALOG,
WAIT
}
# Name of the Escoria core plugin
const ESCORIA_CORE_PLUGIN_NAME: String = "escoria-core"
# Audio bus indices.
const BUS_MASTER = "Master"
const BUS_SFX = "SFX"
const BUS_MUSIC = "Music"
const BUS_SPEECH = "Speech"
const CAMERA_SCENE_PATH = "res://addons/escoria-core/game/scenes/camera_player/camera.tscn"
# Logger used
var logger: ESCLogger
# Several utilities
var utils: ESCUtils
# The inventory manager instance
var inventory_manager: ESCInventoryManager
# The action manager instance
var action_manager: ESCActionManager
# ESC compiler instance
var esc_compiler: ESCCompiler
# ESC Event manager instance
var event_manager: ESCEventManager
# ESC globals registry instance
var globals_manager: ESCGlobalsManager
# ESC room manager instance
var room_manager: ESCRoomManager
# ESC object manager instance
var object_manager: ESCObjectManager
# ESC project settings manager instance
var project_settings_manager: ESCProjectSettingsManager
# ESC command registry instance
var command_registry: ESCCommandRegistry
# Resource cache handler
var resource_cache: ESCResourceCache
# Terrain of the current room
var room_terrain
# Dialog player instantiator. This instance is called directly for dialogs.
var dialog_player: ESCDialogPlayer
# Inventory scene
var inventory
# These are settings that the player can affect and save/load later
var settings: ESCSaveSettings
# The game resolution
onready var game_size = get_viewport().size
# The main scene
onready var main = $main
# The current state of the game
onready var current_state = GAME_STATE.DEFAULT
# The escoria inputs manager
var inputs_manager: ESCInputsManager
# Savegames and settings manager
var save_manager: ESCSaveManager
# The game scene loaded
var game_scene: ESCGame
# The main player camera
var player_camera: ESCCamera
# The compiled start script loaded from ProjectSettings
# escoria/main/game_start_script
var start_script: ESCScript
# Initialize various objects
func _init():
self.logger = ESCLogger.new()
self.utils = ESCUtils.new()
self.inventory_manager = ESCInventoryManager.new()
self.action_manager = ESCActionManager.new()
self.event_manager = ESCEventManager.new()
self.globals_manager = ESCGlobalsManager.new()
self.add_child(self.event_manager)
self.object_manager = ESCObjectManager.new()
self.command_registry = ESCCommandRegistry.new()
self.esc_compiler = ESCCompiler.new()
self.resource_cache = ESCResourceCache.new()
self.resource_cache.start()
self.save_manager = ESCSaveManager.new()
self.inputs_manager = ESCInputsManager.new()
self.room_manager = ESCRoomManager.new()
self.project_settings_manager = ESCProjectSettingsManager.new()
escoria.inventory_manager = ESCInventoryManager.new()
escoria.action_manager = ESCActionManager.new()
escoria.event_manager = ESCEventManager.new()
escoria.globals_manager = ESCGlobalsManager.new()
add_child(escoria.event_manager)
escoria.object_manager = ESCObjectManager.new()
escoria.command_registry = ESCCommandRegistry.new()
escoria.resource_cache = ESCResourceCache.new()
escoria.resource_cache.start()
escoria.save_manager = ESCSaveManager.new()
escoria.inputs_manager = ESCInputsManager.new()
escoria.settings = ESCSaveSettings.new()
settings = ESCSaveSettings.new()
if self.project_settings_manager.get_setting(self.project_settings_manager.GAME_SCENE) == "":
logger.report_errors("escoria.gd",
["Project setting '%s' is not set!" % self.project_settings_manager.GAME_SCENE]
if ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.GAME_SCENE
).empty():
escoria.logger.error(
self,
"Project setting '%s' is not set!" % ESCProjectSettingsManager.GAME_SCENE
)
else:
game_scene = resource_cache.get_resource(
self.project_settings_manager.get_setting(self.project_settings_manager.GAME_SCENE)
escoria.game_scene = escoria.resource_cache.get_resource(
ESCProjectSettingsManager.get_setting(ESCProjectSettingsManager.GAME_SCENE)
).instance()
print("ESC {0}".format([get_script().get_path()]))
# Load settings
func _ready():
_handle_direct_scene_run()
settings = save_manager.load_settings()
apply_settings(settings)
room_manager.register_reserved_globals()
inputs_manager.register_core()
if self.project_settings_manager.get_setting(self.project_settings_manager.GAME_START_SCRIPT).empty():
logger.report_errors("escoria.gd",
[
"Project setting '%s' is not set!" % self.project_settings_manager.GAME_START_SCRIPT
])
start_script = self.esc_compiler.load_esc_file(
self.project_settings_manager.get_setting(self.project_settings_manager.GAME_START_SCRIPT)
escoria.settings = escoria.save_manager.load_settings()
escoria.apply_settings(escoria.settings)
escoria.room_manager.register_reserved_globals()
escoria.inputs_manager.register_core()
if ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.GAME_START_SCRIPT
).empty():
escoria.logger.error(
self,
"Project setting '%s' is not set!"
% ESCProjectSettingsManager.GAME_START_SCRIPT
)
escoria.start_script = escoria.esc_compiler.load_esc_file(
ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.GAME_START_SCRIPT
)
)
escoria.main = main
_perform_plugins_checks()
func _notification(what):
# Verifies that the game is configured with required plugin(s).
# If a required plugin is missing (or disabled) we stop immediately.
func _perform_plugins_checks():
if ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.DIALOG_MANAGERS
).empty():
escoria.logger.error(
self,
"No dialog manager configured. Please add a dialog manager plugin."
)
# Manage notifications received from OS
#
# #### Parameters
# - what: the notification constant received (usually defined in MainLoop)
func _notification(what: int):
match what:
MainLoop.NOTIFICATION_WM_QUIT_REQUEST:
escoria.logger.close_logs()
escoria.is_quitting = true
get_tree().quit()
MainLoop.NOTIFICATION_WM_GO_BACK_REQUEST:
escoria.logger.close_logs()
escoria.is_quitting = true
get_tree().quit()
@@ -173,69 +105,22 @@ func init():
# Don't show the UI until we're ready in order to avoid a sometimes-noticeable
# blink. The UI will be "shown" later via a visibility update to the first room.
escoria.game_scene.escoria_hide_ui()
run_event_from_script(start_script, self.event_manager.EVENT_INIT)
# Called by Main menu "start new game"
func new_game():
run_event_from_script(start_script, self.event_manager.EVENT_NEW_GAME)
# Apply the loaded settings
#
# #### Parameters
#
# * p_settings: Loaded settings
func apply_settings(p_settings: ESCSaveSettings) -> void:
if not Engine.is_editor_hint():
logger.info("******* settings loaded")
if p_settings != null:
settings = p_settings
else:
settings = ESCSaveSettings.new()
AudioServer.set_bus_volume_db(
AudioServer.get_bus_index(BUS_MASTER),
linear2db(settings.master_volume)
)
AudioServer.set_bus_volume_db(
AudioServer.get_bus_index(BUS_SFX),
linear2db(settings.sfx_volume)
)
AudioServer.set_bus_volume_db(
AudioServer.get_bus_index(BUS_MUSIC),
linear2db(settings.music_volume)
)
AudioServer.set_bus_volume_db(
AudioServer.get_bus_index(BUS_SPEECH),
linear2db(settings.speech_volume)
)
TranslationServer.set_locale(settings.text_lang)
game_scene.apply_custom_settings(settings.custom_settings)
run_event_from_script(escoria.start_script, escoria.event_manager.EVENT_INIT)
pass
# Input function to manage specific input keys
func _input(event):
if InputMap.has_action(ESCInputsManager.ESC_SHOW_DEBUG_PROMPT) \
and event.is_action_pressed(ESCInputsManager.ESC_SHOW_DEBUG_PROMPT):
escoria.main.get_node("layers/debug_layer/esc_prompt_popup").popup()
# Pauses or unpause the game
#
# #### Parameters
# - p_paused: if true, pauses the game. If false, unpauses the game.
func set_game_paused(p_paused: bool):
if p_paused:
emit_signal("paused")
else:
emit_signal("resumed")
# - event: the input event to manage.
func _input(event: InputEvent):
if InputMap.has_action(ESCInputsManager.ESC_SHOW_DEBUG_PROMPT) \
and event.is_action_pressed(ESCInputsManager.ESC_SHOW_DEBUG_PROMPT):
main.get_node("layers/debug_layer/esc_prompt_popup").popup()
var scene_tree = get_tree()
if is_instance_valid(scene_tree):
scene_tree.paused = p_paused
if event.is_action_pressed("ui_cancel"):
emit_signal("request_pause_menu")
pass
# Runs the event "event_name" from the "script" ESC script.
@@ -246,121 +131,27 @@ func set_game_paused(p_paused: bool):
# - event_name: Name of the event to run
func run_event_from_script(script: ESCScript, event_name: String):
if script == null:
logger.report_errors(
"escoria.gd:run_event_from_script()",
["Requested action %s on unloaded script %s" % [event_name, script],
"Please load the ESC script using esc_compiler.load_esc_file()."]
escoria.logger.error(
self,
"Requested action %s on unloaded script %s." % [event_name, script] +
"Please load the ESC script using esc_compiler.load_esc_file()."
)
event_manager.queue_event(script.events[event_name])
var rc = yield(event_manager, "event_finished")
escoria.event_manager.queue_event(script.events[event_name])
var rc = yield(escoria.event_manager, "event_finished")
while rc[1] != event_name:
rc = yield(event_manager, "event_finished")
rc = yield(escoria.event_manager, "event_finished")
if rc[0] != ESCExecution.RC_OK:
self.logger.report_errors(
"Start event of the start script returned unsuccessful: %d" % rc[0],
[]
escoria.logger.error(
self,
"Start event of the start script returned unsuccessful: %d." % rc[0]
)
return
# Register a user interface. This should be called in a deferred way
# from the addon's _enter_tree.
#
# #### Parameters
# - game_scene: Path to the game scene extending ESCGame
func register_ui(game_scene: String):
var game_scene_setting_value = escoria.project_settings_manager.get_setting(
escoria.project_settings_manager.GAME_SCENE
)
if not game_scene_setting_value in [
"",
game_scene
]:
logger.report_errors(
"escoria.gd:register_ui()",
[
"Can't register user interface because %s is registered" % \
game_scene_setting_value
]
)
escoria.project_settings_manager.set_setting(
escoria.project_settings_manager.GAME_SCENE,
game_scene
)
# Deregister a user interface
#
# #### Parameters
# - game_scene: Path to the game scene extending ESCGame
func deregister_ui(game_scene: String):
var game_scene_setting_value = escoria.project_settings_manager.get_setting(
escoria.project_settings_manager.GAME_SCENE
)
if game_scene_setting_value != game_scene:
logger.report_errors(
"escoria.gd:deregister_ui()",
[
(
"Can't deregister user interface %s because it " +
"is not registered."
) % game_scene_setting_value
]
)
escoria.project_settings_manager.set_setting(
escoria.project_settings_manager.GAME_SCENE,
""
)
# Register a dialog manager addon. This should be called in a deferred way
# from the addon's _enter_tree.
#
# #### Parameters
# - manager_class: Path to the manager class script
func register_dialog_manager(manager_class: String):
var dialog_managers: Array = escoria.project_settings_manager.get_setting(
escoria.project_settings_manager.DIALOG_MANAGERS
)
if manager_class in dialog_managers:
return
dialog_managers.push_back(manager_class)
escoria.project_settings_manager.set_setting(
escoria.project_settings_manager.DIALOG_MANAGERS,
dialog_managers
)
# Deregister a dialog manager addon
#
# #### Parameters
# - manager_class: Path to the manager class script
func deregister_dialog_manager(manager_class: String):
var dialog_managers: Array = escoria.project_settings_manager.get_setting(
escoria.project_settings_manager.DIALOG_MANAGERS
)
if not manager_class in dialog_managers:
logger.report_warnings(
"escoria.gd:deregister_dialog_manager()",
[
"Dialog manager %s is not registered" % manager_class
]
)
return
dialog_managers.erase(manager_class)
escoria.project_settings_manager.set_setting(
escoria.project_settings_manager.DIALOG_MANAGERS,
dialog_managers
)
# Called from escoria autoload to start a new game.
func new_game():
run_event_from_script(escoria.start_script, escoria.event_manager.EVENT_NEW_GAME)
# Function called to quit the game.
@@ -370,19 +161,8 @@ func quit():
# Handle anything necessary if the game started a scene directly.
func _handle_direct_scene_run() -> void:
var current_scene_root: Node = get_tree().get_current_scene()
if current_scene_root == null:
# there's no 'current scene'
# e.g. you're opening escoria.tscn from the editor
return
if current_scene_root.filename == ProjectSettings.get_setting('application/run/main_scene'):
# This is a normal, full-game run, so there's nothing to do.
return
if current_scene_root is ESCRoom:
escoria.object_manager.set_current_room(current_scene_root)
if escoria.is_direct_room_run:
escoria.object_manager.set_current_room(get_tree().get_current_scene())
# Used by game.gd to determine whether the game scene is ready to take inputs
@@ -393,5 +173,5 @@ func _handle_direct_scene_run() -> void:
# *Returns*
# true if game scene is ready for inputs
func is_ready_for_inputs() -> bool:
return escoria.main.current_scene and escoria.main.current_scene.game \
and escoria.main.current_scene.game.room_ready_for_inputs
return main.current_scene and main.current_scene.game \
and main.current_scene.game.room_ready_for_inputs