Compare commits

..

8 commits

15 changed files with 1106 additions and 1117 deletions

633
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -33,3 +33,8 @@ opt-level = 3
[profile.dev.package.rayon] [profile.dev.package.rayon]
opt-level = 3 opt-level = 3
#this is cursed as fuck
#enabling debug assertions here causes the game to abort
[profile.dev.package.android-activity]
debug-assertions = false

View file

@ -1,29 +1,29 @@
[package] [package]
name = "kubi-server" name = "kubi-server"
version = "0.0.0" version = "0.0.0"
edition = "2021" edition = "2021"
publish = false publish = false
[dependencies] [dependencies]
kubi-shared = { path = "../kubi-shared" } kubi-shared = { path = "../kubi-shared" }
kubi-logging = { path = "../kubi-logging" } kubi-logging = { path = "../kubi-logging" }
log = "0.4" log = "0.4"
shipyard = { git = "https://github.com/leudz/shipyard", rev = "8ef90ea6c4d1eb6c9cb0988f0d2f873f75044d49", default-features = false, features = ["std", "proc", "thread_local"] } shipyard = { git = "https://github.com/leudz/shipyard", rev = "9099b990e", default-features = false, features = ["std", "proc", "thread_local"] }
serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] }
toml = "0.8" toml = "0.8"
glam = { version = "0.24", features = ["debug-glam-assert", "fast-math"] } glam = { version = "0.25", features = ["debug-glam-assert", "fast-math"] }
hashbrown = "0.14" hashbrown = "0.14"
nohash-hasher = "0.2" nohash-hasher = "0.2"
anyhow = "1.0" anyhow = "1.0"
rayon = "1.7" rayon = "1.7"
flume = "0.11" flume = "0.11"
rand = "0.8" rand = "0.8"
uflow = "0.7" uflow = "0.7"
postcard = { version = "1.0", features = ["alloc"] } postcard = { version = "1.0", features = ["alloc"] }
lz4_flex = { version = "0.11", default-features = false, features = ["std"] } lz4_flex = { version = "0.11", default-features = false, features = ["std"] }
[features] [features]
default = ["parallel"] default = ["parallel"]
parallel = ["shipyard/parallel"] parallel = ["shipyard/parallel"]
safe_lz4 = ["lz4_flex/safe-encode", "lz4_flex/safe-decode"] safe_lz4 = ["lz4_flex/safe-encode", "lz4_flex/safe-decode"]
nightly = ["hashbrown/nightly", "rand/nightly", "rand/simd_support", "glam/core-simd", "kubi-shared/nightly"] nightly = ["hashbrown/nightly", "rand/nightly", "rand/simd_support", "glam/core-simd", "kubi-shared/nightly"]

View file

@ -1,28 +1,28 @@
[package] [package]
name = "kubi-shared" name = "kubi-shared"
version = "0.0.0" version = "0.0.0"
edition = "2021" edition = "2021"
publish = false publish = false
[dependencies] [dependencies]
glam = { version = "0.24", features = ["debug-glam-assert", "fast-math", "serde"] } glam = { version = "0.25", features = ["debug-glam-assert", "fast-math", "serde"] }
shipyard = { git = "https://github.com/leudz/shipyard", rev = "8ef90ea6c4d1eb6c9cb0988f0d2f873f75044d49", default-features = false, features = ["std"] } shipyard = { git = "https://github.com/leudz/shipyard", rev = "9099b990e", default-features = false, features = ["std"] }
strum = { version = "0.25", features = ["derive"] } strum = { version = "0.26", features = ["derive"] }
num_enum = "0.7" num_enum = "0.7"
postcard = { version = "1.0", features = ["alloc"] } postcard = { version = "1.0", features = ["alloc"] }
serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] }
serde_with = "3.4" serde_with = "3.4"
bincode = "1.3" bincode = "1.3"
anyhow = "1.0" anyhow = "1.0"
bracket-noise = "0.8" bracket-noise = "0.8"
rand = { version = "0.8", default_features = false, features = ["std", "min_const_gen"] } rand = { version = "0.8", default_features = false, features = ["std", "min_const_gen"] }
rand_xoshiro = "0.6" rand_xoshiro = "0.6"
hashbrown = { version = "0.14", features = ["serde"] } hashbrown = { version = "0.14", features = ["serde"] }
nohash-hasher = "0.2" nohash-hasher = "0.2"
#bytemuck = { version = "1.14", features = ["derive"] } #bytemuck = { version = "1.14", features = ["derive"] }
static_assertions = "1.1" static_assertions = "1.1"
nz = "0.3" nz = "0.3"
[features] [features]
default = [] default = []
nightly = ["hashbrown/nightly", "rand/nightly", "rand/simd_support", "glam/core-simd"] nightly = ["hashbrown/nightly", "rand/nightly", "rand/simd_support", "glam/core-simd"]

View file

@ -10,7 +10,7 @@ publish = false
kubi-ui = { path = "../kubi-ui" } kubi-ui = { path = "../kubi-ui" }
kubi-ui-glium = { path = "../kubi-ui-glium" } kubi-ui-glium = { path = "../kubi-ui-glium" }
kubi-logging = { path = "../kubi-logging" } kubi-logging = { path = "../kubi-logging" }
glium = { git = "https://github.com/glium/glium", rev = "968fc92378caf" } glium = { git = "https://github.com/glium/glium", rev = "a352c667" }
winit = "0.29" winit = "0.29"
glam = "0.24" glam = "0.25"
log = "0.4" log = "0.4"

View file

@ -7,6 +7,6 @@ publish = false
[dependencies] [dependencies]
kubi-ui = { path = "../kubi-ui", default-features = false } kubi-ui = { path = "../kubi-ui", default-features = false }
#kubi-ui = { path = "../kubi-ui" } #kubi-ui = { path = "../kubi-ui" }
glium = { git = "https://github.com/glium/glium", rev = "968fc92378caf" } glium = { git = "https://github.com/glium/glium", rev = "a352c667" }
glam = "0.24" glam = "0.25"
log = "0.4" log = "0.4"

View file

