add raw-evt feature, fix clippy warnings

`raw-evt` is enable by default
forcing it off is required for kb input on android
mouse input is not supported without it yet though
This commit is contained in:
griffi-gh 2023-06-04 15:16:25 +02:00
parent c919aeb81b
commit 601e55fb9f
12 changed files with 109 additions and 74 deletions

View file

@ -41,19 +41,36 @@ build with nightly features
cargo +nightly build --bin kubi -r --features nightly cargo +nightly build --bin kubi -r --features nightly
``` ```
build for android build for android
please note that android support is purely experimental! please note that android support is purely experimental!
gamepad, keyboard and mouse input is currently borked, and touch controls are not available. gamepad, keyboard and mouse input is currently borked, and touch controls are not available.
srgb and blending are broken too, which leads to many rendering issues srgb and blending are broken too, which leads to many rendering issues
prerequisites: Android SDK, NDK, platform-tools, latest JDK (all should be in $PATH) prerequisites: Android SDK, NDK, platform-tools, latest JDK (all should be in $PATH)
Setup:
```bash ```bash
cargo install cargo-apk cargo install cargo-apk
cargo target add aarch64-linux-android cargo target add aarch64-linux-android
cargo apk build -p kubi ```
cargo apk run -p kubi
Build:
`--no-default-features` is required for keyboard input!
```bash
cargo apk build -p kubi --no-default-features
# or, with nighly optimizations:
cargo +nightly apk build -p kubi --no-default-features --features nightly
```
Run:
```bash
cargo apk run -p kubi --features nightly
# or, with nighly optimizations:
cargo +nightly apk run -p kubi --no-default-features --features nightly
``` ```
<h2>mutiplayer</h2> <h2>mutiplayer</h2>

View file

@ -81,7 +81,7 @@ pub fn authenticate_players(
//Find the player ID //Find the player ID
let max_clients = config.server.max_clients as ClientId; let max_clients = config.server.max_clients as ClientId;
let Some(client_id) = (0..max_clients).into_iter().find(|id| { let Some(client_id) = (0..max_clients).find(|id| {
!client_entity_map.0.contains_key(id) !client_entity_map.0.contains_key(id)
}) else { }) else {
client.borrow_mut().send( client.borrow_mut().send(

View file

@ -38,7 +38,6 @@ pub fn bind_server(
keepalive_interval_ms: 5000, keepalive_interval_ms: 5000,
..Default::default() ..Default::default()
}, },
..Default::default()
} }
).expect("Failed to create the server"); ).expect("Failed to create the server");
storages.add_unique_non_send_sync(UdpServer(server)); storages.add_unique_non_send_sync(UdpServer(server));

View file

@ -54,7 +54,7 @@ pub fn check_message_auth<'a, const C_MSG: u8>(
log::error!("Client not authenticated"); log::error!("Client not authenticated");
return None return None
}; };
let Ok(&Client(client_id)) = (&clients).get(entity_id) else { let Ok(&Client(client_id)) = clients.get(entity_id) else {
log::error!("Entity ID is invalid"); log::error!("Entity ID is invalid");
return None return None
}; };

View file

