summaryrefslogtreecommitdiff
path: root/extractor
diff options
context:
space:
mode:
Diffstat (limited to 'extractor')
-rw-r--r--extractor/actions.gd1
-rw-r--r--extractor/extractor_interface.gd45
-rw-r--r--extractor/extractor_interface.tscn98
-rw-r--r--extractor/gnd_format.gd130
-rw-r--r--extractor/grf.gd49
-rw-r--r--extractor/rsm_format.gd65
-rw-r--r--extractor/rsw_format.gd71
7 files changed, 429 insertions, 30 deletions
diff --git a/extractor/actions.gd b/extractor/actions.gd
index 5c94cef..e5dafda 100644
--- a/extractor/actions.gd
+++ b/extractor/actions.gd
@@ -1,3 +1,4 @@
+class_name Actions
extends Node2D
diff --git a/extractor/extractor_interface.gd b/extractor/extractor_interface.gd
new file mode 100644
index 0000000..4d74a20
--- /dev/null
+++ b/extractor/extractor_interface.gd
@@ -0,0 +1,45 @@
+extends Control
+
+
+func _ready() -> void:
+ pass
+
+ var grf = GRF.open("res://client_data/data.grf")
+ #grf.extract("res://client_data")
+ grf.convert("res://client_data")
+
+ #Sprite.from_bytes(FileAccess.get_file_as_bytes("res://client_data/data/sprite/cursors.spr"))
+ #ActionFormat.from_bytes(
+ #ByteStream.from_bytes(
+ #FileAccess.get_file_as_bytes("res://client_data/data/sprite/cursors.act")
+ #)
+ #)
+ #GATFormat.from_bytes(
+ #ByteStream.from_bytes(
+ #FileAccess.get_file_as_bytes("res://client_data/data/int_land02.gat")
+ #)
+ #)
+ #GNDFormat.from_bytes(
+ #ByteStream.from_bytes(
+ #FileAccess.get_file_as_bytes("res://client_data/data/int_land02.gnd")
+ #)
+ #)
+ #var rsw = RSWFormat.from_bytes(
+ #ByteStream.from_bytes(
+ ##FileAccess.get_file_as_bytes("res://client_data/data/int_land02.rsw")
+ #FileAccess.get_file_as_bytes("res://client_data/data/pay_dun00.rsw")
+ #)
+ #)
+ #RSMFormat.from_bytes(
+ #ByteStream.from_bytes(
+ ##FileAccess.get_file_as_bytes("res://client_data/data/model/prontera/chair_01.rsm")
+ #FileAccess.get_file_as_bytes("res://client_data/data/model/izlude/iz_academy.rsm")
+ ## TODO: not parseable
+ ##FileAccess.get_file_as_bytes("res://client_data/data/model/graywolf/bridge_e_01.rsm2")
+ #)
+ #)
+
+ #var scene_root := rsw.convert("pay_dun00", "res://client_data")
+ #var scene := PackedScene.new()
+ #scene.pack(scene_root)
+ #ResourceSaver.save(scene, "res://extractor/test/pay_dun00.tscn")
diff --git a/extractor/extractor_interface.tscn b/extractor/extractor_interface.tscn
new file mode 100644
index 0000000..7220d5c
--- /dev/null
+++ b/extractor/extractor_interface.tscn
@@ -0,0 +1,98 @@
+[gd_scene load_steps=3 format=3 uid="uid://bfi14ujn6fe1n"]
+
+[ext_resource type="Script" uid="uid://db2yelol3joq0" path="res://extractor/extractor_interface.gd" id="1_hyoq1"]
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_hyoq1"]
+bg_color = Color(0.287085, 0.287085, 0.287085, 1)
+border_width_left = 1
+border_width_top = 1
+border_width_right = 1
+border_width_bottom = 1
+border_color = Color(0.47166, 0.47166, 0.471659, 1)
+
+[node name="ExtractorInterface" type="Control"]
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+script = ExtResource("1_hyoq1")
+
+[node name="HBoxContainer" type="HBoxContainer" parent="."]
+layout_mode = 2
+offset_left = 387.0
+offset_top = 307.0
+offset_right = 765.0
+offset_bottom = 340.0
+
+[node name="PanelContainer" type="PanelContainer" parent="HBoxContainer"]
+layout_mode = 2
+theme_override_styles/panel = SubResource("StyleBoxFlat_hyoq1")
+
+[node name="HBoxContainer" type="HBoxContainer" parent="HBoxContainer/PanelContainer"]
+layout_mode = 2
+theme_override_constants/separation = 0
+
+[node name="LineEdit" type="LineEdit" parent="HBoxContainer/PanelContainer/HBoxContainer"]
+layout_mode = 2
+text = "res://client_data/data.grf"
+expand_to_text_length = true
+
+[node name="Button" type="Button" parent="HBoxContainer/PanelContainer/HBoxContainer"]
+layout_mode = 2
+text = "Select File"
+
+[node name="Button" type="Button" parent="HBoxContainer"]
+layout_mode = 2
+text = "Open GRF"
+
+[node name="VBoxContainer" type="VBoxContainer" parent="."]
+layout_mode = 0
+offset_left = 386.0
+offset_top = 349.0
+offset_right = 754.0
+offset_bottom = 389.0
+
+[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer"]
+layout_mode = 2
+
+[node name="PanelContainer2" type="PanelContainer" parent="VBoxContainer/HBoxContainer2"]
+layout_mode = 2
+theme_override_styles/panel = SubResource("StyleBoxFlat_hyoq1")
+
+[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/HBoxContainer2/PanelContainer2"]
+layout_mode = 2
+theme_override_constants/separation = 0
+
+[node name="LineEdit" type="LineEdit" parent="VBoxContainer/HBoxContainer2/PanelContainer2/HBoxContainer"]
+layout_mode = 2
+text = "res://client_data"
+expand_to_text_length = true
+
+[node name="Button" type="Button" parent="VBoxContainer/HBoxContainer2/PanelContainer2/HBoxContainer"]
+layout_mode = 2
+text = "Select Directory"
+
+[node name="Button" type="Button" parent="VBoxContainer/HBoxContainer2"]
+layout_mode = 2
+text = "Extract GRF"
+
+[node name="ProgressBar" type="ProgressBar" parent="VBoxContainer"]
+layout_mode = 2
+
+[node name="Button" type="Button" parent="."]
+layout_mode = 0
+offset_left = 272.0
+offset_top = 433.0
+offset_right = 476.0
+offset_bottom = 464.0
+text = "Convert Sprites & Actions"
+
+[node name="Button2" type="Button" parent="."]
+layout_mode = 0
+offset_left = 498.0
+offset_top = 434.0
+offset_right = 614.0
+offset_bottom = 465.0
+text = "Convert Maps"
diff --git a/extractor/gnd_format.gd b/extractor/gnd_format.gd
index ea8d965..c49bce6 100644
--- a/extractor/gnd_format.gd
+++ b/extractor/gnd_format.gd
@@ -1,6 +1,9 @@
class_name GNDFormat
+const MAP_TILE_SIZE := 10.0
+
+
## Byte Length: 4 [br]
## GRAT
var signature: String = "GRGN"
@@ -88,7 +91,7 @@ static func from_bytes(bytes: ByteStream) -> GNDFormat:
gnd_format.texture_paths = []
for _n in gnd_format.texture_count:
gnd_format.texture_paths.append(
- bytes.get_string_from_ascii(gnd_format.texture_path_length)
+ bytes.get_string_from_ro(gnd_format.texture_path_length)
)
gnd_format.light_map_slice_count = bytes.decode_s32()
@@ -120,6 +123,76 @@ static func from_bytes(bytes: ByteStream) -> GNDFormat:
return gnd_format
+func get_cubes() -> Array:
+ # TODO: return custom type with helper functions for getting neighboring cubes and building a full cube
+
+ var cubes := []
+ for cube in ground_mesh_cubes:
+ cubes.append({
+ "cube": cube,
+ Vector3(0, 1, 0): {
+ "surface": surfaces[cube.upwards_facing_surface_index],
+ "mesh": surfaces[cube.upwards_facing_surface_index].get_mesh({
+ Vector2(0, 0): Vector3(0, cube.top_left_height, 0),
+ Vector2(1, 0): Vector3(MAP_TILE_SIZE, cube.top_right_height, 0),
+ Vector2(1, 1): Vector3(MAP_TILE_SIZE, cube.bottom_right_height, MAP_TILE_SIZE),
+ Vector2(0, 1): Vector3(0, cube.bottom_left_height, MAP_TILE_SIZE),
+ }),
+ },
+ })
+
+ return cubes
+
+
+func convert(data_path: String) -> GridMap:
+ var grid_map := GridMap.new()
+ grid_map.cell_size = Vector3(GNDFormat.MAP_TILE_SIZE, GNDFormat.MAP_TILE_SIZE, GNDFormat.MAP_TILE_SIZE)
+ grid_map.cell_center_x = false
+ grid_map.cell_center_y = false
+ grid_map.cell_center_z = false
+
+ grid_map.position = Vector3(
+ (width * MAP_TILE_SIZE) / 2.0,
+ 0,
+ -(height * MAP_TILE_SIZE) / 2.0,
+ )
+
+ var library := MeshLibrary.new()
+ grid_map.mesh_library = library
+
+ var cubes := get_cubes()
+
+ var cache := {}
+ # TODO: use texture_index and surface uvs as key
+ # TODO: for deduplication of cell items (as long as other sides aren't accounted for..)
+
+ for x in width:
+ for y in height:
+ var cube = cubes[x + y * width]
+
+ # TODO: get all sides of a cube and add that mesh to the library
+ # TODO: so a single mesh per cube
+ for surface_type in [Vector3(0, 1, 0)]:
+ var mesh: ArrayMesh = cube[surface_type].mesh
+ var material := StandardMaterial3D.new()
+ material.albedo_texture = load(
+ "%s/data/texture/%s" % [
+ data_path,
+ texture_paths[cube[surface_type].surface.texture_index]
+ ]
+ )
+
+ mesh.surface_set_material(0, material)
+
+ var id := library.get_last_unused_item_id()
+ library.create_item(id)
+ library.set_item_mesh(id, mesh)
+
+ grid_map.set_cell_item(Vector3(-x, 0, y), id)
+
+ return grid_map
+
+
class LightMapSlice:
## Byte Type: i32 [br]
## Byte Length: 4
@@ -229,6 +302,59 @@ class Surface:
)
+ func get_mesh(vertices: Dictionary[Vector2, Vector3]) -> ArrayMesh:
+ var surface_tool := SurfaceTool.new()
+ surface_tool.begin(Mesh.PRIMITIVE_TRIANGLES)
+
+ var uvs = get_uvs()
+ var color = get_vertex_color()
+
+ surface_tool.add_triangle_fan(
+ PackedVector3Array([
+ vertices[Vector2(0, 0)],
+ vertices[Vector2(1, 0)],
+ vertices[Vector2(1, 1)],
+ ]),
+ PackedVector2Array([
+ uvs[Vector2(0, 0)],
+ uvs[Vector2(1, 0)],
+ uvs[Vector2(1, 1)],
+ ]),
+ PackedColorArray([
+ color, color, color,
+ ])
+ )
+ surface_tool.add_triangle_fan(
+ PackedVector3Array([
+ vertices[Vector2(0, 0)],
+ vertices[Vector2(1, 1)],
+ vertices[Vector2(0, 1)],
+ ]),
+ PackedVector2Array([
+ uvs[Vector2(0, 0)],
+ uvs[Vector2(1, 1)],
+ uvs[Vector2(0, 1)],
+ ]),
+ PackedColorArray([
+ color, color, color,
+ ])
+ )
+
+ return surface_tool.commit()
+
+
+ func get_uv_id() -> String:
+ # TODO: add more data?
+ return (
+ "%d %d %d %d %d %d %d %d" % [
+ u_top_left, v_top_left,
+ u_top_right, v_top_right,
+ u_bottom_right, v_bottom_right,
+ u_bottom_left, v_bottom_left
+ ]
+ ).md5_text()
+
+
static func from_bytes(bytes: ByteStream) -> Surface:
var surface = Surface.new()
@@ -301,3 +427,5 @@ class GroundMeshCube:
#print(inst_to_dict(mesh))
return mesh
+
+ # TODO: convert function to build cube mesh? or at least with neighbor input build full cube struct
diff --git a/extractor/grf.gd b/extractor/grf.gd
index a723fdc..5b7046f 100644
--- a/extractor/grf.gd
+++ b/extractor/grf.gd
@@ -156,7 +156,7 @@ class FileEntry:
var file_access: FileAccess
-static func open(path: String):
+static func open(path: String) -> GRF:
var grf = GRF.new()
grf.file_access = FileAccess.open(path, FileAccess.ModeFlags.READ)
@@ -190,10 +190,13 @@ static func open(path: String):
return grf
+signal extracted_file(index: int)
+
func extract(destination: String = "user://client_data"):
DirAccess.make_dir_recursive_absolute(destination)
- for file_entry in file_entries:
+ for idx in file_entries.size():
+ var file_entry := file_entries[idx]
var file_path: String = file_entry.get_file_path()
var base_directory = DirAccess.open(destination)
@@ -201,6 +204,8 @@ func extract(destination: String = "user://client_data"):
var file = FileAccess.open("%s/%s" % [destination, file_path], FileAccess.WRITE_READ)
file.store_buffer(file_entry.get_contents(file_access))
+
+ extracted_file.emit(idx)
func convert(destination: String = "res://client_data"):
@@ -220,17 +225,40 @@ func convert(destination: String = "res://client_data"):
#DirAccess.make_dir_recursive_absolute(base_file_directory_path)
+ # BMP
+ if file_path.ends_with(".bmp"):
+ #continue
+ if not FileAccess.file_exists("%s/%s" % [destination, file_path]):
+ continue
+
+ # load existing bmp files, so language specific overwrites are kept
+
+ var texture: CompressedTexture2D = load("%s/%s" % [destination, file_path])
+ if not texture:
+ # TODO: check if .godot/imported file is there (alrdy sufficient?)
+ continue
+
+ var texture_image := texture.get_image()
+ texture_image.decompress()
+ var image := BMPTexture.convert_image(
+ texture_image,
+ [Color.MAGENTA]
+ )
+ image.save_png("%s/%s" % [destination, file_path.replace(".bmp", ".png")])
+
+
+ continue
# Sprite.spr and Action.act
- var player_head_path_part = "¸Ó¸®Åë"
- var player_body_path_part = "¸öÅë"
+ var player_head_path_part = "머리통"
+ var player_body_path_part = "몸통"
- if file_path.ends_with(".spr") and file_path.contains(player_head_path_part):
+ if file_path.ends_with(".spr"): #and (file_path.contains(player_head_path_part) or file_path.contains(player_body_path_part)):
continue
var sprite = SpriteFormat.from_bytes(file_entry.get_contents(file_access))
sprite.save_to_file(base_file_directory_path)
- elif file_path.ends_with(".act") and file_path.contains(player_head_path_part): #or file_path.contains(player_body_path_part):
+ elif file_path.ends_with(".act") and file_path.contains("cursors"): #and (file_path.contains(player_head_path_part) or file_path.contains(player_body_path_part)):
#continue
if not FileAccess.file_exists("%s/000.png.import" % base_file_directory_path):
continue
@@ -245,6 +273,7 @@ func convert(destination: String = "res://client_data"):
ResourceSaver.save(scene, "%s/actions.tscn" % base_file_directory_path)
+ continue
# Map.rsw and .gnd and .gat
if file_path.ends_with(".rsw") and (file_path.contains("pay_dun") or file_path.contains("iz_int") or file_path.contains("int_land")):
@@ -257,5 +286,9 @@ func convert(destination: String = "res://client_data"):
static func decode_string(bytes: PackedByteArray):
- # TODO: use iconv to decode EUC-KR
- return bytes.get_string_from_ascii()
+ Engine.print_error_messages = false
+ var string := bytes.get_string_from_multibyte_char("EUC-KR")
+ Engine.print_error_messages = true
+ if string.is_empty():
+ return bytes.get_string_from_ascii()
+ return string
diff --git a/extractor/rsm_format.gd b/extractor/rsm_format.gd
index cf83af9..7f16368 100644
--- a/extractor/rsm_format.gd
+++ b/extractor/rsm_format.gd
@@ -39,10 +39,12 @@ var texture_count: int
## Length: [member texture_count]
## Byte Length: 40
+## Versions: [<2.3]
var texture_names: Array[String]
## Byte Type: u8
## Byte Length: 40
+## Versions: [<2.2]
var root_node_name: String
## Byte Type: u32 [br]
@@ -90,23 +92,24 @@ static func from_bytes(bytes: ByteStream) -> RSMFormat:
rsm_format.texture_names = [] as Array[String]
for _n in rsm_format.texture_count:
- rsm_format.texture_names.append(bytes.get_string_from_utf8(40))
+ rsm_format.texture_names.append(bytes.get_string_from_ro(40))
- rsm_format.root_node_name = bytes.get_string_from_utf8(40)
+ if version.lower_than(2, 2):
+ rsm_format.root_node_name = bytes.get_string_from_ro(40)
if version.higher_than(2, 1): # >= 2.2
rsm_format.root_node_count = bytes.decode_u32()
rsm_format.root_node_names = [] as Array[String]
for _n in rsm_format.root_node_count:
- rsm_format.root_node_names.append(bytes.get_string_from_utf8(40))
+ rsm_format.root_node_names.append(bytes.get_string_from_ro(40))
rsm_format.node_count = bytes.decode_u32()
rsm_format.nodes = [] as Array[ModelNode]
for _n in rsm_format.node_count:
rsm_format.nodes.append(ModelNode.from_bytes(bytes, version))
- print(inst_to_dict(rsm_format))
+ #print(inst_to_dict(rsm_format))
#print(inst_to_dict(rsm_format.nodes[0].texture_coordinates[0]))
#rsm_format.nodes[0].texture_coordinates.clear()
#print(inst_to_dict(rsm_format.nodes[0].faces[0]))
@@ -115,12 +118,16 @@ static func from_bytes(bytes: ByteStream) -> RSMFormat:
return rsm_format
-func convert() -> Node3D:
- var node := Node3D.new()
- node.name = root_node_name
+func convert(data_path: String) -> Node3D:
+ var root_node := Node3D.new()
+ root_node.name = root_node_name
#node.set_script(load("res://extractor/model.gd"))
- return node
+ for model_node in nodes:
+ var node: Node = model_node.convert(texture_names, data_path)
+ root_node.add_child(node)
+
+ return root_node
class ModelNode:
@@ -171,6 +178,7 @@ class ModelNode:
## Byte Type: f32 [br]
## Byte Length: 4 [br]
## Versions: [<2.2]
+ ## Type: Radiants
var rotation_angle: float
## Byte Type: f32 [br]
@@ -245,7 +253,7 @@ class ModelNode:
var node = ModelNode.new()
node.node_name = bytes.get_string_from_utf8(40)
- node.parent_node_name = bytes.get_string_from_utf8(40)
+ node.parent_node_name = bytes.get_string_from_ro(40)
if version.lower_than(2, 3): # < 2.3
node.texture_count = bytes.decode_u32()
@@ -259,7 +267,7 @@ class ModelNode:
node.texture_names = [] as Array[String]
for _n in node.texture_name_count:
- node.texture_names.append(bytes.get_string_from_utf8(40))
+ node.texture_names.append(bytes.get_string_from_ro(40))
node.offset_matrix = [] as Array[Vector3]
for _in in 3:
@@ -345,6 +353,43 @@ class ModelNode:
node.textures_keyframes.append(TexturesKeyframe.from_bytes(bytes))
return node
+
+
+ func convert(textures: Array[String], data_path: String):
+ var node := MeshInstance3D.new()
+ node.name = node_name
+
+ node.translate(translation_2)
+
+ if rotation_axis != Vector3.ZERO:
+ node.rotation = (rotation_axis * rotation_angle) * Vector3(1,-1,1)
+
+ node.scale = scale
+
+ var surface_tool := SurfaceTool.new()
+ surface_tool.begin(Mesh.PRIMITIVE_TRIANGLES)
+
+ var mesh := ArrayMesh.new()
+ for idx in faces.size():
+ var face := faces[idx]
+
+ surface_tool.add_triangle_fan(
+ PackedVector3Array(face.vertex_position_indices.map(func(item_idx):
+ return vertex_positions[item_idx])
+ ),
+ PackedVector2Array(face.texture_coordinate_indices.map(func(item_idx):
+ return texture_coordinates[item_idx].coordinates)
+ )
+ )
+ surface_tool.commit(mesh)
+
+ var material := StandardMaterial3D.new()
+ material.albedo_texture = load("%s/data/texture/%s" % [data_path, textures[face.texture_index]])
+ mesh.surface_set_material(idx, material)
+
+ node.mesh = mesh
+
+ return node
class TextureCoordinate:
diff --git a/extractor/rsw_format.gd b/extractor/rsw_format.gd
index 831a1cb..7e70850 100644
--- a/extractor/rsw_format.gd
+++ b/extractor/rsw_format.gd
@@ -117,7 +117,43 @@ func convert(name: String, data_path: String) -> Node3D:
node.set_script(load("res://extractor/map.gd"))
for resource in map_resources:
- if resource is RSWFormat.SpatialAudioSource:
+ if resource is Animated3DModel:
+ var model_file_path := "%s/data/model/%s" % [data_path, resource.model_file]
+ if not FileAccess.file_exists(model_file_path):
+ continue
+
+ var rsm := RSMFormat.from_bytes(ByteStream.from_bytes(
+ FileAccess.get_file_as_bytes(model_file_path)
+ ))
+
+ var model_root := Node3D.new()
+ model_root.name = resource.name
+ model_root.position = resource.get_position() * Vector3(-1, 1, 1)
+ model_root.rotation_degrees = resource.get_rotation() * Vector3(-1,1,-1)
+ model_root.scale = resource.get_scale()
+
+ node.add_child(model_root)
+ model_root.owner = node
+
+ var model := rsm.convert(data_path)
+ model_root.add_child(model)
+ model.owner = node
+ for child in model.get_children():
+ child.owner = node
+
+ elif resource is DynamicLightSource:
+ continue
+ var light := OmniLight3D.new()
+ light.name = resource.name
+ light.position = resource.get_position()
+ light.light_color = resource.get_diffuse_color()
+ light.omni_range = resource.light_range
+
+ node.add_child(light)
+ light.owner = node
+
+ elif resource is SpatialAudioSource:
+ continue
var audio_file_path := "%s/data/wav/%s" % [data_path, resource.audio_file]
if not FileAccess.file_exists(audio_file_path):
continue
@@ -128,13 +164,23 @@ func convert(name: String, data_path: String) -> Node3D:
audio.position = resource.get_position()
audio.volume_linear = resource.volume_gain
audio.max_distance = resource.audio_range
+
node.add_child(audio, true)
audio.owner = node
+
+ elif resource is ParticleEffectEmitter:
+ continue
+ var particles := CPUParticles3D.new()
+ particles.name = resource.name
+ particles.position = resource.get_position()
+
+ node.add_child(particles, true)
+ particles.owner = node
- var surface_tool := SurfaceTool.new()
- for surface: GNDFormat.Surface in gnd.surfaces:
- pass
- #surface_tool.add_vertex()
+ var grid_map := gnd.convert(data_path)
+ grid_map.name = "Ground"
+ node.add_child(grid_map)
+ grid_map.owner = node
return node
@@ -312,14 +358,17 @@ class Animated3DModel extends MapResource:
## Byte Type: f32 [br]
## Byte Length: 4
+ ## Type: Degrees
var rotation_x: float
## Byte Type: f32 [br]
## Byte Length: 4
+ ## Type: Degrees
var rotation_y: float
## Byte Type: f32 [br]
## Byte Length: 4
+ ## Type: Degrees
var rotation_z: float
## Byte Type: f32 [br]
@@ -350,11 +399,11 @@ class Animated3DModel extends MapResource:
static func from_bytes(bytes: ByteStream) -> Animated3DModel:
var resource = Animated3DModel.new()
- resource.name = bytes.get_string_from_ascii(40)
+ resource.name = bytes.get_string_from_ro(40)
resource.animation_type = bytes.decode_u32()
resource.animation_speed_percent = bytes.decode_float()
resource.collision_flags = bytes.decode_u32()
- resource.model_file = bytes.get_string_from_ascii(80)
+ resource.model_file = bytes.get_string_from_ro(80)
resource.root_node_name = bytes.get_string_from_utf8(80)
resource.position_x = bytes.decode_float()
resource.position_y = bytes.decode_float()
@@ -415,7 +464,7 @@ class DynamicLightSource extends MapResource:
static func from_bytes(bytes: ByteStream) -> DynamicLightSource:
var resource = DynamicLightSource.new()
- resource.name = bytes.get_string_from_ascii(80)
+ resource.name = bytes.get_string_from_ro(80)
resource.position_x = bytes.decode_float()
resource.position_y = bytes.decode_float()
resource.position_z = bytes.decode_float()
@@ -481,8 +530,8 @@ class SpatialAudioSource extends MapResource:
static func from_bytes(bytes: ByteStream) -> SpatialAudioSource:
var resource = SpatialAudioSource.new()
- resource.name = bytes.get_string_from_ascii(80)
- resource.audio_file = bytes.get_string_from_ascii(80)
+ resource.name = bytes.get_string_from_ro(80)
+ resource.audio_file = bytes.get_string_from_ro(80)
resource.position_x = bytes.decode_float()
resource.position_y = bytes.decode_float()
resource.position_z = bytes.decode_float()
@@ -546,7 +595,7 @@ class ParticleEffectEmitter extends MapResource:
static func from_bytes(bytes: ByteStream) -> ParticleEffectEmitter:
var resource = ParticleEffectEmitter.new()
- resource.name = bytes.get_string_from_ascii(80)
+ resource.name = bytes.get_string_from_ro(80)
resource.position_x = bytes.decode_float()
resource.position_y = bytes.decode_float()
resource.position_z = bytes.decode_float()