@ -50,8 +50,8 @@ impl BufferPair {
pub fn new<F: Facade>(facade: &F) -> Self { pub fn new<F: Facade>(facade: &F) -> Self {
log::debug!("init ui buffers..."); log::debug!("init ui buffers...");
Self { Self {
vertex_buffer: VertexBuffer::empty_persistent(facade, 1024).unwrap(), vertex_buffer: VertexBuffer::empty_dynamic(facade, 1024).unwrap(),
index_buffer: IndexBuffer::empty_persistent(facade, PrimitiveType::TrianglesList, 1024).unwrap(), index_buffer: IndexBuffer::empty_dynamic(facade, PrimitiveType::TrianglesList, 1024).unwrap(),
vertex_count: 0, vertex_count: 0,
index_count: 0, index_count: 0,
} }
@ -68,13 +68,13 @@ impl BufferPair {
let new_idx_size = (need_idx + 1).next_power_of_two(); let new_idx_size = (need_idx + 1).next_power_of_two();
log::debug!("resizing buffers: vtx {} -> {}, idx {} -> {}", current_vtx_size, new_vtx_size, current_idx_size, new_idx_size); log::debug!("resizing buffers: vtx {} -> {}, idx {} -> {}", current_vtx_size, new_vtx_size, current_idx_size, new_idx_size);
if current_vtx_size != new_vtx_size { if current_vtx_size != new_vtx_size {
self.vertex_buffer = VertexBuffer::empty_persistent( self.vertex_buffer = VertexBuffer::empty_dynamic(
self.vertex_buffer.get_context(), self.vertex_buffer.get_context(),
new_vtx_size new_vtx_size
).unwrap(); ).unwrap();
} }
if current_idx_size != new_idx_size { if current_idx_size != new_idx_size {
self.index_buffer = IndexBuffer::empty_persistent( self.index_buffer = IndexBuffer::empty_dynamic(
self.index_buffer.get_context(), self.index_buffer.get_context(),
PrimitiveType::TrianglesList, PrimitiveType::TrianglesList,
new_idx_size new_idx_size

View file

@ -1,19 +1,19 @@
[package] [package]
name = "kubi-ui" name = "kubi-ui"
version = "0.0.0" version = "0.0.0"
edition = "2021" edition = "2021"
publish = false publish = false
[dependencies] [dependencies]
hashbrown = "0.14" hashbrown = "0.14"
nohash-hasher = "0.2" nohash-hasher = "0.2"
glam = "0.24" glam = "0.25"
fontdue = "0.8" fontdue = "0.8"
rect_packer = "0.2" rect_packer = "0.2"
log = "0.4" log = "0.4"
[features] [features]
default = ["builtin_elements", "builtin_font"] default = ["builtin_elements", "builtin_font"]
builtin_font = [] builtin_font = []
builtin_elements = [] builtin_elements = []
#parallel = ["dep:rayon", "fontdue/parallel"] #parallel = ["dep:rayon", "fontdue/parallel"]

View file

@ -1,83 +1,89 @@
[package] [package]
name = "kubi" name = "kubi"
version = "0.0.0" version = "0.0.0"
edition = "2021" edition = "2021"
publish = false publish = false
[lib] [lib]
name = "kubilib" name = "kubilib"
crate-type = ["lib", "cdylib"] crate-type = ["lib", "cdylib"]
[dependencies] [dependencies]
kubi-shared = { path = "../kubi-shared" } kubi-shared = { path = "../kubi-shared" }
kubi-logging = { path = "../kubi-logging" } kubi-logging = { path = "../kubi-logging" }
kubi-ui = { path = "../kubi-ui" } kubi-ui = { path = "../kubi-ui" }
kubi-ui-glium = { path = "../kubi-ui-glium" } kubi-ui-glium = { path = "../kubi-ui-glium" }
log = "0.4" log = "0.4"
glium = { git = "https://github.com/glium/glium", rev = "968fc92378caf" } glium = { git = "https://github.com/glium/glium", rev = "a352c667" }
glutin = "0.31" glutin = "0.31"
winit = { version = "0.29", features = ["android-native-activity"] } winit = { version = "0.29", features = ["android-native-activity"] }
glutin-winit = "0.4" glutin-winit = "0.4"
raw-window-handle = "0.5" raw-window-handle = "=0.5.*"
glam = { version = "0.24", features = ["debug-glam-assert", "fast-math"] } glam = { version = "0.25", features = ["debug-glam-assert", "fast-math"] }
image = { version = "0.24", default_features = false, features = ["png"] } image = { version = "0.24", default_features = false, features = ["png"] }
strum = { version = "0.25", features = ["derive"] } strum = { version = "0.26", features = ["derive"] }
hashbrown = "0.14" hashbrown = "0.14"
nohash-hasher = "0.2" nohash-hasher = "0.2"
rayon = "1.7" rayon = "1.7"
shipyard = { git = "https://github.com/leudz/shipyard", rev = "8ef90ea6c4d1eb6c9cb0988f0d2f873f75044d49", default-features = false, features = ["std", "proc", "thread_local"] } shipyard = { git = "https://github.com/leudz/shipyard", rev = "9099b990e", default-features = false, features = ["std", "proc", "thread_local"] }
anyhow = "1.0" anyhow = "1.0"
flume = "0.11" flume = "0.11"
gilrs = { version = "0.10", default_features = false, features = ["xinput"] } gilrs = { version = "0.10", default_features = false, features = ["xinput"] }
uflow = "0.7" uflow = "0.7"
postcard = { version = "1.0", features = ["alloc"] } postcard = { version = "1.0", features = ["alloc"] }
lz4_flex = { version = "0.11", default-features = false, features = ["std"] } lz4_flex = { version = "0.11", default-features = false, features = ["std"] }
static_assertions = "1.1" static_assertions = "1.1"
tinyset = "0.4" tinyset = "0.4"
serde_json = { version = "1.0", optional = true } #only used for `generate_visualizer_data` serde_json = { version = "1.0", optional = true } #only used for `generate_visualizer_data`
[target.'cfg(target_os = "android")'.dependencies] [target.'cfg(target_os = "android")'.dependencies]
android-activity = "0.5" android-activity = "^0.5.2"
ndk = "0.8" ndk = "0.8"
[target.'cfg(target_os = "windows")'.dependencies] [target.'cfg(target_os = "windows")'.dependencies]
winapi = "0.3" winapi = "0.3"
[features] [features]
default = ["raw-evt"] default = ["raw-evt"]
raw-evt = [] #required for mouse input, but breaks keyboard on android raw-evt = [] #required for mouse input, but breaks keyboard on android
generate_visualizer_data = ["dep:serde_json", "shipyard/serde1"] generate_visualizer_data = ["dep: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"] # causes some serious issues! parallel = ["shipyard/parallel"] # causes some serious issues!
nightly = ["hashbrown/nightly", "glam/core-simd", "static_assertions/nightly", "lz4_flex/nightly", "kubi-shared/nightly"] nightly = ["hashbrown/nightly", "glam/core-simd", "static_assertions/nightly", "lz4_flex/nightly", "kubi-shared/nightly"]
#part of wip android support #part of wip android support
[package.metadata.android] [package.metadata.android]
package = "com.ggh.kubi" package = "com.ggh.kubi"
build_targets = ["aarch64-linux-android"] build_targets = ["aarch64-linux-android"]
assets = "../assets" assets = "../assets"
apk_name = "kubi" apk_name = "kubi"
theme = "@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen" theme = "@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen"
label = "Kubi" label = "Kubi"
orientation = "sensorLandscape"
[package.metadata.android.sdk]
[package.metadata.android.sdk] min_sdk_version = 16
min_sdk_version = 16 target_sdk_version = 30
target_sdk_version = 30
[[package.metadata.android.uses_feature]]
[[package.metadata.android.uses_feature]] glEsVersion = 0x00030000
required = true required = true
glEsVersion = 0x00030000
[[package.metadata.android.uses_feature]]
[[package.metadata.android.uses_feature]] name = "android.hardware.touchscreen.multitouch"
name = "android.hardware.touchscreen.multitouch" required = true
required = true
[[package.metadata.android.uses_feature]]
[[package.metadata.android.uses_feature]] name = "android.hardware.touchscreen.multitouch.distinct"
name = "android.hardware.touchscreen.multitouch.distinct" required = true
required = true
[package.metadata.android.application.activity]
[package.metadata.android.application.activity] label = "Kubi"
config_changes = "orientation|keyboardHidden|screenLayout|screenSize" launch_mode = "singleTop"
exported = true orientation = "sensorLandscape"
resizeable_activity = true config_changes = "orientation|keyboardHidden|screenLayout|screenSize"
exported = true
resizeable_activity = true
# [package.metadata.android.signing.release]
# path = "$HOME/.android/debug.keystore"
# keystore_password = "android"

View file

@ -0,0 +1,52 @@
//TODO client-side physics
//TODO move this to shared
use glam::{Mat4, Vec3};
use kubi_shared::transform::Transform;
use shipyard::{track, AllStoragesView, Component, IntoIter, Unique, UniqueView, View, ViewMut};
use crate::delta_time::DeltaTime;
#[derive(Unique)]
pub struct GlobalClPhysicsConfig {
pub gravity: Vec3,
}
#[derive(Component)]
pub struct ClPhysicsActor {
pub forces: Vec3,
pub velocity: Vec3,
pub terminal_velocity: f32,
//TODO: this should be configurable per block
pub friction_agains_ground: f32,
}
impl Default for ClPhysicsActor {
fn default() -> Self {
Self {
forces: Vec3::ZERO,
velocity: Vec3::ZERO,
terminal_velocity: 40.,
friction_agains_ground: 0.5,
}
}
}
pub fn init_client_physics(
storages: AllStoragesView,
) {
storages.add_unique(GlobalClPhysicsConfig {
gravity: Vec3::new(0., -9.8, 0.),
});
}
pub fn update_client_physics_late(
controllers: View<ClPhysicsActor>,
mut transforms: ViewMut<Transform, track::All>,
dt: UniqueView<DeltaTime>,
phy_conf: UniqueView<GlobalClPhysicsConfig>,
) {
// for (_, mut transform) in (&controllers, &mut transforms).iter() {
// let (scale, rotation, mut translation) = transform.0.to_scale_rotation_translation();
// translation.y -= dt.0.as_secs_f32() * 100.;
// transform.0 = Mat4::from_scale_rotation_translation(scale, rotation, translation);
// }
}

View file

@ -1,36 +1,36 @@
use shipyard::{AllStoragesView, Unique, NonSendSync, UniqueView, UniqueViewMut}; use shipyard::{AllStoragesView, Unique, NonSendSync, UniqueView, UniqueViewMut};
use crate::rendering::Renderer; use crate::rendering::Renderer;
use winit::window::CursorGrabMode; use winit::window::CursorGrabMode;
#[derive(Unique)] #[derive(Unique)]
pub struct CursorLock(pub bool); pub struct CursorLock(pub bool);
pub fn update_cursor_lock_state( pub fn update_cursor_lock_state(
lock: UniqueView<CursorLock>, lock: UniqueView<CursorLock>,
display: NonSendSync<UniqueView<Renderer>> display: NonSendSync<UniqueView<Renderer>>
) { ) {
if cfg!(target_os = "android") { if cfg!(target_os = "android") {
return return
} }
if lock.is_inserted_or_modified() { if lock.is_inserted_or_modified() {
//TODO MIGRATION //TODO MIGRATION
let window = &display.window; let window = &display.window;
window.set_cursor_grab(match lock.0 { window.set_cursor_grab(match lock.0 {
true => CursorGrabMode::Confined, true => CursorGrabMode::Confined,
false => CursorGrabMode::None, false => CursorGrabMode::None,
}).expect("Failed to change cursor grab state"); }).expect("Failed to change cursor grab state");
window.set_cursor_visible(!lock.0); window.set_cursor_visible(!lock.0);
} }
} }
pub fn insert_lock_state( pub fn insert_lock_state(
storages: AllStoragesView storages: AllStoragesView
) { ) {
storages.add_unique(CursorLock(false)) storages.add_unique(CursorLock(false))
} }
pub fn lock_cursor_now( pub fn lock_cursor_now(
mut lock: UniqueViewMut<CursorLock> mut lock: UniqueViewMut<CursorLock>
) { ) {
lock.0 = true lock.0 = true
} }

View file

@ -1,106 +1,106 @@
use glam::UVec2; use glam::UVec2;
use shipyard::{World, Component, AllStoragesViewMut, SparseSet, NonSendSync, UniqueView}; use shipyard::{World, Component, AllStoragesViewMut, SparseSet, NonSendSync, UniqueView};
use winit::event::{Event, DeviceEvent, DeviceId, WindowEvent, Touch, RawKeyEvent, TouchPhase}; use winit::event::{Event, DeviceEvent, DeviceId, WindowEvent, Touch};
use crate::rendering::Renderer; use crate::rendering::Renderer;
pub mod player_actions; pub mod player_actions;
#[derive(Component, Clone, Copy, Debug, Default)] #[derive(Component, Clone, Copy, Debug, Default)]
pub struct EventComponent; pub struct EventComponent;
#[derive(Component, Clone, Copy, Debug, Default)] #[derive(Component, Clone, Copy, Debug, Default)]
pub struct OnBeforeExitEvent; pub struct OnBeforeExitEvent;
#[derive(Component, Clone, Debug)] #[derive(Component, Clone, Debug)]
pub struct InputDeviceEvent{ pub struct InputDeviceEvent{
pub device_id: DeviceId, pub device_id: DeviceId,
pub event: DeviceEvent pub event: DeviceEvent
} }
#[derive(Component, Clone, Copy, Debug)] #[derive(Component, Clone, Copy, Debug)]
#[repr(transparent)] #[repr(transparent)]
pub struct TouchEvent(pub Touch); pub struct TouchEvent(pub Touch);
#[derive(Component, Clone, Copy, Debug, Default)] #[derive(Component, Clone, Copy, Debug, Default)]
pub struct WindowResizedEvent(pub UVec2); pub struct WindowResizedEvent(pub UVec2);
pub fn process_glutin_events(world: &mut World, event: &Event<()>) { pub fn process_winit_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"))] #[cfg(not(feature = "raw-evt"))]
WindowEvent::KeyboardInput { device_id, event, .. } => { WindowEvent::KeyboardInput { device_id, event, .. } => {
world.add_entity(( world.add_entity((
EventComponent, EventComponent,
InputDeviceEvent { InputDeviceEvent {
device_id: *device_id, device_id: *device_id,
event: DeviceEvent::Key(RawKeyEvent { event: DeviceEvent::Key(RawKeyEvent {
physical_key: event.physical_key, physical_key: event.physical_key,
state: event.state, state: event.state,
}) })
} }
)); ));
} }
WindowEvent::Touch(touch) => { WindowEvent::Touch(touch) => {
// if matches!(touch.phase, TouchPhase::Started | TouchPhase::Cancelled | TouchPhase::Ended) { // if matches!(touch.phase, TouchPhase::Started | TouchPhase::Cancelled | TouchPhase::Ended) {
// println!("TOUCH ==================== {:#?}", touch); // println!("TOUCH ==================== {:#?}", touch);
// } else { // } else {
// println!("TOUCH MOVED {:?} {}", touch.phase, touch.id); // println!("TOUCH MOVED {:?} {}", touch.phase, touch.id);
// } // }
world.add_entity(( world.add_entity((
EventComponent, EventComponent,
TouchEvent(*touch) TouchEvent(*touch)
)); ));
} }
_ => () _ => ()
}, },
#[cfg(feature = "raw-evt")] #[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::LoopExiting => { Event::LoopExiting => {
world.add_entity(( world.add_entity((
EventComponent, EventComponent,
OnBeforeExitEvent OnBeforeExitEvent
)); ));
}, },
_ => (), _ => (),
} }
} }
pub fn initial_resize_event( pub fn initial_resize_event(
mut storages: AllStoragesViewMut, mut storages: AllStoragesViewMut,
) { ) {
let (w, h) = { let (w, h) = {
let renderer = storages.borrow::<NonSendSync<UniqueView<Renderer>>>().unwrap(); let renderer = storages.borrow::<NonSendSync<UniqueView<Renderer>>>().unwrap();
renderer.display.get_framebuffer_dimensions() renderer.display.get_framebuffer_dimensions()
}; };
storages.add_entity(( storages.add_entity((
EventComponent, EventComponent,
WindowResizedEvent(UVec2::new(w, h)) WindowResizedEvent(UVec2::new(w, h))
)); ));
} }
pub fn clear_events( pub fn clear_events(
mut all_storages: AllStoragesViewMut, mut all_storages: AllStoragesViewMut,
) { ) {
all_storages.delete_any::<SparseSet<EventComponent>>(); all_storages.delete_any::<SparseSet<EventComponent>>();
} }

View file

@ -1,52 +1,53 @@
use glam::{Vec3, Mat4, Quat, EulerRot, Vec2}; use glam::{Vec3, Mat4, Quat, EulerRot, Vec2};
use shipyard::{Component, View, ViewMut, IntoIter, UniqueView, Workload, IntoWorkload, track}; use shipyard::{Component, View, ViewMut, IntoIter, UniqueView, Workload, IntoWorkload, track};
use std::f32::consts::PI; use std::f32::consts::PI;
use crate::{transform::Transform, input::Inputs, settings::GameSettings, delta_time::DeltaTime}; use crate::{transform::Transform, input::Inputs, settings::GameSettings, delta_time::DeltaTime};
#[derive(Component)] #[derive(Component)]
pub struct FlyController; pub struct FlyController;
pub fn update_controllers() -> Workload { pub fn update_controllers() -> Workload {
( (
update_look, update_look,
update_movement update_movement
).into_sequential_workload() ).into_sequential_workload()
} }
const MAX_PITCH: f32 = PI/2. - 0.05; const MAX_PITCH: f32 = PI/2. - 0.05;
fn update_look( fn update_look(
controllers: View<FlyController>, controllers: View<FlyController>,
mut transforms: ViewMut<Transform, track::All>, mut transforms: ViewMut<Transform, track::All>,
inputs: UniqueView<Inputs>, inputs: UniqueView<Inputs>,
settings: UniqueView<GameSettings>, settings: UniqueView<GameSettings>,
dt: UniqueView<DeltaTime>, dt: UniqueView<DeltaTime>,
) { ) {
let look = inputs.look * settings.mouse_sensitivity * dt.0.as_secs_f32(); let look = inputs.look * settings.mouse_sensitivity * dt.0.as_secs_f32();
if look == Vec2::ZERO { return } if look == Vec2::ZERO { return }
for (_, mut transform) in (&controllers, &mut transforms).iter() { for (_, mut transform) in (&controllers, &mut transforms).iter() {
let (scale, mut rotation, translation) = transform.0.to_scale_rotation_translation(); let (scale, mut rotation, translation) = transform.0.to_scale_rotation_translation();
let (mut yaw, mut pitch, _roll) = rotation.to_euler(EulerRot::YXZ); let (mut yaw, mut pitch, _roll) = rotation.to_euler(EulerRot::YXZ);
yaw -= look.x; yaw -= look.x;
pitch -= look.y; pitch -= look.y;
pitch = pitch.clamp(-MAX_PITCH, MAX_PITCH); pitch = pitch.clamp(-MAX_PITCH, MAX_PITCH);
rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, 0.).normalize(); rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, 0.).normalize();
transform.0 = Mat4::from_scale_rotation_translation(scale, rotation, translation); transform.0 = Mat4::from_scale_rotation_translation(scale, rotation, translation);
} }
} }
fn update_movement( fn update_movement(
controllers: View<FlyController>, controllers: View<FlyController>,
mut transforms: ViewMut<Transform, track::All>, mut transforms: ViewMut<Transform, track::All>,
inputs: UniqueView<Inputs>, inputs: UniqueView<Inputs>,
dt: UniqueView<DeltaTime>, dt: UniqueView<DeltaTime>,
) { ) {
if inputs.movement == Vec2::ZERO { return } if inputs.movement == Vec2::ZERO { return }
let movement = inputs.movement * 30. * dt.0.as_secs_f32(); let movement = inputs.movement * 30. * dt.0.as_secs_f32();
for (_, mut transform) in (&controllers, &mut transforms).iter() { for (_, mut transform) in (&controllers, &mut transforms).iter() {
let (scale, rotation, mut translation) = transform.0.to_scale_rotation_translation(); let (scale, rotation, mut translation) = transform.0.to_scale_rotation_translation();
translation += (rotation * Vec3::NEG_Z).normalize() * movement.y; let rotation_norm = rotation.normalize();
translation += (rotation * Vec3::X).normalize() * movement.x; translation += (rotation_norm * Vec3::NEG_Z).normalize() * movement.y;
transform.0 = Mat4::from_scale_rotation_translation(scale, rotation, translation); translation += (rotation_norm * Vec3::X).normalize() * movement.x;
} transform.0 = Mat4::from_scale_rotation_translation(scale, rotation_norm, translation);
} }
}