@ -71,7 +71,7 @@ fn process_chunk_requests(
//TODO Start task here if status is "Nothing" //TODO Start task here if status is "Nothing"
if let Some(blocks) = &chunk.blocks { if let Some(blocks) = &chunk.blocks {
send_chunk_compressed( send_chunk_compressed(
&message.client, message.client,
&ServerToClientMessage::ChunkResponse { &ServerToClientMessage::ChunkResponse {
chunk: chunk_position, chunk: chunk_position,
data: blocks.clone(), data: blocks.clone(),

View file

@ -9,7 +9,7 @@ use crate::{
}; };
fn mountain_ramp(mut x: f32) -> f32 { fn mountain_ramp(mut x: f32) -> f32 {
x = x * 2.0; x *= 2.0;
if x < 0.4 { if x < 0.4 {
0.5 * x 0.5 * x
} else if x < 0.55 { } else if x < 0.55 {
@ -94,7 +94,7 @@ pub fn generate_world(chunk_position: IVec3, seed: u64) -> (BlockData, Vec<Queue
let mut rng = Xoshiro256StarStar::seed_from_u64( let mut rng = Xoshiro256StarStar::seed_from_u64(
seed seed
^ ((chunk_position.x as u32 as u64) << 0) ^ (chunk_position.x as u32 as u64)
^ ((chunk_position.z as u32 as u64) << 32) ^ ((chunk_position.z as u32 as u64) << 32)
); );
let rng_map_a: [[f32; CHUNK_SIZE]; CHUNK_SIZE] = rng.gen(); let rng_map_a: [[f32; CHUNK_SIZE]; CHUNK_SIZE] = rng.gen();
@ -133,20 +133,18 @@ pub fn generate_world(chunk_position: IVec3, seed: u64) -> (BlockData, Vec<Queue
} }
} }
//Generate ravines //Generate ravines
if height < 0 { if height < 0 && raw_ravine_location_value > 0.4 {
if raw_ravine_location_value > 0.4 { let raw_ravine_value = ravine_nose_line.get_noise(noise_x, noise_y);
let raw_ravine_value = ravine_nose_line.get_noise(noise_x, noise_y); if (-0.0125..0.0125).contains(&(raw_ravine_value.powi(2))) {
if (-0.0125..0.0125).contains(&(raw_ravine_value.powi(2))) { is_surface = false;
is_surface = false; height -= (100. * (0.0125 - raw_ravine_value.powi(2)) * (1. / 0.0125)).round() as i32;
height -= (100. * (0.0125 - raw_ravine_value.powi(2)) * (1. / 0.0125)).round() as i32;
}
} }
} }
height height
}; };
//add to heightmap //add to heightmap
if is_surface { if is_surface {
deco_heightmap[x as usize][z as usize] = Some(height); deco_heightmap[x][z] = Some(height);
//place dirt //place dirt
for y in 0..local_height(height, chunk_position) { for y in 0..local_height(height, chunk_position) {
blocks[x][y][z] = Block::Dirt; blocks[x][y][z] = Block::Dirt;
@ -162,29 +160,27 @@ pub fn generate_world(chunk_position: IVec3, seed: u64) -> (BlockData, Vec<Queue
blocks[x][y][z] = Block::Grass; blocks[x][y][z] = Block::Grass;
within_heightmap = true; within_heightmap = true;
} }
} else if let Some(river_fill_height) = river_fill_height {
//Place water
for y in 0..local_height(river_fill_height, chunk_position) {
blocks[x][y][z] = Block::Water;
within_heightmap = true;
}
//Place stone
for y in 0..local_height(height, chunk_position) {
blocks[x][y][z] = Block::Stone;
within_heightmap = true;
}
//Place dirt
if let Some(y) = local_y_position(height, chunk_position) {
blocks[x][y][z] = Block::Dirt;
within_heightmap = true;
}
} else { } else {
if let Some(river_fill_height) = river_fill_height { //Place stone
//Place water for y in 0..local_height(height, chunk_position) {
for y in 0..local_height(river_fill_height, chunk_position) { blocks[x][y][z] = Block::Stone;
blocks[x][y][z] = Block::Water; within_heightmap = true;
within_heightmap = true;
}
//Place stone
for y in 0..local_height(height, chunk_position) {
blocks[x][y][z] = Block::Stone;
within_heightmap = true;
}
//Place dirt
if let Some(y) = local_y_position(height, chunk_position) {
blocks[x][y][z] = Block::Dirt;
within_heightmap = true;
}
} else {
//Place stone
for y in 0..local_height(height, chunk_position) {
blocks[x][y][z] = Block::Stone;
within_heightmap = true;
}
} }
} }
} }

View file

@ -37,7 +37,8 @@ ndk-glue = "0.7"
winapi = { version = "0.3" } winapi = { version = "0.3" }
[features] [features]
default = [] default = ["raw-evt"]
raw-evt = []
generate_visualizer_data = ["serde_json", "shipyard/serde1"] generate_visualizer_data = ["serde_json", "shipyard/serde1"]
safe_lz4 = ["lz4_flex/safe-encode", "lz4_flex/safe-decode"] safe_lz4 = ["lz4_flex/safe-encode", "lz4_flex/safe-decode"]
parallel = ["shipyard/parallel"] parallel = ["shipyard/parallel"]

View file

@ -24,29 +24,46 @@ pub fn process_glutin_events(world: &mut World, event: &Event<'_, ()>) {
#[allow(clippy::collapsible_match, clippy::single_match)] #[allow(clippy::collapsible_match, clippy::single_match)]
match event { match event {
Event::WindowEvent { window_id: _, event } => match event { Event::WindowEvent { window_id: _, event } => match event {
WindowEvent::Resized(size) => { WindowEvent::Resized(size) => {
world.add_entity(( world.add_entity((
EventComponent, EventComponent,
WindowResizedEvent(UVec2::new(size.width as _, size.height as _)) WindowResizedEvent(UVec2::new(size.width as _, size.height as _))
)); ));
}, },
#[cfg(not(feature = "raw-evt"))]
WindowEvent::KeyboardInput { device_id, input, is_synthetic } => {
world.add_entity((
EventComponent,
InputDeviceEvent {
device_id: *device_id,
event: DeviceEvent::Key(*input)
}
));
}
_ => () _ => ()
}, },
#[cfg(feature = "raw-evt")]
Event::DeviceEvent { device_id, event } => { Event::DeviceEvent { device_id, event } => {
world.add_entity(( world.add_entity((
EventComponent, EventComponent,
InputDeviceEvent { InputDeviceEvent {
device_id: *device_id, device_id: *device_id,
event: event.clone() event: event.clone()
} }
)); ));
}, },
Event::LoopDestroyed => { Event::LoopDestroyed => {
world.add_entity(( world.add_entity((
EventComponent, EventComponent,
OnBeforeExitEvent OnBeforeExitEvent
)); ));
}, },
_ => (), _ => (),
} }
} }

View file

@ -4,7 +4,6 @@ use anyhow::Result;
pub trait ReadOnly: Read + Seek {} pub trait ReadOnly: Read + Seek {}
impl<T: Read + Seek> ReadOnly for T {} impl<T: Read + Seek> ReadOnly for T {}
#[allow(unreachable_code)]
pub fn open_asset(path: &Path) -> Result<Box<dyn ReadOnly>> { pub fn open_asset(path: &Path) -> Result<Box<dyn ReadOnly>> {
#[cfg(target_os = "android")] { #[cfg(target_os = "android")] {
use anyhow::Context; use anyhow::Context;
@ -13,8 +12,10 @@ pub fn open_asset(path: &Path) -> Result<Box<dyn ReadOnly>> {
let asset_manager = ndk_glue::native_activity().asset_manager(); let asset_manager = ndk_glue::native_activity().asset_manager();
let path_cstr = CString::new(path.to_string_lossy().as_bytes())?; let path_cstr = CString::new(path.to_string_lossy().as_bytes())?;
let handle = asset_manager.open(&path_cstr).context("Asset doesn't exist")?; let handle = asset_manager.open(&path_cstr).context("Asset doesn't exist")?;
return Ok(Box::new(handle)); Ok(Box::new(handle))
}
#[cfg(not(target_os = "android"))] {
let asset_path = Path::new("./assets/").join(path);
Ok(Box::new(File::open(asset_path)?))
} }
let asset_path = Path::new("./assets/").join(path);
return Ok(Box::new(File::open(asset_path)?))
} }

View file

@ -14,15 +14,15 @@ use crate::{
world::{ world::{
tasks::{ChunkTaskResponse, ChunkTaskManager}, tasks::{ChunkTaskResponse, ChunkTaskManager},
queue::BlockUpdateQueue queue::BlockUpdateQueue
}, },
}; };
use super::{NetworkEvent, UdpClient}; use super::{NetworkEvent, UdpClient};
//TODO multithreaded decompression //TODO multithreaded decompression
fn decompress_chunk_packet(data: &Box<[u8]>) -> Result<ServerToClientMessage> { fn decompress_chunk_packet(data: &[u8]) -> Result<ServerToClientMessage> {
let mut decompressed = decompress_size_prepended(&data[1..])?; let mut decompressed = decompress_size_prepended(&data[1..])?;
decompressed.insert(0, data[0]); decompressed.insert(0, data[0]);
Ok(postcard::from_bytes(&decompressed).ok().context("Deserialization failed")?) postcard::from_bytes(&decompressed).ok().context("Deserialization failed")
} }
//TODO get rid of this, this is awfulll //TODO get rid of this, this is awfulll
@ -38,7 +38,7 @@ pub fn inject_network_responses_into_manager_queue(
chunk, data, queued chunk, data, queued
} = packet else { unreachable!() }; } = packet else { unreachable!() };
manager.add_sussy_response(ChunkTaskResponse::LoadedChunk { manager.add_sussy_response(ChunkTaskResponse::LoadedChunk {
position: chunk, position: chunk,
chunk_data: data, chunk_data: data,
queued queued
}); });

