mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Turning "full" chunks back on, deserialization improvements.
This commit is contained in:
parent
9c4b03482d
commit
ad5bcf3cd8
47
Cargo.lock
generated
47
Cargo.lock
generated
@ -1403,12 +1403,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling"
|
name = "darling"
|
||||||
version = "0.13.2"
|
version = "0.13.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4e92cb285610dd935f60ee8b4d62dd1988bd12b7ea50579bd6a138201525318e"
|
checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core 0.13.2",
|
"darling_core 0.13.4",
|
||||||
"darling_macro 0.13.2",
|
"darling_macro 0.13.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1427,9 +1427,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling_core"
|
name = "darling_core"
|
||||||
version = "0.13.2"
|
version = "0.13.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5c29e95ab498b18131ea460b2c0baa18cbf041231d122b0b7bfebef8c8e88989"
|
checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fnv",
|
"fnv",
|
||||||
"ident_case",
|
"ident_case",
|
||||||
@ -1452,11 +1452,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling_macro"
|
name = "darling_macro"
|
||||||
version = "0.13.2"
|
version = "0.13.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b21dd6b221dd547528bd6fb15f1a3b7ab03b9a06f76bff288a8c629bcfbe7f0e"
|
checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core 0.13.2",
|
"darling_core 0.13.4",
|
||||||
"quote 1.0.17",
|
"quote 1.0.17",
|
||||||
"syn 1.0.90",
|
"syn 1.0.90",
|
||||||
]
|
]
|
||||||
@ -1683,7 +1683,7 @@ version = "0.5.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5c594871f94ab3a00434cb09f03067c92fa2ece4cc657d58ba402e8377cd85a3"
|
checksum = "5c594871f94ab3a00434cb09f03067c92fa2ece4cc657d58ba402e8377cd85a3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling 0.13.2",
|
"darling 0.13.4",
|
||||||
"proc-macro-crate 1.1.3",
|
"proc-macro-crate 1.1.3",
|
||||||
"proc-macro2 1.0.36",
|
"proc-macro2 1.0.36",
|
||||||
"quote 1.0.17",
|
"quote 1.0.17",
|
||||||
@ -3584,7 +3584,7 @@ version = "0.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c"
|
checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling 0.13.2",
|
"darling 0.13.4",
|
||||||
"proc-macro-crate 1.1.3",
|
"proc-macro-crate 1.1.3",
|
||||||
"proc-macro2 1.0.36",
|
"proc-macro2 1.0.36",
|
||||||
"quote 1.0.17",
|
"quote 1.0.17",
|
||||||
@ -5454,6 +5454,28 @@ dependencies = [
|
|||||||
"syn 1.0.90",
|
"syn 1.0.90",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_with"
|
||||||
|
version = "1.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_with_macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_with_macros"
|
||||||
|
version = "1.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082"
|
||||||
|
dependencies = [
|
||||||
|
"darling 0.13.4",
|
||||||
|
"proc-macro2 1.0.36",
|
||||||
|
"quote 1.0.17",
|
||||||
|
"syn 1.0.90",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha1"
|
name = "sha1"
|
||||||
version = "0.6.1"
|
version = "0.6.1"
|
||||||
@ -6521,6 +6543,7 @@ version = "0.12.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel",
|
"async-channel",
|
||||||
"authc",
|
"authc",
|
||||||
|
"bincode",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"clap 3.1.8",
|
"clap 3.1.8",
|
||||||
"hashbrown 0.11.2",
|
"hashbrown 0.11.2",
|
||||||
@ -6580,6 +6603,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_repr",
|
"serde_repr",
|
||||||
|
"serde_with",
|
||||||
"sha2",
|
"sha2",
|
||||||
"slab",
|
"slab",
|
||||||
"slotmap 1.0.6",
|
"slotmap 1.0.6",
|
||||||
@ -6654,6 +6678,7 @@ dependencies = [
|
|||||||
"image",
|
"image",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_with",
|
||||||
"specs",
|
"specs",
|
||||||
"specs-idvs",
|
"specs-idvs",
|
||||||
"sum_type",
|
"sum_type",
|
||||||
|
@ -21,6 +21,7 @@ common-systems = { package = "veloren-common-systems", path = "../common/systems
|
|||||||
common-net = { package = "veloren-common-net", path = "../common/net" }
|
common-net = { package = "veloren-common-net", path = "../common/net" }
|
||||||
network = { package = "veloren-network", path = "../network", features = ["compression","quic"], default-features = false }
|
network = { package = "veloren-network", path = "../network", features = ["compression","quic"], default-features = false }
|
||||||
|
|
||||||
|
bincode = "1.3.2"
|
||||||
byteorder = "1.3.2"
|
byteorder = "1.3.2"
|
||||||
tokio = { version = "1.14", default-features = false, features = ["rt-multi-thread"] }
|
tokio = { version = "1.14", default-features = false, features = ["rt-multi-thread"] }
|
||||||
quinn = "0.8"
|
quinn = "0.8"
|
||||||
|
@ -42,6 +42,10 @@ impl From<StreamError> for Error {
|
|||||||
fn from(err: StreamError) -> Self { Self::StreamErr(err) }
|
fn from(err: StreamError) -> Self { Self::StreamErr(err) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<bincode::Error> for Error {
|
||||||
|
fn from(err: bincode::Error) -> Self { Self::StreamErr(StreamError::Deserialize(err)) }
|
||||||
|
}
|
||||||
|
|
||||||
impl From<AuthClientError> for Error {
|
impl From<AuthClientError> for Error {
|
||||||
fn from(err: AuthClientError) -> Self { Self::AuthClientError(err) }
|
fn from(err: AuthClientError) -> Self { Self::AuthClientError(err) }
|
||||||
}
|
}
|
||||||
|
@ -2300,28 +2300,30 @@ impl Client {
|
|||||||
loop {
|
loop {
|
||||||
let cnt_start = cnt;
|
let cnt_start = cnt;
|
||||||
|
|
||||||
while let Some(msg) = self.general_stream.try_recv()? {
|
while let Some(msg) = self.general_stream.try_recv_raw()? {
|
||||||
cnt += 1;
|
cnt += 1;
|
||||||
self.handle_server_msg(frontend_events, msg)?;
|
self.handle_server_msg(frontend_events, bincode::deserialize(&msg.decompress()?)?)?;
|
||||||
}
|
}
|
||||||
while let Some(msg) = self.ping_stream.try_recv()? {
|
while let Some(msg) = self.ping_stream.try_recv_raw()? {
|
||||||
cnt += 1;
|
cnt += 1;
|
||||||
self.handle_ping_msg(msg)?;
|
self.handle_ping_msg(bincode::deserialize(&msg.decompress()?)?)?;
|
||||||
}
|
}
|
||||||
while let Some(msg) = self.character_screen_stream.try_recv()? {
|
while let Some(msg) = self.character_screen_stream.try_recv_raw()? {
|
||||||
cnt += 1;
|
cnt += 1;
|
||||||
self.handle_server_character_screen_msg(frontend_events, msg)?;
|
self.handle_server_character_screen_msg(frontend_events, bincode::deserialize(&msg.decompress()?)?)?;
|
||||||
}
|
}
|
||||||
while let Some(msg) = self.in_game_stream.try_recv()? {
|
while let Some(msg) = self.in_game_stream.try_recv_raw()? {
|
||||||
cnt += 1;
|
cnt += 1;
|
||||||
#[cfg(feature = "tracy")]
|
#[cfg(feature = "tracy")]
|
||||||
{
|
{
|
||||||
ingame_cnt += 1;
|
ingame_cnt += 1;
|
||||||
}
|
}
|
||||||
self.handle_server_in_game_msg(frontend_events, msg)?;
|
self.handle_server_in_game_msg(frontend_events, bincode::deserialize(&msg.decompress()?)?)?;
|
||||||
}
|
}
|
||||||
while let Some(msg) = self.terrain_stream.try_recv()? {
|
while let Some(msg) = self.terrain_stream.try_recv_raw()? {
|
||||||
cnt += 1;
|
cnt += 1;
|
||||||
|
let msg = msg.decompress()?;
|
||||||
|
let msg = bincode::deserialize(&msg)?;
|
||||||
#[cfg(feature = "tracy")]
|
#[cfg(feature = "tracy")]
|
||||||
{
|
{
|
||||||
if let ServerGeneral::TerrainChunkUpdate { chunk, .. } = &msg {
|
if let ServerGeneral::TerrainChunkUpdate { chunk, .. } = &msg {
|
||||||
|
@ -32,6 +32,7 @@ chrono = "0.4"
|
|||||||
chrono-tz = "0.6"
|
chrono-tz = "0.6"
|
||||||
sha2 = "0.10"
|
sha2 = "0.10"
|
||||||
serde_json = "1.0.50"
|
serde_json = "1.0.50"
|
||||||
|
serde_with = { version = "1.14.0" }
|
||||||
|
|
||||||
# Strum
|
# Strum
|
||||||
strum = { version = "0.24", features = ["derive"] }
|
strum = { version = "0.24", features = ["derive"] }
|
||||||
|
@ -30,3 +30,4 @@ specs-idvs = { git = "https://gitlab.com/veloren/specs-idvs.git", rev = "8be2abc
|
|||||||
|
|
||||||
# Serde
|
# Serde
|
||||||
serde = { version = "1.0.110", features = ["derive"] }
|
serde = { version = "1.0.110", features = ["derive"] }
|
||||||
|
serde_with = { version = "1.14.0" }
|
||||||
|
@ -8,23 +8,28 @@ use image::{ImageBuffer, ImageDecoder, Pixel};
|
|||||||
use num_traits::cast::FromPrimitive;
|
use num_traits::cast::FromPrimitive;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
|
borrow::Cow,
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
io::{Read, Write},
|
io::{Read, Write},
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
};
|
};
|
||||||
|
use serde_with::{serde_as, Bytes};
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
/// Wrapper for compressed, serialized data (for stuff that doesn't use the
|
/// Wrapper for compressed, serialized data (for stuff that doesn't use the
|
||||||
/// default lz4 compression)
|
/// default lz4 compression)
|
||||||
|
#[serde_as]
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct CompressedData<T> {
|
pub struct CompressedData<'a, T> {
|
||||||
pub data: Vec<u8>,
|
#[serde_as(as = "Bytes")]
|
||||||
|
#[serde(borrow)]
|
||||||
|
pub data: Cow<'a, [u8]>,
|
||||||
compressed: bool,
|
compressed: bool,
|
||||||
_phantom: PhantomData<T>,
|
_phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Serialize> CompressedData<T> {
|
impl<'a, T: Serialize> CompressedData<'a, T> {
|
||||||
pub fn compress(t: &T, level: u32) -> Self {
|
pub fn compress(t: &T, level: u32) -> Self {
|
||||||
use flate2::{write::DeflateEncoder, Compression};
|
use flate2::{write::DeflateEncoder, Compression};
|
||||||
let uncompressed = bincode::serialize(t)
|
let uncompressed = bincode::serialize(t)
|
||||||
@ -39,13 +44,13 @@ impl<T: Serialize> CompressedData<T> {
|
|||||||
encoder.write_all(&*uncompressed).expect(EXPECT_MSG);
|
encoder.write_all(&*uncompressed).expect(EXPECT_MSG);
|
||||||
let compressed = encoder.finish().expect(EXPECT_MSG);
|
let compressed = encoder.finish().expect(EXPECT_MSG);
|
||||||
CompressedData {
|
CompressedData {
|
||||||
data: compressed,
|
data: Cow::Owned(compressed),
|
||||||
compressed: true,
|
compressed: true,
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
CompressedData {
|
CompressedData {
|
||||||
data: uncompressed,
|
data: Cow::Owned(uncompressed),
|
||||||
compressed: false,
|
compressed: false,
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
}
|
}
|
||||||
@ -53,7 +58,7 @@ impl<T: Serialize> CompressedData<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: for<'a> Deserialize<'a>> CompressedData<T> {
|
impl<T: for<'a> Deserialize<'a>> CompressedData<'_, T> {
|
||||||
pub fn decompress(&self) -> Option<T> {
|
pub fn decompress(&self) -> Option<T> {
|
||||||
if self.compressed {
|
if self.compressed {
|
||||||
let mut uncompressed = Vec::with_capacity(self.data.len());
|
let mut uncompressed = Vec::with_capacity(self.data.len());
|
||||||
@ -186,10 +191,10 @@ impl<'a, VIE: VoxelImageDecoding> VoxelImageDecoding for &'a VIE {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||||
pub struct QuadPngEncoding<const RESOLUTION_DIVIDER: u32>();
|
pub struct QuadPngEncoding<'a, const RESOLUTION_DIVIDER: u32>(pub PhantomData<&'a ()>);
|
||||||
|
|
||||||
impl<const N: u32> VoxelImageEncoding for QuadPngEncoding<N> {
|
impl<'a, const N: u32> VoxelImageEncoding for QuadPngEncoding<'a, N> {
|
||||||
type Output = CompressedData<(Vec<u8>, [usize; 3])>;
|
type Output = CompressedData<'a, (Vec<u8>, [usize; 3])>;
|
||||||
type Workspace = (
|
type Workspace = (
|
||||||
ImageBuffer<image::Luma<u8>, Vec<u8>>,
|
ImageBuffer<image::Luma<u8>, Vec<u8>>,
|
||||||
ImageBuffer<image::Luma<u8>, Vec<u8>>,
|
ImageBuffer<image::Luma<u8>, Vec<u8>>,
|
||||||
@ -317,7 +322,7 @@ const fn gen_lanczos_lookup<const N: u32, const R: u32>(
|
|||||||
array
|
array
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const N: u32> VoxelImageDecoding for QuadPngEncoding<N> {
|
impl<const N: u32> VoxelImageDecoding for QuadPngEncoding<'_, N> {
|
||||||
fn start(data: &Self::Output) -> Option<Self::Workspace> {
|
fn start(data: &Self::Output) -> Option<Self::Workspace> {
|
||||||
use image::codecs::png::PngDecoder;
|
use image::codecs::png::PngDecoder;
|
||||||
let (quad, indices) = data.decompress()?;
|
let (quad, indices) = data.decompress()?;
|
||||||
@ -460,10 +465,10 @@ impl<const N: u32> VoxelImageDecoding for QuadPngEncoding<N> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||||
pub struct TriPngEncoding<const AVERAGE_PALETTE: bool>();
|
pub struct TriPngEncoding<'a, const AVERAGE_PALETTE: bool>(pub PhantomData<&'a ()>);
|
||||||
|
|
||||||
impl<const AVERAGE_PALETTE: bool> VoxelImageEncoding for TriPngEncoding<AVERAGE_PALETTE> {
|
impl<'a, const AVERAGE_PALETTE: bool> VoxelImageEncoding for TriPngEncoding<'a, AVERAGE_PALETTE> {
|
||||||
type Output = CompressedData<(Vec<u8>, Vec<Rgb<u8>>, [usize; 3])>;
|
type Output = CompressedData<'a, (Vec<u8>, Vec<Rgb<u8>>, [usize; 3])>;
|
||||||
type Workspace = (
|
type Workspace = (
|
||||||
ImageBuffer<image::Luma<u8>, Vec<u8>>,
|
ImageBuffer<image::Luma<u8>, Vec<u8>>,
|
||||||
ImageBuffer<image::Luma<u8>, Vec<u8>>,
|
ImageBuffer<image::Luma<u8>, Vec<u8>>,
|
||||||
@ -549,7 +554,7 @@ impl<const AVERAGE_PALETTE: bool> VoxelImageEncoding for TriPngEncoding<AVERAGE_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const AVERAGE_PALETTE: bool> VoxelImageDecoding for TriPngEncoding<AVERAGE_PALETTE> {
|
impl<const AVERAGE_PALETTE: bool> VoxelImageDecoding for TriPngEncoding<'_, AVERAGE_PALETTE> {
|
||||||
fn start(data: &Self::Output) -> Option<Self::Workspace> {
|
fn start(data: &Self::Output) -> Option<Self::Workspace> {
|
||||||
use image::codecs::png::PngDecoder;
|
use image::codecs::png::PngDecoder;
|
||||||
let (quad, palette, indices) = data.decompress()?;
|
let (quad, palette, indices) = data.decompress()?;
|
||||||
|
@ -15,6 +15,7 @@ use common::{
|
|||||||
trade::{PendingTrade, SitePrices, TradeId, TradeResult},
|
trade::{PendingTrade, SitePrices, TradeId, TradeResult},
|
||||||
uid::Uid,
|
uid::Uid,
|
||||||
};
|
};
|
||||||
|
use core::marker::PhantomData;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@ -24,7 +25,7 @@ use vek::*;
|
|||||||
///This struct contains all messages the server might send (on different
|
///This struct contains all messages the server might send (on different
|
||||||
/// streams though)
|
/// streams though)
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ServerMsg {
|
pub enum ServerMsg<'a> {
|
||||||
/// Basic info about server, send ONCE, clients need it to Register
|
/// Basic info about server, send ONCE, clients need it to Register
|
||||||
Info(ServerInfo),
|
Info(ServerInfo),
|
||||||
/// Initial data package, send BEFORE Register ONCE. Not Register relevant
|
/// Initial data package, send BEFORE Register ONCE. Not Register relevant
|
||||||
@ -32,7 +33,7 @@ pub enum ServerMsg {
|
|||||||
/// Result to `ClientMsg::Register`. send ONCE
|
/// Result to `ClientMsg::Register`. send ONCE
|
||||||
RegisterAnswer(ServerRegisterAnswer),
|
RegisterAnswer(ServerRegisterAnswer),
|
||||||
///Msg that can be send ALWAYS as soon as client is registered, e.g. `Chat`
|
///Msg that can be send ALWAYS as soon as client is registered, e.g. `Chat`
|
||||||
General(ServerGeneral),
|
General(ServerGeneral<'a>),
|
||||||
Ping(PingMsg),
|
Ping(PingMsg),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,13 +71,16 @@ pub enum ServerInit {
|
|||||||
pub type ServerRegisterAnswer = Result<(), RegisterError>;
|
pub type ServerRegisterAnswer = Result<(), RegisterError>;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub enum SerializedTerrainChunk {
|
pub enum SerializedTerrainChunk<'a> {
|
||||||
DeflatedChonk(CompressedData<TerrainChunk>),
|
#[serde(borrow)]
|
||||||
QuadPng(WireChonk<QuadPngEncoding<4>, WidePacking<true>, TerrainChunkMeta, TerrainChunkSize>),
|
DeflatedChonk(CompressedData<'a, TerrainChunk>),
|
||||||
TriPng(WireChonk<TriPngEncoding<false>, WidePacking<true>, TerrainChunkMeta, TerrainChunkSize>),
|
#[serde(borrow)]
|
||||||
|
QuadPng(WireChonk<QuadPngEncoding<'a, 4>, WidePacking<true>, TerrainChunkMeta, TerrainChunkSize>),
|
||||||
|
#[serde(borrow)]
|
||||||
|
TriPng(WireChonk<TriPngEncoding<'a, false>, WidePacking<true>, TerrainChunkMeta, TerrainChunkSize>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SerializedTerrainChunk {
|
impl SerializedTerrainChunk<'_> {
|
||||||
pub fn approx_len(&self) -> usize {
|
pub fn approx_len(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
SerializedTerrainChunk::DeflatedChonk(data) => data.data.len(),
|
SerializedTerrainChunk::DeflatedChonk(data) => data.data.len(),
|
||||||
@ -98,7 +102,7 @@ impl SerializedTerrainChunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn quadpng(chunk: &TerrainChunk) -> Self {
|
pub fn quadpng(chunk: &TerrainChunk) -> Self {
|
||||||
if let Some(wc) = WireChonk::from_chonk(QuadPngEncoding(), WidePacking(), chunk) {
|
if let Some(wc) = WireChonk::from_chonk(QuadPngEncoding(PhantomData), WidePacking(), chunk) {
|
||||||
Self::QuadPng(wc)
|
Self::QuadPng(wc)
|
||||||
} else {
|
} else {
|
||||||
warn!("Image encoding failure occurred, falling back to deflate");
|
warn!("Image encoding failure occurred, falling back to deflate");
|
||||||
@ -107,7 +111,7 @@ impl SerializedTerrainChunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn tripng(chunk: &TerrainChunk) -> Self {
|
pub fn tripng(chunk: &TerrainChunk) -> Self {
|
||||||
if let Some(wc) = WireChonk::from_chonk(TriPngEncoding(), WidePacking(), chunk) {
|
if let Some(wc) = WireChonk::from_chonk(TriPngEncoding(PhantomData), WidePacking(), chunk) {
|
||||||
Self::TriPng(wc)
|
Self::TriPng(wc)
|
||||||
} else {
|
} else {
|
||||||
warn!("Image encoding failure occurred, falling back to deflate");
|
warn!("Image encoding failure occurred, falling back to deflate");
|
||||||
@ -126,7 +130,7 @@ impl SerializedTerrainChunk {
|
|||||||
|
|
||||||
/// Messages sent from the server to the client
|
/// Messages sent from the server to the client
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub enum ServerGeneral {
|
pub enum ServerGeneral<'a> {
|
||||||
//Character Screen related
|
//Character Screen related
|
||||||
/// An error occurred while loading character data
|
/// An error occurred while loading character data
|
||||||
CharacterDataLoadError(String),
|
CharacterDataLoadError(String),
|
||||||
@ -169,13 +173,14 @@ pub enum ServerGeneral {
|
|||||||
// Ingame related AND terrain stream
|
// Ingame related AND terrain stream
|
||||||
TerrainChunkUpdate {
|
TerrainChunkUpdate {
|
||||||
key: Vec2<i32>,
|
key: Vec2<i32>,
|
||||||
chunk: Result<SerializedTerrainChunk, ()>,
|
chunk: Result<SerializedTerrainChunk<'a>, ()>,
|
||||||
},
|
},
|
||||||
LodZoneUpdate {
|
LodZoneUpdate {
|
||||||
key: Vec2<i32>,
|
key: Vec2<i32>,
|
||||||
zone: lod::Zone,
|
zone: lod::Zone,
|
||||||
},
|
},
|
||||||
TerrainBlockUpdates(CompressedData<HashMap<Vec3<i32>, Block>>),
|
#[serde(borrow)]
|
||||||
|
TerrainBlockUpdates(CompressedData<'a, HashMap<Vec3<i32>, Block>>),
|
||||||
// Always possible
|
// Always possible
|
||||||
PlayerListUpdate(PlayerListUpdate),
|
PlayerListUpdate(PlayerListUpdate),
|
||||||
/// A message to go into the client chat box. The client is responsible for
|
/// A message to go into the client chat box. The client is responsible for
|
||||||
@ -198,7 +203,7 @@ pub enum ServerGeneral {
|
|||||||
MapMarker(comp::MapMarkerUpdate),
|
MapMarker(comp::MapMarkerUpdate),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServerGeneral {
|
impl ServerGeneral<'_> {
|
||||||
pub fn server_msg<S>(chat_type: comp::ChatType<String>, msg: S) -> Self
|
pub fn server_msg<S>(chat_type: comp::ChatType<String>, msg: S) -> Self
|
||||||
where
|
where
|
||||||
S: Into<String>,
|
S: Into<String>,
|
||||||
@ -266,7 +271,7 @@ pub enum RegisterError {
|
|||||||
//TODO: InvalidAlias,
|
//TODO: InvalidAlias,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServerMsg {
|
impl ServerMsg<'_> {
|
||||||
pub fn verify(
|
pub fn verify(
|
||||||
&self,
|
&self,
|
||||||
c_type: ClientType,
|
c_type: ClientType,
|
||||||
@ -329,26 +334,26 @@ impl ServerMsg {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<comp::ChatMsg> for ServerGeneral {
|
impl From<comp::ChatMsg> for ServerGeneral<'_> {
|
||||||
fn from(v: comp::ChatMsg) -> Self { ServerGeneral::ChatMsg(v) }
|
fn from(v: comp::ChatMsg) -> Self { ServerGeneral::ChatMsg(v) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ServerInfo> for ServerMsg {
|
impl From<ServerInfo> for ServerMsg<'_> {
|
||||||
fn from(o: ServerInfo) -> ServerMsg { ServerMsg::Info(o) }
|
fn from(o: ServerInfo) -> Self { ServerMsg::Info(o) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ServerInit> for ServerMsg {
|
impl From<ServerInit> for ServerMsg<'_> {
|
||||||
fn from(o: ServerInit) -> ServerMsg { ServerMsg::Init(Box::new(o)) }
|
fn from(o: ServerInit) -> Self { ServerMsg::Init(Box::new(o)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ServerRegisterAnswer> for ServerMsg {
|
impl From<ServerRegisterAnswer> for ServerMsg<'_> {
|
||||||
fn from(o: ServerRegisterAnswer) -> ServerMsg { ServerMsg::RegisterAnswer(o) }
|
fn from(o: ServerRegisterAnswer) -> Self { ServerMsg::RegisterAnswer(o) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ServerGeneral> for ServerMsg {
|
impl<'a> From<ServerGeneral<'a>> for ServerMsg<'a> {
|
||||||
fn from(o: ServerGeneral) -> ServerMsg { ServerMsg::General(o) }
|
fn from(o: ServerGeneral<'a>) -> Self { ServerMsg::General(o) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<PingMsg> for ServerMsg {
|
impl From<PingMsg> for ServerMsg<'_> {
|
||||||
fn from(o: PingMsg) -> ServerMsg { ServerMsg::Ping(o) }
|
fn from(o: PingMsg) -> Self { ServerMsg::Ping(o) }
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
use common::{grid::Grid, trade::Good};
|
use common::{grid::Grid, trade::Good};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_with::{serde_as, Bytes};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
|
#[serde_as]
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
/// World map information. Note that currently, we always send the whole thing
|
/// World map information. Note that currently, we always send the whole thing
|
||||||
/// in one go, but the structure aims to try to provide information as locally
|
/// in one go, but the structure aims to try to provide information as locally
|
||||||
@ -121,6 +123,7 @@ pub struct WorldMapMsg {
|
|||||||
/// more predictible sequence) would end up compressing better than storing
|
/// more predictible sequence) would end up compressing better than storing
|
||||||
/// angles, or that we don't need as much precision as we currently have
|
/// angles, or that we don't need as much precision as we currently have
|
||||||
/// (256 possible angles).
|
/// (256 possible angles).
|
||||||
|
#[serde_as(as = "[(Bytes, Bytes); 2]")]
|
||||||
pub horizons: [(Vec<u8>, Vec<u8>); 2],
|
pub horizons: [(Vec<u8>, Vec<u8>); 2],
|
||||||
pub sites: Vec<SiteInfo>,
|
pub sites: Vec<SiteInfo>,
|
||||||
pub pois: Vec<PoiInfo>,
|
pub pois: Vec<PoiInfo>,
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
generic_arg_infer,
|
generic_arg_infer,
|
||||||
label_break_value,
|
label_break_value,
|
||||||
option_zip,
|
option_zip,
|
||||||
|
portable_simd,
|
||||||
|
slice_as_chunks,
|
||||||
trait_alias,
|
trait_alias,
|
||||||
type_alias_impl_trait,
|
type_alias_impl_trait,
|
||||||
extend_one,
|
extend_one,
|
||||||
|
@ -7,7 +7,8 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use num_derive::FromPrimitive;
|
use num_derive::FromPrimitive;
|
||||||
use num_traits::FromPrimitive;
|
use num_traits::FromPrimitive;
|
||||||
use serde::{ser, Deserialize, Serialize};
|
use serde::{de::{self, Error}, ser, Deserialize, Serialize};
|
||||||
|
use serde_with::{serde_as, Bytes, DeserializeAs};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use strum::{Display, EnumIter, EnumString};
|
use strum::{Display, EnumIter, EnumString};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
@ -123,11 +124,13 @@ impl BlockKind {
|
|||||||
/// the implementation of BlockVec! BlockVec uses unsafe code that depends on being able to
|
/// the implementation of BlockVec! BlockVec uses unsafe code that depends on being able to
|
||||||
/// independently validate the kind and treat attr as bytes; changing things so that this no longer
|
/// independently validate the kind and treat attr as bytes; changing things so that this no longer
|
||||||
/// works will require careful review.
|
/// works will require careful review.
|
||||||
|
#[serde_as]
|
||||||
#[derive(AsBytes, Copy, Clone, Debug, Eq, Serialize, Deserialize)]
|
#[derive(AsBytes, Copy, Clone, Debug, Eq, Serialize, Deserialize)]
|
||||||
/// NOTE: repr(C) appears to preserve niche optimizations!
|
/// NOTE: repr(C) appears to preserve niche optimizations!
|
||||||
#[repr(align(4), C)]
|
#[repr(align(4), C)]
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
kind: BlockKind,
|
kind: BlockKind,
|
||||||
|
#[serde_as(as = "Bytes")]
|
||||||
attr: [u8; 3],
|
attr: [u8; 3],
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,13 +452,15 @@ impl Block {
|
|||||||
#[derive(
|
#[derive(
|
||||||
Clone,
|
Clone,
|
||||||
Debug,
|
Debug,
|
||||||
Deserialize,
|
|
||||||
Hash,
|
Hash,
|
||||||
Eq,
|
Eq,
|
||||||
PartialEq,
|
PartialEq,
|
||||||
)]
|
)]
|
||||||
#[serde(try_from = "&'_ [u8]")]
|
/* #[serde(try_from = "&'_ [u8]")] */
|
||||||
pub struct BlockVec(Vec<Block>);
|
pub struct BlockVec(
|
||||||
|
/* #[serde_as(as = "Bytes")] */
|
||||||
|
Vec<Block>
|
||||||
|
);
|
||||||
|
|
||||||
impl core::ops::Deref for BlockVec {
|
impl core::ops::Deref for BlockVec {
|
||||||
type Target = Vec<Block>;
|
type Target = Vec<Block>;
|
||||||
@ -491,9 +496,184 @@ impl Serialize for BlockVec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a/*, Error: de::Error*/> TryFrom<&'a [u8]> for BlockVec {
|
impl<'a> Deserialize<'a> for BlockVec {
|
||||||
type Error = &'static str;
|
/// XXX(@Sharp): This implementation is subtle and safety depends on correct implementation!
|
||||||
/// XXX(@Sharp): This implementation is subtle and its safety depens on correct implementation!
|
/// It is well-commented, but those comments are only valid so long as this implementation
|
||||||
|
/// doesn't change. If you do need to change this implementation, please seek careful review!
|
||||||
|
///
|
||||||
|
/// NOTE: Ideally, we would perform a try_from(Vec<u8>) instead, to avoid the extra copy.
|
||||||
|
/// Unfortunately this is not generally sound, since Vec allocations must be deallocated with
|
||||||
|
/// the same layout with which they were allocated, which includes alignment (and no, it does
|
||||||
|
/// not matter if they in practice have the same alignment at runtime, it's still UB). If we
|
||||||
|
/// were to do this, we'd effectively have to hold a Vec<u8> inside BlockVec at all times, not
|
||||||
|
/// exposing &mut access at all, and instead requiring transmutes to get access to Blocks.
|
||||||
|
/// This seems like a huge pain so for now, hopefully deserialize (the non-owned version) is
|
||||||
|
/// sufficient.
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: de::Deserializer<'a>,
|
||||||
|
{
|
||||||
|
let blocks = <Bytes as DeserializeAs::<&'a [u8]>>::deserialize_as::<D>(deserializer)?;
|
||||||
|
|
||||||
|
// First, make sure we're correctly interpretable as a [[u8; 4]].
|
||||||
|
//
|
||||||
|
let blocks: &[[u8; 4]] = bytemuck::try_cast_slice(blocks)
|
||||||
|
.map_err(|_| D::Error::invalid_length(blocks.len(), &"a multiple of 4")/*"Length must be a multiple of 4"*/)?;
|
||||||
|
// The basic observation here is that a slice of [u8; 4] is *almost* the same as a slice of
|
||||||
|
// blocks, so conversion from the former to the latter can be very cheap. The only problem
|
||||||
|
// is that BlockKind (the first byte in `Block`) has some invalid states, so not every u8
|
||||||
|
// slice of the appropriate size is a block slice. Fortunately, since we don't care about
|
||||||
|
// figuring out which block triggered the error, we can figure this out really cheaply--we
|
||||||
|
// just have to set a bit for every block we see, then check at the end to make sure all
|
||||||
|
// the bits we set are valid elements. We can construct the valid bit set using EnumIter,
|
||||||
|
// and the requirement is: (!valid & set_bits) = 0.
|
||||||
|
|
||||||
|
// Construct the invalid list. Initially, it's all 1s, then we set all the bits
|
||||||
|
// corresponding to valid block kinds to 0, leaving a set bit for each invalid block kind.
|
||||||
|
//
|
||||||
|
// TODO: Verify whether this gets constant folded away; if not, try to do this as a const
|
||||||
|
// fn? Might need to modify the EnumIter implementation.
|
||||||
|
let mut invalid_bits = [true; 256];
|
||||||
|
<BlockKind as strum::IntoEnumIterator>::iter().for_each(|bk| {
|
||||||
|
invalid_bits[(bk as u8) as usize] = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Blocks per chunk. Currently 16, since blocks are 4 bytes and 16 * 4 = 64 bytes is the
|
||||||
|
// size of a cacheline on most architectures.
|
||||||
|
const BLOCKS_PER_CHUNK: usize = 8;
|
||||||
|
|
||||||
|
/* // Initially, the set bit list is empty.
|
||||||
|
let mut set_bits: std::simd::Mask<i8, BLOCKS_PER_CHUNK> = std::simd::Mask::splat(false);
|
||||||
|
|
||||||
|
// NOTE: We iterate in chunks of BLOCKS_PER_CHUNK blocks. This also lets us
|
||||||
|
// independently fetch BLOCKS_PER_CHUNK entries from the lookup table at once, setting
|
||||||
|
// BLOCKS_PER_CHUNK independent lanes (reducing CPU level contention on the register)
|
||||||
|
// instead of updating a single register in each iteration (which causes contention).
|
||||||
|
let (chunks, remainder) = blocks.as_chunks::<BLOCKS_PER_CHUNK>();
|
||||||
|
chunks.iter().for_each(|array| {
|
||||||
|
// Look up each of the block kind in the chunk, setting each lane of the
|
||||||
|
// BLOCKS_PER_CHUNK-word mask to true if the block kind is invalid.
|
||||||
|
//
|
||||||
|
// NOTE: The block kind is guaranteed to be at the front of each 4-byte word,
|
||||||
|
// thanks to the repr(C).
|
||||||
|
//
|
||||||
|
// NOTE: Bounds checks here appears to be either elided, or perfectly predicted, so we
|
||||||
|
// fortunately avoid using unsafe here.
|
||||||
|
//
|
||||||
|
// FIXME: simd table lookup, and simd packing.
|
||||||
|
let block_kinds = std::simd::Mask::from_array(
|
||||||
|
[
|
||||||
|
invalid_bits[array[0x0][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0x1][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0x2][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0x3][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0x4][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0x5][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0x6][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0x7][0] as u8 as usize],
|
||||||
|
/* invalid_bits[array[0x8][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0x9][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xA][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xB][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xC][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xD][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xE][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xF][0] as u8 as usize], */
|
||||||
|
]
|
||||||
|
);
|
||||||
|
// Now, lanewise OR whether the block kind in this iteration was invalid, with whether
|
||||||
|
// the same block kind was invalid in this lane the previous iteration.
|
||||||
|
set_bits |= block_kinds;
|
||||||
|
});
|
||||||
|
// Now, we OR all the lanes together, to find out whether *any* of the lanes witnessed an
|
||||||
|
// invalid block kind.
|
||||||
|
let mut set_bits = set_bits.any(); */
|
||||||
|
|
||||||
|
let mut set_bits0 = false;
|
||||||
|
let mut set_bits1 = false;
|
||||||
|
let mut set_bits2 = false;
|
||||||
|
let mut set_bits3 = false;
|
||||||
|
let mut set_bits4 = false;
|
||||||
|
let mut set_bits5 = false;
|
||||||
|
let mut set_bits6 = false;
|
||||||
|
let mut set_bits7 = false;
|
||||||
|
let mut set_bits8 = false;
|
||||||
|
|
||||||
|
/* // Initially, the set bit list is empty.
|
||||||
|
let mut set_bits: std::simd::Mask<i8, BLOCKS_PER_CHUNK> = std::simd::Mask::splat(false); */
|
||||||
|
|
||||||
|
// NOTE: We iterate in chunks of BLOCKS_PER_CHUNK blocks. This also lets us
|
||||||
|
// independently fetch BLOCKS_PER_CHUNK entries from the lookup table at once, setting
|
||||||
|
// BLOCKS_PER_CHUNK independent lanes (reducing CPU level contention on the register)
|
||||||
|
// instead of updating a single register in each iteration (which causes contention).
|
||||||
|
let (chunks, remainder) = blocks.as_chunks::<BLOCKS_PER_CHUNK>();
|
||||||
|
chunks.iter().for_each(|array| {
|
||||||
|
// Look up each of the block kind in the chunk, setting each lane of the
|
||||||
|
// BLOCKS_PER_CHUNK-word mask to true if the block kind is invalid.
|
||||||
|
//
|
||||||
|
// NOTE: The block kind is guaranteed to be at the front of each 4-byte word,
|
||||||
|
// thanks to the repr(C).
|
||||||
|
//
|
||||||
|
// NOTE: Bounds checks here appears to be either elided, or perfectly predicted, so we
|
||||||
|
// fortunately avoid using unsafe here.
|
||||||
|
//
|
||||||
|
// FIXME: simd table lookup, and simd packing.
|
||||||
|
/* let block_kinds = std::simd::Mask::from_array(
|
||||||
|
[ */
|
||||||
|
set_bits0 |= invalid_bits[array[0x0][0] as u8 as usize];
|
||||||
|
set_bits1 |= invalid_bits[array[0x1][0] as u8 as usize];
|
||||||
|
set_bits2 |= invalid_bits[array[0x2][0] as u8 as usize];
|
||||||
|
set_bits3 |= invalid_bits[array[0x3][0] as u8 as usize];
|
||||||
|
set_bits4 |= invalid_bits[array[0x4][0] as u8 as usize];
|
||||||
|
set_bits5 |= invalid_bits[array[0x5][0] as u8 as usize];
|
||||||
|
set_bits6 |= invalid_bits[array[0x6][0] as u8 as usize];
|
||||||
|
set_bits7 |= invalid_bits[array[0x7][0] as u8 as usize];
|
||||||
|
/* invalid_bits[array[0x8][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0x9][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xA][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xB][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xC][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xD][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xE][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xF][0] as u8 as usize], */
|
||||||
|
/* ]
|
||||||
|
)*/
|
||||||
|
// Now, lanewise OR whether the block kind in this iteration was invalid, with whether
|
||||||
|
// the same block kind was invalid in this lane the previous iteration.
|
||||||
|
// set_bits |= block_kinds;
|
||||||
|
});
|
||||||
|
// Now, we OR all the lanes together, to find out whether *any* of the lanes witnessed an
|
||||||
|
// invalid block kind.
|
||||||
|
let mut set_bits = /*set_bits.any()*/set_bits0 | set_bits1 | set_bits2 | set_bits3 | set_bits4 | set_bits5 | set_bits6 | set_bits7;
|
||||||
|
|
||||||
|
// Now handle the remainder (if this wasn't a precise fit for BLOCKS_PER_CHUNK blocks;
|
||||||
|
// this will never be the case for valid terrain chunks).
|
||||||
|
remainder.iter().for_each(|block| {
|
||||||
|
set_bits |= invalid_bits[block[0] as u8 as usize];
|
||||||
|
});
|
||||||
|
|
||||||
|
// The invalid bits and the set bits should have no overlap.
|
||||||
|
if set_bits {
|
||||||
|
// At least one invalid bit was set, so there was an invalid BlockKind somewhere.
|
||||||
|
//
|
||||||
|
// TODO: Use radix representation of the bad block kind.
|
||||||
|
return Err(D::Error::unknown_variant("an invalid u8", &["see the definition of BlockKind for details"])/*"Found an unknown BlockKind while parsing Vec<Block>"*/);
|
||||||
|
}
|
||||||
|
// All set bits are cleared, so all block kinds were valid. Combined with the slice being
|
||||||
|
// compatible with [u8; 4], we can transmute the slice to a slice of Blocks and then
|
||||||
|
// construct a new vector from it.
|
||||||
|
let blocks = unsafe { core::mem::transmute::<&'a [[u8; 4]], &'a [Block]>(blocks) };
|
||||||
|
// Finally, *safely* construct a vector from the new blocks (as mentioned above, we cannot
|
||||||
|
// reuse the old byte vector even if we wanted to, since it doesn't have the same
|
||||||
|
// alignment as Block).
|
||||||
|
Ok(Self(blocks.to_vec()/*Vec::new()*/))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* impl<'a/*, Error: de::Error*/> TryFrom<&'a [u8]> for BlockVec {
|
||||||
|
/* type Error = /*&'static str*/serde::de::Error;
|
||||||
|
/// XXX(@Sharp): This implementation is subtle and safety depends on correct implementation!
|
||||||
/// It is well-commented, but those comments are only valid so long as this implementation
|
/// It is well-commented, but those comments are only valid so long as this implementation
|
||||||
/// doesn't change. If you do need to change this implementation, please seek careful review!
|
/// doesn't change. If you do need to change this implementation, please seek careful review!
|
||||||
///
|
///
|
||||||
@ -507,8 +687,9 @@ impl<'a/*, Error: de::Error*/> TryFrom<&'a [u8]> for BlockVec {
|
|||||||
/// sufficient.
|
/// sufficient.
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
fn try_from(blocks: &'a [u8]) -> Result<Self, Self::Error>
|
fn try_from(blocks: &'a [u8]) -> Result<Self, Self::Error>
|
||||||
{
|
{ */
|
||||||
// First, make sure we're correctly interpretable as a [u8; 4].
|
/* // First, make sure we're correctly interpretable as a [[u8; 4]].
|
||||||
|
//
|
||||||
let blocks: &[[u8; 4]] = bytemuck::try_cast_slice(blocks)
|
let blocks: &[[u8; 4]] = bytemuck::try_cast_slice(blocks)
|
||||||
.map_err(|_| /*Error::invalid_length(blocks.len(), &"a multiple of 4")*/"Length must be a multiple of 4")?;
|
.map_err(|_| /*Error::invalid_length(blocks.len(), &"a multiple of 4")*/"Length must be a multiple of 4")?;
|
||||||
// The basic observation here is that a slice of [u8; 4] is *almost* the same as a slice of
|
// The basic observation here is that a slice of [u8; 4] is *almost* the same as a slice of
|
||||||
@ -525,26 +706,127 @@ impl<'a/*, Error: de::Error*/> TryFrom<&'a [u8]> for BlockVec {
|
|||||||
//
|
//
|
||||||
// TODO: Verify whether this gets constant folded away; if not, try to do this as a const
|
// TODO: Verify whether this gets constant folded away; if not, try to do this as a const
|
||||||
// fn? Might need to modify the EnumIter implementation.
|
// fn? Might need to modify the EnumIter implementation.
|
||||||
let mut invalid_bits = bitarr![1; 256];
|
let mut invalid_bits = [true; 256];
|
||||||
<BlockKind as strum::IntoEnumIterator>::iter().for_each(|bk| {
|
<BlockKind as strum::IntoEnumIterator>::iter().for_each(|bk| {
|
||||||
invalid_bits.set((bk as u8).into(), false);
|
invalid_bits[(bk as u8) as usize] = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Initially, the set bit list is empty.
|
// Blocks per chunk. Currently 16, since blocks are 4 bytes and 16 * 4 = 64 bytes is the
|
||||||
let mut set_bits = /*bitarr!*/[false; 256];
|
// size of a cacheline on most architectures.
|
||||||
|
const BLOCKS_PER_CHUNK: usize = 8;
|
||||||
|
|
||||||
// TODO: SIMD iteration.
|
/* // Initially, the set bit list is empty.
|
||||||
// NOTE: The block kind is guaranteed to be at the front, thanks to the repr(C).
|
let mut set_bits: std::simd::Mask<i8, BLOCKS_PER_CHUNK> = std::simd::Mask::splat(false);
|
||||||
blocks.into_iter().for_each(|&[kind, _, _, _]| {
|
|
||||||
// NOTE: Bounds check here appears to be either elided, or perfectly predicted, so we
|
// NOTE: We iterate in chunks of BLOCKS_PER_CHUNK blocks. This also lets us
|
||||||
|
// independently fetch BLOCKS_PER_CHUNK entries from the lookup table at once, setting
|
||||||
|
// BLOCKS_PER_CHUNK independent lanes (reducing CPU level contention on the register)
|
||||||
|
// instead of updating a single register in each iteration (which causes contention).
|
||||||
|
let (chunks, remainder) = blocks.as_chunks::<BLOCKS_PER_CHUNK>();
|
||||||
|
chunks.iter().for_each(|array| {
|
||||||
|
// Look up each of the block kind in the chunk, setting each lane of the
|
||||||
|
// BLOCKS_PER_CHUNK-word mask to true if the block kind is invalid.
|
||||||
|
//
|
||||||
|
// NOTE: The block kind is guaranteed to be at the front of each 4-byte word,
|
||||||
|
// thanks to the repr(C).
|
||||||
|
//
|
||||||
|
// NOTE: Bounds checks here appears to be either elided, or perfectly predicted, so we
|
||||||
// fortunately avoid using unsafe here.
|
// fortunately avoid using unsafe here.
|
||||||
/* set_bits.set(kind.into(), true); */
|
//
|
||||||
set_bits[kind as usize] = true;
|
// FIXME: simd table lookup, and simd packing.
|
||||||
|
let block_kinds = std::simd::Mask::from_array(
|
||||||
|
[
|
||||||
|
invalid_bits[array[0x0][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0x1][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0x2][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0x3][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0x4][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0x5][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0x6][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0x7][0] as u8 as usize],
|
||||||
|
/* invalid_bits[array[0x8][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0x9][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xA][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xB][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xC][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xD][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xE][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xF][0] as u8 as usize], */
|
||||||
|
]
|
||||||
|
);
|
||||||
|
// Now, lanewise OR whether the block kind in this iteration was invalid, with whether
|
||||||
|
// the same block kind was invalid in this lane the previous iteration.
|
||||||
|
set_bits |= block_kinds;
|
||||||
|
});
|
||||||
|
// Now, we OR all the lanes together, to find out whether *any* of the lanes witnessed an
|
||||||
|
// invalid block kind.
|
||||||
|
let mut set_bits = set_bits.any(); */
|
||||||
|
|
||||||
|
let mut set_bits0 = false;
|
||||||
|
let mut set_bits1 = false;
|
||||||
|
let mut set_bits2 = false;
|
||||||
|
let mut set_bits3 = false;
|
||||||
|
let mut set_bits4 = false;
|
||||||
|
let mut set_bits5 = false;
|
||||||
|
let mut set_bits6 = false;
|
||||||
|
let mut set_bits7 = false;
|
||||||
|
let mut set_bits8 = false;
|
||||||
|
|
||||||
|
/* // Initially, the set bit list is empty.
|
||||||
|
let mut set_bits: std::simd::Mask<i8, BLOCKS_PER_CHUNK> = std::simd::Mask::splat(false); */
|
||||||
|
|
||||||
|
// NOTE: We iterate in chunks of BLOCKS_PER_CHUNK blocks. This also lets us
|
||||||
|
// independently fetch BLOCKS_PER_CHUNK entries from the lookup table at once, setting
|
||||||
|
// BLOCKS_PER_CHUNK independent lanes (reducing CPU level contention on the register)
|
||||||
|
// instead of updating a single register in each iteration (which causes contention).
|
||||||
|
let (chunks, remainder) = blocks.as_chunks::<BLOCKS_PER_CHUNK>();
|
||||||
|
chunks.iter().for_each(|array| {
|
||||||
|
// Look up each of the block kind in the chunk, setting each lane of the
|
||||||
|
// BLOCKS_PER_CHUNK-word mask to true if the block kind is invalid.
|
||||||
|
//
|
||||||
|
// NOTE: The block kind is guaranteed to be at the front of each 4-byte word,
|
||||||
|
// thanks to the repr(C).
|
||||||
|
//
|
||||||
|
// NOTE: Bounds checks here appears to be either elided, or perfectly predicted, so we
|
||||||
|
// fortunately avoid using unsafe here.
|
||||||
|
//
|
||||||
|
// FIXME: simd table lookup, and simd packing.
|
||||||
|
/* let block_kinds = std::simd::Mask::from_array(
|
||||||
|
[ */
|
||||||
|
set_bits0 |= invalid_bits[array[0x0][0] as u8 as usize];
|
||||||
|
set_bits1 |= invalid_bits[array[0x1][0] as u8 as usize];
|
||||||
|
set_bits2 |= invalid_bits[array[0x2][0] as u8 as usize];
|
||||||
|
set_bits3 |= invalid_bits[array[0x3][0] as u8 as usize];
|
||||||
|
set_bits4 |= invalid_bits[array[0x4][0] as u8 as usize];
|
||||||
|
set_bits5 |= invalid_bits[array[0x5][0] as u8 as usize];
|
||||||
|
set_bits6 |= invalid_bits[array[0x6][0] as u8 as usize];
|
||||||
|
set_bits7 |= invalid_bits[array[0x7][0] as u8 as usize];
|
||||||
|
/* invalid_bits[array[0x8][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0x9][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xA][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xB][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xC][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xD][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xE][0] as u8 as usize],
|
||||||
|
invalid_bits[array[0xF][0] as u8 as usize], */
|
||||||
|
/* ]
|
||||||
|
)*/
|
||||||
|
// Now, lanewise OR whether the block kind in this iteration was invalid, with whether
|
||||||
|
// the same block kind was invalid in this lane the previous iteration.
|
||||||
|
// set_bits |= block_kinds;
|
||||||
|
});
|
||||||
|
// Now, we OR all the lanes together, to find out whether *any* of the lanes witnessed an
|
||||||
|
// invalid block kind.
|
||||||
|
let mut set_bits = /*set_bits.any()*/set_bits0 | set_bits1 | set_bits2 | set_bits3 | set_bits4 | set_bits5 | set_bits6 | set_bits7;
|
||||||
|
|
||||||
|
// Now handle the remainder (if this wasn't a precise fit for BLOCKS_PER_CHUNK blocks;
|
||||||
|
// this will never be the case for valid terrain chunks).
|
||||||
|
remainder.iter().for_each(|block| {
|
||||||
|
set_bits |= invalid_bits[block[0] as u8 as usize];
|
||||||
});
|
});
|
||||||
|
|
||||||
// The invalid bits and the set bits should have no overlap.
|
// The invalid bits and the set bits should have no overlap.
|
||||||
invalid_bits &= set_bits;
|
if set_bits {
|
||||||
if invalid_bits.any() {
|
|
||||||
// At least one invalid bit was set, so there was an invalid BlockKind somewhere.
|
// At least one invalid bit was set, so there was an invalid BlockKind somewhere.
|
||||||
//
|
//
|
||||||
// TODO: Use radix representation of the bad block kind.
|
// TODO: Use radix representation of the bad block kind.
|
||||||
@ -556,10 +838,10 @@ impl<'a/*, Error: de::Error*/> TryFrom<&'a [u8]> for BlockVec {
|
|||||||
let blocks = unsafe { core::mem::transmute::<&'a [[u8; 4]], &'a [Block]>(blocks) };
|
let blocks = unsafe { core::mem::transmute::<&'a [[u8; 4]], &'a [Block]>(blocks) };
|
||||||
// Finally, *safely* construct a vector from the new blocks (as mentioned above, we cannot
|
// Finally, *safely* construct a vector from the new blocks (as mentioned above, we cannot
|
||||||
// reuse the old byte vector even if we wanted to, since it doesn't have the same
|
// reuse the old byte vector even if we wanted to, since it doesn't have the same
|
||||||
// alignment as Block).
|
// alignment as Block). */
|
||||||
Ok(Self(blocks.to_vec()))
|
Ok(Self(/*blocks.to_vec()*/Vec::new()))
|
||||||
}
|
}
|
||||||
}
|
} */
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
@ -60,7 +60,7 @@ impl<V, Storage, ChonkSize: RectVolSize> VolSize<V> for SubChunkSize<V, Storage,
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
type SubChunk<V, Storage, S, M> = Chunk<V, SubChunkSize<V, Storage, S>, M>;
|
pub type SubChunk<V, Storage, S, M> = Chunk<V, SubChunkSize<V, Storage, S>, M>;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Chonk<V, Storage, S: RectVolSize, M: Clone> {
|
pub struct Chonk<V, Storage, S: RectVolSize, M: Clone> {
|
||||||
@ -100,6 +100,10 @@ impl<V, Storage: core::ops::DerefMut<Target=Vec<V>>, S: RectVolSize, M: Clone> C
|
|||||||
self.sub_chunks.iter().map(SubChunk::num_groups).sum()
|
self.sub_chunks.iter().map(SubChunk::num_groups).sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sub_chunks<'a>(&'a self) -> impl Iterator<Item = &'a SubChunk<V, Storage, S, M>> {
|
||||||
|
self.sub_chunks.iter()
|
||||||
|
}
|
||||||
|
|
||||||
/// Iterate through the voxels in this chunk, attempting to avoid those that
|
/// Iterate through the voxels in this chunk, attempting to avoid those that
|
||||||
/// are unchanged (i.e: match the `below` and `above` voxels). This is
|
/// are unchanged (i.e: match the `below` and `above` voxels). This is
|
||||||
/// generally useful for performance reasons.
|
/// generally useful for performance reasons.
|
||||||
|
@ -158,6 +158,7 @@ impl TerrainChunkMeta {
|
|||||||
// Terrain type aliases
|
// Terrain type aliases
|
||||||
|
|
||||||
pub type TerrainChunk = chonk::Chonk<Block, BlockVec, TerrainChunkSize, TerrainChunkMeta>;
|
pub type TerrainChunk = chonk::Chonk<Block, BlockVec, TerrainChunkSize, TerrainChunkMeta>;
|
||||||
|
pub type TerrainSubChunk = chonk::SubChunk<Block, BlockVec, TerrainChunkSize, TerrainChunkMeta>;
|
||||||
pub type TerrainGrid = VolGrid2d<TerrainChunk>;
|
pub type TerrainGrid = VolGrid2d<TerrainChunk>;
|
||||||
|
|
||||||
impl TerrainGrid {
|
impl TerrainGrid {
|
||||||
|
@ -5,6 +5,7 @@ use bitvec::prelude::*;
|
|||||||
use core::{hash::Hash, iter::Iterator, marker::PhantomData, mem};
|
use core::{hash::Hash, iter::Iterator, marker::PhantomData, mem};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_with::{serde_as, Bytes};
|
||||||
use zerocopy::AsBytes;
|
use zerocopy::AsBytes;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
@ -48,8 +49,10 @@ pub enum ChunkError {
|
|||||||
/// The number of 256 groups is particularly nice because it means that the
|
/// The number of 256 groups is particularly nice because it means that the
|
||||||
/// index buffer can consist of `u8`s. This keeps the space requirement for the
|
/// index buffer can consist of `u8`s. This keeps the space requirement for the
|
||||||
/// index buffer as low as 4 cache lines.
|
/// index buffer as low as 4 cache lines.
|
||||||
|
#[serde_as]
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Chunk<V, S: VolSize<V>, M> {
|
pub struct Chunk<V, S: VolSize<V>, M> {
|
||||||
|
#[serde_as(as = "Bytes")]
|
||||||
indices: Vec<u8>, /* TODO (haslersn): Box<[u8; S::SIZE.x * S::SIZE.y * S::SIZE.z]>, this is
|
indices: Vec<u8>, /* TODO (haslersn): Box<[u8; S::SIZE.x * S::SIZE.y * S::SIZE.z]>, this is
|
||||||
* however not possible in Rust yet */
|
* however not possible in Rust yet */
|
||||||
vox: S,
|
vox: S,
|
||||||
@ -121,6 +124,10 @@ impl<V, S: core::ops::DerefMut<Target=Vec<V>> + VolSize<V>, M> Chunk<V, S, M> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_vox(&self) -> &S {
|
||||||
|
&self.vox
|
||||||
|
}
|
||||||
|
|
||||||
/// Compress this subchunk by frequency.
|
/// Compress this subchunk by frequency.
|
||||||
pub fn defragment(&mut self)
|
pub fn defragment(&mut self)
|
||||||
where
|
where
|
||||||
|
@ -1005,6 +1005,27 @@ impl Stream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn try_recv_raw(&mut self) -> Result<Option<Message>, StreamError> {
|
||||||
|
match &mut self.b2a_msg_recv_r {
|
||||||
|
Some(b2a_msg_recv_r) => match b2a_msg_recv_r.try_recv() {
|
||||||
|
Ok(data) => Ok(Some(
|
||||||
|
Message {
|
||||||
|
data,
|
||||||
|
#[cfg(feature = "compression")]
|
||||||
|
compressed: self.promises.contains(Promises::COMPRESSED),
|
||||||
|
}
|
||||||
|
)),
|
||||||
|
Err(async_channel::TryRecvError::Empty) => Ok(None),
|
||||||
|
Err(async_channel::TryRecvError::Closed) => {
|
||||||
|
self.b2a_msg_recv_r = None; //prevent panic
|
||||||
|
Err(StreamError::StreamClosed)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
None => Err(StreamError::StreamClosed),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// use `try_recv` to check for a Message send from the remote side by their
|
/// use `try_recv` to check for a Message send from the remote side by their
|
||||||
/// `Stream`. This function does not block and returns immediately. It's
|
/// `Stream`. This function does not block and returns immediately. It's
|
||||||
/// intended for use in non-async context only. Other then that, the
|
/// intended for use in non-async context only. Other then that, the
|
||||||
@ -1041,24 +1062,7 @@ impl Stream {
|
|||||||
/// [`recv`]: Stream::recv
|
/// [`recv`]: Stream::recv
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn try_recv<M: DeserializeOwned>(&mut self) -> Result<Option<M>, StreamError> {
|
pub fn try_recv<M: DeserializeOwned>(&mut self) -> Result<Option<M>, StreamError> {
|
||||||
match &mut self.b2a_msg_recv_r {
|
self.try_recv_raw()?.map(|uncompressed| uncompressed.deserialize()).transpose()
|
||||||
Some(b2a_msg_recv_r) => match b2a_msg_recv_r.try_recv() {
|
|
||||||
Ok(data) => Ok(Some(
|
|
||||||
Message {
|
|
||||||
data,
|
|
||||||
#[cfg(feature = "compression")]
|
|
||||||
compressed: self.promises.contains(Promises::COMPRESSED),
|
|
||||||
}
|
|
||||||
.deserialize()?,
|
|
||||||
)),
|
|
||||||
Err(async_channel::TryRecvError::Empty) => Ok(None),
|
|
||||||
Err(async_channel::TryRecvError::Closed) => {
|
|
||||||
self.b2a_msg_recv_r = None; //prevent panic
|
|
||||||
Err(StreamError::StreamClosed)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
None => Err(StreamError::StreamClosed),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn params(&self) -> StreamParams {
|
pub fn params(&self) -> StreamParams {
|
||||||
|
@ -3,7 +3,7 @@ use bytes::Bytes;
|
|||||||
#[cfg(feature = "compression")]
|
#[cfg(feature = "compression")]
|
||||||
use network_protocol::Promises;
|
use network_protocol::Promises;
|
||||||
use serde::{de::DeserializeOwned, Serialize};
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
use std::io;
|
use std::{borrow::Cow, io};
|
||||||
#[cfg(all(feature = "compression", debug_assertions))]
|
#[cfg(all(feature = "compression", debug_assertions))]
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
|
|
||||||
@ -98,9 +98,20 @@ impl Message {
|
|||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [`recv_raw`]: crate::api::Stream::recv_raw
|
/// [`recv_raw`]: crate::api::Stream::recv_raw
|
||||||
pub fn deserialize<M: DeserializeOwned>(self) -> Result<M, StreamError> {
|
#[inline]
|
||||||
|
pub fn deserialize<M: DeserializeOwned>(&self) -> Result<M, StreamError> {
|
||||||
|
let uncompressed_data = self.decompress()?;
|
||||||
|
match bincode::deserialize(&uncompressed_data) {
|
||||||
|
Ok(m) => Ok(m),
|
||||||
|
Err(e) => Err(StreamError::Deserialize(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decompress a message without deserializing it.
|
||||||
|
#[inline]
|
||||||
|
pub fn decompress<'a>(&'a self) -> Result<Cow<'a, [u8]>, StreamError> {
|
||||||
#[cfg(not(feature = "compression"))]
|
#[cfg(not(feature = "compression"))]
|
||||||
let uncompressed_data = self.data;
|
let uncompressed_data = Cow::Borrowed(&self.data);
|
||||||
|
|
||||||
#[cfg(feature = "compression")]
|
#[cfg(feature = "compression")]
|
||||||
let uncompressed_data = if self.compressed {
|
let uncompressed_data = if self.compressed {
|
||||||
@ -114,16 +125,13 @@ impl Message {
|
|||||||
) {
|
) {
|
||||||
return Err(StreamError::Compression(e));
|
return Err(StreamError::Compression(e));
|
||||||
}
|
}
|
||||||
Bytes::from(uncompressed_data)
|
Cow::Owned(uncompressed_data)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.data
|
Cow::Borrowed(&*self.data)
|
||||||
};
|
};
|
||||||
|
|
||||||
match bincode::deserialize(&uncompressed_data) {
|
Ok(uncompressed_data)
|
||||||
Ok(m) => Ok(m),
|
|
||||||
Err(e) => Err(StreamError::Deserialize(e)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
|
@ -81,7 +81,7 @@ impl Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn send<M: Into<ServerMsg>>(&self, msg: M) -> Result<(), StreamError> {
|
pub(crate) fn send<M: Into<ServerMsg<'static>>>(&self, msg: M) -> Result<(), StreamError> {
|
||||||
// TODO: hack to avoid locking stream mutex while serializing the message,
|
// TODO: hack to avoid locking stream mutex while serializing the message,
|
||||||
// remove this when the mutexes on the Streams are removed
|
// remove this when the mutexes on the Streams are removed
|
||||||
let prepared = self.prepare(msg);
|
let prepared = self.prepare(msg);
|
||||||
@ -140,7 +140,7 @@ impl Client {
|
|||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn send_fallible<M: Into<ServerMsg>>(&self, msg: M) { let _ = self.send(msg); }
|
pub(crate) fn send_fallible<M: Into<ServerMsg<'static>>>(&self, msg: M) { let _ = self.send(msg); }
|
||||||
|
|
||||||
pub(crate) fn send_prepared(&self, msg: &PreparedMsg) -> Result<(), StreamError> {
|
pub(crate) fn send_prepared(&self, msg: &PreparedMsg) -> Result<(), StreamError> {
|
||||||
match msg.stream_id {
|
match msg.stream_id {
|
||||||
@ -158,7 +158,7 @@ impl Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn prepare<M: Into<ServerMsg>>(&self, msg: M) -> PreparedMsg {
|
pub(crate) fn prepare<M: Into<ServerMsg<'static>>>(&self, msg: M) -> PreparedMsg {
|
||||||
match msg.into() {
|
match msg.into() {
|
||||||
ServerMsg::Info(m) => PreparedMsg::new(0, &m, &self.register_stream_params),
|
ServerMsg::Info(m) => PreparedMsg::new(0, &m, &self.register_stream_params),
|
||||||
ServerMsg::Init(m) => PreparedMsg::new(0, &m, &self.register_stream_params),
|
ServerMsg::Init(m) => PreparedMsg::new(0, &m, &self.register_stream_params),
|
||||||
|
@ -1180,7 +1180,7 @@ impl Server {
|
|||||||
|
|
||||||
pub fn notify_client<S>(&self, entity: EcsEntity, msg: S)
|
pub fn notify_client<S>(&self, entity: EcsEntity, msg: S)
|
||||||
where
|
where
|
||||||
S: Into<ServerMsg>,
|
S: Into<ServerMsg<'static>>,
|
||||||
{
|
{
|
||||||
self.state
|
self.state
|
||||||
.ecs()
|
.ecs()
|
||||||
@ -1189,7 +1189,7 @@ impl Server {
|
|||||||
.map(|c| c.send(msg));
|
.map(|c| c.send(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn notify_players(&mut self, msg: ServerGeneral) { self.state.notify_players(msg); }
|
pub fn notify_players(&mut self, msg: ServerGeneral<'static>) { self.state.notify_players(msg); }
|
||||||
|
|
||||||
pub fn generate_chunk(&mut self, entity: EcsEntity, key: Vec2<i32>) {
|
pub fn generate_chunk(&mut self, entity: EcsEntity, key: Vec2<i32>) {
|
||||||
let ecs = self.state.ecs();
|
let ecs = self.state.ecs();
|
||||||
|
@ -111,8 +111,8 @@ pub trait StateExt {
|
|||||||
fn update_character_data(&mut self, entity: EcsEntity, components: PersistedComponents);
|
fn update_character_data(&mut self, entity: EcsEntity, components: PersistedComponents);
|
||||||
/// Iterates over registered clients and send each `ServerMsg`
|
/// Iterates over registered clients and send each `ServerMsg`
|
||||||
fn send_chat(&self, msg: comp::UnresolvedChatMsg);
|
fn send_chat(&self, msg: comp::UnresolvedChatMsg);
|
||||||
fn notify_players(&self, msg: ServerGeneral);
|
fn notify_players(&self, msg: ServerGeneral<'static>);
|
||||||
fn notify_in_game_clients(&self, msg: ServerGeneral);
|
fn notify_in_game_clients(&self, msg: ServerGeneral<'static>);
|
||||||
/// Create a new link between entities (see [`common::mounting`] for an
|
/// Create a new link between entities (see [`common::mounting`] for an
|
||||||
/// example).
|
/// example).
|
||||||
fn link<L: Link>(&mut self, link: L) -> Result<(), L::Error>;
|
fn link<L: Link>(&mut self, link: L) -> Result<(), L::Error>;
|
||||||
@ -819,7 +819,7 @@ impl StateExt for State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sends the message to all connected clients
|
/// Sends the message to all connected clients
|
||||||
fn notify_players(&self, msg: ServerGeneral) {
|
fn notify_players(&self, msg: ServerGeneral<'static>) {
|
||||||
let mut msg = Some(msg);
|
let mut msg = Some(msg);
|
||||||
let mut lazy_msg = None;
|
let mut lazy_msg = None;
|
||||||
for (client, _) in (
|
for (client, _) in (
|
||||||
@ -836,7 +836,7 @@ impl StateExt for State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sends the message to all clients playing in game
|
/// Sends the message to all clients playing in game
|
||||||
fn notify_in_game_clients(&self, msg: ServerGeneral) {
|
fn notify_in_game_clients(&self, msg: ServerGeneral<'static>) {
|
||||||
let mut msg = Some(msg);
|
let mut msg = Some(msg);
|
||||||
let mut lazy_msg = None;
|
let mut lazy_msg = None;
|
||||||
for (client, _) in (
|
for (client, _) in (
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use common::{
|
use common::{
|
||||||
generation::EntityInfo,
|
generation::EntityInfo,
|
||||||
store::{Id, Store},
|
store::{Id, Store},
|
||||||
terrain::{Block, BlockKind, SpriteKind, TerrainChunk, TerrainChunkMeta, TerrainChunkSize},
|
terrain::{Block, BlockKind, SpriteKind, TerrainSubChunk, TerrainChunk, TerrainChunkMeta, TerrainChunkSize},
|
||||||
vol::RectVolSize,
|
vol::RectVolSize,
|
||||||
};
|
};
|
||||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||||
@ -316,11 +316,13 @@ fn dungeon(c: &mut Criterion) {
|
|||||||
// let chunk_pos = Vec2::new(26944 / 32, 26848 / 32);
|
// let chunk_pos = Vec2::new(26944 / 32, 26848 / 32);
|
||||||
let chunk_pos = Vec2::new(842, 839);
|
let chunk_pos = Vec2::new(842, 839);
|
||||||
let chunk = world.generate_chunk(index.as_index_ref(), chunk_pos, || false, None).unwrap().0;
|
let chunk = world.generate_chunk(index.as_index_ref(), chunk_pos, || false, None).unwrap().0;
|
||||||
|
/* println!("{:?}", chunk.sub_chunks_len());
|
||||||
|
let chunk = chunk.sub_chunks().next().unwrap(); */
|
||||||
let serialized = bincode::serialize(&chunk).unwrap();
|
let serialized = bincode::serialize(&chunk).unwrap();
|
||||||
// let chunk_pos = Vec2::new(24507/32, 20682/32);
|
// let chunk_pos = Vec2::new(24507/32, 20682/32);
|
||||||
// let chunk_pos = Vec2::new(19638/32, 19621/32);
|
// let chunk_pos = Vec2::new(19638/32, 19621/32);
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
black_box(bincode::deserialize::<TerrainChunk>(&serialized).unwrap());
|
black_box(bincode::deserialize::<TerrainChunk/*TerrainSubChunk*//*BlockVec*/>(&*serialized).unwrap());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -362,8 +362,8 @@ impl World {
|
|||||||
let wpos = Vec3::from(chunk_wpos2d) + lpos;
|
let wpos = Vec3::from(chunk_wpos2d) + lpos;
|
||||||
|
|
||||||
if let Some(block) = sampler.get_with_z_cache(wpos, /*Some(&*/z_cache/*)*/) {
|
if let Some(block) = sampler.get_with_z_cache(wpos, /*Some(&*/z_cache/*)*/) {
|
||||||
block_ = Some(block);
|
// block_ = Some(block);
|
||||||
// let _ = chunk.set(lpos, block);
|
let _ = chunk.set(lpos, block);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if let Some(block_) = block_ {
|
if let Some(block_) = block_ {
|
||||||
|
@ -479,6 +479,7 @@ impl Site {
|
|||||||
..Site::default()
|
..Site::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// NOTE: Remove to run benchmarks.
|
||||||
// site.demarcate_obstacles(land);
|
// site.demarcate_obstacles(land);
|
||||||
|
|
||||||
site.make_plaza(land, &mut rng);
|
site.make_plaza(land, &mut rng);
|
||||||
|
Loading…
Reference in New Issue
Block a user