View file

@ -1,310 +1,318 @@
#![allow(clippy::too_many_arguments)] // allowed because systems often need a lot of arguments #![allow(clippy::too_many_arguments)] // allowed because systems often need a lot of arguments
use shipyard::{ use shipyard::{
World, Workload, IntoWorkload, World, Workload, IntoWorkload,
UniqueView, UniqueViewMut, UniqueView, UniqueViewMut,
NonSendSync, WorkloadModificator, NonSendSync, WorkloadModificator,
SystemModificator SystemModificator
}; };
use winit::{ use winit::{
event_loop::{EventLoop, ControlFlow}, event_loop::{EventLoop, ControlFlow},
event::{Event, WindowEvent} event::{Event, WindowEvent}
}; };
use glam::vec3; use glam::vec3;
use std::time::Instant; use std::time::Instant;
pub use kubi_shared::transform; pub use kubi_shared::transform;
pub(crate) mod rendering; pub(crate) mod rendering;
pub(crate) mod world; pub(crate) mod world;
pub(crate) mod player; pub(crate) mod player;
pub(crate) mod prefabs; pub(crate) mod prefabs;
pub(crate) mod settings; pub(crate) mod settings;
pub(crate) mod camera; pub(crate) mod camera;
pub(crate) mod events; pub(crate) mod events;
pub(crate) mod input; pub(crate) mod input;
pub(crate) mod fly_controller; pub(crate) mod fly_controller;
pub(crate) mod block_placement; pub(crate) mod block_placement;
pub(crate) mod delta_time; pub(crate) mod delta_time;
pub(crate) mod cursor_lock; pub(crate) mod cursor_lock;
pub(crate) mod control_flow; pub(crate) mod control_flow;
pub(crate) mod state; pub(crate) mod state;
pub(crate) mod kubi_ui_integration; pub(crate) mod kubi_ui_integration;
pub(crate) mod networking; pub(crate) mod networking;
pub(crate) mod init; pub(crate) mod init;
pub(crate) mod color; pub(crate) mod color;
pub(crate) mod loading_screen; pub(crate) mod loading_screen;
pub(crate) mod connecting_screen; pub(crate) mod connecting_screen;
pub(crate) mod fixed_timestamp; pub(crate) mod fixed_timestamp;
pub(crate) mod filesystem; pub(crate) mod filesystem;
pub(crate) mod client_physics;
use world::{
init_game_world, use world::{
loading::update_loaded_world_around_player, init_game_world,
raycast::update_raycasts, loading::update_loaded_world_around_player,
queue::apply_queued_blocks, raycast::update_raycasts,
tasks::ChunkTaskManager, queue::apply_queued_blocks,
}; tasks::ChunkTaskManager,
use player::{spawn_player, MainPlayer}; };
use prefabs::load_prefabs; use player::{spawn_player, MainPlayer};
use settings::{load_settings, GameSettings}; use prefabs::load_prefabs;
use camera::compute_cameras; use settings::{load_settings, GameSettings};
use events::{ use camera::compute_cameras;
clear_events, use events::{
process_glutin_events, clear_events,
initial_resize_event, process_winit_events,
player_actions::generate_move_events, initial_resize_event,
}; player_actions::generate_move_events,
use input::{init_input, process_inputs}; };
use fly_controller::update_controllers; use input::{init_input, process_inputs};
use rendering::{ use fly_controller::update_controllers;
Renderer, use rendering::{
RenderTarget, Renderer,
BackgroundColor, RenderTarget,
clear_background, BackgroundColor,
init_window_size, clear_background,
update_window_size, init_window_size,
primitives::init_primitives, update_window_size,
world::{draw_world, draw_current_chunk_border}, primitives::init_primitives,
selection_box::render_selection_box, world::{draw_world, draw_current_chunk_border},
entities::render_entities, selection_box::render_selection_box,
}; entities::render_entities,
use block_placement::update_block_placement; };
use delta_time::{DeltaTime, init_delta_time}; use block_placement::update_block_placement;
use cursor_lock::{insert_lock_state, update_cursor_lock_state, lock_cursor_now}; use delta_time::{DeltaTime, init_delta_time};
use control_flow::{exit_on_esc, insert_control_flow_unique, RequestExit}; use cursor_lock::{insert_lock_state, update_cursor_lock_state, lock_cursor_now};
use state::{is_ingame, is_ingame_or_loading, is_loading, init_state, update_state, is_connecting}; use control_flow::{exit_on_esc, insert_control_flow_unique, RequestExit};
use networking::{update_networking, update_networking_late, is_multiplayer, disconnect_on_exit, is_singleplayer}; use state::{is_ingame, is_ingame_or_loading, is_loading, init_state, update_state, is_connecting};
use init::initialize_from_args; use networking::{update_networking, update_networking_late, is_multiplayer, disconnect_on_exit, is_singleplayer};
use kubi_ui_integration::{kubi_ui_init, kubi_ui_begin, kubi_ui_end, kubi_ui_draw}; use init::initialize_from_args;
use loading_screen::update_loading_screen; use kubi_ui_integration::{kubi_ui_init, kubi_ui_begin, kubi_ui_end, kubi_ui_draw};
use connecting_screen::switch_to_loading_if_connected; use loading_screen::update_loading_screen;
use fixed_timestamp::init_fixed_timestamp_storage; use connecting_screen::switch_to_loading_if_connected;
use filesystem::AssetManager; use fixed_timestamp::init_fixed_timestamp_storage;
use filesystem::AssetManager;
/// stuff required to init the renderer and other basic systems use client_physics::{init_client_physics, update_client_physics_late};
fn pre_startup() -> Workload {
( /// stuff required to init the renderer and other basic systems
load_settings, fn pre_startup() -> Workload {
).into_sequential_workload() (
} load_settings,
).into_sequential_workload()
fn startup() -> Workload { }
(
init_fixed_timestamp_storage, fn startup() -> Workload {
initial_resize_event, (
init_window_size, init_fixed_timestamp_storage,
kubi_ui_init, initial_resize_event,
load_prefabs, init_window_size,
init_primitives, kubi_ui_init,
insert_lock_state, load_prefabs,
init_state, init_primitives,
initialize_from_args, insert_lock_state,
lock_cursor_now, init_state,
init_input, initialize_from_args,
insert_control_flow_unique, lock_cursor_now,
init_delta_time, init_input,
).into_sequential_workload() insert_control_flow_unique,
} init_delta_time,
init_client_physics,
fn update() -> Workload { ).into_sequential_workload()
( }
update_window_size,
update_cursor_lock_state, fn update() -> Workload {
process_inputs, (
kubi_ui_begin, update_window_size,
( update_cursor_lock_state,
init_game_world.run_if_missing_unique::<ChunkTaskManager>(), process_inputs,
( kubi_ui_begin,
spawn_player.run_if_storage_empty::<MainPlayer>(), (
).into_sequential_workload().run_if(is_singleplayer), init_game_world.run_if_missing_unique::<ChunkTaskManager>(),
).into_sequential_workload().run_if(is_ingame_or_loading), (
update_networking().run_if(is_multiplayer), spawn_player.run_if_storage_empty::<MainPlayer>(),
( ).into_sequential_workload().run_if(is_singleplayer),
switch_to_loading_if_connected ).into_sequential_workload().run_if(is_ingame_or_loading),
).into_sequential_workload().run_if(is_connecting), update_networking().run_if(is_multiplayer),
( (
update_loading_screen, switch_to_loading_if_connected
).into_sequential_workload().run_if(is_loading), ).into_sequential_workload().run_if(is_connecting),
( (
update_loaded_world_around_player, update_loading_screen,
).into_sequential_workload().run_if(is_ingame_or_loading), ).into_sequential_workload().run_if(is_loading),
( (
update_controllers, update_loaded_world_around_player,
generate_move_events, ).into_sequential_workload().run_if(is_ingame_or_loading),
update_raycasts, (
update_block_placement, update_controllers,
apply_queued_blocks, update_client_physics_late,
).into_sequential_workload().run_if(is_ingame), generate_move_events,
update_networking_late.run_if(is_multiplayer), update_raycasts,
compute_cameras, update_block_placement,
kubi_ui_end, apply_queued_blocks,
update_state, ).into_sequential_workload().run_if(is_ingame),
exit_on_esc, update_networking_late.run_if(is_multiplayer),
disconnect_on_exit.run_if(is_multiplayer), compute_cameras,
).into_sequential_workload() kubi_ui_end,
} update_state,
exit_on_esc,
fn render() -> Workload { disconnect_on_exit.run_if(is_multiplayer),
( ).into_sequential_workload()
clear_background, }
(
draw_world, fn render() -> Workload {
draw_current_chunk_border, (
render_selection_box, clear_background,
render_entities, (
).into_sequential_workload().run_if(is_ingame), draw_world,
kubi_ui_draw, draw_current_chunk_border,
).into_sequential_workload() render_selection_box,
} render_entities,
).into_sequential_workload().run_if(is_ingame),
fn after_frame_end() -> Workload { kubi_ui_draw,
( ).into_sequential_workload()
clear_events, }
).into_sequential_workload()
} fn after_frame_end() -> Workload {
(
#[cfg(all(windows, not(debug_assertions)))] clear_events,
fn attach_console() { ).into_sequential_workload()
use winapi::um::wincon::{AttachConsole, ATTACH_PARENT_PROCESS}; }
unsafe { AttachConsole(ATTACH_PARENT_PROCESS); }
} #[cfg(all(windows, not(debug_assertions)))]
fn attach_console() {
#[no_mangle] use winapi::um::wincon::{AttachConsole, ATTACH_PARENT_PROCESS};
#[cfg(target_os = "android")] unsafe { AttachConsole(ATTACH_PARENT_PROCESS); }
pub fn android_main(app: android_activity::AndroidApp) { }
use android_activity::WindowManagerFlags;
app.set_window_flags(WindowManagerFlags::FULLSCREEN, WindowManagerFlags::empty()); #[no_mangle]
kubi_main(app) #[cfg(target_os = "android")]
} pub fn android_main(app: android_activity::AndroidApp) {
use android_activity::WindowManagerFlags;
#[no_mangle] app.set_window_flags(WindowManagerFlags::FULLSCREEN, WindowManagerFlags::empty());
pub fn kubi_main(#[cfg(target_os = "android")] app: android_activity::AndroidApp) { kubi_main(app)
//Attach console on release builds on windows }
#[cfg(all(windows, not(debug_assertions)))] attach_console();
#[no_mangle]
//Print version pub fn kubi_main(
println!("{:─^54}", format!("[ ▄▀ Kubi client v. {} ]", env!("CARGO_PKG_VERSION"))); #[cfg(target_os = "android")]
app: android_activity::AndroidApp
//Init env_logger ) {
kubi_logging::init(); //Attach console on release builds on windows
#[cfg(all(windows, not(debug_assertions)))]
//Create a shipyard world attach_console();
let mut world = World::new();
//Print version
//Init assman println!("{:─^54}", format!("[ ▄▀ Kubi client v. {} ]", env!("CARGO_PKG_VERSION")));
world.add_unique(AssetManager {
#[cfg(target_os = "android")] //Init env_logger
app: app.clone() kubi_logging::init();
});
//Create a shipyard world
//Register workloads let mut world = World::new();
world.add_workload(pre_startup);
world.add_workload(startup); //Init assman
world.add_workload(update); world.add_unique(AssetManager {
world.add_workload(render); #[cfg(target_os = "android")]
world.add_workload(after_frame_end); app: app.clone()
});
//Save _visualizer.json
#[cfg(feature = "generate_visualizer_data")] //Register workloads
std::fs::write( world.add_workload(pre_startup);
"_visualizer.json", world.add_workload(startup);
serde_json::to_string(&world.workloads_info()).unwrap(), world.add_workload(update);
).unwrap(); world.add_workload(render);
world.add_workload(after_frame_end);
//Run pre-startup procedure
world.run_workload(pre_startup).unwrap(); //Save _visualizer.json
#[cfg(feature = "generate_visualizer_data")]
//Create event loop std::fs::write(
let event_loop ={ "_visualizer.json",
#[cfg(not(target_os = "android"))] { EventLoop::new().unwrap() } serde_json::to_string(&world.workloads_info()).unwrap(),
#[cfg(target_os = "android")] { ).unwrap();
use winit::{
platform::android::EventLoopBuilderExtAndroid, //Run pre-startup procedure
event_loop::EventLoopBuilder world.run_workload(pre_startup).unwrap();
};
EventLoopBuilder::new().with_android_app(app).build().unwrap() //Create event loop
} let event_loop ={
}; #[cfg(not(target_os = "android"))] { EventLoop::new().unwrap() }
#[cfg(target_os = "android")] {
//Run the event loop use winit::{
let mut last_update = Instant::now(); platform::android::EventLoopBuilderExtAndroid,
let mut ready = false; event_loop::EventLoopBuilder
event_loop.run(move |event, window_target| { };
//Wait for the window to become active (required for android) EventLoopBuilder::new().with_android_app(app).build().unwrap()
if !ready { }
if Event::Resumed != event { };
window_target.set_control_flow(ControlFlow::Wait);
return //Run the event loop
} let mut last_update = Instant::now();
let mut ready = false;
//Initialize renderer event_loop.run(move |event, window_target| {
{ //Wait for the window to become active (required for android)
let settings = world.borrow::<UniqueView<GameSettings>>().unwrap(); if !ready {
world.add_unique_non_send_sync(Renderer::init(window_target, &settings)); if Event::Resumed != event {
} window_target.set_control_flow(ControlFlow::Wait);
world.add_unique(BackgroundColor(vec3(0.5, 0.5, 1.))); return
}
//Run startup systems
world.run_workload(startup).unwrap(); //Initialize renderer
{
ready = true; let settings = world.borrow::<UniqueView<GameSettings>>().unwrap();
} world.add_unique_non_send_sync(Renderer::init(window_target, &settings));
}
window_target.set_control_flow(ControlFlow::Poll); world.add_unique(BackgroundColor(vec3(0.5, 0.5, 1.)));
process_glutin_events(&mut world, &event); //Run startup systems
world.run_workload(startup).unwrap();
#[allow(clippy::collapsible_match, clippy::single_match)]
match event { ready = true;
#[cfg(target_os = "android")] }
Event::Suspended => {
window_target.exit(); window_target.set_control_flow(ControlFlow::Poll);
}
process_winit_events(&mut world, &event);
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => { #[allow(clippy::collapsible_match, clippy::single_match)]
log::info!("exit requested"); match event {
window_target.exit(); #[cfg(target_os = "android")]
}, Event::Suspended => {
_ => (), window_target.exit();
}, }
Event::AboutToWait => { Event::WindowEvent { event, .. } => match event {
//Update delta time (maybe move this into a system?) WindowEvent::CloseRequested => {
{ log::info!("exit requested");
let mut dt_view = world.borrow::<UniqueViewMut<DeltaTime>>().unwrap(); window_target.exit();
let now = Instant::now(); },
dt_view.0 = now - last_update; _ => (),
last_update = now; },
}
Event::AboutToWait => {
//Run update workflows //Update delta time (maybe move this into a system?)
world.run_workload(update).unwrap(); {
let mut dt_view = world.borrow::<UniqueViewMut<DeltaTime>>().unwrap();
//Start rendering (maybe use custom views for this?) let now = Instant::now();
let target = { dt_view.0 = now - last_update;
let renderer = world.borrow::<NonSendSync<UniqueView<Renderer>>>().unwrap(); last_update = now;
renderer.display.draw() }
};
world.add_unique_non_send_sync(RenderTarget(target)); //Run update workflows
world.run_workload(update).unwrap();
//Run render workflow
world.run_workload(render).unwrap(); //Start rendering (maybe use custom views for this?)
let target = {
//Finish rendering let renderer = world.borrow::<NonSendSync<UniqueView<Renderer>>>().unwrap();
let target = world.remove_unique::<RenderTarget>().unwrap(); renderer.display.draw()
target.0.finish().unwrap(); };
world.add_unique_non_send_sync(RenderTarget(target));
//After frame end
world.run_workload(after_frame_end).unwrap(); //Run render workflow
world.run_workload(render).unwrap();
//Process control flow changes
if world.borrow::<UniqueView<RequestExit>>().unwrap().0 { //Finish rendering
window_target.exit(); let target = world.remove_unique::<RenderTarget>().unwrap();
} target.0.finish().unwrap();
},
_ => (), //After frame end
}; world.run_workload(after_frame_end).unwrap();
}).unwrap();
} //Process control flow changes
if world.borrow::<UniqueView<RequestExit>>().unwrap().0 {
window_target.exit();
}
},
_ => (),
};
}).unwrap();
}