View file

@ -41,6 +41,11 @@ impl Renderer {
.with_maximized(true) .with_maximized(true)
.with_min_inner_size(PhysicalSize::new(640, 480)) .with_min_inner_size(PhysicalSize::new(640, 480))
.with_fullscreen({ .with_fullscreen({
//this has no effect on android, so skip this pointless stuff
#[cfg(target_os = "android")] {
None
}
#[cfg(not(target_os = "android"))]
if let Some(fs_settings) = &settings.fullscreen { if let Some(fs_settings) = &settings.fullscreen {
let monitor = event_loop.primary_monitor().or_else(|| { let monitor = event_loop.primary_monitor().or_else(|| {
event_loop.available_monitors().next() event_loop.available_monitors().next()
@ -104,7 +109,7 @@ impl Renderer {
} }
pub fn clear_background( pub fn clear_background(
mut target: NonSendSync<UniqueViewMut<RenderTarget>>, mut target: NonSendSync<UniqueViewMut<RenderTarget>>,
color: UniqueView<BackgroundColor>, color: UniqueView<BackgroundColor>,
) { ) {
target.0.clear_color_srgb_and_depth((color.0.x, color.0.y, color.0.z, 1.), 1.); target.0.clear_color_srgb_and_depth((color.0.x, color.0.y, color.0.z, 1.), 1.);

View file

@ -1,9 +1,8 @@
use strum::EnumIter; use strum::EnumIter;
use glam::{Vec3, vec3, IVec3, ivec3}; use glam::{Vec3, vec3, IVec3, ivec3};
use std::f32::consts::FRAC_1_SQRT_2;
use crate::rendering::world::ChunkVertex; use crate::rendering::world::ChunkVertex;
const INV_SQRT_2: f32 = 0.70710678118655; // 1 / 2.sqrt()
#[repr(usize)] #[repr(usize)]
#[derive(Clone, Copy, Debug, EnumIter)] #[derive(Clone, Copy, Debug, EnumIter)]
pub enum CubeFace { pub enum CubeFace {
@ -28,7 +27,7 @@ const CUBE_FACE_VERTICES: [[Vec3; 4]; 6] = [
[vec3(1., 0., 1.), vec3(1., 1., 1.), vec3(0., 0., 1.), vec3(0., 1., 1.)], [vec3(1., 0., 1.), vec3(1., 1., 1.), vec3(0., 0., 1.), vec3(0., 1., 1.)],
[vec3(0., 0., 1.), vec3(0., 0., 0.), vec3(1., 0., 1.), vec3(1., 0., 0.)], [vec3(0., 0., 1.), vec3(0., 0., 0.), vec3(1., 0., 1.), vec3(1., 0., 0.)],
]; ];
const CUBE_FACE_NORMALS_IVEC3: [IVec3; 6] = [ const CUBE_FACE_NORMALS_IVEC3: [IVec3; 6] = [
ivec3( 0, 1, 0), ivec3( 0, 1, 0),
ivec3( 0, 0, -1), ivec3( 0, 0, -1),
ivec3(-1, 0, 0), ivec3(-1, 0, 0),
@ -36,7 +35,7 @@ const CUBE_FACE_NORMALS_IVEC3: [IVec3; 6] = [
ivec3( 0, 0, 1), ivec3( 0, 0, 1),
ivec3( 0, -1, 0) ivec3( 0, -1, 0)
]; ];
const CUBE_FACE_NORMALS: [Vec3; 6] = [ const CUBE_FACE_NORMALS: [Vec3; 6] = [
vec3(0., 1., 0.), vec3(0., 1., 0.),
vec3(0., 0., -1.), vec3(0., 0., -1.),
vec3(-1.,0., 0.), vec3(-1.,0., 0.),
@ -53,25 +52,25 @@ pub enum DiagonalFace {
} }
const CROSS_FACES: [[Vec3; 4]; 2] = [ const CROSS_FACES: [[Vec3; 4]; 2] = [
[ [
vec3(0., 0., 0.), vec3(0., 0., 0.),
vec3(0., 1., 0.), vec3(0., 1., 0.),
vec3(1., 0., 1.), vec3(1., 0., 1.),
vec3(1., 1., 1.), vec3(1., 1., 1.),
], ],
[ [
vec3(0., 0., 1.), vec3(0., 0., 1.),
vec3(0., 1., 1.), vec3(0., 1., 1.),
vec3(1., 0., 0.), vec3(1., 0., 0.),
vec3(1., 1., 0.), vec3(1., 1., 0.),
] ]
]; ];
const CROSS_FACE_NORMALS: [Vec3; 2] = [ const CROSS_FACE_NORMALS: [Vec3; 2] = [
vec3(-INV_SQRT_2, 0., INV_SQRT_2), vec3(-FRAC_1_SQRT_2, 0., FRAC_1_SQRT_2),
vec3(INV_SQRT_2, 0., INV_SQRT_2), vec3( FRAC_1_SQRT_2, 0., FRAC_1_SQRT_2),
]; ];
const CROSS_FACE_NORMALS_BACK: [Vec3; 2] = [ const CROSS_FACE_NORMALS_BACK: [Vec3; 2] = [
vec3(INV_SQRT_2, 0., -INV_SQRT_2), vec3( FRAC_1_SQRT_2, 0., -FRAC_1_SQRT_2),
vec3(-INV_SQRT_2, 0., -INV_SQRT_2), vec3(-FRAC_1_SQRT_2, 0., -FRAC_1_SQRT_2),
]; ];
const CROSS_FACE_INDICES: [u32; 12] = [ const CROSS_FACE_INDICES: [u32; 12] = [
0, 1, 2, 2, 1, 3, //Front side 0, 1, 2, 2, 1, 3, //Front side
@ -109,7 +108,7 @@ impl MeshBuilder {
self.vertex_buffer.push(ChunkVertex { self.vertex_buffer.push(ChunkVertex {
position: (coord + vert[i]).to_array(), position: (coord + vert[i]).to_array(),
normal: norm.to_array(), normal: norm.to_array(),
uv: UV_COORDS[i], uv: UV_COORDS[i],
tex_index: texture tex_index: texture
}); });
} }
@ -149,7 +148,7 @@ impl MeshBuilder {
self.index_buffer.extend_from_slice(&CROSS_FACE_INDICES.map(|x| x + self.idx_counter)); self.index_buffer.extend_from_slice(&CROSS_FACE_INDICES.map(|x| x + self.idx_counter));
//Increment idx counter //Increment idx counter
self.idx_counter += 8; self.idx_counter += 8;
} }
pub fn add_model(&mut self, position: Vec3, vertices: &[ChunkVertex], indices: Option<&[u32]>) { pub fn add_model(&mut self, position: Vec3, vertices: &[ChunkVertex], indices: Option<&[u32]>) {