|  |  |  | @tool | 
					
						
							|  |  |  | extends Node3D | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func get_resource_name(resource: Resource) -> String: return resource.resource_path.get_file().trim_suffix('.tres') # todo 性能 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func snap_vector3(value: Vector3) -> Vector3: return Vector3(snap_float(value.x), snap_float(value.y), snap_float(value.z)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func snap_float(value: float) -> float: return floor(value / Setting.pixel_size) * Setting.pixel_size | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func dir_angle(dir: Vector2) -> float: | 
					
						
							|  |  |  | 	dir.x = abs(dir.x) | 
					
						
							|  |  |  | 	return dir.angle_to(Vector2.RIGHT) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func angle_dir(angle: float) -> Vector2: | 
					
						
							|  |  |  | 	return Vector2.RIGHT.rotated(angle) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func vector_reduce(vector: Vector2, reduce: float) -> Vector2: | 
					
						
							|  |  |  | 	var length: float = vector.length() | 
					
						
							|  |  |  | 	if length == 0: | 
					
						
							|  |  |  | 		return vector | 
					
						
							|  |  |  | 	var new_len = max(length - reduce, 0) | 
					
						
							|  |  |  | 	var scale_rate = new_len / length | 
					
						
							|  |  |  | 	return vector * scale_rate | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func get_level_grid_pos(pos: Vector3) -> Vector3i: | 
					
						
							|  |  |  | 	var grid_size: float = Setting.pixel_size * Setting.grid_pixel_size | 
					
						
							|  |  |  | 	var ret: Vector3i = Vector3i(get_div_scale(pos.x, grid_size), get_div_scale(pos.y, grid_size), get_div_scale(pos.z, grid_size)) | 
					
						
							|  |  |  | 	return ret | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func get_level_grid_pos2(pos: Vector3) -> Vector3i: | 
					
						
							|  |  |  | 	pos += Vector3.ONE * Setting.pixel_size * Setting.grid_pixel_size; | 
					
						
							|  |  |  | 	var grid_size: float = Setting.pixel_size * Setting.grid_pixel_size * 2 | 
					
						
							|  |  |  | 	var ret: Vector3i = Vector3i(get_div_scale(pos.x, grid_size), get_div_scale(pos.y, grid_size), get_div_scale(pos.z, grid_size)) | 
					
						
							|  |  |  | 	return ret | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func get_level_float_pos(pos: Vector3i) -> Vector3: | 
					
						
							|  |  |  | 	var grid_size: float = Setting.pixel_size * Setting.grid_pixel_size | 
					
						
							|  |  |  | 	return Vector3(pos.x * grid_size, pos.y * grid_size, pos.z * grid_size) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func get_level_float_pos2(pos: Vector3i) -> Vector3: | 
					
						
							|  |  |  | 	var grid_size: float = Setting.pixel_size * Setting.grid_pixel_size * 2 | 
					
						
							|  |  |  | 	return Vector3(pos.x * grid_size, pos.y * grid_size, pos.z * grid_size) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func get_level_float_pos2_floor(pos: Vector3i) -> Vector3: | 
					
						
							|  |  |  | 	var grid_size: float = Setting.pixel_size * Setting.grid_pixel_size | 
					
						
							|  |  |  | 	return get_level_float_pos2(pos) - Vector3(0, grid_size, 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func get_level_id(pos: Vector3) -> Vector3i: | 
					
						
							|  |  |  | 	var ret: Vector3i = Vector3i(get_div_scale(pos.x, Setting.size_basic.x), get_div_scale(pos.y, Setting.size_basic.y), get_div_scale(pos.z, Setting.size_basic.z)) | 
					
						
							|  |  |  | 	return ret | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func get_div_scale(a: float, b: float) -> int: | 
					
						
							|  |  |  | 	#解决浮点数精度问题 | 
					
						
							|  |  |  | 	var div: float = a / b | 
					
						
							|  |  |  | 	var is_positive: bool = div > 0 | 
					
						
							|  |  |  | 	var decimal: float = abs(div - int(div)) | 
					
						
							|  |  |  | 	if is_positive and decimal > 0.999: | 
					
						
							|  |  |  | 		div += 0.001 | 
					
						
							|  |  |  | 	if not is_positive and decimal < 0.001: | 
					
						
							|  |  |  | 		div += 0.001 | 
					
						
							|  |  |  | 	return floor(div) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func raycast_character(shape: Shape3D, origin: Vector3, dir: Vector2) -> Array[Character]: | 
					
						
							|  |  |  | 	var space_state: PhysicsDirectSpaceState3D = get_world_3d().direct_space_state | 
					
						
							|  |  |  | 	var query: PhysicsShapeQueryParameters3D = PhysicsShapeQueryParameters3D.new() | 
					
						
							|  |  |  | 	var angle: float = dir_angle(dir) | 
					
						
							|  |  |  | 	query.shape = shape | 
					
						
							|  |  |  | 	query.transform.origin = origin | 
					
						
							|  |  |  | 	query.transform.basis = query.transform.basis.rotated(Vector3.UP, angle) | 
					
						
							|  |  |  | 	var result: Array[Dictionary] = space_state.intersect_shape(query) | 
					
						
							|  |  |  | 	var result2: Array = result.map(func(v): return v["collider"]).filter(func(v): return v is Character) | 
					
						
							|  |  |  | 	var result3: Array[Character] | 
					
						
							|  |  |  | 	for node in result2: | 
					
						
							|  |  |  | 		result3.append(node as Character) | 
					
						
							|  |  |  | 	return result3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func clean_animation_lib(): | 
					
						
							|  |  |  | 	#删除技能配置中没有的animation文件 | 
					
						
							|  |  |  | 	#todo 非阻断 有空再说 | 
					
						
							|  |  |  | 	pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func refresh_animation_lib(): | 
					
						
							|  |  |  | 	#刷新animation库 使其与animation文件同步 | 
					
						
							|  |  |  | 	var animation_library_path: String = "res://resource/skill_animation_library/animation_library.tres" | 
					
						
							|  |  |  | 	var animation_library = load(animation_library_path) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var dir_path: String = "res://resource/skill_animation" | 
					
						
							|  |  |  | 	var dir: DirAccess = DirAccess.open(dir_path) | 
					
						
							|  |  |  | 	for file in dir.get_files(): | 
					
						
							|  |  |  | 		var path: String = dir_path + "/" + file | 
					
						
							|  |  |  | 		var res = load(path) | 
					
						
							|  |  |  | 		if res is Animation: | 
					
						
							|  |  |  | 			var animation: Animation = res as Animation | 
					
						
							|  |  |  | 			var animation_name: String = Util.get_resource_name(animation) | 
					
						
							|  |  |  | 			print("refresh_animation_lib: ", animation_name) | 
					
						
							|  |  |  | 			animation_library.add_animation(animation_name, animation) | 
					
						
							|  |  |  | 			animation_library.animation_added.emit(animation_name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ResourceSaver.save(animation_library, animation_library_path) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func refresh_mesh_library(path_list: Array, from_editor_tool: bool = false): | 
					
						
							|  |  |  | 	print("refresh_mesh_library") | 
					
						
							|  |  |  | 	var default_shape_normal_full: Array[Variant] = [load("res://resource/mesh_library/default_shape_normal_full.tres") as Shape3D, Transform3D.IDENTITY] | 
					
						
							|  |  |  | 	var default_shape_normal_half: Array[Variant] = [load("res://resource/mesh_library/default_shape_normal_half.tres") as Shape3D, Transform3D.IDENTITY] | 
					
						
							|  |  |  | 	var default_shape_normal_stair1: Array[Variant] = [load("res://resource/mesh_library/default_shape_normal_stair1.tres") as Shape3D, Transform3D.IDENTITY] | 
					
						
							|  |  |  | 	var default_shape_normal_stair2: Array[Variant] = [load("res://resource/mesh_library/default_shape_normal_stair2.tres") as Shape3D, Transform3D.IDENTITY] | 
					
						
							|  |  |  | 	var default_shape_large_full: Array[Variant] = [load("res://resource/mesh_library/default_shape_large_full.tres") as Shape3D, Transform3D.IDENTITY] | 
					
						
							|  |  |  | 	var default_shape_large_half: Array[Variant] = [load("res://resource/mesh_library/default_shape_large_half.tres") as Shape3D, Transform3D.IDENTITY] | 
					
						
							|  |  |  | 	var default_shape_large_stair1: Array[Variant] = [load("res://resource/mesh_library/default_shape_large_stair1.tres") as Shape3D, Transform3D.IDENTITY] | 
					
						
							|  |  |  | 	var default_shape_large_stair2: Array[Variant] = [load("res://resource/mesh_library/default_shape_large_stair2.tres") as Shape3D, Transform3D.IDENTITY] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var mesh_library_main: MeshLibrary = load("res://resource/mesh_library/mesh_library_main.tres") as MeshLibrary | 
					
						
							|  |  |  | 	var mesh_library_sub: MeshLibrary = load("res://resource/mesh_library/mesh_library_sub.tres") as MeshLibrary | 
					
						
							|  |  |  | 	var mesh_library_deco1: MeshLibrary = load("res://resource/mesh_library/mesh_library_deco1.tres") as MeshLibrary | 
					
						
							|  |  |  | 	var mesh_library_deco2: MeshLibrary = load("res://resource/mesh_library/mesh_library_deco2.tres") as MeshLibrary | 
					
						
							|  |  |  | 	var mesh_library_chara: MeshLibrary = load("res://resource/mesh_library/mesh_library_chara.tres") as MeshLibrary | 
					
						
							|  |  |  | 	var mesh_library_main_id_list: Array[int] = [] | 
					
						
							|  |  |  | 	var mesh_library_sub_id_list: Array[int] = [] | 
					
						
							|  |  |  | 	var mesh_library_deco1_id_list: Array[int] = [] | 
					
						
							|  |  |  | 	var mesh_library_deco2_id_list: Array[int] = [] | 
					
						
							|  |  |  | 	var mesh_library_chara_id_list: Array[int] = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var material_grid_block: Material = load("res://render/material/level_grid_block.tres") as Material | 
					
						
							|  |  |  | 	var material_grid_mark_white: Material = load("res://render/material/level_grid_mark_white.tres") as Material | 
					
						
							|  |  |  | 	var material_grid_mark_black: Material = load("res://render/material/level_grid_mark_black.tres") as Material | 
					
						
							|  |  |  | 	var material_grid_mark_green: Material = load("res://render/material/level_grid_mark_green.tres") as Material | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var reimport_files: Array[String] = [] | 
					
						
							|  |  |  | 	for file_name_full in path_list: | 
					
						
							|  |  |  | 		var mesh_name = file_name_full.get_file().split('-')[0].trim_suffix('.vox') | 
					
						
							|  |  |  | 		if not mesh_name.contains("_"): | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		var name_prefix = mesh_name.split("_")[0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var mesh_library: MeshLibrary | 
					
						
							|  |  |  | 		var mesh_library_id_list: Array[int] | 
					
						
							|  |  |  | 		var has_material: bool | 
					
						
							|  |  |  | 		var has_shape: bool | 
					
						
							|  |  |  | 		match name_prefix: | 
					
						
							|  |  |  | 			"main": | 
					
						
							|  |  |  | 				mesh_library = mesh_library_main; mesh_library_id_list = mesh_library_main_id_list; has_material = true; has_shape = true; | 
					
						
							|  |  |  | 			"sub": | 
					
						
							|  |  |  | 				mesh_library = mesh_library_sub; mesh_library_id_list = mesh_library_sub_id_list; has_material = true; has_shape = true; | 
					
						
							|  |  |  | 			"deco1": | 
					
						
							|  |  |  | 				mesh_library = mesh_library_deco1; mesh_library_id_list = mesh_library_deco1_id_list; has_material = true; | 
					
						
							|  |  |  | 			"deco2": | 
					
						
							|  |  |  | 				mesh_library = mesh_library_deco2; mesh_library_id_list = mesh_library_deco2_id_list; has_material = true; | 
					
						
							|  |  |  | 			"chara": | 
					
						
							|  |  |  | 				mesh_library = mesh_library_chara; mesh_library_id_list = mesh_library_chara_id_list; | 
					
						
							|  |  |  | 			_: continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var mesh: Mesh = load(file_name_full) as Mesh | 
					
						
							|  |  |  | 		var mesh_id: int = mesh_library.find_item_by_name(mesh_name) | 
					
						
							|  |  |  | 		if mesh_id == -1: | 
					
						
							|  |  |  | 			mesh_id = mesh_library.get_last_unused_item_id() | 
					
						
							|  |  |  | 			mesh_library.create_item(mesh_id) | 
					
						
							|  |  |  | 		mesh_library_id_list.append(mesh_id) | 
					
						
							|  |  |  | 		mesh_library.set_item_name(mesh_id, mesh_name) | 
					
						
							|  |  |  | 		mesh_library.set_item_mesh(mesh_id, mesh) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if has_material: | 
					
						
							|  |  |  | 			var material_set: Material = material_grid_block | 
					
						
							|  |  |  | 			if mesh_name.contains("mark_black"): | 
					
						
							|  |  |  | 				material_set = material_grid_mark_black | 
					
						
							|  |  |  | 			elif mesh_name.contains("mark_white"): | 
					
						
							|  |  |  | 				material_set = material_grid_mark_white | 
					
						
							|  |  |  | 			elif mesh_name.contains("mark_green"): | 
					
						
							|  |  |  | 				material_set = material_grid_mark_green | 
					
						
							|  |  |  | 			if from_editor_tool: | 
					
						
							|  |  |  | 				reimport_files.append(file_name_full) | 
					
						
							|  |  |  | 			else: | 
					
						
							|  |  |  | 				print("surface_set_material") | 
					
						
							|  |  |  | 				mesh.surface_set_material(0, material_set) | 
					
						
							|  |  |  | 				ResourceSaver.save(mesh, file_name_full) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if has_shape: | 
					
						
							|  |  |  | 			var item_shapes: Array | 
					
						
							|  |  |  | 			var is_main = name_prefix == "main" | 
					
						
							|  |  |  | 			var name_subfix = mesh_name.split("_")[-1] | 
					
						
							|  |  |  | 			match name_subfix: | 
					
						
							|  |  |  | 				"full": item_shapes = default_shape_normal_full if not is_main else default_shape_large_full | 
					
						
							|  |  |  | 				"half": item_shapes = default_shape_normal_half if not is_main else default_shape_large_half | 
					
						
							|  |  |  | 				"stair1": item_shapes = default_shape_normal_stair1 if not is_main else default_shape_large_stair1 | 
					
						
							|  |  |  | 				"stair2": item_shapes = default_shape_normal_stair2 if not is_main else default_shape_large_stair2 | 
					
						
							|  |  |  | 				"auto": item_shapes = [mesh.create_convex_shape(), Transform3D.IDENTITY] | 
					
						
							|  |  |  | 				_: pass | 
					
						
							|  |  |  | 			if item_shapes: | 
					
						
							|  |  |  | 				mesh_library.set_item_shapes(mesh_id, item_shapes) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_save_mesh_library(mesh_library_main, mesh_library_main_id_list, from_editor_tool) | 
					
						
							|  |  |  | 	_save_mesh_library(mesh_library_sub, mesh_library_sub_id_list, from_editor_tool) | 
					
						
							|  |  |  | 	_save_mesh_library(mesh_library_deco1, mesh_library_deco1_id_list, from_editor_tool) | 
					
						
							|  |  |  | 	_save_mesh_library(mesh_library_deco2, mesh_library_deco2_id_list, from_editor_tool) | 
					
						
							|  |  |  | 	_save_mesh_library(mesh_library_chara, mesh_library_chara_id_list, from_editor_tool) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if from_editor_tool and reimport_files: | 
					
						
							|  |  |  | 		EditorInterface.get_resource_filesystem().reimport_files(reimport_files) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func _save_mesh_library(mesh_library: MeshLibrary, id_list: Array[int], from_editor_tool: bool): | 
					
						
							|  |  |  | 	if from_editor_tool: | 
					
						
							|  |  |  | 		var ids: PackedInt32Array = mesh_library.get_item_list() | 
					
						
							|  |  |  | 		for id in ids: | 
					
						
							|  |  |  | 			if not id in id_list: | 
					
						
							|  |  |  | 				mesh_library.remove_item(id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var meshes: Array[Variant] = [] | 
					
						
							|  |  |  | 	for id in id_list: | 
					
						
							|  |  |  | 		meshes.append(mesh_library.get_item_mesh(id)) | 
					
						
							|  |  |  | 	var previews: Array[Texture2D] = EditorInterface.make_mesh_previews(meshes, 64) | 
					
						
							|  |  |  | 	for i in range(len(id_list)): | 
					
						
							|  |  |  | 		mesh_library.set_item_preview(id_list[i], previews[i]) | 
					
						
							|  |  |  | 	ResourceSaver.save(mesh_library) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func refresh_all_animation_by_sprite_frames(sprite_frames: SpriteFrames): | 
					
						
							|  |  |  | 	var dir_path: String = "res://resource/skill_animation" | 
					
						
							|  |  |  | 	var dir: DirAccess = DirAccess.open(dir_path) | 
					
						
							|  |  |  | 	var sprite_frames_name: String = sprite_frames.resource_path.get_file().split('-')[0] | 
					
						
							|  |  |  | 	for file in dir.get_files(): | 
					
						
							|  |  |  | 		var path: String = dir_path + "/" + file | 
					
						
							|  |  |  | 		var res = load(path) | 
					
						
							|  |  |  | 		if not res is Animation: | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		var animation: Animation = res as Animation | 
					
						
							|  |  |  | 		var sprite_frames_track: int = animation.find_track(NodePath("View:sprite_frames"), Animation.TYPE_VALUE) | 
					
						
							|  |  |  | 		if sprite_frames_track < 0: | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		var sprite_frames_track_key_count: int = animation.track_get_key_count(sprite_frames_track) | 
					
						
							|  |  |  | 		if sprite_frames_track_key_count == 0: | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		var sprite_frames_value: SpriteFrames = animation.track_get_key_value(sprite_frames_track, 0) as SpriteFrames | 
					
						
							|  |  |  | 		var target_sprite_frames_name: String = sprite_frames_value.resource_path.get_file().split('-')[0] | 
					
						
							|  |  |  | 		if sprite_frames_name != target_sprite_frames_name: | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		var animation_track: int = animation.find_track(NodePath("View:animation"), Animation.TYPE_VALUE) | 
					
						
							|  |  |  | 		if animation_track < 0: | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		var animation_track_key_count: int = animation.track_get_key_count(animation_track) | 
					
						
							|  |  |  | 		if animation_track_key_count == 0: | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		var animation_value: String = animation.track_get_key_value(animation_track, 0) as String | 
					
						
							|  |  |  | 		refresh_animation_by_sprite_frames(path, sprite_frames, animation_value, animation) | 
					
						
							|  |  |  | 	Util.refresh_animation_lib() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func refresh_animation_by_sprite_frames(animation_path: String, sprite_frames: SpriteFrames, animation_name: String, animation: Animation) -> void: | 
					
						
							|  |  |  | 	if not sprite_frames.has_animation(animation_name): | 
					
						
							|  |  |  | 		print("动画不存在: ", animation_name) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	var track_sprite_frames: int = animation.find_track(NodePath("View:sprite_frames"), Animation.TYPE_VALUE) | 
					
						
							|  |  |  | 	if track_sprite_frames < 0: | 
					
						
							|  |  |  | 		track_sprite_frames = animation.add_track(Animation.TYPE_VALUE) | 
					
						
							|  |  |  | 		animation.track_set_path(track_sprite_frames, "View:sprite_frames") | 
					
						
							|  |  |  | 		animation.track_insert_key(track_sprite_frames, 0, sprite_frames) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var track_animation: int = animation.find_track(NodePath("View:animation"), Animation.TYPE_VALUE) | 
					
						
							|  |  |  | 	if track_animation < 0: | 
					
						
							|  |  |  | 		track_animation = animation.add_track(Animation.TYPE_VALUE) | 
					
						
							|  |  |  | 		animation.track_set_path(track_animation, "View:animation") | 
					
						
							|  |  |  | 		animation.track_insert_key(track_animation, 0, animation_name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var track_frame: int = animation.find_track(NodePath("View:frame"), Animation.TYPE_VALUE) | 
					
						
							|  |  |  | 	if track_frame >= 0: | 
					
						
							|  |  |  | 		animation.remove_track(track_frame) | 
					
						
							|  |  |  | 	track_frame = animation.add_track(Animation.TYPE_VALUE) | 
					
						
							|  |  |  | 	animation.track_set_path(track_frame, "View:frame") | 
					
						
							|  |  |  | 	var animation_speed: float = Setting.animation_frame_rate | 
					
						
							|  |  |  | 	var animation_frame_count: int = sprite_frames.get_frame_count(animation_name) | 
					
						
							|  |  |  | 	animation.length = animation_speed * animation_frame_count | 
					
						
							|  |  |  | 	for i in range(0, animation_frame_count): | 
					
						
							|  |  |  | 		var time = i * animation_speed | 
					
						
							|  |  |  | 		animation.track_insert_key(track_frame, time, i) | 
					
						
							|  |  |  | 	animation.value_track_set_update_mode(track_sprite_frames, Animation.UPDATE_DISCRETE) | 
					
						
							|  |  |  | 	animation.value_track_set_update_mode(track_animation, Animation.UPDATE_DISCRETE) | 
					
						
							|  |  |  | 	animation.value_track_set_update_mode(track_frame, Animation.UPDATE_DISCRETE) | 
					
						
							|  |  |  | 	print("refresh_animation: ", animation_name, "(", animation_frame_count, " frames)") | 
					
						
							|  |  |  | 	ResourceSaver.save(animation, animation_path) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func get_all_skill() -> Array[SkillCfg]: | 
					
						
							|  |  |  | 	var ret: Array[SkillCfg] = [] | 
					
						
							|  |  |  | 	var dir_path: String = "res://config" | 
					
						
							|  |  |  | 	var dir: DirAccess = DirAccess.open(dir_path) | 
					
						
							|  |  |  | 	for sub_dir_name: String in dir.get_directories(): | 
					
						
							|  |  |  | 		if not sub_dir_name.begins_with("skill_"): | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		var sub_dir_path: String = dir_path + "/" + sub_dir_name | 
					
						
							|  |  |  | 		var sub_dir: DirAccess = DirAccess.open(sub_dir_path) | 
					
						
							|  |  |  | 		for file: String in sub_dir.get_files(): | 
					
						
							|  |  |  | 			var path: String = sub_dir_path + "/" + file | 
					
						
							|  |  |  | 			var res = load(path) | 
					
						
							|  |  |  | 			if res is SkillCfg: | 
					
						
							|  |  |  | 				ret.append(res) | 
					
						
							|  |  |  | 	return ret | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func get_all_skill_player_weapon() -> Array[SkillWeaponCfg]: | 
					
						
							|  |  |  | 	var ret: Array[SkillWeaponCfg] = [] | 
					
						
							|  |  |  | 	var dir_path: String = "res://config/skill_player_weapon" | 
					
						
							|  |  |  | 	var dir: DirAccess = DirAccess.open(dir_path) | 
					
						
							|  |  |  | 	for file: String in dir.get_files(): | 
					
						
							|  |  |  | 		var path: String = dir_path + "/" + file | 
					
						
							|  |  |  | 		var res = load(path) | 
					
						
							|  |  |  | 		if res is SkillWeaponCfg: | 
					
						
							|  |  |  | 			ret.append(res) | 
					
						
							|  |  |  | 	return ret | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func get_all_skill_player_basic() -> Array[SkillWeaponCfg]: | 
					
						
							|  |  |  | 	var ret: Array[SkillWeaponCfg] = [] | 
					
						
							|  |  |  | 	var dir_path: String = "res://config/skill_player_basic" | 
					
						
							|  |  |  | 	var dir: DirAccess = DirAccess.open(dir_path) | 
					
						
							|  |  |  | 	for file: String in dir.get_files(): | 
					
						
							|  |  |  | 		var path: String = dir_path + "/" + file | 
					
						
							|  |  |  | 		var res = load(path) | 
					
						
							|  |  |  | 		if res is SkillWeaponCfg: | 
					
						
							|  |  |  | 			ret.append(res) | 
					
						
							|  |  |  | 	return ret | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func get_skill_player_weapon_by_weapon(weapon: WeaponCfg) -> Array[SkillWeaponCfg]: | 
					
						
							|  |  |  | 	var ret: Array[SkillWeaponCfg] = [] | 
					
						
							|  |  |  | 	var dir_path: String = "res://config/skill_player_weapon" | 
					
						
							|  |  |  | 	var dir: DirAccess = DirAccess.open(dir_path) | 
					
						
							|  |  |  | 	for file: String in dir.get_files(): | 
					
						
							|  |  |  | 		var path: String = dir_path + "/" + file | 
					
						
							|  |  |  | 		var res = load(path) | 
					
						
							|  |  |  | 		if res is SkillWeaponCfg: | 
					
						
							|  |  |  | 			if res.weapon == weapon: | 
					
						
							|  |  |  | 				ret.append(res) | 
					
						
							|  |  |  | 	return ret | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func get_character_cfg_by_name(name: String) -> CharacterCfg: | 
					
						
							|  |  |  | 	var path_default: String = "res://config/character/%s.tres" % name | 
					
						
							|  |  |  | 	if ResourceLoader.exists(path_default): | 
					
						
							|  |  |  | 		var res = load(path_default) | 
					
						
							|  |  |  | 		if res is CharacterCfg: | 
					
						
							|  |  |  | 			return res | 
					
						
							|  |  |  | 	return null | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func get_level_active_scene_by_name(name: String) -> PackedScene: | 
					
						
							|  |  |  | 	var path_default: String = "res://scene/level_active/%s.tscn" % name | 
					
						
							|  |  |  | 	if ResourceLoader.exists(path_default): | 
					
						
							|  |  |  | 		var res = load(path_default) | 
					
						
							|  |  |  | 		return res | 
					
						
							|  |  |  | 	return null |