pub mod event;
pub use event::Events;
use macros::named_list_chunk;
use macros::num_enum;
use crate::prelude::*;
use crate::util::init::num_enum_from;
use crate::util::init::vec_with_capacity;
use crate::wad::deserialize::reader::DataReader;
use crate::wad::elements::GMElement;
use crate::wad::elements::element_stub;
use crate::wad::elements::sprite::GMSprite;
use crate::wad::reference::GMRef;
use crate::wad::serialize::builder::DataBuilder;
#[named_list_chunk("OBJT")]
pub struct GMGameObjects {
pub game_objects: Vec<GMGameObject>,
pub exists: bool,
}
impl GMElement for GMGameObjects {
fn deserialize(reader: &mut DataReader) -> Result<Self> {
let pointers: Vec<u32> = reader.read_simple_list()?;
let mut game_objects: Vec<GMGameObject> = Vec::with_capacity(pointers.len());
for pointer in pointers {
reader.assert_pos(pointer, "Game Object")?;
let name: String = reader.read_gm_string()?;
let sprite: Option<GMRef<GMSprite>> = reader.read_resource_by_id_opt()?;
let visible = reader.read_bool32()?;
let mut managed: Option<bool> = None;
if reader.general_info.is_version_at_least((2022, 5)) {
managed = Some(reader.read_bool32()?);
}
let solid = reader.read_bool32()?;
let depth = reader.read_i32()?;
let persistent = reader.read_bool32()?;
let parent_id = reader.read_i32()?;
let parent: Option<GMRef<GMGameObject>> = match parent_id {
-100 => None, -1 => Some(game_objects.len().into()), _ => Some(GMRef::new(parent_id as u32)),
};
let texture_mask: Option<GMRef<GMSprite>> = reader.read_resource_by_id_opt()?;
let uses_physics = reader.read_bool32()?;
let is_sensor = reader.read_bool32()?;
let collision_shape: CollisionShape = num_enum_from(reader.read_i32()?)?;
let density = reader.read_f32()?;
let restitution = reader.read_f32()?;
let group = reader.read_u32()?;
let linear_damping = reader.read_f32()?;
let angular_damping = reader.read_f32()?;
let physics_shape_vertex_count = reader.read_count("Physics Shape Vertex Count")?;
let friction = reader.read_f32()?;
let awake = reader.read_bool32()?;
let kinematic = reader.read_bool32()?;
let mut physics_shape_vertices: Vec<(f32, f32)> =
vec_with_capacity(physics_shape_vertex_count)?;
for _ in 0..physics_shape_vertex_count {
let x = reader.read_f32()?;
let y = reader.read_f32()?;
physics_shape_vertices.push((x, y));
}
let events = Events::deserialize(reader).context("parsing game object events")?;
game_objects.push(GMGameObject {
name,
sprite,
visible,
managed,
solid,
depth,
persistent,
parent,
texture_mask,
uses_physics,
is_sensor,
collision_shape,
density,
restitution,
group,
linear_damping,
angular_damping,
friction,
awake,
kinematic,
physics_shape_vertices,
events,
});
}
Ok(Self { game_objects, exists: true })
}
fn serialize(&self, builder: &mut DataBuilder) -> Result<()> {
builder.write_usize(self.game_objects.len())?;
let pointer_list_pos = builder.len();
for _ in 0..self.game_objects.len() {
builder.write_u32(0xDEAD_C0DE);
}
for (i, game_object) in self.game_objects.iter().enumerate() {
builder.overwrite_pointer_with_cur_pos(pointer_list_pos, i)?;
builder.write_gm_string(&game_object.name);
builder.write_resource_id_opt(game_object.sprite);
builder.write_bool32(game_object.visible);
builder.write_if_ver(&game_object.managed, "Managed", (2022, 5))?;
builder.write_bool32(game_object.solid);
builder.write_i32(game_object.depth);
builder.write_bool32(game_object.persistent);
match game_object.parent {
None => builder.write_i32(-100), Some(obj_ref) if obj_ref.index == i as u32 => {
builder.write_i32(-1);
} Some(obj_ref) => builder.write_resource_id(obj_ref), }
builder.write_resource_id_opt(game_object.texture_mask);
builder.write_bool32(game_object.uses_physics);
builder.write_bool32(game_object.is_sensor);
builder.write_i32(game_object.collision_shape.into());
builder.write_f32(game_object.density);
builder.write_f32(game_object.restitution);
builder.write_u32(game_object.group);
builder.write_f32(game_object.linear_damping);
builder.write_f32(game_object.angular_damping);
builder.write_usize(game_object.physics_shape_vertices.len())?; builder.write_f32(game_object.friction);
builder.write_bool32(game_object.awake);
builder.write_bool32(game_object.kinematic);
for (x, y) in &game_object.physics_shape_vertices {
builder.write_f32(*x);
builder.write_f32(*y);
}
game_object.events.serialize(builder)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct GMGameObject {
pub name: String,
pub sprite: Option<GMRef<GMSprite>>,
pub visible: bool,
pub managed: Option<bool>,
pub solid: bool,
pub depth: i32,
pub persistent: bool,
pub parent: Option<GMRef<Self>>,
pub texture_mask: Option<GMRef<GMSprite>>,
pub uses_physics: bool,
pub is_sensor: bool,
pub collision_shape: CollisionShape,
pub density: f32,
pub restitution: f32,
pub group: u32,
pub linear_damping: f32,
pub angular_damping: f32,
pub friction: f32,
pub awake: bool,
pub kinematic: bool,
pub physics_shape_vertices: Vec<(f32, f32)>,
pub events: Events,
}
element_stub!(GMGameObject);
#[num_enum(i32)]
pub enum CollisionShape {
Circle = 0,
Box = 1,
Custom = 2,
}