实现可配置的自动存档机制
This commit is contained in:
parent
cdac22503b
commit
33f3088ba7
@ -1,8 +0,0 @@
|
|||||||
#1111
|
|
||||||
class_name EntryPoint
|
|
||||||
extends Marker2D
|
|
||||||
|
|
||||||
@export var direction := heroine.Direction.RIGHT
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
add_to_group("entry_points")
|
|
File diff suppressed because one or more lines are too long
9
config/archive/assembled_archive.gd
Normal file
9
config/archive/assembled_archive.gd
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
class_name AssembledArchive extends Resource
|
||||||
|
|
||||||
|
@export var archive_id := 0
|
||||||
|
@export var current_chapter := 0
|
||||||
|
@export var current_section := 0
|
||||||
|
@export var game_seconds_all := 0
|
||||||
|
@export var game_seconds_current := 0
|
||||||
|
|
||||||
|
@export var created_time := "2024-12-24 00:00:00"
|
@ -5,8 +5,7 @@ class DeploymentItemConfig:
|
|||||||
extends Resource
|
extends Resource
|
||||||
var entity_name: String = ""
|
var entity_name: String = ""
|
||||||
var position: Vector2 = Vector2(0, 0)
|
var position: Vector2 = Vector2(0, 0)
|
||||||
var initial_state := ""
|
|
||||||
|
|
||||||
|
|
||||||
@export var scene_name: String = ""
|
@export var scene_name: String = ""
|
||||||
@export var items: Array[DeploymentItemConfig]
|
@export var items := {} # entity_name: DeploymentItemConfig
|
||||||
|
@ -1,10 +1,17 @@
|
|||||||
class_name DialogConfig extends Resource
|
class_name DialogConfig extends Resource
|
||||||
|
|
||||||
@export var dialog_name: String
|
|
||||||
# font style and effect are defined according to the character
|
# font style and effect are defined according to the character
|
||||||
@export var dialog_character_name: String
|
|
||||||
@export var effect := ""
|
|
||||||
@export var dialog_character_animation: String # empty string means no animation
|
class DialogItem:
|
||||||
@export var dialog_content: String
|
extends Resource
|
||||||
@export var dialog_audio: String
|
var dialog_character_name: String = ""
|
||||||
@export var dialog_skipable := true
|
var effect: String = ""
|
||||||
|
var dialog_character_animation: String = ""
|
||||||
|
var dialog_content: String = ""
|
||||||
|
var dialog_audio: String = ""
|
||||||
|
var dialog_skipable: bool = true
|
||||||
|
|
||||||
|
|
||||||
|
@export var dialog_name: String
|
||||||
|
@export var dialog_items: Array[DialogItem]
|
||||||
|
@ -3,29 +3,22 @@ class_name EntityConfig extends Resource
|
|||||||
|
|
||||||
class EntityStateConfig:
|
class EntityStateConfig:
|
||||||
extends Resource
|
extends Resource
|
||||||
var state_name: String = ""
|
|
||||||
var animation: String = ""
|
var animation: String = ""
|
||||||
|
var scale: Vector2 = Vector2.ONE
|
||||||
|
var offset: Vector2 = Vector2.ZERO
|
||||||
|
var expected_duration: float = 1.0 # for placeholder demo only
|
||||||
var loop: bool = false
|
var loop: bool = false
|
||||||
var sound: String = ""
|
var sound: String = ""
|
||||||
var state_title: String = "" # use default if empty
|
|
||||||
var state_note: String = "" # use default if empty
|
|
||||||
var actions: Array[String] = []
|
|
||||||
|
|
||||||
|
|
||||||
class EntityActionConfig:
|
|
||||||
extends Resource
|
|
||||||
var action_name: String = ""
|
|
||||||
var next_state: String = "" # empty means keep current state
|
|
||||||
var animation: String = ""
|
|
||||||
var sound: String = ""
|
|
||||||
var callback: Callable
|
|
||||||
|
|
||||||
|
|
||||||
@export var entity_name: String = ""
|
@export var entity_name: String = ""
|
||||||
@export var placeholder_size: Vector2 = Vector2(32, 64)
|
@export var placeholder_size := Vector2(32, 64)
|
||||||
@export var offset: Vector2 = Vector2(0, 0)
|
@export var offset := Vector2(0, 0)
|
||||||
@export var entity_title: String = ""
|
@export var entity_title: String = ""
|
||||||
@export var entity_note: String = ""
|
@export var entity_note: String = ""
|
||||||
@export var initializer: Callable
|
@export var entity_state_default: EntityStateConfig
|
||||||
@export var entity_states: Array[EntityStateConfig]
|
@export var physical_vibe_effect: PackedScene
|
||||||
@export var entity_actions: Array[EntityActionConfig]
|
@export var pickable := false
|
||||||
|
@export var entity_state_hud: EntityStateConfig
|
||||||
|
@export var entity_state_inspection: EntityStateConfig
|
||||||
|
@export var inspection_gameplay: PackedScene
|
||||||
|
@ -13,11 +13,10 @@
|
|||||||
{
|
{
|
||||||
"event_date": "12/23/2024",
|
"event_date": "12/23/2024",
|
||||||
"item_id": "4123576587",
|
"item_id": "4123576587",
|
||||||
"log_content": "动画资产管理:分页加载资源\n\n定义基本的规格配置、组装部署、资产填充数据结构",
|
"log_content": "* 完善消息提示功能\n * 0.5s 浮现,显示 3s,0.5s 隐藏(通过调整 alpha 通道实现)\n * 支持堆积消息\n * 如果有堆积的消息,显示 2s(而不是 3s)",
|
||||||
"tags": [
|
"tags": [
|
||||||
"2@ui",
|
"2@ui",
|
||||||
"3@art_tool",
|
"2@code"
|
||||||
"2@design"
|
|
||||||
],
|
],
|
||||||
"update_date": "12/24/2024"
|
"update_date": "12/24/2024"
|
||||||
},
|
},
|
||||||
|
@ -1,124 +1,159 @@
|
|||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
@export var user_archive_root_dir := "user://archive/" # must end with "/"
|
@export var user_root_dir := "user://data/" # must end with "/"
|
||||||
@export var save_dir_prefix := "save"
|
@export var archive_dir := "user://data/archives/"
|
||||||
|
@export var archive_prefix := "save"
|
||||||
|
@export var archive: AssembledArchive # current archive
|
||||||
|
|
||||||
var accessible := false
|
|
||||||
var archives: Array[int] # archive id list in ascending order
|
var archives: Array[int] # archive id list in ascending order
|
||||||
|
|
||||||
var managers = {
|
|
||||||
"TimeManager": TimeManager,
|
|
||||||
"EntityManager": EntityManager,
|
|
||||||
"SceneManager": SceneManager,
|
|
||||||
"InputManager": InputManager,
|
|
||||||
# "ArchiveManager" : ArchiveManager, #self
|
|
||||||
# "AudioManager" : AudioManager,
|
|
||||||
# "EventManager" : EventManager,
|
|
||||||
# "CameraManager" : CameraManager,
|
|
||||||
# "DialogManager" : DialogManager,
|
|
||||||
# "CgManager": CgManager,
|
|
||||||
}
|
|
||||||
|
|
||||||
var autosave_timer := Timer.new()
|
var autosave_timer := Timer.new()
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
accessible = _check_archive_dirs()
|
if not _check_dirs_and_archives():
|
||||||
if !accessible:
|
# TODO warning and exist
|
||||||
return
|
return
|
||||||
# _open_log_file()
|
|
||||||
add_child(autosave_timer)
|
|
||||||
autosave_timer.wait_time = GlobalConfigManager.config.auto_save_seconds
|
|
||||||
autosave_timer.one_shot = false
|
|
||||||
autosave_timer.timeout.connect(_try_auto_save)
|
autosave_timer.timeout.connect(_try_auto_save)
|
||||||
autosave_timer.stop()
|
autosave_timer.stop()
|
||||||
GlobalConfigManager.config.current_selected_save_changed.connect(_check_autosave_options)
|
add_child(autosave_timer)
|
||||||
GlobalConfigManager.config.auto_save_seconds_changed.connect(_check_autosave_options)
|
# config should be loaded first
|
||||||
load_all()
|
load_config()
|
||||||
|
# TODO NOTICE auto load archive on debug mode
|
||||||
|
if GlobalConfig.DEBUG:
|
||||||
|
if archives.size() == 0:
|
||||||
|
create_and_use_new_archive()
|
||||||
|
else:
|
||||||
|
GlobalConfigManager.config.current_selected_archive_id = archives[0]
|
||||||
|
|
||||||
|
|
||||||
|
func _archive_id_changed():
|
||||||
|
var selected_id = GlobalConfigManager.config.current_selected_archive_id
|
||||||
|
if archive:
|
||||||
|
if selected_id != archive.archive_id:
|
||||||
|
ResourceSaver.save(archive)
|
||||||
|
archive = null
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
if selected_id < 0:
|
||||||
|
return
|
||||||
|
var path = archive_dir + archive_prefix + str(selected_id) + GlobalConfig.RES_FILE_FORMAT
|
||||||
|
archive = ResourceLoader.load(path, "", ResourceLoader.CACHE_MODE_REPLACE_DEEP)
|
||||||
|
if !archive:
|
||||||
|
create_and_use_new_archive(selected_id)
|
||||||
|
SceneManager.pop_notification("已创建新存档")
|
||||||
|
else:
|
||||||
|
load_archive()
|
||||||
|
|
||||||
|
|
||||||
func _check_autosave_options():
|
func _check_autosave_options():
|
||||||
if (
|
if archive and GlobalConfigManager.config.auto_save_seconds > 1:
|
||||||
GlobalConfigManager.config.auto_save_seconds > 5
|
# reset left time
|
||||||
and GlobalConfigManager.config.current_selected_save >= 0
|
autosave_timer.stop()
|
||||||
):
|
autosave_timer.one_shot = false
|
||||||
|
autosave_timer.wait_time = GlobalConfigManager.config.auto_save_seconds
|
||||||
autosave_timer.start()
|
autosave_timer.start()
|
||||||
else:
|
else:
|
||||||
autosave_timer.stop()
|
autosave_timer.stop()
|
||||||
|
|
||||||
|
|
||||||
func _try_auto_save():
|
func _try_auto_save():
|
||||||
if (
|
print("Auto save")
|
||||||
GlobalConfigManager.config.auto_save_seconds > 5
|
if archive and GlobalConfigManager.config.auto_save_seconds > 1:
|
||||||
and GlobalConfigManager.config.current_selected_save >= 0
|
|
||||||
):
|
|
||||||
save_all()
|
save_all()
|
||||||
SceneManager.pop_notification("自动保存成功")
|
SceneManager.pop_notification("自动保存成功")
|
||||||
|
|
||||||
|
|
||||||
func _check_archive_dirs() -> bool:
|
func _check_dirs_and_archives() -> bool:
|
||||||
|
if !DirAccess.dir_exists_absolute(user_root_dir):
|
||||||
|
DirAccess.make_dir_recursive_absolute(user_root_dir)
|
||||||
|
print("Create user_root_dir:", user_root_dir)
|
||||||
# Check if the archive directory is accessible
|
# Check if the archive directory is accessible
|
||||||
if !DirAccess.dir_exists_absolute(user_archive_root_dir):
|
if !DirAccess.dir_exists_absolute(archive_dir):
|
||||||
DirAccess.make_dir_recursive_absolute(user_archive_root_dir)
|
DirAccess.make_dir_recursive_absolute(archive_dir)
|
||||||
print("Create archive directory:", user_archive_root_dir)
|
print("Create archive_dir:", archive_dir)
|
||||||
var archive_dir_access = DirAccess.open(user_archive_root_dir)
|
var archive_dir_access = DirAccess.open(archive_dir)
|
||||||
if !archive_dir_access:
|
if !archive_dir_access:
|
||||||
printerr("Archive directory is not accessible")
|
_handle_load_error("存档目录", "读取")
|
||||||
# TODO pop up a dialog to inform the user
|
# TODO pop up a dialog to inform the user
|
||||||
return false
|
return false
|
||||||
var files = archive_dir_access.get_files()
|
var files = archive_dir_access.get_files()
|
||||||
# get archive number
|
# get archive number
|
||||||
for file in files:
|
for file in files:
|
||||||
if file.begins_with(save_dir_prefix):
|
if file.begins_with(archive_prefix):
|
||||||
var id_str = file.substr(save_dir_prefix.length())
|
var id_str = file.substr(archive_prefix.length())
|
||||||
var id = int(id_str)
|
var id = int(id_str)
|
||||||
archives.append(id)
|
archives.append(id)
|
||||||
archives.sort()
|
archives.sort()
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
|
||||||
|
# id = -1 means create a new archive, otherwise create an archive with the given id
|
||||||
|
func create_and_use_new_archive(id := -1) -> void:
|
||||||
|
_check_dirs_and_archives()
|
||||||
|
archive = AssembledArchive.new()
|
||||||
|
var archive_path = archive_dir + archive_prefix + str(id) + GlobalConfig.RES_FILE_FORMAT
|
||||||
|
if id < 0:
|
||||||
|
id = 0
|
||||||
|
# find a new id
|
||||||
|
archive_path = (archive_dir + archive_prefix + str(id) + GlobalConfig.RES_FILE_FORMAT)
|
||||||
|
while FileAccess.file_exists(archive_path):
|
||||||
|
id += 1
|
||||||
|
archive_path = (archive_dir + archive_prefix + str(id) + GlobalConfig.RES_FILE_FORMAT)
|
||||||
|
archive.archive_id = id
|
||||||
|
archive.resource_path = archive_path
|
||||||
|
archive.created_time = Time.get_datetime_string_from_system(false, true)
|
||||||
|
ResourceSaver.save(archive, archive_path)
|
||||||
|
archives.append(id)
|
||||||
|
# this will auto trigger signal and load the new archive
|
||||||
|
GlobalConfigManager.config.current_selected_archive_id = id
|
||||||
|
|
||||||
|
|
||||||
func save_all() -> void:
|
func save_all() -> void:
|
||||||
# save config
|
# save config
|
||||||
var config = GlobalConfigManager.config
|
var config = GlobalConfigManager.config
|
||||||
var path = user_archive_root_dir + "config" + GlobalConfig.RES_FILE_FORMAT
|
if config:
|
||||||
ResourceSaver.save(config, path)
|
ResourceSaver.save(config)
|
||||||
if not accessible or GlobalConfigManager.config.current_selected_save == -1:
|
if archive:
|
||||||
|
ResourceSaver.save(archive)
|
||||||
|
# reset autosave timer
|
||||||
|
_check_autosave_options()
|
||||||
|
|
||||||
|
|
||||||
|
func load_config() -> void:
|
||||||
|
if GlobalConfigManager.config:
|
||||||
return
|
return
|
||||||
# Save all managers by the current selected save
|
var path = user_root_dir + "config" + GlobalConfig.RES_FILE_FORMAT
|
||||||
for manager in managers:
|
|
||||||
# .tres
|
|
||||||
var res = managers[manager].get_data_res()
|
|
||||||
if !res:
|
|
||||||
continue
|
|
||||||
# save to file
|
|
||||||
path = (
|
|
||||||
user_archive_root_dir
|
|
||||||
+ str(config.current_selected_save)
|
|
||||||
+ "/"
|
|
||||||
+ manager
|
|
||||||
+ GlobalConfig.RES_FILE_FORMAT
|
|
||||||
)
|
|
||||||
ResourceSaver.save(res, path)
|
|
||||||
|
|
||||||
|
|
||||||
func load_all() -> void:
|
|
||||||
_check_archive_dirs()
|
|
||||||
# load config
|
|
||||||
var path = user_archive_root_dir + "config" + GlobalConfig.RES_FILE_FORMAT
|
|
||||||
var config
|
|
||||||
if FileAccess.file_exists(path):
|
if FileAccess.file_exists(path):
|
||||||
config = ResourceLoader.load(path)
|
var config = ResourceLoader.load(path)
|
||||||
GlobalConfigManager.load_data_res(config)
|
GlobalConfigManager.config = config
|
||||||
else:
|
else:
|
||||||
config = GlobalConfigManager.config
|
var config = GlobalConfig.new()
|
||||||
# save config
|
GlobalConfigManager.config = config
|
||||||
ResourceSaver.save(config, path)
|
ResourceSaver.save(config, path)
|
||||||
if not accessible or config.current_selected_save == -1:
|
GlobalConfigManager.config.resource_path = path
|
||||||
|
# connect signals
|
||||||
|
GlobalConfigManager.config.current_selected_archive_id_changed.connect(_archive_id_changed)
|
||||||
|
GlobalConfigManager.config.auto_save_seconds_changed.connect(_check_autosave_options)
|
||||||
|
|
||||||
|
|
||||||
|
func load_archive() -> void:
|
||||||
|
_check_dirs_and_archives()
|
||||||
|
var selected_id = GlobalConfigManager.config.current_selected_archive_id
|
||||||
|
if not archives.has(selected_id):
|
||||||
|
_handle_load_error(str(selected_id) + " 号存档", "查找")
|
||||||
return
|
return
|
||||||
# Load managers by the current selected save
|
var path = archive_dir + archive_prefix + str(selected_id) + GlobalConfig.RES_FILE_FORMAT
|
||||||
path = user_archive_root_dir + save_dir_prefix + str(config.current_selected_save) + "/"
|
archive = ResourceLoader.load(path)
|
||||||
for manager in managers:
|
if !archive:
|
||||||
var manager_path = path + manager + GlobalConfig.RES_FILE_FORMAT
|
_handle_load_error(str(selected_id) + " 号存档", "加载")
|
||||||
if FileAccess.file_exists(manager_path):
|
return
|
||||||
var res = ResourceLoader.load(manager_path)
|
archive.resource_path = path
|
||||||
managers[manager].load_data_res(res)
|
_check_autosave_options()
|
||||||
|
|
||||||
|
|
||||||
|
func _handle_load_error(target, action) -> void:
|
||||||
|
var msg = str(target) + " " + str(action) + " 失败"
|
||||||
|
SceneManager.pop_notification(msg)
|
||||||
|
printerr(msg)
|
||||||
|
# TODO handle error
|
||||||
|
@ -1,11 +1,5 @@
|
|||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
|
|
||||||
# Called when the node enters the scene tree for the first time.
|
func play_sfx(sfx: String) -> void:
|
||||||
func _ready() -> void:
|
|
||||||
pass # Replace with function body.
|
|
||||||
|
|
||||||
|
|
||||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
|
||||||
func _process(delta: float) -> void:
|
|
||||||
pass
|
pass
|
@ -13,16 +13,15 @@ const CANVAS_LAYER_UI = 99
|
|||||||
const CANVAS_LAYER_FG = 50
|
const CANVAS_LAYER_FG = 50
|
||||||
const CANVAS_LAYER_BG = -100
|
const CANVAS_LAYER_BG = -100
|
||||||
|
|
||||||
signal current_selected_save_changed
|
signal current_selected_archive_id_changed
|
||||||
signal auto_save_seconds_changed
|
signal auto_save_seconds_changed
|
||||||
|
|
||||||
# 注意:编辑与新增属性时,需要同时编辑 GlobalConfigManager.gd 中的 load_data_res 方法
|
|
||||||
@export var game_total_seconds := 0 # 游戏总时长
|
@export var game_total_seconds := 0 # 游戏总时长
|
||||||
@export var game_rounds := 1 # 当前周目数
|
@export var game_rounds := 1 # 当前周目数
|
||||||
@export var current_selected_save := -1: # 当前选定存档 id, -1 means no save selected
|
@export var current_selected_archive_id := -1: # 当前选定存档, -1 为未选择
|
||||||
set(val):
|
set(val):
|
||||||
current_selected_save = val
|
current_selected_archive_id = val
|
||||||
current_selected_save_changed.emit()
|
current_selected_archive_id_changed.emit()
|
||||||
@export var auto_save_seconds := 60:
|
@export var auto_save_seconds := 60:
|
||||||
set(val):
|
set(val):
|
||||||
auto_save_seconds = val
|
auto_save_seconds = val
|
||||||
|
@ -1,15 +1,3 @@
|
|||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
var config = GlobalConfig.new()
|
var config: GlobalConfig
|
||||||
|
|
||||||
|
|
||||||
func get_data_res() -> Resource:
|
|
||||||
return config
|
|
||||||
|
|
||||||
|
|
||||||
func load_data_res(data: Resource) -> void:
|
|
||||||
var new_config = data as GlobalConfig
|
|
||||||
config.game_total_seconds = new_config.game_total_seconds
|
|
||||||
config.game_rounds = new_config.game_rounds
|
|
||||||
config.current_selected_save = new_config.current_selected_save
|
|
||||||
config.auto_save_seconds = new_config.auto_save_seconds
|
|
||||||
|
3
manager/deploy/assemble/assembler.tscn
Normal file
3
manager/deploy/assemble/assembler.tscn
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[gd_scene format=3 uid="uid://ducfqojekphh6"]
|
||||||
|
|
||||||
|
[node name="Assembler" type="Node2D"]
|
23
manager/deploy/assemble/placeholder_2d.gd
Normal file
23
manager/deploy/assemble/placeholder_2d.gd
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
@tool
|
||||||
|
extends Node2D
|
||||||
|
|
||||||
|
@export var placeholder_name := "placeholder":
|
||||||
|
set(val):
|
||||||
|
placeholder_name = val
|
||||||
|
_reload()
|
||||||
|
@export var placeholder_size: Vector2 = Vector2(32, 64):
|
||||||
|
set(val):
|
||||||
|
placeholder_size = val
|
||||||
|
_reload()
|
||||||
|
@export var offset: Vector2 = Vector2(0, 0):
|
||||||
|
set(val):
|
||||||
|
offset = val
|
||||||
|
_reload()
|
||||||
|
@export var packed_scene: PackedScene:
|
||||||
|
set(val):
|
||||||
|
packed_scene = val
|
||||||
|
_reload()
|
||||||
|
|
||||||
|
|
||||||
|
func _reload():
|
||||||
|
pass
|
6
manager/deploy/assemble/placeholder_2d.tscn
Normal file
6
manager/deploy/assemble/placeholder_2d.tscn
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://c1ekdt4b08nac"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://manager/deploy/assemble/placeholder_2d.gd" id="1_0l7tn"]
|
||||||
|
|
||||||
|
[node name="Placeholder2D" type="Node2D"]
|
||||||
|
script = ExtResource("1_0l7tn")
|
74
manager/deploy/entity/entity_loader.gd
Normal file
74
manager/deploy/entity/entity_loader.gd
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
@tool
|
||||||
|
class_name EntityLoader extends Node2D
|
||||||
|
|
||||||
|
@export var state: String:
|
||||||
|
set(value):
|
||||||
|
state = value
|
||||||
|
_init_state()
|
||||||
|
@export var entity_config: EntityConfig:
|
||||||
|
set(value):
|
||||||
|
entity_config = value
|
||||||
|
entity_config.changed.connect(_reload)
|
||||||
|
# Load the entity config
|
||||||
|
_reload()
|
||||||
|
@export
|
||||||
|
var sprite_frames = preload("res://config/animation/player_sprite_frames.tres") as SpriteFrames
|
||||||
|
|
||||||
|
@onready var sprite2d = %AnimatedSprite2D as AnimatedSprite2D
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
if GlobalConfig.DEBUG:
|
||||||
|
add_child(DebugLabel.new())
|
||||||
|
|
||||||
|
|
||||||
|
func _reload() -> void:
|
||||||
|
# rm children
|
||||||
|
state = entity_config.initial_state
|
||||||
|
_init_state()
|
||||||
|
|
||||||
|
|
||||||
|
func _init_state() -> void:
|
||||||
|
if not entity_config:
|
||||||
|
return
|
||||||
|
## free unused children
|
||||||
|
# TODO Load current state according to entity config
|
||||||
|
var success := false
|
||||||
|
# Add placeholder if state's missing
|
||||||
|
if not success:
|
||||||
|
_init_placeholder()
|
||||||
|
else:
|
||||||
|
sprite2d.scale = entity_config.scale
|
||||||
|
|
||||||
|
|
||||||
|
func _init_placeholder():
|
||||||
|
if not entity_config.placeholder_size:
|
||||||
|
return
|
||||||
|
var sprite = get_node_or_null("PlaceholderSprite") as Node2D
|
||||||
|
if sprite:
|
||||||
|
sprite.visible = true
|
||||||
|
else:
|
||||||
|
sprite = Sprite2D.new()
|
||||||
|
add_child(sprite)
|
||||||
|
sprite.texture = placeholder_pic
|
||||||
|
sprite.scale = entity_config.placeholder_size / sprite.texture.get_size()
|
||||||
|
sprite.offset = entity_config.offset
|
||||||
|
sprite.name = "PlaceholderSprite"
|
||||||
|
var label = get_node_or_null("PlaceholderLabel") as Node2D
|
||||||
|
if label:
|
||||||
|
label.visible = true
|
||||||
|
else:
|
||||||
|
label = Label.new()
|
||||||
|
add_child(label)
|
||||||
|
label.text = "[" + entity_config.entity_name + "]" + entity_config.entity_title + ":" + state
|
||||||
|
label.modulate = Color.GREEN
|
||||||
|
label.name = "PlaceholderLabel"
|
||||||
|
|
||||||
|
|
||||||
|
func switch_state(state_name: String) -> void:
|
||||||
|
state = state_name
|
||||||
|
_init_state()
|
||||||
|
|
||||||
|
|
||||||
|
func action(action_name: String) -> void:
|
||||||
|
# TODO
|
||||||
|
pass
|
65
manager/deploy/entity/entity_loader.tscn
Normal file
65
manager/deploy/entity/entity_loader.tscn
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
[gd_scene load_steps=7 format=3 uid="uid://do5j7vqrviv48"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://manager/deploy/entity/entity_loader.gd" id="1_0ynbr"]
|
||||||
|
[ext_resource type="SpriteFrames" uid="uid://cs44glabs8sma" path="res://config/animation/player_sprite_frames.tres" id="2_7crsu"]
|
||||||
|
|
||||||
|
[sub_resource type="GDScript" id="GDScript_gcl2t"]
|
||||||
|
|
||||||
|
[sub_resource type="GDScript" id="GDScript_dhqgj"]
|
||||||
|
|
||||||
|
[sub_resource type="GDScript" id="GDScript_ybgaq"]
|
||||||
|
script/source = "class_name EntityConfig extends Resource
|
||||||
|
|
||||||
|
|
||||||
|
class EntityStateConfig:
|
||||||
|
extends Resource
|
||||||
|
var state_name: String = \"default\"
|
||||||
|
var animation: String = \"\"
|
||||||
|
var loop: bool = false
|
||||||
|
var sound: String = \"\"
|
||||||
|
var state_title: String = \"\" # use default if empty
|
||||||
|
var state_note: String = \"\" # use default if empty
|
||||||
|
var actions: Array[String] = []
|
||||||
|
|
||||||
|
|
||||||
|
class EntityActionConfig:
|
||||||
|
extends Resource
|
||||||
|
var action_name: String = \"\"
|
||||||
|
var next_state: String = \"\" # empty means keep current state
|
||||||
|
var animation: String = \"\"
|
||||||
|
var sound: String = \"\"
|
||||||
|
var callback: Callable # receive the entity as argument
|
||||||
|
|
||||||
|
|
||||||
|
@export var entity_name: String = \"\"
|
||||||
|
@export var placeholder_size: Vector2 = Vector2(32, 64)
|
||||||
|
@export var offset: Vector2 = Vector2(0, 0)
|
||||||
|
@export var entity_title: String = \"\"
|
||||||
|
@export var entity_note: String = \"\"
|
||||||
|
@export var initial_state: String = \"default\"
|
||||||
|
@export var initializer: Callable
|
||||||
|
@export var entity_states: Array[EntityStateConfig]
|
||||||
|
@export var entity_actions: Array[EntityActionConfig]
|
||||||
|
"
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_6wfuj"]
|
||||||
|
script = SubResource("GDScript_ybgaq")
|
||||||
|
entity_name = ""
|
||||||
|
placeholder_size = Vector2(32, 64)
|
||||||
|
offset = Vector2(0, 0)
|
||||||
|
entity_title = ""
|
||||||
|
entity_note = ""
|
||||||
|
initial_state = "default"
|
||||||
|
initializer = Callable()
|
||||||
|
entity_states = Array[SubResource("GDScript_dhqgj")]([])
|
||||||
|
entity_actions = Array[SubResource("GDScript_gcl2t")]([])
|
||||||
|
|
||||||
|
[node name="EntityLoader" type="Node2D"]
|
||||||
|
script = ExtResource("1_0ynbr")
|
||||||
|
state = "default"
|
||||||
|
entity_config = SubResource("Resource_6wfuj")
|
||||||
|
sprite_frames = null
|
||||||
|
|
||||||
|
[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
sprite_frames = ExtResource("2_7crsu")
|
@ -9,10 +9,3 @@ func _ready() -> void:
|
|||||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
func get_data_res() -> Resource:
|
|
||||||
return null
|
|
||||||
|
|
||||||
|
|
||||||
func load_data_res(data: Resource) -> void:
|
|
||||||
pass
|
|
BIN
manager/deploy/entity/placeholder_pic.webp
Normal file
BIN
manager/deploy/entity/placeholder_pic.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
@ -6,10 +6,3 @@ func pop_notification(msg: String, number := 1) -> void:
|
|||||||
notification_node.show_notification(msg, number)
|
notification_node.show_notification(msg, number)
|
||||||
else:
|
else:
|
||||||
printerr("Notification node not found")
|
printerr("Notification node not found")
|
||||||
|
|
||||||
func get_data_res() -> Resource:
|
|
||||||
return null
|
|
||||||
|
|
||||||
|
|
||||||
func load_data_res(data: Resource) -> void:
|
|
||||||
pass
|
|
@ -10,10 +10,3 @@ func _ready() -> void:
|
|||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
func get_data_res() -> Resource:
|
|
||||||
return null
|
|
||||||
|
|
||||||
|
|
||||||
func load_data_res(data: Resource) -> void:
|
|
||||||
pass
|
|
@ -1,15 +1,11 @@
|
|||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
@export var current_chapter := 0
|
|
||||||
@export var current_section := 0
|
|
||||||
@export var game_seconds_all := 0
|
|
||||||
@export var game_seconds_current := 0
|
|
||||||
|
|
||||||
var timer: Timer
|
var timer: Timer
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
timer = Timer.new()
|
timer = Timer.new()
|
||||||
timer.wait_time = 1
|
timer.wait_time = 5
|
||||||
timer.one_shot = false
|
timer.one_shot = false
|
||||||
timer.timeout.connect(_on_timer_timeout)
|
timer.timeout.connect(_on_timer_timeout)
|
||||||
add_child(timer)
|
add_child(timer)
|
||||||
@ -17,33 +13,40 @@ func _ready() -> void:
|
|||||||
|
|
||||||
|
|
||||||
func _on_timer_timeout():
|
func _on_timer_timeout():
|
||||||
game_seconds_all += 1
|
var archive = ArchiveManager.archive
|
||||||
game_seconds_current += 1
|
if archive:
|
||||||
GlobalConfigManager.config.game_total_seconds += 1
|
archive.game_seconds_all += 5
|
||||||
|
archive.game_seconds_current += 5
|
||||||
|
GlobalConfigManager.config.game_total_seconds += 5
|
||||||
|
|
||||||
|
|
||||||
func pack_current_time():
|
func pack_current_time():
|
||||||
var packed_time = PackedTime.new()
|
var packed_time = PackedTime.new()
|
||||||
packed_time.time = Time.get_datetime_string_from_system(false, true)
|
packed_time.time = Time.get_datetime_string_from_system(false, true)
|
||||||
packed_time.chapter = current_chapter
|
var archive = ArchiveManager.archive
|
||||||
packed_time.section = current_section
|
if archive:
|
||||||
packed_time.game_archive_id = ArchiveManager.current_archive_id
|
packed_time.chapter = archive.current_chapter
|
||||||
packed_time.game_seconds_all = game_seconds_all
|
packed_time.section = archive.current_section
|
||||||
packed_time.game_seconds_current = game_seconds_current
|
packed_time.game_archive_id = archive.archive_id
|
||||||
|
packed_time.game_seconds_all = archive.game_seconds_all
|
||||||
|
packed_time.game_seconds_current = archive.game_seconds_current
|
||||||
|
|
||||||
|
|
||||||
# for log use
|
# for log use
|
||||||
func get_concise_timemark() -> String:
|
func get_concise_timemark() -> String:
|
||||||
var hour := game_seconds_current / 3600 as int
|
var archive = ArchiveManager.archive
|
||||||
var minute := (game_seconds_current % 3600) / 60 as int
|
if not archive:
|
||||||
var second := game_seconds_current % 60
|
return "r0_c0_s0 00:00:00"
|
||||||
|
var hour = archive.game_seconds_current / 3600 as int
|
||||||
|
var minute = (archive.game_seconds_current % 3600) / 60 as int
|
||||||
|
var second = archive.game_seconds_current % 60
|
||||||
return (
|
return (
|
||||||
"r"
|
"r"
|
||||||
+ str(ArchiveManager.current_archive_id)
|
+ str(ArchiveManager.current_archive_id)
|
||||||
+ "_c"
|
+ "_c"
|
||||||
+ str(current_chapter)
|
+ str(archive.current_chapter)
|
||||||
+ "_s"
|
+ "_s"
|
||||||
+ str(current_section)
|
+ str(archive.current_section)
|
||||||
+ " "
|
+ " "
|
||||||
+ str(hour)
|
+ str(hour)
|
||||||
+ ":"
|
+ ":"
|
||||||
@ -51,13 +54,3 @@ func get_concise_timemark() -> String:
|
|||||||
+ ":"
|
+ ":"
|
||||||
+ str(second)
|
+ str(second)
|
||||||
)
|
)
|
||||||
|
|
||||||
func get_data_res() -> Resource:
|
|
||||||
return pack_current_time()
|
|
||||||
|
|
||||||
func load_data_res(data: Resource) -> void:
|
|
||||||
var packed_time = data as PackedTime
|
|
||||||
game_seconds_all = packed_time.game_seconds_all
|
|
||||||
game_seconds_current = packed_time.game_seconds_current
|
|
||||||
current_chapter = packed_time.chapter
|
|
||||||
current_section = packed_time.section
|
|
||||||
|
@ -34,11 +34,11 @@ buses/default_bus_layout="res://config/default_bus_layout.tres"
|
|||||||
DebugMenu="*res://addons/debug_menu/debug_menu.tscn"
|
DebugMenu="*res://addons/debug_menu/debug_menu.tscn"
|
||||||
GlobalConfigManager="*res://manager/config_manager/global_config_manager.gd"
|
GlobalConfigManager="*res://manager/config_manager/global_config_manager.gd"
|
||||||
TimeManager="*res://manager/time_manager/time_manager.gd"
|
TimeManager="*res://manager/time_manager/time_manager.gd"
|
||||||
EntityManager="*res://manager/assemble/entity/entity_manager.gd"
|
EntityManager="*res://manager/deploy/entity/entity_manager.gd"
|
||||||
SceneManager="*res://manager/assemble/scene/scene_manager.gd"
|
SceneManager="*res://manager/deploy/scene/scene_manager.gd"
|
||||||
AudioManager="*res://manager/audio_manager/audio_manager.gd"
|
AudioManager="*res://manager/audio_manager/audio_manager.gd"
|
||||||
EventManager="*res://manager/event_manager/event_manager.gd"
|
EventManager="*res://manager/event_manager/event_manager.gd"
|
||||||
DialogManager="*res://manager/assemble/dialog/dialog_manager.gd"
|
DialogManager="*res://manager/deploy/dialog/dialog_manager.gd"
|
||||||
CameraManager="*res://manager/camera_manager/camera_manager.gd"
|
CameraManager="*res://manager/camera_manager/camera_manager.gd"
|
||||||
CgManager="*res://manager/cg_manager/cg_manager.gd"
|
CgManager="*res://manager/cg_manager/cg_manager.gd"
|
||||||
InputManager="*res://manager/input/input_manager.gd"
|
InputManager="*res://manager/input/input_manager.gd"
|
||||||
|
@ -40,7 +40,7 @@ func show_notification(msg, number):
|
|||||||
|
|
||||||
|
|
||||||
func _check_next():
|
func _check_next():
|
||||||
|
tweening = false
|
||||||
if pending_notifications.size() > 0:
|
if pending_notifications.size() > 0:
|
||||||
var n = pending_notifications.pop_front()
|
var n = pending_notifications.pop_front()
|
||||||
tweening = false
|
|
||||||
show_notification(n[0], n[1])
|
show_notification(n[0], n[1])
|
||||||
|
22
util/debug_label.gd
Normal file
22
util/debug_label.gd
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
class_name DebugLabel extends Label
|
||||||
|
|
||||||
|
@export var enabled := false:
|
||||||
|
set(value):
|
||||||
|
enabled = value
|
||||||
|
if enabled:
|
||||||
|
_display()
|
||||||
|
else:
|
||||||
|
_hide()
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
if not GlobalConfig.DEBUG:
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
func _hide():
|
||||||
|
visible = false
|
||||||
|
|
||||||
|
|
||||||
|
func _display():
|
||||||
|
pass
|
Loading…
Reference in New Issue
Block a user