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, } enum QuadTreeQuadrant { BottomLeft = 0, BottomRight = 1, TopLeft = 2, TopRight = 3, } 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 class QuadTree: ## Byte Type: f32 [br] ## Byte Length: 4 [br] ## coordinate of the corner at the lowest altitude var bottom_x: float ## Byte Type: f32 [br] ## Byte Length: 4 var bottom_y: float ## Byte Type: f32 [br] ## Byte Length: 4 var bottom_z: float ## Byte Type: f32 [br] ## Byte Length: 4 [br] ## coordinate of the corner at the highest altitude var top_x: float ## Byte Type: f32 [br] ## Byte Length: 4 var top_y: float ## Byte Type: f32 [br] ## Byte Length: 4 var top_z: float ## Byte Type: f32 [br] ## Byte Length: 4 [br] ## width of the bounding box (when interpreted as a cuboid) var diameter_x: float ## Byte Type: f32 [br] ## Byte Length: 4 [br] ## height of the bounding box (when interpreted as a cuboid) var diameter_y: float ## Byte Type: f32 [br] ## Byte Length: 4 [br] ## depth of the bounding box (when interpreted as a cuboid) var diameter_z: float ## Byte Type: f32 [br] ## Byte Length: 4 [br] ## coordinate of the point in the exact center of the box var center_x: float ## Byte Type: f32 [br] ## Byte Length: 4 var center_y: float ## Byte Type: f32 [br] ## Byte Length: 4 var center_z: float ## Length: 4 [br] ## null if leaf node at sub-tree level 5 [br] ## indexes are [enum QuadTreeQuadrant] var quadrants: Array[QuadTree] func get_bottom() -> Vector3: return Vector3(bottom_x, bottom_y, bottom_z) func get_top() -> Vector3: return Vector3(top_x, top_y, top_z) func get_diameter() -> Vector3: return Vector3(diameter_x, diameter_y, diameter_z) func get_center() -> Vector3: return Vector3(center_x, center_y, center_z) static func from_bytes(bytes: ByteStream) -> QuadTree: var tree = QuadTree.new() tree.bottom_x = bytes.decode_float() return tree static func from_bytes_recursive(bytes: ByteStream, tree: QuadTree, depth: int): if depth == 5 or tree.quadrants.size() == 4: pass