Vox spawn hack

This commit is contained in:
Imbris 2019-07-04 20:07:38 -04:00 committed by Monty Marz
parent 61edae79ae
commit 6a6d68ddb9
13 changed files with 259 additions and 10 deletions

6
Cargo.lock generated
View File

@ -1421,9 +1421,8 @@ dependencies = [
[[package]]
name = "dot_vox"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83c18405ef54de0398b77a3ec8394d3a1639e7bf060e1385201e8db40c44ab41"
version = "4.0.0"
source = "git+https://github.com/Imberflur/dot_vox.git#23a877bcaeba0f86035a50bc49a89e5391eb38c7"
dependencies = [
"byteorder",
"lazy_static",
@ -5744,6 +5743,7 @@ dependencies = [
"dot_vox",
"enum-iterator",
"hashbrown 0.11.2",
"image",
"indexmap",
"lazy_static",
"num-derive",

BIN
assets/coliseum.vox (Stored with Git LFS) Normal file

Binary file not shown.

3
assets/place.ron Normal file
View File

@ -0,0 +1,3 @@
(pieces: [
("coliseum", (0, 0, 0)),
])

BIN
assets/thing.vox (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -47,7 +47,8 @@ rand = "0.8"
# Assets
common-assets = {package = "veloren-common-assets", path = "assets"}
dot_vox = "4.0"
dot_vox = { git = "https://github.com/Imberflur/dot_vox.git" }
image = { version = "0.23.12", default-features = false, features = ["png"] }
# Assets
serde_repr = "0.1.6"

View File

@ -9,7 +9,7 @@ version = "0.10.0"
lazy_static = "1.4.0"
assets_manager = {version = "0.5.0", features = ["bincode", "ron", "json", "hot-reloading"]}
ron = { version = "0.6", default-features = false }
dot_vox = "4.0"
dot_vox = { git = "https://github.com/Imberflur/dot_vox.git" }
image = { version = "0.23.12", default-features = false, features = ["png"] }
tracing = "0.1"

View File

@ -9,8 +9,8 @@ pub use self::{
};
use crate::{
vol::{IntoFullPosIterator, IntoFullVolIterator, ReadVol, SizedVol, Vox, WriteVol},
volumes::dyna::Dyna,
vol::{IntoFullPosIterator, IntoFullVolIterator, ReadVol, SizedVol, VolSize, Vox, WriteVol},
volumes::{chunk::Chunk, dyna::Dyna, vol_grid_3d::VolGrid3d},
};
use dot_vox::DotVoxData;
use vek::*;
@ -252,3 +252,93 @@ impl MatSegment {
impl From<&DotVoxData> for MatSegment {
fn from(dot_vox_data: &DotVoxData) -> Self { Self::from_vox(dot_vox_data, false) }
}
#[derive(Clone, Debug)]
pub struct SscSize;
impl VolSize for SscSize {
const SIZE: Vec3<u32> = Vec3 {
x: 32,
y: 32,
z: 32,
};
}
pub type SparseScene = VolGrid3d<Chunk<Cell, SscSize, ()>>;
impl From<&DotVoxData> for SparseScene {
fn from(dot_vox_data: &DotVoxData) -> Self {
let mut sparse_scene = match VolGrid3d::new() {
Ok(ok) => ok,
Err(_) => panic!(),
};
let mut models = dot_vox_data.scene.clone();
// Needed to work with vox files without a scene graph
if models.is_empty() {
models.push((
dot_vox::Transform {
t: [0, 0, 0],
r: [[1, 0, 0], [0, 1, 0], [0, 0, 1]],
},
0,
));
}
for (transform, model_id) in models {
if let Some(model) = dot_vox_data.models.get(model_id) {
let palette = dot_vox_data
.palette
.iter()
.map(|col| Rgba::from(col.to_ne_bytes()).into())
.collect::<Vec<_>>();
// Rotation
let rot = Mat3::from_row_arrays(transform.r).map(|e| e as i32);
// Get the rotated size of the model
let size = rot.map(|e| e.abs() as u32)
* Vec3::new(model.size.x, model.size.y, model.size.z);
// Position of min corner
let pos = Vec3::<i32>::from(transform.t)
.map2(size, |m, s| (s, m))
.map2(rot * Vec3::<i32>::one(), |(s, m), f| {
m - (s as i32 + f.min(0) * -1) / 2
});
// dbg!(pos);
// Insert required chunks
let min_key = sparse_scene.pos_key(pos);
let max_key = sparse_scene.pos_key(pos + size.map(|e| e as i32 - 1));
for x in min_key.x..=max_key.x {
for y in min_key.y..=max_key.y {
for z in min_key.z..=max_key.z {
let key = Vec3::new(x, y, z);
if sparse_scene.get_key_arc(key).is_none() {
sparse_scene.insert(
key,
std::sync::Arc::new(Chunk::filled(Cell::empty(), ())),
);
}
}
}
}
let offset = (rot
* Vec3::new(model.size.x, model.size.y, model.size.z).map(|e| e as i32))
.map(|e| if e > 0 { 0 } else { -e - 1 });
for voxel in &model.voxels {
if let Some(&color) = palette.get(voxel.i as usize) {
sparse_scene
.set(
(rot * Vec3::new(voxel.x, voxel.y, voxel.z).map(|e| i32::from(e)))
+ offset
+ pos,
Cell::new(color, false, false),
)
.unwrap();
}
}
}
}
sparse_scene
}
}

View File

@ -89,7 +89,7 @@ crossbeam-utils = "0.8.1"
crossbeam-channel = "0.5"
# TODO: remove
directories-next = "2.0"
dot_vox = "4.0"
dot_vox = { git = "https://github.com/Imberflur/dot_vox.git" }
enum-iterator = "0.6"
futures-executor = "0.3"
guillotiere = "0.6"

View File

@ -174,6 +174,9 @@ impl From<&crate::settings::GamepadSettings> for ControllerSettings {
map.entry(settings.game_buttons.swap_loadout)
.or_default()
.push(GameInput::SwapLoadout);
map.entry(settings.game_buttons.place_vox)
.or_default()
.push(GameInput::PlaceVox);
map
},
menu_button_map: {

View File

@ -9,9 +9,9 @@ use vek::*;
use client::{self, Client};
use common::{
assets::AssetExt,
comp,
assets::{self, Asset, AssetExt, AssetHandle, DotVoxAsset},
comp::{
self,
inventory::slot::{EquipSlot, Slot},
invite::InviteKind,
item::{tool::ToolKind, ItemDef, ItemDesc},
@ -32,6 +32,7 @@ use common_net::{
msg::{server::InviteAnswer, PresenceKind},
sync::WorldSyncExt,
};
use serde::{Deserialize, Serialize};
use crate::{
audio::sfx::SfxEvent,
@ -54,6 +55,57 @@ enum TickAction {
// Disconnected (i.e. go to main menu)
Disconnect,
}
#[derive(Serialize, Deserialize)]
struct VoxSpec(String, [i32; 3]);
#[derive(Serialize, Deserialize)]
struct PlaceSpec {
pieces: Vec<VoxSpec>,
}
impl Asset for PlaceSpec {
type Loader = assets::RonLoader;
const EXTENSION: &'static str = "ron";
}
impl PlaceSpec {
// pub fn load_watched() -> std::sync::Arc<Self> {
// PlaceSpec::load("place")
// }
pub fn build_place(&self) -> (common::figure::SparseScene, Vec3<i32>) {
// TODO add sparse scene combination
//use common::figure::{DynaUnionizer, Segment};
fn graceful_load_vox(name: &str) -> AssetHandle<DotVoxAsset> {
match DotVoxAsset::load(name) {
Ok(dot_vox) => dot_vox,
Err(_) => {
error!("Could not load vox file for placement: {}", name);
DotVoxAsset::load_expect("voxygen.voxel.not_found")
},
}
}
//let mut unionizer = DynaUnionizer::new();
//for VoxSpec(specifier, offset) in &self.pieces {
// let seg = Segment::from(graceful_load_vox(&specifier,
// indicator).as_ref()); unionizer = unionizer.add(seg,
// (*offset).into());
//}
//unionizer.unify()
let hack = "asset that doesn't exist";
(
match self.pieces.get(0) {
Some(VoxSpec(specifier, _offset)) => {
common::figure::SparseScene::from(&graceful_load_vox(&specifier).read().0)
},
None => common::figure::SparseScene::from(&graceful_load_vox(&hack).read().0),
},
Vec3::zero(),
)
}
}
pub struct SessionState {
scene: Scene,
@ -75,6 +127,14 @@ pub struct SessionState {
interactable: Option<Interactable>,
saved_zoom_dist: Option<f32>,
hitboxes: HashMap<specs::Entity, DebugShapeId>,
placing_vox: Vec<(
Vec3<i32>,
Arc<common::volumes::chunk::Chunk<common::figure::Cell, common::figure::SscSize, ()>>,
)>,
last_sent: Option<(Vec3<i32>, Block)>,
vox: common::figure::SparseScene,
placepos: Vec3<i32>,
}
/// Represents an active game session (i.e., the one being played).
@ -123,6 +183,13 @@ impl SessionState {
interactable: None,
saved_zoom_dist: None,
hitboxes: HashMap::new(),
placing_vox: Vec::new(),
last_sent: None,
// let mut place_indicator = PlaceSpec::load_expect("place");
// TODO: use offset
vox: PlaceSpec::load_expect("place").read().build_place().0,
placepos: Vec3::zero(),
}
}
@ -268,6 +335,13 @@ impl SessionState {
impl PlayState for SessionState {
fn enter(&mut self, global_state: &mut GlobalState, _: Direction) {
// Clear vox spawining things
self.placing_vox = Vec::new();
self.last_sent = None;
// TODO: use offset
self.vox = PlaceSpec::load_expect("place").read().build_place().0;
self.placepos = Vec3::zero();
// Trap the cursor.
global_state.window.grab_cursor(true);
@ -290,6 +364,7 @@ impl PlayState for SessionState {
let client = self.client.borrow();
(client.presence(), client.registered())
};
if client_presence.is_some() {
let camera = self.scene.camera_mut();
@ -766,6 +841,24 @@ impl PlayState for SessionState {
client.decline_invite();
}
},
GameInput::PlaceVox if state => {
// start placing
if let Some(build_pos) = build_pos.filter(|_| can_build) {
self.placepos = build_pos.map(|e| e.floor() as i32);
// reload in case vox was changed
self.vox =
PlaceSpec::load_expect("place").read().build_place().0;
self.placing_vox = self
.vox
.iter()
.map(|(key, chunk)| (key, Arc::clone(chunk)))
.collect::<Vec<_>>()
.into_iter()
.rev()
.collect();
self.last_sent = None;
}
},
_ => {},
}
}
@ -958,6 +1051,53 @@ impl PlayState for SessionState {
.camera_mut()
.compute_dependents(&*self.client.borrow().state().terrain());
// Only send next portion when the previous subchunk finishes sending
if let Some((world_pos, block)) = self.last_sent.as_ref().copied() {
if self
.client
.borrow()
.state()
.terrain()
.get(world_pos)
.map(|b| *b == block)
.unwrap_or(true)
{
self.last_sent = None;
}
}
if self.last_sent.is_none() {
if let Some((key, chunk)) = self.placing_vox.pop() {
use common::vol::IntoFullVolIterator;
for (pos, cell) in chunk.full_vol_iter() {
let world_pos = self.vox.key_pos(key) + pos + self.placepos;
match cell.get_color() {
Some(color) => {
let block = Block::new(BlockKind::Misc, color);
self.client.borrow_mut().place_block(world_pos, block);
self.last_sent = Some((world_pos, block))
},
None => {
// Comment out this section to not carve out the empty space
let mut client = self.client.borrow_mut();
// Only remove the block if there is something there
if client
.state()
.terrain()
.get(world_pos)
.map(|block| !block.is_fluid())
.unwrap_or(false)
{
client.remove_block(world_pos);
self.last_sent = Some((world_pos, Block::empty()))
}
},
}
}
}
}
// Generate debug info, if needed (it iterates through enough data that we might
// as well avoid it unless we need it).
let debug_info = global_state

View File

@ -170,6 +170,7 @@ impl ControlSettings {
GameInput::DeclineGroupInvite => KeyMouse::Key(VirtualKeyCode::N),
GameInput::MapZoomIn => KeyMouse::Key(VirtualKeyCode::Plus),
GameInput::MapZoomOut => KeyMouse::Key(VirtualKeyCode::Minus),
GameInput::PlaceVox => KeyMouse::Key(VirtualKeyCode::F7),
}
}
}

View File

@ -85,6 +85,7 @@ pub mod con_settings {
pub interact: Button,
pub toggle_wield: Button,
pub swap_loadout: Button,
pub place_vox: Button,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
@ -175,6 +176,7 @@ pub mod con_settings {
interact: Button::Simple(GilButton::North),
toggle_wield: Button::Simple(GilButton::West),
swap_loadout: Button::Simple(GilButton::LeftThumb),
place_vox: Button::Simple(GilButton::Unknown),
}
}
}

View File

@ -79,6 +79,7 @@ pub enum GameInput {
DeclineGroupInvite,
MapZoomIn,
MapZoomOut,
PlaceVox,
}
impl GameInput {
@ -145,6 +146,7 @@ impl GameInput {
GameInput::DeclineGroupInvite => "gameinput.declinegroupinvite",
GameInput::MapZoomIn => "gameinput.mapzoomin",
GameInput::MapZoomOut => "gameinput.mapzoomout",
GameInput::PlaceVox => "gameinput.placevox",
}
}
@ -211,6 +213,7 @@ impl GameInput {
GameInput::DeclineGroupInvite,
GameInput::MapZoomIn,
GameInput::MapZoomOut,
GameInput::PlaceVox,
]
.iter()
.copied()