mirror of
https://github.com/IntQuant/noita_entangled_worlds.git
synced 2025-10-19 07:03:16 +00:00
Sync physics entities.
This commit is contained in:
parent
59f8381a95
commit
9955f3c4b2
8 changed files with 203 additions and 21 deletions
|
@ -17,6 +17,9 @@ pub struct Obj(pub usize);
|
|||
|
||||
pub struct Color(pub u32);
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct PhysicsBodyID(pub i32);
|
||||
|
||||
pub trait Component: From<ComponentID> + Into<ComponentID> {
|
||||
const NAME_STR: &'static str;
|
||||
}
|
||||
|
@ -132,7 +135,7 @@ pub mod raw {
|
|||
use eyre::eyre;
|
||||
use eyre::Context;
|
||||
|
||||
use super::{Color, ComponentID, EntityID, Obj};
|
||||
use super::{Color, ComponentID, EntityID, Obj, PhysicsBodyID};
|
||||
use crate::lua::LuaGetValue;
|
||||
use crate::lua::LuaPutValue;
|
||||
use std::borrow::Cow;
|
||||
|
@ -171,4 +174,27 @@ pub mod raw {
|
|||
lua.call((2 + T::SIZE_ON_STACK).try_into()?, 0);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn physics_body_id_get_transform(
|
||||
body: PhysicsBodyID,
|
||||
) -> eyre::Result<Option<(f32, f32, f32, f32, f32, f32)>> {
|
||||
let lua = LuaState::current()?;
|
||||
lua.get_global(c"PhysicsBodyIDGetTransform");
|
||||
lua.push_integer(body.0 as isize);
|
||||
lua.call(1, 6);
|
||||
if lua.is_nil_or_none(-1) {
|
||||
Ok(None)
|
||||
} else {
|
||||
match LuaGetValue::get(lua, -1) {
|
||||
Ok(ret) => {
|
||||
lua.pop_last_n(6);
|
||||
Ok(Some(ret))
|
||||
}
|
||||
Err(err) => {
|
||||
lua.pop_last_n(6);
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use std::{
|
|||
use eyre::{bail, Context, OptionExt};
|
||||
use lua_bindings::{lua_CFunction, lua_State, Lua51, LUA_GLOBALSINDEX};
|
||||
|
||||
use crate::{Color, ComponentID, EntityID, Obj};
|
||||
use crate::{Color, ComponentID, EntityID, Obj, PhysicsBodyID};
|
||||
|
||||
thread_local! {
|
||||
static CURRENT_LUA_STATE: Cell<Option<LuaState>> = Cell::default();
|
||||
|
@ -153,7 +153,7 @@ impl LuaState {
|
|||
unreachable!()
|
||||
}
|
||||
|
||||
fn is_nil_or_none(&self, index: i32) -> bool {
|
||||
pub fn is_nil_or_none(&self, index: i32) -> bool {
|
||||
(unsafe { LUA.lua_type(self.lua, index) }) <= 0
|
||||
}
|
||||
|
||||
|
@ -321,6 +321,12 @@ impl LuaPutValue for Obj {
|
|||
}
|
||||
}
|
||||
|
||||
impl LuaPutValue for PhysicsBodyID {
|
||||
fn put(&self, lua: LuaState) {
|
||||
lua.push_integer(self.0 as isize);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: LuaPutValue> LuaPutValue for Option<T> {
|
||||
fn put(&self, lua: LuaState) {
|
||||
const { assert!(T::SIZE_ON_STACK == 1) }
|
||||
|
@ -439,6 +445,15 @@ impl LuaGetValue for Color {
|
|||
}
|
||||
}
|
||||
|
||||
impl LuaGetValue for PhysicsBodyID {
|
||||
fn get(lua: LuaState, index: i32) -> eyre::Result<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Ok(PhysicsBodyID(lua.to_integer(index) as i32))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: LuaGetValue> LuaGetValue for Option<T> {
|
||||
fn get(lua: LuaState, index: i32) -> eyre::Result<Self> {
|
||||
Ok(if lua.is_nil_or_none(index) {
|
||||
|
@ -457,7 +472,7 @@ impl<T: LuaGetValue> LuaGetValue for Vec<T> {
|
|||
let len = lua.objlen(index);
|
||||
let mut res = Vec::with_capacity(len);
|
||||
for i in 1..=len {
|
||||
lua.index_table(index, dbg!(i));
|
||||
lua.index_table(index, i);
|
||||
let get = T::get(lua, -1);
|
||||
lua.pop_last();
|
||||
res.push(get?);
|
||||
|
|
|
@ -60,6 +60,8 @@ enum Typ2 {
|
|||
Obj,
|
||||
#[serde(rename = "color")]
|
||||
Color,
|
||||
#[serde(rename = "physics_body_id")]
|
||||
PhysicsBodyID,
|
||||
}
|
||||
|
||||
impl Typ2 {
|
||||
|
@ -73,6 +75,7 @@ impl Typ2 {
|
|||
Typ2::ComponentID => quote!(ComponentID),
|
||||
Typ2::Obj => quote! {Obj},
|
||||
Typ2::Color => quote!(Color),
|
||||
Typ2::PhysicsBodyID => quote! {PhysicsBodyID},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4901,12 +4901,80 @@
|
|||
"desc": "Nolla forgot to include a description :(",
|
||||
"rets": []
|
||||
},
|
||||
{
|
||||
"fn_name": "PhysicsBodyIDGetFromEntity",
|
||||
"args": [
|
||||
{
|
||||
"name": "entity_id",
|
||||
"typ": "entity_id",
|
||||
"default": null
|
||||
},
|
||||
{
|
||||
"name": "component_id",
|
||||
"typ": "component_id",
|
||||
"default": "0"
|
||||
}
|
||||
],
|
||||
"desc": "NOTE! If component_id is given, will return all the bodies linked to that component. If component_id is not given, will return all the bodies linked to the entity (with joints or through components).",
|
||||
"rets": [
|
||||
{
|
||||
"name": null,
|
||||
"typ": "physics_body_id",
|
||||
"optional": false,
|
||||
"is_vec": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"fn_name": "PhysicsBodyIDQueryBodies",
|
||||
"args": [
|
||||
{
|
||||
"name": "world_pos_min_x",
|
||||
"typ": "number",
|
||||
"default": null
|
||||
},
|
||||
{
|
||||
"name": "world_pos_min_y",
|
||||
"typ": "number",
|
||||
"default": null
|
||||
},
|
||||
{
|
||||
"name": "world_pos_max_x",
|
||||
"typ": "number",
|
||||
"default": null
|
||||
},
|
||||
{
|
||||
"name": "world_pos_max_y",
|
||||
"typ": "number",
|
||||
"default": null
|
||||
},
|
||||
{
|
||||
"name": "include_static_bodies",
|
||||
"typ": "bool",
|
||||
"default": "false"
|
||||
},
|
||||
{
|
||||
"name": "are_these_box2d_units",
|
||||
"typ": "bool",
|
||||
"default": "false"
|
||||
}
|
||||
],
|
||||
"desc": "NOTE! returns an array of physics_body_id(s) of all the box2d bodies in the given area. The default coordinates are in game world space. If passing a sixth argument with true, we will assume the coordinates are in box2d units.",
|
||||
"rets": [
|
||||
{
|
||||
"name": null,
|
||||
"typ": "physics_body_id",
|
||||
"optional": false,
|
||||
"is_vec": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"fn_name": "PhysicsBodyIDSetTransform",
|
||||
"args": [
|
||||
{
|
||||
"name": "physics_body_id",
|
||||
"typ": "int",
|
||||
"typ": "physics_body_id",
|
||||
"default": null
|
||||
},
|
||||
{
|
||||
|
@ -4948,7 +5016,7 @@
|
|||
"args": [
|
||||
{
|
||||
"name": "physics_body_id",
|
||||
"typ": "int",
|
||||
"typ": "physics_body_id",
|
||||
"default": null
|
||||
},
|
||||
{
|
||||
|
@ -4980,7 +5048,7 @@
|
|||
"args": [
|
||||
{
|
||||
"name": "physics_body_id",
|
||||
"typ": "int",
|
||||
"typ": "physics_body_id",
|
||||
"default": null
|
||||
},
|
||||
{
|
||||
|
@ -5012,7 +5080,7 @@
|
|||
"args": [
|
||||
{
|
||||
"name": "physics_body_id",
|
||||
"typ": "int",
|
||||
"typ": "physics_body_id",
|
||||
"default": null
|
||||
},
|
||||
{
|
||||
|
@ -5029,7 +5097,7 @@
|
|||
"args": [
|
||||
{
|
||||
"name": "physics_body_id",
|
||||
"typ": "int",
|
||||
"typ": "physics_body_id",
|
||||
"default": null
|
||||
}
|
||||
],
|
||||
|
@ -5054,7 +5122,7 @@
|
|||
"args": [
|
||||
{
|
||||
"name": "physics_body_id",
|
||||
"typ": "int",
|
||||
"typ": "physics_body_id",
|
||||
"default": null
|
||||
}
|
||||
],
|
||||
|
@ -5079,7 +5147,7 @@
|
|||
"args": [
|
||||
{
|
||||
"name": "physics_body_id",
|
||||
"typ": "int",
|
||||
"typ": "physics_body_id",
|
||||
"default": null
|
||||
},
|
||||
{
|
||||
|
@ -5101,7 +5169,7 @@
|
|||
"args": [
|
||||
{
|
||||
"name": "physics_body_id",
|
||||
"typ": "int",
|
||||
"typ": "physics_body_id",
|
||||
"default": null
|
||||
}
|
||||
],
|
||||
|
@ -5120,7 +5188,7 @@
|
|||
"args": [
|
||||
{
|
||||
"name": "physics_body_id",
|
||||
"typ": "int",
|
||||
"typ": "physics_body_id",
|
||||
"default": null
|
||||
},
|
||||
{
|
||||
|
|
|
@ -52,7 +52,7 @@ impl Default for EntitySync {
|
|||
|
||||
impl EntitySync {
|
||||
fn should_be_tracked(&mut self, entity: EntityID) -> eyre::Result<bool> {
|
||||
Ok(entity.has_tag("enemy"))
|
||||
Ok(entity.has_tag("enemy") || entity.has_tag("prop_physics"))
|
||||
}
|
||||
|
||||
/// Looks for newly spawned entities that might need to be tracked.
|
||||
|
@ -154,7 +154,7 @@ impl Module for EntitySync {
|
|||
)?;
|
||||
}
|
||||
|
||||
self.local_diff_model.update()?;
|
||||
self.local_diff_model.update_pending_authority()?;
|
||||
|
||||
if frame_num % 2 == 0 {
|
||||
self.local_diff_model
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::mem;
|
||||
|
||||
use bimap::BiHashMap;
|
||||
use eyre::OptionExt;
|
||||
use eyre::{eyre, OptionExt};
|
||||
use noita_api::{
|
||||
game_print, AIAttackComponent, AdvancedFishAIComponent, AnimalAIComponent,
|
||||
CameraBoundComponent, CharacterDataComponent, DamageModelComponent, EntityID,
|
||||
|
@ -11,8 +11,8 @@ use noita_api::{
|
|||
use rustc_hash::FxHashMap;
|
||||
use shared::{
|
||||
des::{
|
||||
EntityInfo, EntitySpawnInfo, EntityUpdate, FullEntityData, Gid, Lid, ProjectileFired,
|
||||
UpdatePosition, AUTHORITY_RADIUS,
|
||||
EntityInfo, EntitySpawnInfo, EntityUpdate, FullEntityData, Gid, Lid, PhysBodyInfo,
|
||||
ProjectileFired, UpdatePosition, AUTHORITY_RADIUS,
|
||||
},
|
||||
WorldPos,
|
||||
};
|
||||
|
@ -83,6 +83,7 @@ impl LocalDiffModel {
|
|||
vx: 0.0,
|
||||
vy: 0.0,
|
||||
hp: 1.0,
|
||||
phys: Vec::new(),
|
||||
},
|
||||
gid,
|
||||
},
|
||||
|
@ -96,7 +97,7 @@ impl LocalDiffModel {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn update(&mut self) -> eyre::Result<()> {
|
||||
pub(crate) fn update_pending_authority(&mut self) -> eyre::Result<()> {
|
||||
for entity_data in mem::take(&mut self.pending_authority) {
|
||||
let entity = spawn_entity_by_data(
|
||||
&entity_data.data,
|
||||
|
@ -166,6 +167,28 @@ impl LocalDiffModel {
|
|||
let hp = damage.hp()?;
|
||||
current.hp = hp as f32;
|
||||
}
|
||||
|
||||
let phys_bodies = noita_api::raw::physics_body_id_get_from_entity(*entity, None)?;
|
||||
current.phys = phys_bodies
|
||||
.into_iter()
|
||||
.map(|body| -> eyre::Result<PhysBodyInfo> {
|
||||
let (x, y, angle, vx, vy, av) = noita_api::raw::physics_body_id_get_transform(
|
||||
body,
|
||||
)?
|
||||
.ok_or_else(
|
||||
|| eyre!("Couldn't get transform of an entity that we checked that it exists? Phys body: {body:?} Ent: {entity:?}"),
|
||||
)?;
|
||||
let (x, y) = noita_api::raw::physics_pos_to_game_pos(x.into(), Some(y.into()))?;
|
||||
Ok(PhysBodyInfo {
|
||||
x: x as f32,
|
||||
y: y as f32,
|
||||
angle,
|
||||
vx,
|
||||
vy,
|
||||
av,
|
||||
})
|
||||
})
|
||||
.collect::<eyre::Result<Vec<_>>>()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -208,6 +231,12 @@ impl LocalDiffModel {
|
|||
had_any_delta = true;
|
||||
}
|
||||
|
||||
if current.phys != last.phys {
|
||||
res.push(EntityUpdate::SetPhysInfo(current.phys.clone()));
|
||||
last.phys = current.phys.clone();
|
||||
had_any_delta = true;
|
||||
}
|
||||
|
||||
// Remove the CurrentEntity thing because it's not necessary.
|
||||
if !had_any_delta {
|
||||
res.pop();
|
||||
|
@ -269,6 +298,12 @@ impl RemoteDiffModel {
|
|||
};
|
||||
entity_info.hp = *hp;
|
||||
}
|
||||
EntityUpdate::SetPhysInfo(vec) => {
|
||||
let Some(entity_info) = self.entity_infos.get_mut(¤t_lid) else {
|
||||
continue;
|
||||
};
|
||||
entity_info.phys = vec.clone();
|
||||
}
|
||||
EntityUpdate::RemoveEntity(lid) => {
|
||||
if let Some((_, entity)) = self.tracked.remove_by_left(lid) {
|
||||
entity.kill();
|
||||
|
@ -312,6 +347,27 @@ impl RemoteDiffModel {
|
|||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
if !entity_info.phys.is_empty() {
|
||||
let phys_bodies =
|
||||
noita_api::raw::physics_body_id_get_from_entity(*entity, None)?;
|
||||
for (p, physics_body_id) in entity_info.phys.iter().zip(phys_bodies.iter())
|
||||
{
|
||||
let (x, y) = noita_api::raw::game_pos_to_physics_pos(
|
||||
p.x.into(),
|
||||
Some(p.y.into()),
|
||||
)?;
|
||||
noita_api::raw::physics_body_id_set_transform(
|
||||
*physics_body_id,
|
||||
x,
|
||||
y,
|
||||
p.angle.into(),
|
||||
p.vx.into(),
|
||||
p.vy.into(),
|
||||
p.av.into(),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let entity = spawn_entity_by_data(
|
||||
|
|
|
@ -29,8 +29,10 @@ def maybe_map_types(name, typ):
|
|||
typ = "bool"
|
||||
if typ == "item_entity_id":
|
||||
typ = "entity_id"
|
||||
if typ == "physics_body_id":
|
||||
raise ValueError(f"{typ} not supported")
|
||||
#if typ == "physics_body_id":
|
||||
# raise ValueError(f"{typ} not supported")
|
||||
if name == "physics_body_id":
|
||||
typ = "physics_body_id"
|
||||
return typ
|
||||
|
||||
def parse_arg(arg_s):
|
||||
|
|
|
@ -56,6 +56,16 @@ pub struct InterestRequest {
|
|||
pub radius: i32,
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Clone, Copy, PartialEq)]
|
||||
pub struct PhysBodyInfo {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
pub angle: f32,
|
||||
pub vx: f32,
|
||||
pub vy: f32,
|
||||
pub av: f32,
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Clone)]
|
||||
pub struct EntityInfo {
|
||||
pub entity_data: EntitySpawnInfo,
|
||||
|
@ -64,6 +74,7 @@ pub struct EntityInfo {
|
|||
pub vx: f32,
|
||||
pub vy: f32,
|
||||
pub hp: f32,
|
||||
pub phys: Vec<PhysBodyInfo>,
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Clone)]
|
||||
|
@ -75,6 +86,7 @@ pub enum EntityUpdate {
|
|||
SetPosition(f32, f32),
|
||||
SetVelocity(f32, f32),
|
||||
SetHp(f32),
|
||||
SetPhysInfo(Vec<PhysBodyInfo>),
|
||||
// TODO...
|
||||
RemoveEntity(Lid),
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue