From 672de409e01199704cfd529974dd7937c35cdf85 Mon Sep 17 00:00:00 2001 From: zhouzihao <1042181618@qq.com> Date: Thu, 14 Sep 2023 16:12:56 +0800 Subject: [PATCH 1/2] =?UTF-8?q?dev-=E6=B7=BB=E5=8A=A0=E5=88=87=E6=8D=A2?= =?UTF-8?q?=E6=96=B9=E5=9D=97=E7=9A=84=E6=96=B9=E5=90=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../textures/\346\265\213\350\257\2251.png" | Bin 0 -> 370 bytes .../textures/\346\265\213\350\257\2252.png" | Bin 0 -> 429 bytes .../textures/\346\265\213\350\257\2253.png" | Bin 0 -> 529 bytes .../textures/\346\265\213\350\257\2254.png" | Bin 0 -> 458 bytes .../textures/\346\265\213\350\257\2255.png" | Bin 0 -> 536 bytes .../textures/\346\265\213\350\257\2256.png" | Bin 0 -> 502 bytes src/client/player/mouse_control.rs | 30 +++++- src/client/voxels/mesh.rs | 58 +++++++++-- src/client/voxels/voxel_materail_config.rs | 33 +++++- src/lib.rs | 2 +- src/server/async_chunk.rs | 11 +- src/voxel_world/voxel.rs | 98 +++++++++++++++++- staff.ron | 19 ++-- staff_rules.ron | 12 +++ volex.ron | 15 +++ 15 files changed, 250 insertions(+), 28 deletions(-) create mode 100644 "assets/textures/\346\265\213\350\257\2251.png" create mode 100644 "assets/textures/\346\265\213\350\257\2252.png" create mode 100644 "assets/textures/\346\265\213\350\257\2253.png" create mode 100644 "assets/textures/\346\265\213\350\257\2254.png" create mode 100644 "assets/textures/\346\265\213\350\257\2255.png" create mode 100644 "assets/textures/\346\265\213\350\257\2256.png" diff --git "a/assets/textures/\346\265\213\350\257\2251.png" "b/assets/textures/\346\265\213\350\257\2251.png" new file mode 100644 index 0000000000000000000000000000000000000000..65de12261f87495ae2be99513c36883397337e6a GIT binary patch literal 370 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEV6^mfaSW-L^LADsU$cUM%fgp` zt0u;6SiV?sBj?6z+jf08X7TL$}tP;e%_fcF^}jR}|kLk$L1a i&G48+au1*8QuR43#y@ujKQ97?C4;A{pUXO@geCy;(39r? literal 0 HcmV?d00001 diff --git "a/assets/textures/\346\265\213\350\257\2252.png" "b/assets/textures/\346\265\213\350\257\2252.png" new file mode 100644 index 0000000000000000000000000000000000000000..1df689b97354874bf9d350ed8bcdff7669d6bbf7 GIT binary patch literal 429 zcmV;e0aE^nP){;!N7!oqaRU}>+X?f080*Ir?ir6BN4mQ-I#SsI^nt`FoJ&n?dEoQK#i z-KW$*NQzp4ApoYZ1i&W!DW#{?A2-Z|cW6prbs?0()B#qaN1y>{+urnWM1UXx_z*r* z_oZ!*>OoKoK-g^yz)^`Ys2F5pY}RaTKNMJl_%VEJY7vty*ta=*1Yp?u;9X)C2kf%{5B-2khOFvt>z zK+!gWFM=QU1uic~X~b7x4miuabpsXY06Os%bO}({enhrhi8OO^aR8|n2@$6D!pR!)?5T>>plpAAP9oMJ??Rjd)(t5_qfMBDW&uR XG<{`p%syCsV425Ab@Bhk7m~l+45)n@?#D2eavtH=&P-<~g5ImcVjJ}l8eQeJ8e{jBX9=pcS zd6d`fD-1w_uM|WeqnHSAfSCwZ0%Z2HnFZcfH?|C#V&VXv^y=@UiSRCF4zLQC<0T22 zq2>U#^c@~z;R;a!mZgnG)k=JYEQP86b+m9<>`s7=mnJBd9ibIg{3Ojfz=Z&4pdo{4BV&hrmi;u_lRnKVabaO}8k4r-w-nXa&%C@mV`X60gW+o1?ujQQ&#P zeOsJ~O5FfqihTjrT!FfFs*Mrm28au0-5GjL4&a~@?c?_bLjVV3xD0X{gaaIm!ITid z!5B;l0UV6sGRV#`RDe1##jiUcH=51?=zRkT0W@3yyMe?=Z+`}V1bgzX1xWnUxEucu z(CjMLYa*NmZHkgXZ5o+$yZfXedb(kPMzbx>#ppR_hnH`RgCGckAP9n~Nhy5*M&Or- T@3`NX00000NkvXXu0mjfymRJk literal 0 HcmV?d00001 diff --git "a/assets/textures/\346\265\213\350\257\2254.png" "b/assets/textures/\346\265\213\350\257\2254.png" new file mode 100644 index 0000000000000000000000000000000000000000..302d380e5c1eedd1a0493327b1060e6195dab75e GIT binary patch literal 458 zcmV;*0X6=KP)uJ=iWq+)&U6+2OtwZ0&@V12n20nl6B9TW~g zVkrQn3#5xbiWQ4MXq-L zh2D#;9Z)Ozu&uyKfHd<#XlL=-c>vWR>QVzP*8P;XLHgtudhG(I)+Y_La>v;($}) zBP4u8r3j9gc&1qZjied=C4#>u2cF+wlbgOP>;e$P0L29$h+)1rMVW8`2x5TZ0uaOi z1t!2B{lc!G9RR-$`Vv3~Fmf}+aU92SMka*t0~}mqnXf5L%K!iX07*qoM6N<$f`}Z# Apa1{> literal 0 HcmV?d00001 diff --git "a/assets/textures/\346\265\213\350\257\2255.png" "b/assets/textures/\346\265\213\350\257\2255.png" new file mode 100644 index 0000000000000000000000000000000000000000..6fdecba0712a4acf05670cda8324a868bce6772b GIT binary patch literal 536 zcmV+z0_XjSP)tW26i~n2Qw`8i%L6;DUfXkDiJ6aBe8gEAhK+|HV0!YOtecKC` zzn~Q$y89!s#~|^*a22q)hdwh@0o7n=uHMF~-=_i#;b5sr5N0`@SK4o`GeP!nQz|HZ zis3!u(TFIZ6AGh_poYU`Pf@)eaC1>2rGIXRY)3+jK@9o+jv z%l15`K5c+aJke&0xq_(yop{FG1oH$$!`cAZ-R@(+BLOvnaK_XCG3!_5Z|3}2zmNs@ zlbY@dR`TXfu8!@r2b72($H-+`bw_uLAG9M~gmVk$|xACtwCdIPMw& znSk)|C(uJ6d<-B4tP+0$m4LXJ7a*5Gb?0|*`txy#<(y$s4Jx9K#z+(YD}bAU8mwIT z^{qequ8(`Qv&0!#BtUJk*0Vw!f8bO=(tu3B?j2_Y2s2=3h-d?TE`d8E8lt`7t3hGj z^f7=mVA=u5_6$f`Z+{*DHDKnfjoJ@n0s^$b73g`u%w5|+4RHyS0jT}Oa{GWODM0l; z0WkoyZZEqJpcGtA0>, + keyboard_input: Res>, choose_cube: Res, controller_flag: Res, mut client: ResMut, tool_bar_data: Res, mut attack_timer: ResMut, player_query: Query<(&Player, &Transform)>, + chunk_map: Res, ) { if !controller_flag.flag { // println!("3:{}", controller_flag.flag); return; } + + // 移动数据的方向 + if mouse_button_input.just_released(MouseButton::Left) + && keyboard_input.pressed(KeyCode::ShiftLeft) + { + if let Some(pos) = choose_cube.center { + let (chunk_key, xyz) = vec3_to_chunk_key_any_xyz(pos); + if let Some(voxel_type) = chunk_map.get_block(chunk_key, xyz) { + // FIXME: 这里要判断是否每种情况都可以去旋转! + let new_voxel = voxel_type.next_direction(); + println!("这里发送了旋转方块的指令{:?}", new_voxel); + let message = bincode::serialize(&ChunkQuery::Change { + chunk_key, + pos: xyz, + voxel_type: new_voxel, + center: pos, + active_index: None, + }) + .unwrap(); + client.send_message(ClientChannel::ChunkQuery, message); + } + } + } + if mouse_button_input.just_pressed(MouseButton::Left) || attack_timer.pressed { attack_timer.pressed = true; // println!("4:{}", controller_flag.flag); diff --git a/src/client/voxels/mesh.rs b/src/client/voxels/mesh.rs index a971478..81c69dc 100644 --- a/src/client/voxels/mesh.rs +++ b/src/client/voxels/mesh.rs @@ -10,7 +10,7 @@ use ndshape::{ConstShape, ConstShape3u32, Shape}; use crate::{ client::voxels::mesh_material::ATTRIBUTE_DATA, - voxel_world::voxel::{Voxel, VoxelMaterial, Water}, + voxel_world::voxel::{Voxel, VoxelDirection, VoxelMaterial, Water}, CHUNK_SIZE, CHUNK_SIZE_ADD_2_U32, }; @@ -52,14 +52,53 @@ where indices.extend_from_slice(&face.quad_mesh_indices(positions.len() as u32)); positions.extend_from_slice(&face.quad_mesh_positions(quad, 1.0)); normals.extend_from_slice(&face.quad_mesh_normals()); - tex_coords.extend_from_slice(&face.tex_coords( - RIGHT_HANDED_Y_UP_CONFIG.u_flip_face, - true, - quad, - )); - // 这里可以生成Data???? 但是怎么知道 是那个面的? + // 这里可以生成Data 但是怎么知道 是那个面的? let index = >::linearize(quad.minimum); + // 这里处理一下问题 + if block_face_normal_index == 1 || block_face_normal_index == 4 { + match voxels[index as usize].direction.clone() { + VoxelDirection::Z => { + tex_coords.extend_from_slice(&[ + [0.0, quad.height as f32], + [quad.width as f32, quad.height as f32], + [0.0, 0.0], + [quad.width as f32, 0.0], + ]); + } + VoxelDirection::X => { + tex_coords.extend_from_slice(&[ + [quad.width as f32, quad.height as f32], + [quad.width as f32, 0.0], + [0.0, quad.height as f32], + [0.0, 0.0], + ]); + } + VoxelDirection::NZ => { + tex_coords.extend_from_slice(&[ + [quad.width as f32, 0.0], + [0.0, 0.0], + [quad.width as f32, quad.height as f32], + [0.0, quad.height as f32], + ]); + } + VoxelDirection::NX => { + tex_coords.extend_from_slice(&[ + [0.0, 0.0], + [0.0, quad.height as f32], + [quad.width as f32, 0.0], + [quad.width as f32, quad.height as f32], + ]); + } + } + } else { + tex_coords.extend_from_slice(&face.tex_coords( + RIGHT_HANDED_Y_UP_CONFIG.u_flip_face, + true, + quad, + )); + } + // 法向量值 let normol_num = (block_face_normal_index as u32) << 8u32; // 计算贴图索引 @@ -67,8 +106,10 @@ where material_config.clone(), block_face_normal_index as u8, &voxels[index as usize].id, + voxels[index as usize].direction.clone(), ); - // todo 这里后面要知道是那个面的方便渲染 + + // 这里后面要知道是那个面的方便渲染 data.extend_from_slice(&[normol_num | (txt_index); 4]); } } @@ -165,6 +206,7 @@ pub fn gen_mesh_water(voxels: Vec, material_config: MaterailConfiguration material_config.clone(), block_face_normal_index as u8, &Water::ID, + VoxelDirection::Z, ); data.extend_from_slice(&[normol_num | (txt_index); 4]); } diff --git a/src/client/voxels/voxel_materail_config.rs b/src/client/voxels/voxel_materail_config.rs index 6c85723..020c6a7 100644 --- a/src/client/voxels/voxel_materail_config.rs +++ b/src/client/voxels/voxel_materail_config.rs @@ -5,7 +5,7 @@ use bevy_inspector_egui::prelude::*; use serde::{Deserialize, Serialize}; use walkdir::WalkDir; -use crate::voxel_world::voxel::{Grass, Soli, Stone, VoxelMaterial}; +use crate::voxel_world::voxel::{Grass, Soli, Stone, VoxelDirection, VoxelMaterial}; #[derive(Debug, Clone, Serialize, Deserialize, Default, Reflect, InspectorOptions)] #[reflect(InspectorOptions)] @@ -124,10 +124,17 @@ impl MaterailConfiguration { } // 通过面 和 体素类型获取 图片的索引 - pub fn find_volex_index(self, normal: u8, volex_type: &u8) -> u32 { + pub fn find_volex_index(self, normal: u8, volex_type: &u8, direction: VoxelDirection) -> u32 { + let change_normal = match direction { + VoxelDirection::Z => rotate_times(normal, 0), + VoxelDirection::X => rotate_times(normal, 1), + VoxelDirection::NZ => rotate_times(normal, 2), + VoxelDirection::NX => rotate_times(normal, 3), + }; + return match self.voxels.get(volex_type) { Some(config) => { - return match config.normal.get(&normal) { + return match config.normal.get(&change_normal) { Some(vconfig) => vconfig.index, None => config.default.index, }; @@ -136,3 +143,23 @@ impl MaterailConfiguration { }; } } + +fn rotate_times(normal: u8, times: usize) -> u8 { + let mut ret = normal; + if times > 0 { + for _ in 0..times { + ret = rotate_half_pi(ret); + } + } + ret +} + +fn rotate_half_pi(normal: u8) -> u8 { + return match normal { + 0 => 5, + 2 => 0, + 3 => 2, + 5 => 3, + _ => normal, + }; +} diff --git a/src/lib.rs b/src/lib.rs index a21f9f6..34f7ff3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,7 +27,7 @@ pub const CHUNK_SIZE: i32 = 16; pub const CHUNK_SIZE_U32: u32 = CHUNK_SIZE as u32; pub const CHUNK_SIZE_ADD_2_U32: u32 = CHUNK_SIZE_U32 + 2; // 贴图个数 -pub const MAX_TEXTURE_COUNT: usize = 16; +pub const MAX_TEXTURE_COUNT: usize = 22; // 物体选择半径 pub const TOUCH_RADIUS: f32 = 5.; pub const CLIENT_DEBUG: bool = false; diff --git a/src/server/async_chunk.rs b/src/server/async_chunk.rs index 9f9c1f5..5e08a3e 100644 --- a/src/server/async_chunk.rs +++ b/src/server/async_chunk.rs @@ -105,7 +105,10 @@ pub fn deal_chunk_query_system( warn!("基岩无法破坏"); continue; } - if old_voxel.id != Voxel::EMPTY.id && voxel_type.id != Voxel::EMPTY.id { + if old_voxel.id != Voxel::EMPTY.id + && voxel_type.id != Voxel::EMPTY.id + && active_index != None + { warn!("放置错误"); continue; } @@ -130,7 +133,11 @@ pub fn deal_chunk_query_system( } } else { warn!("{}|角色没有当前生成的index", client_id); - continue; + if old_voxel.direction == voxel_type.direction { + continue; + } else { + println!("转动方向"); + } } } else { warn!("{}|{}没有找到资源对应关系", client_id, voxel_type.id); diff --git a/src/voxel_world/voxel.rs b/src/voxel_world/voxel.rs index b38da62..9936d37 100644 --- a/src/voxel_world/voxel.rs +++ b/src/voxel_world/voxel.rs @@ -4,12 +4,47 @@ use serde::{Deserialize, Serialize}; /** * 体素类型 + * + * 这里要设计使用 u32的数据 + * voxel_data >> 8u & 0b111 8位后的数据 9 10 11位置的数据 + * voxel_data & 255u 表示取最后的8位 + * 方块是否透明是否要记录呢?不用在数据库中,但是转回来的时候我要知道。并且可以生成对应的mesh在地图中 + * + * 存储类型: + * 体素类型 方块方向 + * [0-8] [9 10] + * todo 在某种情况下计算不同位置的 图片索引和贴图? + * + * 展示时的数据 + * 贴图索引 法向量 方块方向 + * [0-8] [9-11] [12 13] + * + * 是否可视等 是在其他地方定义的 + * */ #[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, Reflect, PartialEq, Eq, Hash)] pub struct Voxel { pub id: u8, + pub direction: VoxelDirection, } +// 体素方向 +#[derive(Debug, Clone, Copy, Reflect, Serialize, Deserialize, Default, PartialEq, Eq, Hash)] +pub enum VoxelDirection { + #[default] + Z, + NZ, // 指向Z的负数半轴 + X, + NX, // 指向X的负数半轴 +} + +pub const VOXEL_DIRECTION_VEC: [VoxelDirection; 4] = [ + VoxelDirection::Z, + VoxelDirection::NZ, + VoxelDirection::X, + VoxelDirection::NX, +]; + impl PartialOrd for Voxel { fn partial_cmp(&self, other: &Self) -> Option { self.id.partial_cmp(&other.id) @@ -23,8 +58,53 @@ impl Ord for Voxel { } impl Voxel { - pub const EMPTY: Self = Self { id: 0 }; - pub const FILLED: Self = Self { id: 1 }; + pub const EMPTY: Self = Self { + id: 0, + direction: VoxelDirection::Z, + }; + pub const FILLED: Self = Self { + id: 1, + direction: VoxelDirection::Z, + }; + + // 转换成32位的存在类型 + pub fn into_save_u32(&self) -> u32 { + let direction_base = match self.direction { + VoxelDirection::Z => 0u32 << 8u32, + VoxelDirection::NZ => 1u32 << 8u32, + VoxelDirection::X => 2u32 << 8u32, + VoxelDirection::NX => 3u32 << 8u32, + }; + (self.id as u32) | direction_base + } + + // u32 位置类型转换成 体素类型 + pub fn u32_into_voxel(data: u32) -> Self { + Self { + id: Self::pick_id(data), + direction: Self::pick_direction(data), + } + } + + pub fn pick_id(data: u32) -> u8 { + (data & 255u32) as u8 + } + + pub fn pick_direction(data: u32) -> VoxelDirection { + VOXEL_DIRECTION_VEC[(data >> 8u32 & 0b11) as usize] + } + + pub fn next_direction(&self) -> Self { + Self { + id: self.id, + direction: match self.direction { + VoxelDirection::Z => VoxelDirection::X, + VoxelDirection::X => VoxelDirection::NZ, + VoxelDirection::NZ => VoxelDirection::NX, + VoxelDirection::NX => VoxelDirection::Z, + }, + } + } } impl MeshVoxel for Voxel { @@ -49,7 +129,18 @@ pub trait VoxelMaterial { const ID: u8; fn into_voxel() -> Voxel { - Voxel { id: Self::ID } + Voxel { + id: Self::ID, + ..Default::default() + } + } + + // 转化成 有方向的体素数据 + fn into_voxel_with_dir(direction: VoxelDirection) -> Voxel { + Voxel { + id: Self::ID, + direction, + } } } @@ -81,3 +172,4 @@ voxel_material!(DryGrass, 干草地, 8); voxel_material!(BuleGrass, 苍翠地, 9); voxel_material!(AppleWood, 苹果树原木, 10); voxel_material!(AppleLeaf, 苹果树叶子, 11); +voxel_material!(TestCube, 测试方块, 12); diff --git a/staff.ron b/staff.ron index 5b02c00..49c4646 100644 --- a/staff.ron +++ b/staff.ron @@ -1,17 +1,18 @@ ( configs:[ - (id:0,name:"Stone",icon_string:"textures/002.png",staff_type:Voxel((id:1))), - (id:1,name:"Grass",icon_string:"textures/草坪.png",staff_type:Voxel((id:3))), - (id:2,name:"Soli",icon_string:"textures/003.png",staff_type:Voxel((id:2))), - (id:3,name:"Sand",icon_string:"textures/沙子.png",staff_type:Voxel((id:6))), - (id:4,name:"Sown",icon_string:"textures/雪.png",staff_type:Voxel((id:4))), + (id:0,name:"Stone",icon_string:"textures/002.png",staff_type:Voxel((id:1,direction:Z))), + (id:1,name:"Grass",icon_string:"textures/草坪.png",staff_type:Voxel((id:3,direction:Z))), + (id:2,name:"Soli",icon_string:"textures/003.png",staff_type:Voxel((id:2,direction:Z))), + (id:3,name:"Sand",icon_string:"textures/沙子.png",staff_type:Voxel((id:6,direction:Z))), + (id:4,name:"Sown",icon_string:"textures/雪.png",staff_type:Voxel((id:4,direction:Z))), (id:5,name:"FireWork",icon_string:"staff/烟花.png",staff_type:Consumable(0)), - (id:6,name:"DryGrass",icon_string:"textures/干草地.png",staff_type:Voxel((id:8))), - (id:7,name:"BlueGrass",icon_string:"textures/苍翠地.png",staff_type:Voxel((id:9))), - (id:8,name:"AppleWood",icon_string:"textures/苹果树A面.png",staff_type:Voxel((id:10))), - (id:9,name:"AppleLeaf",icon_string:"textures/苹果叶子.png",staff_type:Voxel((id:11))), + (id:6,name:"DryGrass",icon_string:"textures/干草地.png",staff_type:Voxel((id:8,direction:Z))), + (id:7,name:"BlueGrass",icon_string:"textures/苍翠地.png",staff_type:Voxel((id:9,direction:Z))), + (id:8,name:"AppleWood",icon_string:"textures/苹果树A面.png",staff_type:Voxel((id:10,direction:Z))), + (id:9,name:"AppleLeaf",icon_string:"textures/苹果叶子.png",staff_type:Voxel((id:11,direction:Z))), (id:10,name:"Apple",icon_string:"textures/苹果.png",staff_type:Consumable(0)), (id:11,name:"AppleLog",icon_string:"textures/棍子.png",staff_type:Consumable(0)), + (id:12,name:"TestCube",icon_string:"textures/测试1.png",staff_type:Voxel((id:12,direction:Z))), ], // 掉落配置 filled_configs:[ diff --git a/staff_rules.ron b/staff_rules.ron index 7397063..61601ff 100644 --- a/staff_rules.ron +++ b/staff_rules.ron @@ -14,4 +14,16 @@ base_on:None, desc:"测试使用的合成烟花的公式(测试一个合成多个)", ), + ( + id:1, + input:[ + (staff_id:0,num_needed:1), + ], + // 合成测试方块 + output: [ + (staff_id:12,num_needed:1), + ], + base_on:None, + desc:"合成测试使用的摆放方块", + ), ] \ No newline at end of file diff --git a/volex.ron b/volex.ron index 2e4b076..90a750e 100644 --- a/volex.ron +++ b/volex.ron @@ -1,5 +1,13 @@ ( voxels:{ + 12:(type_name:"TestCube",type_ch_name:"测试使用方块",default:(index:21,path:"textures/测试6.png"),normal:{ + 1:(index:16,path:"textures/测试1.png"), + 2:(index:17,path:"textures/测试2.png"), + 3:(index:18,path:"textures/测试3.png"), + 4:(index:19,path:"textures/测试4.png"), + 5:(index:20,path:"textures/测试5.png"), + 0:(index:21,path:"textures/测试6.png"), + }), 11:(type_name:"AppleLeaf",type_ch_name:"苹果树叶子",default:(index:15,path:"textures/苹果叶子.png"),normal:{}), 10:(type_name:"AppleWood",type_ch_name:"苹果树原木",default:(index:13,path:"textures/苹果树A面.png"),normal:{ 4:(index:14,path:"textures/苹果树B面.png"), @@ -44,4 +52,11 @@ "textures/苹果树B面.png", //15 "textures/苹果叶子.png", + "textures/测试1.png", + "textures/测试2.png", + "textures/测试3.png", + "textures/测试4.png", + //20 + "textures/测试5.png", + "textures/测试6.png", ]) \ No newline at end of file From 6ba29d884fbc593f862c10fdb75f809cb3b86311 Mon Sep 17 00:00:00 2001 From: zhouzihao <1042181618@qq.com> Date: Thu, 14 Sep 2023 16:16:00 +0800 Subject: [PATCH 2/2] doc --- README.md | 1 + README_CN.md | 2 ++ 2 files changed, 3 insertions(+) diff --git a/README.md b/README.md index b80768e..35f3d54 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ pub const CLIENT_MAP_GEN: bool = true; - T - toggle One/Thrid Person - E - Open composite rules list - Q - throw active toolbar object +- (Hold Left-Shift Left-Click)-rotation Cube Direction # Feature List - [x] Load unlimited maps diff --git a/README_CN.md b/README_CN.md index eceaeac..a77e36e 100644 --- a/README_CN.md +++ b/README_CN.md @@ -33,6 +33,8 @@ cargo run --release --bin client - T 切换视角 - E 打开合成表 - Q 丢弃toolbar上激活中的物品 +- 按住左Shirt+左键单机。旋转方块方向 + # LIB 中的配置常量 ```rust