summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--byte_stream.gd3
-rw-r--r--client.gd11
-rw-r--r--extensions/rust/.gdignore0
-rw-r--r--extractor/action_format.gd2
-rw-r--r--extractor/gat_format.gd8
-rw-r--r--extractor/gnd_format.gd294
-rw-r--r--extractor/rsw_format.gd519
-rw-r--r--packets/map_server/moving_entity_appeared_packet.gd181
-rw-r--r--ui/login.tscn2
9 files changed, 1012 insertions, 8 deletions
diff --git a/byte_stream.gd b/byte_stream.gd
index 2ef85d2..219e977 100644
--- a/byte_stream.gd
+++ b/byte_stream.gd
@@ -97,3 +97,6 @@ func decode_float() -> float:
func get_string_from_utf8(length: int) -> String:
return get_buffer(length).bytes.get_string_from_utf8()
+
+func get_string_from_ascii(length: int) -> String:
+ return get_buffer(length).bytes.get_string_from_ascii()
diff --git a/client.gd b/client.gd
index 0d9766b..5025c8c 100644
--- a/client.gd
+++ b/client.gd
@@ -26,3 +26,14 @@ func _ready() -> void:
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")
+ )
+ )
+ 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")
+ )
+ )
diff --git a/extensions/rust/.gdignore b/extensions/rust/.gdignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/extensions/rust/.gdignore
diff --git a/extractor/action_format.gd b/extractor/action_format.gd
index 97f6771..d61c590 100644
--- a/extractor/action_format.gd
+++ b/extractor/action_format.gd
@@ -49,7 +49,7 @@ func get_byte_length() -> int:
static func from_bytes(bytes: ByteStream) -> ActionFormat:
var action_format = ActionFormat.new()
- bytes.seek(2)
+ bytes.advance(action_format.signature.length())
@warning_ignore("shadowed_variable")
var version = Version.new()
diff --git a/extractor/gat_format.gd b/extractor/gat_format.gd
index 213972a..712657b 100644
--- a/extractor/gat_format.gd
+++ b/extractor/gat_format.gd
@@ -45,22 +45,22 @@ static func from_bytes(bytes: ByteStream) -> GATFormat:
class Tile:
## Byte Type: f32 [br]
## Byte Length: 4 [br]
- ## Orignal Coordinates_ (0, 0)
+ ## Orignal Coordinates: (0, 0)
var bottom_left_altitude: int
## Byte Type: f32 [br]
## Byte Length: 4 [br]
- ## Orignal Coordinates_ (1, 0)
+ ## Orignal Coordinates: (1, 0)
var bottom_right_altitude: int
## Byte Type: f32 [br]
## Byte Length: 4 [br]
- ## Orignal Coordinates_ (0, 1)
+ ## Orignal Coordinates: (0, 1)
var top_left_altitude: int
## Byte Type: f32 [br]
## Byte Length: 4 [br]
- ## Orignal Coordinates_ (1, 1)
+ ## Orignal Coordinates: (1, 1)
var top_right_altitude: int
## Byte Type: u32 ?[br]
diff --git a/extractor/gnd_format.gd b/extractor/gnd_format.gd
new file mode 100644
index 0000000..f13956e
--- /dev/null
+++ b/extractor/gnd_format.gd
@@ -0,0 +1,294 @@
+class_name GNDFormat
+
+
+## Byte Length: 4 [br]
+## GRAT
+var signature: String = "GRGN"
+
+## Byte Type: u8 [br]
+## Byte Length: 2
+var version: Version
+
+## Byte Type: i32 [br]
+## Byte Length: 4
+var width: int
+
+## Byte Type: i32 [br]
+## Byte Length: 4
+var height: int
+
+## Byte Type: f32 [br]
+## Byte Length: 4 [br]
+## Always 10.
+var scale: float
+
+## Byte Type: i32 [br]
+## Byte Length: 4
+var texture_count: int
+
+## Byte Type: i32 [br]
+## Byte Length: 4
+## Always 80.
+var texture_path_length: int
+
+## Byte Length: [member texture_count] * [member texture_path_length] [br]
+var texture_paths: Array
+
+## Byte Type: i32 [br]
+## Byte Length: 4
+var light_map_slice_count: int
+
+## Byte Type: i32 [br]
+## Byte Length: 4
+var light_map_width: int
+
+## Byte Type: i32 [br]
+## Byte Length: 4
+var light_map_slice_height: int
+
+## Byte Type: i32 [br]
+## Byte Length: 4
+var light_map_cells_per_grid: int
+
+## Length: [member light_map_slice_count]
+var light_map_slices: Array
+
+## Byte Type: i32 [br]
+## Byte Length: 4
+var surface_count: int
+
+## Length: [member surface_count]
+var surfaces: Array[Surface]
+
+## Length: [member width] * [member height]
+var ground_mesh_cubes: Array[GroundMeshCube]
+
+
+static func from_bytes(bytes: ByteStream) -> GNDFormat:
+ var gnd_format = GNDFormat.new()
+
+ bytes.advance(gnd_format.signature.length())
+
+ @warning_ignore("shadowed_variable")
+ var version = Version.new()
+ version.major = bytes.decode_u8()
+ version.minor = bytes.decode_u8()
+ gnd_format.version = version
+
+ if version.minor > 7:
+ print(version)
+ return gnd_format
+
+ gnd_format.width = bytes.decode_s32()
+ gnd_format.height = bytes.decode_s32()
+ gnd_format.scale = bytes.decode_float()
+ gnd_format.texture_count = bytes.decode_s32()
+ gnd_format.texture_path_length = bytes.decode_s32()
+
+ 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)
+ )
+
+ gnd_format.light_map_slice_count = bytes.decode_s32()
+ gnd_format.light_map_width = bytes.decode_s32()
+ gnd_format.light_map_slice_height = bytes.decode_s32()
+ gnd_format.light_map_cells_per_grid = bytes.decode_s32()
+
+ #gnd_format.light_map_slices = []
+ #for _n in gnd_format.light_map_slice_count:
+ #gnd_format.light_map_slices.append(LightMapSlice.from_bytes(bytes))
+ bytes.advance(
+ gnd_format.light_map_slice_count *
+ gnd_format.light_map_width *
+ gnd_format.light_map_slice_height *
+ 4
+ )
+
+ gnd_format.surface_count = bytes.decode_s32()
+
+ gnd_format.surfaces = [] as Array[Surface]
+ for _n in gnd_format.surface_count:
+ gnd_format.surfaces.append(Surface.from_bytes(bytes))
+
+ gnd_format.ground_mesh_cubes = [] as Array[GroundMeshCube]
+ for _n in (gnd_format.width * gnd_format.height):
+ gnd_format.ground_mesh_cubes.append(GroundMeshCube.from_bytes(bytes))
+
+ #print(inst_to_dict(gnd_format))
+ return gnd_format
+
+
+class LightMapSlice:
+ ## Byte Type: i32 [br]
+ ## Byte Length: 4
+ var pixel_format: int
+
+ ## Byte Type: i32 [br]
+ ## Byte Length: 4
+ var width: int
+
+ ## Byte Type: i32 [br]
+ ## Byte Length: 4
+ var height: int
+
+ ## Byte Length: [member width] * [member height]
+ var shadow_map_pixels: ByteStream
+
+ ## Byte Length: [member width] * [member height]
+ var light_map_pixels: ByteStream
+
+
+ static func from_bytes(bytes: ByteStream) -> LightMapSlice:
+ var slice = LightMapSlice.new()
+
+ slice.pixel_format = bytes.decode_s32()
+ slice.width = bytes.decode_s32()
+ slice.height = bytes.decode_s32()
+ slice.shadow_map_pixels = bytes.get_buffer(slice.width * slice.height)
+ slice.light_map_pixels = bytes.get_buffer(slice.width * slice.height)
+
+ #print(inst_to_dict(slice))
+ return slice
+
+
+class Surface:
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var u_bottom_left: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var u_bottom_right: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var u_top_left: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var u_top_right: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var v_bottom_left: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var v_bottom_right: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var v_top_left: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var v_top_right: float
+
+ ## Byte Type: i16 [br]
+ ## Byte Length: 2
+ var texture_index: int
+
+ ## Byte Type: i16 [br]
+ ## Byte Length: 2
+ var light_map_index: int
+
+ ## Byte Type: u8 [br]
+ ## Byte Length: 1
+ var vertex_color_blue: int
+
+ ## Byte Type: u8 [br]
+ ## Byte Length: 1
+ var vertex_color_green: int
+
+ ## Byte Type: u8 [br]
+ ## Byte Length: 1
+ var vertex_color_red: int
+
+ ## Byte Type: u8 [br]
+ ## Byte Length: 1
+ var vertex_color_alpha: int
+
+
+ func get_uvs() -> Dictionary: # Dictionary[Vector2, Vector2]
+ return {
+ Vector2(0, 0): Vector2(u_top_left, v_top_left),
+ Vector2(1, 0): Vector2(u_top_right, v_top_right),
+ Vector2(0, 1): Vector2(u_bottom_left, v_bottom_left),
+ Vector2(1, 1): Vector2(u_bottom_right, v_bottom_right),
+ }
+
+
+ static func from_bytes(bytes: ByteStream) -> Surface:
+ var surface = Surface.new()
+
+ surface.u_bottom_left = bytes.decode_float()
+ surface.u_bottom_right = bytes.decode_float()
+ surface.u_top_left = bytes.decode_float()
+ surface.u_top_right = bytes.decode_float()
+ surface.v_bottom_left = bytes.decode_float()
+ surface.v_bottom_right = bytes.decode_float()
+ surface.v_top_left = bytes.decode_float()
+ surface.v_top_right = bytes.decode_float()
+ surface.texture_index = bytes.decode_s16()
+ surface.light_map_index = bytes.decode_s16()
+ surface.vertex_color_blue = bytes.decode_u8()
+ surface.vertex_color_green = bytes.decode_u8()
+ surface.vertex_color_red = bytes.decode_u8()
+ surface.vertex_color_alpha = bytes.decode_u8()
+
+ #print(inst_to_dict(surface))
+ return surface
+
+
+class GroundMeshCube:
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ ## upper left?
+ var bottom_left_height: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ ## upper right?
+ var bottom_right_height: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ ## lower left?
+ var top_left_height: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ ## lower right?
+ var top_right_height: float
+
+ ## Byte Type: i32 [br]
+ ## Byte Length: 4
+ ## top surface index?
+ var upwards_facing_surface_index: int
+
+ ## Byte Type: i32 [br]
+ ## Byte Length: 4
+ ## front surface index?
+ var northern_wall_surface_index: int
+
+ ## Byte Type: i32 [br]
+ ## Byte Length: 4
+ ## right surface index?
+ var eastern_wall_surface_index: int
+
+
+ static func from_bytes(bytes: ByteStream) -> GroundMeshCube:
+ var mesh = GroundMeshCube.new()
+
+ mesh.bottom_left_height = bytes.decode_float()
+ mesh.bottom_right_height = bytes.decode_float()
+ mesh.top_left_height = bytes.decode_float()
+ mesh.top_right_height = bytes.decode_float()
+ mesh.upwards_facing_surface_index = bytes.decode_s32()
+ mesh.northern_wall_surface_index = bytes.decode_s32()
+ mesh.eastern_wall_surface_index = bytes.decode_s32()
+
+ #print(inst_to_dict(mesh))
+ return mesh
diff --git a/extractor/rsw_format.gd b/extractor/rsw_format.gd
new file mode 100644
index 0000000..18874e2
--- /dev/null
+++ b/extractor/rsw_format.gd
@@ -0,0 +1,519 @@
+class_name RSWFormat
+
+
+## Byte Length: 4 [br]
+## GRAT
+var signature: String = "GRSW"
+
+## Byte Type: u8 [br]
+## Byte Length: 2
+var version: Version
+
+## Byte Type: u8, u32 [br]
+## Byte Length: 1, 4
+## Versions: [2.2, 2.5]
+var build_number: int
+
+## Byte Type: u8 [br]
+## Byte Length: 1
+## Versions: [2.5]
+var unknown_render_flag: int
+
+## Byte Type: u8 [br]
+## Byte Length: 40
+var ini_file: String
+
+## Byte Type: u8 [br]
+## Byte Length: 40
+var gnd_file: String
+
+## Byte Type: u8 [br]
+## Byte Length: 40
+var gat_file: String
+
+## Byte Type: u8 [br]
+## Byte Length: 40
+## Versions: [1.4]
+var source_file: String
+
+var water_configuration: WaterConfiguration
+var lighting_parameters: LightingParameters
+
+## Byte Type: u32 [br]
+## Byte Length: 4
+var map_resource_count: int
+
+## Length: [member map_resource_count]
+var map_resources: Array[MapResource]
+
+var quad_tree
+
+
+static func from_bytes(bytes: ByteStream) -> RSWFormat:
+ var rsw_format = RSWFormat.new()
+
+ bytes.advance(rsw_format.signature.length())
+
+ @warning_ignore("shadowed_variable")
+ var version = Version.new()
+ version.major = bytes.decode_u8()
+ version.minor = bytes.decode_u8()
+ rsw_format.version = version
+
+ if version.major < 2:
+ print(version)
+ return rsw_format
+
+ if version.major >= 2 and version.minor >= 5:
+ rsw_format.build_number = bytes.decode_u32()
+ rsw_format.unknown_render_flag = bytes.decode_u8()
+ elif version.major >= 2 and version.minor >= 2:
+ rsw_format.build_number = bytes.decode_u8()
+
+ rsw_format.ini_file = bytes.get_string_from_utf8(40)
+ rsw_format.gnd_file = bytes.get_string_from_utf8(40)
+ rsw_format.gat_file = bytes.get_string_from_utf8(40)
+ rsw_format.source_file = bytes.get_string_from_utf8(40)
+
+ if version.major >= 2 and version.minor <= 5:
+ rsw_format.water_configuration = WaterConfiguration.from_bytes(bytes)
+
+ rsw_format.lighting_parameters = LightingParameters.from_bytes(bytes)
+
+ bytes.advance(16) # map boundaries - bounding box # TODO
+
+ rsw_format.map_resource_count = bytes.decode_u32()
+ rsw_format.map_resources = [] as Array[MapResource]
+ for _n in rsw_format.map_resource_count:
+ var resource_type = bytes.decode_u32()
+ var resource: MapResource
+
+ if resource_type == MapResourceType.Animated3DModel:
+ resource = Animated3DModel.from_bytes(bytes)
+ elif resource_type == MapResourceType.DynamicLightSource:
+ resource = DynamicLightSource.from_bytes(bytes)
+ elif resource_type == MapResourceType.SpatialAudioSource:
+ resource = SpatialAudioSource.from_bytes(bytes)
+ elif resource_type == MapResourceType.ParticleEffectEmitter:
+ resource = ParticleEffectEmitter.from_bytes(bytes)
+
+ rsw_format.map_resources.append(resource)
+
+ # TODO: quadtree
+
+ #print(inst_to_dict(rsw_format))
+ return rsw_format
+
+
+class WaterConfiguration:
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var water_level: int
+
+ ## Byte Type: i32 [br]
+ ## Byte Length: 4
+ var water_type: int
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var wave_height: int
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var wave_speed: int
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var wave_pitch: int
+
+ ## Byte Type: i32 [br]
+ ## Byte Length: 4
+ var water_animation_speed: int
+
+
+ static func from_bytes(bytes: ByteStream) -> WaterConfiguration:
+ var config = WaterConfiguration.new()
+
+ config.water_level = bytes.decode_float()
+ config.water_type = bytes.decode_u32()
+ config.wave_height = bytes.decode_float()
+ config.wave_speed = bytes.decode_float()
+ config.wave_pitch = bytes.decode_float()
+ config.water_animation_speed = bytes.decode_u32()
+
+ return config
+
+
+class LightingParameters:
+ ## Byte Type: i32 [br]
+ ## Byte Length: 4
+ var longitude: int
+
+ ## Byte Type: i32 [br]
+ ## Byte Length: 4
+ var latitude: int
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var diffuse_color_r: int
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var diffuse_color_g: int
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var diffuse_color_b: int
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var ambient_color_r: int
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var ambient_color_g: int
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var ambient_color_b: int
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ ## Shadow Map Alpha
+ var intensity: int
+
+
+ func get_diffuse_color() -> Color:
+ return Color(diffuse_color_r, diffuse_color_g, diffuse_color_b)
+
+
+ func get_ambient_color() -> Color:
+ return Color(ambient_color_r, ambient_color_g, ambient_color_b)
+
+
+ static func from_bytes(bytes: ByteStream) -> LightingParameters:
+ var params = LightingParameters.new()
+
+ params.longitude = bytes.decode_s32()
+ params.latitude = bytes.decode_s32()
+ params.diffuse_color_r = bytes.decode_float()
+ params.diffuse_color_g = bytes.decode_float()
+ params.diffuse_color_b = bytes.decode_float()
+ params.ambient_color_r = bytes.decode_float()
+ params.ambient_color_g = bytes.decode_float()
+ params.ambient_color_b = bytes.decode_float()
+ params.intensity = bytes.decode_float()
+
+ return params
+
+
+class MapResource:
+ pass
+
+enum MapResourceType {
+ Animated3DModel = 1,
+ DynamicLightSource = 2,
+ SpatialAudioSource = 3,
+ ParticleEffectEmitter = 4,
+}
+
+enum ModelAnimationType {
+ None = 0,
+ Looping = 2,
+}
+
+enum ParticlePresetEffect {
+ None = -1,
+ Hit_1 = 1,
+ Hit_2 = 2,
+ Hit_3 = 3,
+ Torch = 47,
+ TunaParty = 1097,
+}
+
+
+class Animated3DModel extends MapResource:
+ ## Byte Type: u8 [br]
+ ## Byte Length: 40
+ var name: String
+
+ ## Byte Type: u32 [br]
+ ## Byte Length: 4
+ var animation_type: ModelAnimationType
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var animation_speed_percent: float
+
+ ## Byte Type: u32 [br]
+ ## Byte Length: 4
+ var collision_flags: int
+
+ ## Byte Type: u8 [br]
+ ## Byte Length: 80
+ var model_file: String
+
+ ## Byte Type: u8 [br]
+ ## Byte Length: 80
+ var root_node_name: String
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var position_x: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var position_y: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var position_z: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var rotation_x: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var rotation_y: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var rotation_z: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var scale_x: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var scale_y: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var scale_z: float
+
+
+ func get_position() -> Vector3:
+ return Vector3(position_x, position_y, position_z)
+
+
+ func get_rotation() -> Vector3:
+ return Vector3(rotation_x, rotation_y, rotation_z)
+
+
+ func get_scale() -> Vector3:
+ return Vector3(scale_x, scale_y, scale_z)
+
+
+ static func from_bytes(bytes: ByteStream) -> Animated3DModel:
+ var resource = Animated3DModel.new()
+
+ resource.name = bytes.get_string_from_ascii(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.root_node_name = bytes.get_string_from_utf8(80)
+ resource.position_x = bytes.decode_float()
+ resource.position_y = bytes.decode_float()
+ resource.position_z = bytes.decode_float()
+ resource.rotation_x = bytes.decode_float()
+ resource.rotation_y = bytes.decode_float()
+ resource.rotation_z = bytes.decode_float()
+ resource.scale_x = bytes.decode_float()
+ resource.scale_y = bytes.decode_float()
+ resource.scale_z = bytes.decode_float()
+
+ #print(inst_to_dict(resource))
+ return resource
+
+
+class DynamicLightSource extends MapResource:
+ ## Byte Type: u8 [br]
+ ## Byte Length: 80
+ var name: String
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var position_x: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var position_y: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var position_z: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var diffuse_color_r: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var diffuse_color_g: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var diffuse_color_b: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var light_range: float
+
+
+ func get_position() -> Vector3:
+ return Vector3(position_x, position_y, position_z)
+
+
+ func get_diffuse_color() -> Color:
+ return Color(diffuse_color_r, diffuse_color_g, diffuse_color_b)
+
+
+ static func from_bytes(bytes: ByteStream) -> DynamicLightSource:
+ var resource = DynamicLightSource.new()
+
+ resource.name = bytes.get_string_from_ascii(80)
+ resource.position_x = bytes.decode_float()
+ resource.position_y = bytes.decode_float()
+ resource.position_z = bytes.decode_float()
+ resource.diffuse_color_r = bytes.decode_float()
+ resource.diffuse_color_g = bytes.decode_float()
+ resource.diffuse_color_b = bytes.decode_float()
+ resource.light_range = bytes.decode_float()
+
+ #print(inst_to_dict(resource))
+ return resource
+
+
+class SpatialAudioSource extends MapResource:
+ ## Byte Type: u8 [br]
+ ## Byte Length: 80
+ var name: String
+
+ ## Byte Type: u8 [br]
+ ## Byte Length: 80
+ var audio_file: String
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var position_x: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var position_y: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var position_z: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var volume_gain: float
+
+ ## Byte Type: u32 [br]
+ ## Byte Length: 4
+ var width: int
+
+ ## Byte Type: u32 [br]
+ ## Byte Length: 4
+ var height: int
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var audio_range: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var duration: float
+
+
+ func get_position() -> Vector3:
+ return Vector3(position_x, position_y, position_z)
+
+
+ func get_size() -> Vector2:
+ return Vector2(width, height)
+
+
+ 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.position_x = bytes.decode_float()
+ resource.position_y = bytes.decode_float()
+ resource.position_z = bytes.decode_float()
+ resource.volume_gain = bytes.decode_float()
+ resource.width = bytes.decode_u32()
+ resource.height = bytes.decode_u32()
+ resource.audio_range = bytes.decode_float()
+ resource.duration = bytes.decode_float()
+
+ return resource
+
+
+class ParticleEffectEmitter extends MapResource:
+ ## Byte Type: u8 [br]
+ ## Byte Length: 80
+ var name: String
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var position_x: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var position_y: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var position_z: float
+
+ @warning_ignore("enum_variable_without_default")
+ ## Byte Type: u32 [br]
+ ## Byte Length: 4
+ var preset_effect: ParticlePresetEffect
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4 [br]
+ ## in frames; 60 means 1 second
+ var emission_delay: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var launch_parameter_a: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var launch_parameter_b: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var launch_parameter_c: float
+
+ ## Byte Type: f32 [br]
+ ## Byte Length: 4
+ var launch_parameter_d: float
+
+
+ func get_position() -> Vector3:
+ return Vector3(position_x, position_y, position_z)
+
+
+ static func from_bytes(bytes: ByteStream) -> ParticleEffectEmitter:
+ var resource = ParticleEffectEmitter.new()
+
+ resource.name = bytes.get_string_from_ascii(80)
+ resource.position_x = bytes.decode_float()
+ resource.position_y = bytes.decode_float()
+ resource.position_z = bytes.decode_float()
+ resource.preset_effect = bytes.decode_u32()
+ resource.emission_delay = bytes.decode_float()
+ resource.launch_parameter_a = bytes.decode_float()
+ resource.launch_parameter_b = bytes.decode_float()
+ resource.launch_parameter_c = bytes.decode_float()
+ resource.launch_parameter_d = bytes.decode_float()
+
+ return resource
diff --git a/packets/map_server/moving_entity_appeared_packet.gd b/packets/map_server/moving_entity_appeared_packet.gd
index 50afaf5..4ff9a9e 100644
--- a/packets/map_server/moving_entity_appeared_packet.gd
+++ b/packets/map_server/moving_entity_appeared_packet.gd
@@ -21,12 +21,187 @@ var object_type: int
## Byte Length: 4
var entity_id: int
-# TODO
+## Byte Type: u32
+## Byte Length: 4
+var group_id: int
+## Byte Type: u16
+## Byte Length: 2
+var movement_speed: int
+
+## Byte Type: u16
+## Byte Length: 2
+var body_state: int
+
+## Byte Type: u16
+## Byte Length: 2
+var health_state: int
+
+## Byte Type: u32
+## Byte Length: 4
+var effect_state: int
+
+## Byte Type: u16
+## Byte Length: 2
+var job: int
+
+## Byte Type: u16
+## Byte Length: 2
+var head: int
+
+## Byte Type: u32
+## Byte Length: 4
+var weapon: int
+
+## Byte Type: u32
+## Byte Length: 4
+var shield: int
+
+## Byte Type: u16
+## Byte Length: 2
+var accessory: int
+
+## Byte Type: u32
+## Byte Length: 4
+var move_start_time: int
+
+## Byte Type: u16
+## Byte Length: 2
+var accessory2: int
+
+## Byte Type: u16
+## Byte Length: 2
+var accessory3: int
+
+## Byte Type: u16
+## Byte Length: 2
+var head_palette: int
+
+## Byte Type: u16
+## Byte Length: 2
+var body_palette: int
+
+## Byte Type: u16
+## Byte Length: 2
+var head_direction: int
+
+## Byte Type: u16
+## Byte Length: 2
+var robe: int
-static func from_bytes(bytes: PackedByteArray) -> MovingEntityAppearedPacket:
+## Byte Type: u32
+## Byte Length: 4
+var guild_id: int
+
+## Byte Type: u16
+## Byte Length: 2
+var emblem_version: int
+
+## Byte Type: u16
+## Byte Length: 2
+var honor: int
+
+## Byte Type: u32
+## Byte Length: 4
+var virtue: int
+
+## Byte Type: u8
+## Byte Length: 1
+var is_pk_mode_on: bool
+
+## Byte Type: u8
+## Byte Length: 1
+var gender: Constants.Gender
+
+## Byte Type: u8
+## Byte Length: 6
+var position: PackedByteArray
+
+## Byte Type: u8
+## Byte Length: 1
+var size_x: int
+
+## Byte Type: u8
+## Byte Length: 1
+var size_y: int
+
+## Byte Type: u16
+## Byte Length: 2
+var c_level: int
+
+## Byte Type: u16
+## Byte Length: 2
+var font: int
+
+## Byte Type: i32
+## Byte Length: 4
+var maximum_health_points: int
+
+## Byte Type: i32
+## Byte Length: 4
+var health_points: int
+
+## Byte Type: u8
+## Byte Length: 1
+var is_boss: bool
+
+## Byte Type: u16
+## Byte Length: 2
+var body: int
+
+## Byte Length: 24
+var name: String
+
+
+func get_size() -> Vector2:
+ return Vector2(
+ size_x,
+ size_y
+ )
+
+
+static func from_bytes(pbytes: PackedByteArray) -> MovingEntityAppearedPacket:
+ var bytes := ByteStream.from_bytes(pbytes)
+
var packet = MovingEntityAppearedPacket.new()
- packet.packet_length = bytes.decode_u16(2)
+ bytes.advance(2) # skip header
+
+ packet.packet_length = bytes.decode_u16()
+ packet.object_type = bytes.decode_u8()
+ packet.entity_id = bytes.decode_u32()
+ packet.group_id = bytes.decode_u32()
+ packet.movement_speed = bytes.decode_u16()
+ packet.body_state = bytes.decode_u16()
+ packet.health_state = bytes.decode_u16()
+ packet.effect_state = bytes.decode_u32()
+ packet.job = bytes.decode_u16()
+ packet.head = bytes.decode_u16()
+ packet.weapon = bytes.decode_u32()
+ packet.shield = bytes.decode_u32()
+ packet.accessory = bytes.decode_u16()
+ packet.move_start_time = bytes.decode_u32()
+ packet.accessory2 = bytes.decode_u16()
+ packet.accessory3 = bytes.decode_u16()
+ packet.head_palette = bytes.decode_u16()
+ packet.body_palette = bytes.decode_u16()
+ packet.head_direction = bytes.decode_u16()
+ packet.robe = bytes.decode_u16()
+ packet.guild_id = bytes.decode_u32()
+ packet.emblem_version = bytes.decode_u16()
+ packet.honor = bytes.decode_u16()
+ packet.virtue = bytes.decode_u32()
+ packet.is_pk_mode_on = bytes.decode_u8()
+ packet.gender = bytes.decode_u8()
+ packet.position = bytes.get_buffer(6).bytes
+ packet.size_x = bytes.decode_u8()
+ packet.size_y = bytes.decode_u8()
+ packet.c_level = bytes.decode_u16()
+ packet.font = bytes.decode_u16()
+ packet.maximum_health_points = bytes.decode_s32()
+ packet.health_points = bytes.decode_s32()
+ packet.is_boss = bytes.decode_u8()
+ packet.body = bytes.decode_u16()
+ packet.name = bytes.get_string_from_utf8(24)
return packet
diff --git a/ui/login.tscn b/ui/login.tscn
index c38df26..66bdd70 100644
--- a/ui/login.tscn
+++ b/ui/login.tscn
@@ -66,6 +66,8 @@ custom_minimum_size = Vector2(100, 0)
layout_mode = 2
text = "ragnarok"
placeholder_text = "Password"
+secret = true
+secret_character = "ยง"
[node name="Login" type="Button" parent="Login/PanelContainer/MarginContainer/VBoxContainer"]
layout_mode = 2