Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dev-添加vox物品摆放时的物理碰撞体 #84

Merged
merged 1 commit into from
Sep 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/bin/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use just_join::{
async_chunk::ChunkDataPlugin, chunk::ServerChunkPlugin,
cross_through_check::CossTroughCheckPlugin, deal_message_system,
object_filing::ObjectFilingPlugin, player::ServerLobby, server_connect_system,
staff_rule_sync::ServerStaffRulePlugin, sync_body_and_head,
sp_physics::SpPhysicsPlugin, staff_rule_sync::ServerStaffRulePlugin, sync_body_and_head,
terrain_physics::TerrainPhysicsPlugin,
},
sky::ServerSkyPlugins,
Expand Down Expand Up @@ -128,6 +128,7 @@ fn main() {
CossTroughCheckPlugin,
OtherTreePlugin,
VoxelMeshPlugin,
SpPhysicsPlugin,
));

let (server, transport) = new_renet_server();
Expand Down
6 changes: 3 additions & 3 deletions src/client/sp_mesh_display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ fn sp_mesh_tasks_update(
if let Some((v, entity)) = index_voxels_entity_map.get(&(i as u32)) {
// 如果方向发生了变化里面 马上改变方向
if v.direction != voxels[i].direction {
commands.entity(*entity).insert(get_tfr(
commands.entity(*entity).insert(get_sp_tfr(
chunk_key.clone(),
i as u32,
voxels[i].direction,
Expand Down Expand Up @@ -159,7 +159,7 @@ fn deal_sp_mesh_tasks(
if let Some(meta) = voxel_mesh_storge.data.get(&v.id) {
let entity = commands
.spawn(PbrBundle {
transform: get_tfr(chunk_key.clone(), index as u32, v.direction),
transform: get_sp_tfr(chunk_key.clone(), index as u32, v.direction),
// FIXME:这里 暂时取第一个 后面要根据生成器取置换
mesh: meta.vox_list[0].clone(),
material: stdmats.add(Color::rgb(1., 1., 1.).into()),
Expand Down Expand Up @@ -247,7 +247,7 @@ fn get_pos(chunk_key: ChunkKey, index: u32) -> Vec3 {
chunk_key_any_xyz_to_vec3(chunk_key, xyz)
}

fn get_tfr(chunk_key: ChunkKey, index: u32, direction: VoxelDirection) -> Transform {
pub fn get_sp_tfr(chunk_key: ChunkKey, index: u32, direction: VoxelDirection) -> Transform {
Transform {
translation: get_pos(chunk_key, index),
rotation: direction.to_quat(),
Expand Down
11 changes: 11 additions & 0 deletions src/server/async_chunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use crate::{
map_database::{DbSaveTasks, MapDataBase},
player_state::PlayerOnTimeState,
voxel::{BasicStone, Voxel, VoxelMaterial},
voxel_mesh::VOXEL_MESH_MAP,
},
CHUNK_SIZE, CHUNK_SIZE_U32,
};
Expand All @@ -25,6 +26,7 @@ use super::{
message_def::chunk_result::ChunkResult,
object_filing::ObjectFillEvent,
player::ServerLobby,
sp_physics::DespawnSpEvent,
terrain_physics::{ColliderManager, ColliderTasksManager, ColliderUpdateTasksManager},
};

Expand All @@ -49,6 +51,7 @@ pub fn deal_chunk_query_system(
mut query_state: Query<&mut PlayerOnTimeState>,
server_lobby: Res<ServerLobby>,
mut other_tree_tasks_map: ResMut<OtherTreeTasksMap>,
mut event_writer: EventWriter<DespawnSpEvent>,
) {
let pool = AsyncComputeTaskPool::get();
for client_id in server.clients_id() {
Expand Down Expand Up @@ -164,6 +167,14 @@ pub fn deal_chunk_query_system(
// 发送物体被打下来的消息 old_voxel chunk_key, pos, 还原物体的位置!
if old_voxel.id != Voxel::EMPTY.id && voxel_type.id == Voxel::EMPTY.id {
println!("cube被打下来了: {:?}", old_voxel);
if VOXEL_MESH_MAP.contains_key(&old_voxel.id) {
// 如果是特殊物体被破坏要处理物理地形
event_writer.send(DespawnSpEvent {
chunk_key,
index: index.clone(),
});
}

// 物体时被打下来了 这里通过配置掉落
if let Some(staff_list) =
staff_info_stroge.voxel_to_staff_list(old_voxel)
Expand Down
1 change: 1 addition & 0 deletions src/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub mod cross_through_check;
pub mod message_def;
pub mod object_filing;
pub mod player;
pub mod sp_physics;
pub mod staff_rule_sync;
pub mod terrain_physics;
pub mod tool_bar_sync;
Expand Down
256 changes: 256 additions & 0 deletions src/server/sp_physics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
use bevy::{
prelude::{
Assets, Commands, Entity, Event, EventReader, EventWriter, GlobalTransform, Mesh, Plugin,
PreUpdate, Res, ResMut, Resource, Vec3,
},
tasks::{AsyncComputeTaskPool, Task},
utils::{HashMap, HashSet},
};
use bevy_rapier3d::prelude::{Collider, CollisionGroups, Group, RigidBody};

use crate::{
client::sp_mesh_display::get_sp_tfr,
common::ServerClipSpheres,
voxel_world::{
chunk::{find_chunk_keys_array_by_sphere, generate_offset_array, ChunkKey},
chunk_map::ChunkMap,
voxel::VoxelDirection,
voxel_mesh::{MeshMateData, VoxelMeshStorge, VOXEL_MESH_MAP},
},
PY_DISTANCE,
};

use super::terrain_physics::TerrainPhysics;

// 管理特殊的物理对象
#[derive(Debug, Clone, Resource)]
pub struct SpPhysicsManager {
pub entities: HashMap<ChunkKey, HashMap<usize, Entity>>,
}

impl SpPhysicsManager {
pub fn has_data(&self, chunk_key: ChunkKey, index: usize) -> bool {
if let Some(inner_map) = self.entities.get(&chunk_key) {
return inner_map.contains_key(&index);
}
false
}

pub fn insert(&mut self, chunk_key: ChunkKey, index: usize, entity: Entity) {
if !self.entities.contains_key(&chunk_key) {
self.entities.insert(chunk_key, HashMap::new());
}
if let Some(inner_map) = self.entities.get_mut(&chunk_key) {
inner_map.insert(index, entity);
}
}

pub fn remove(&mut self, chunk_key: ChunkKey, index: usize) -> Option<Entity> {
if self.has_data(chunk_key, index) {
if let Some(inner_map) = self.entities.get_mut(&chunk_key) {
return inner_map.remove(&index);
}
}
None
}
}

impl Default for SpPhysicsManager {
fn default() -> Self {
Self {
entities: Default::default(),
}
}
}

// 处理生成物理引擎任务
#[derive(Debug, Resource)]
pub struct SpPhysicsTasks {
pub tasks: Vec<Task<(ChunkKey, u32, MeshMateData, VoxelDirection)>>,
}

impl Default for SpPhysicsTasks {
fn default() -> Self {
Self {
tasks: Default::default(),
}
}
}

pub struct SpPhysicsPlugin;

impl Plugin for SpPhysicsPlugin {
fn build(&self, app: &mut bevy::prelude::App) {
app.add_event::<DespawnSpEvent>();
app.insert_resource(SpPhysicsManager::default());
app.insert_resource(SpPhysicsTasks::default());
// 处理生成和销毁
app.add_systems(
PreUpdate,
(
gen_sp_physics_tasks,
deal_gen_collider,
despawn_sp_event_gen,
deal_events,
),
);
}
}

// 生成物理模型的tasks
fn gen_sp_physics_tasks(
sp_physics_manager: Res<SpPhysicsManager>,
mut sp_physics_tasks: ResMut<SpPhysicsTasks>,
chunk_map: Res<ChunkMap>,
server_clip_spheres: Res<ServerClipSpheres>,
voxel_mesh_storge: Res<VoxelMeshStorge>,
) {
let pool = AsyncComputeTaskPool::get();
let mut keys: HashSet<ChunkKey> = HashSet::new();
for (_client_id, clip_spheres) in server_clip_spheres.clip_spheres.iter() {
for chunk_key in find_chunk_keys_array_by_sphere(
clip_spheres.new_sphere,
generate_offset_array(PY_DISTANCE),
)
.drain(..)
{
if !keys.contains(&chunk_key) {
keys.insert(chunk_key);
// 在一次的system中没有的情况才处理
if let Some(voxels) = chunk_map.get(chunk_key) {
// 存在地图数据
for i in 0..voxels.len() {
if VOXEL_MESH_MAP.contains_key(&voxels[i].id)
&& !sp_physics_manager.has_data(chunk_key, i)
// 原来没有数据
{
// 存在SP的类型的方块
if let Some(meta_data) = voxel_mesh_storge.data.get(&voxels[i].id) {
let ret = (
chunk_key.clone(),
i as u32,
meta_data.clone(),
voxels[i].direction,
);
let task = pool.spawn(async move { ret });
sp_physics_tasks.tasks.push(task);
}
}
}
}
}
}
}
}

// 生成碰撞体数据
fn deal_gen_collider(
mut commands: Commands,
mut sp_physics_manager: ResMut<SpPhysicsManager>,
mut sp_physics_tasks: ResMut<SpPhysicsTasks>,
mesh_assets: Res<Assets<Mesh>>,
) {
let len = sp_physics_tasks.tasks.len().min(256);
for ele in sp_physics_tasks.tasks.drain(..len) {
if let Some((chunk_key, index, mate_data, direction)) =
futures_lite::future::block_on(futures_lite::future::poll_once(ele))
{
if !sp_physics_manager.has_data(chunk_key, index as usize) {
// FIXME: 后续这里要其他的地方接管 碰撞体的生成
if let Some(mesh) = mesh_assets.get(&mate_data.vox_list[0].clone()) {
if let Some(collider) = get_collider_by_mesh(mesh) {
println!("这里生成碰撞体");
let entity = commands
.spawn((
TerrainPhysics,
get_sp_tfr(chunk_key.clone(), index.clone(), direction),
GlobalTransform::default(),
))
.insert(RigidBody::Fixed)
.insert(collider)
.insert(CollisionGroups::new(
Group::GROUP_1,
Group::GROUP_2 | Group::GROUP_3,
))
.id();
sp_physics_manager.insert(chunk_key, index as usize, entity);
}
}
}
}
}
}

#[derive(Debug, Event)]
pub struct DespawnSpEvent {
pub chunk_key: ChunkKey,
pub index: usize,
}
// 删除多余的数据
fn despawn_sp_event_gen(
sp_physics_manager: Res<SpPhysicsManager>,
server_clip_spheres: Res<ServerClipSpheres>,
mut event_writer: EventWriter<DespawnSpEvent>,
) {
// FIXME: 这里是重复的代码 需要重新整理
let neighbour_offest = generate_offset_array(PY_DISTANCE);
let mut chunks_to_remove = HashSet::new();
for (_client_id, clip_spheres) in server_clip_spheres.clip_spheres.iter() {
for key in
find_chunk_keys_array_by_sphere(clip_spheres.old_sphere, neighbour_offest.clone())
.drain(..)
{
chunks_to_remove.insert(key);
}

for key in
find_chunk_keys_array_by_sphere(clip_spheres.new_sphere, neighbour_offest.clone())
.drain(..)
{
chunks_to_remove.remove(&key);
}
}

for chunk_key in chunks_to_remove.into_iter() {
if let Some(inner_map) = sp_physics_manager.entities.get(&chunk_key) {
for (index, _) in inner_map {
event_writer.send(DespawnSpEvent {
chunk_key,
index: index.clone(),
});
}
}
}
}

fn deal_events(
mut commands: Commands,
mut sp_physics_manager: ResMut<SpPhysicsManager>,
mut event_reader: EventReader<DespawnSpEvent>,
) {
for event in event_reader.iter() {
if let Some(entity) = sp_physics_manager.remove(event.chunk_key, event.index) {
commands.entity(entity).despawn();
}
}
}

// 通过mesh生成碰撞体
fn get_collider_by_mesh(mesh: &Mesh) -> Option<Collider> {
let collider_vertices: Vec<Vec3> = mesh
.attribute(Mesh::ATTRIBUTE_POSITION)
.unwrap()
.as_float3()
.unwrap()
.to_vec()
.iter()
.cloned()
.map(Vec3::from)
.collect();
let indices: Vec<u32> = mesh.indices().unwrap().iter().map(|x| x as u32).collect();
let collider_indices: Vec<[u32; 3]> = indices.chunks(3).map(|i| [i[0], i[1], i[2]]).collect();
// println!("{:?}", collider_vertices);
// println!("{:?}", collider_indices);
let collider = Collider::trimesh(collider_vertices, collider_indices);
Some(collider)
}
2 changes: 1 addition & 1 deletion src/voxel_world/voxel_mesh/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ fn init_mesh_resource(assets: Res<AssetServer>, mut voxel_mesh_storge: ResMut<Vo
for (key, config) in VOXEL_MESH_MAP.iter() {
let mut vox_list: Vec<Handle<Mesh>> = Vec::new();
for vox_str in config.vox_list.iter() {
println!("加载了模型: {}", vox_str);
vox_list.push(assets.load(vox_str));
}
let mut image_list: Vec<Handle<Image>> = Vec::new();
Expand All @@ -76,4 +77,3 @@ fn init_mesh_resource(assets: Res<AssetServer>, mut voxel_mesh_storge: ResMut<Vo
);
}
}

Loading