View file

@ -1,87 +1,89 @@
use glam::Mat4; use glam::Mat4;
use shipyard::{Component, AllStoragesViewMut, UniqueViewMut}; use shipyard::{Component, AllStoragesViewMut, UniqueViewMut};
use kubi_shared::{ use kubi_shared::{
entity::{Entity, Health}, entity::{Entity, Health},
player::{Player, PLAYER_HEALTH, PlayerHolding}, player::{Player, PLAYER_HEALTH, PlayerHolding},
block::Block, block::Block,
networking::{ networking::{
client::{Username, Client, ClientIdMap}, client::{Username, Client, ClientIdMap},
messages::ClientInitData messages::ClientInitData
} }
}; };
use crate::{ use crate::{
transform::Transform, camera::Camera,
camera::Camera, client_physics::ClPhysicsActor,
fly_controller::FlyController, fly_controller::FlyController,
world::raycast::LookingAtBlock, transform::Transform,
}; world::raycast::LookingAtBlock
};
#[derive(Component)]
pub struct MainPlayer; #[derive(Component)]
pub struct MainPlayer;
pub fn spawn_player (
mut storages: AllStoragesViewMut, pub fn spawn_player (
) { mut storages: AllStoragesViewMut,
log::info!("spawning player"); ) {
storages.add_entity(( log::info!("spawning player");
Player, storages.add_entity(((
MainPlayer, Player,
Entity, MainPlayer,
Health::new(PLAYER_HEALTH), Entity,
Transform::default(), Health::new(PLAYER_HEALTH),
Camera::default(), Transform::default(),
FlyController, Camera::default(),
LookingAtBlock::default(), FlyController,
PlayerHolding(Some(Block::Cobblestone)), LookingAtBlock::default(),
Username("LocalPlayer".into()) PlayerHolding(Some(Block::Cobblestone)),
)); Username("LocalPlayer".into()),
} ),(
ClPhysicsActor::default(),
pub fn spawn_local_player_multiplayer ( )));
storages: &mut AllStoragesViewMut, }
init: ClientInitData
) { pub fn spawn_local_player_multiplayer (
log::info!("spawning local multiplayer player"); storages: &mut AllStoragesViewMut,
let entity_id = storages.add_entity(( init: ClientInitData
( ) {
Player, log::info!("spawning local multiplayer player");
Client(init.client_id), let entity_id = storages.add_entity(((
MainPlayer, Player,
Entity, Client(init.client_id),
init.health, MainPlayer,
Transform(Mat4::from_rotation_translation(init.direction, init.position)), Entity,
Camera::default(), init.health,
FlyController, Transform(Mat4::from_rotation_translation(init.direction, init.position)),
LookingAtBlock::default(), Camera::default(),
PlayerHolding::default(), FlyController,
),( LookingAtBlock::default(),
Username(init.username) PlayerHolding::default(),
) ),(
)); Username(init.username),
ClPhysicsActor::default(),
//Add ourself to the client id map )));
let mut client_id_map = storages.borrow::<UniqueViewMut<ClientIdMap>>().unwrap();
client_id_map.0.insert(init.client_id, entity_id); //Add ourself to the client id map
} let mut client_id_map = storages.borrow::<UniqueViewMut<ClientIdMap>>().unwrap();
client_id_map.0.insert(init.client_id, entity_id);
pub fn spawn_remote_player_multiplayer( }
storages: &mut AllStoragesViewMut,
init: ClientInitData pub fn spawn_remote_player_multiplayer(
) { storages: &mut AllStoragesViewMut,
log::info!("spawning remote multiplayer player"); init: ClientInitData
) {
//Spawn player locally log::info!("spawning remote multiplayer player");
let entity_id = storages.add_entity((
Username(init.username), //Spawn player locally
Client(init.client_id), let entity_id = storages.add_entity((
Player, Username(init.username),
Entity, Client(init.client_id),
init.health, Player,
Transform(Mat4::from_rotation_translation(init.direction, init.position)), Entity,
PlayerHolding::default(), init.health,
)); Transform(Mat4::from_rotation_translation(init.direction, init.position)),
PlayerHolding::default(),
//Add it to the client id map ));
let mut client_id_map = storages.borrow::<UniqueViewMut<ClientIdMap>>().unwrap();
client_id_map.0.insert(init.client_id, entity_id); //Add it to the client id map
} let mut client_id_map = storages.borrow::<UniqueViewMut<ClientIdMap>>().unwrap();
client_id_map.0.insert(init.client_id, entity_id);
}