mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added basic networked communications, chat communication
Former-commit-id: 06bafdf69486f4da5fbc416835e34c5bed8c2caa
This commit is contained in:
parent
187b7939d7
commit
dbbcc1e80e
@ -2,6 +2,7 @@
|
||||
members = [
|
||||
"common",
|
||||
"client",
|
||||
"chat-cli",
|
||||
"server",
|
||||
"server-cli",
|
||||
"voxygen",
|
||||
|
3
chat-cli/.gitignore
vendored
Normal file
3
chat-cli/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
12
chat-cli/Cargo.toml
Normal file
12
chat-cli/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "veloren-chat-cli"
|
||||
version = "0.1.0"
|
||||
authors = ["Joshua Barretto <joshua.s.barretto@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
client = { package = "veloren-client", path = "../client" }
|
||||
common = { package = "veloren-common", path = "../common" }
|
||||
|
||||
log = "0.4"
|
||||
pretty_env_logger = "0.3"
|
37
chat-cli/src/main.rs
Normal file
37
chat-cli/src/main.rs
Normal file
@ -0,0 +1,37 @@
|
||||
use std::time::Duration;
|
||||
use log::info;
|
||||
use client::{Input, Client, Event};
|
||||
use common::clock::Clock;
|
||||
|
||||
const FPS: u64 = 60;
|
||||
|
||||
fn main() {
|
||||
// Init logging
|
||||
pretty_env_logger::init();
|
||||
|
||||
info!("Starting chat-cli...");
|
||||
|
||||
// Set up an fps clock
|
||||
let mut clock = Clock::new();
|
||||
|
||||
// Create client
|
||||
let mut client = Client::new(([127, 0, 0, 1], 59003))
|
||||
.expect("Failed to create client instance");
|
||||
|
||||
loop {
|
||||
let events = client.tick(Input::default(), clock.get_last_delta())
|
||||
.expect("Failed to tick client");
|
||||
|
||||
for event in events {
|
||||
match event {
|
||||
Event::Chat(msg) => println!("[chat] {}", msg),
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up the server after a tick
|
||||
client.cleanup();
|
||||
|
||||
// Wait for the next tick
|
||||
clock.tick(Duration::from_millis(1000 / FPS));
|
||||
}
|
||||
}
|
17
client/src/error.rs
Normal file
17
client/src/error.rs
Normal file
@ -0,0 +1,17 @@
|
||||
use common::net::PostError;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Network(PostError),
|
||||
ServerShutdown,
|
||||
Other(String),
|
||||
}
|
||||
|
||||
impl From<PostError> for Error {
|
||||
fn from(err: PostError) -> Self {
|
||||
match err {
|
||||
PostError::Disconnected => Error::ServerShutdown,
|
||||
err => Error::Network(err),
|
||||
}
|
||||
}
|
||||
}
|
14
client/src/input.rs
Normal file
14
client/src/input.rs
Normal file
@ -0,0 +1,14 @@
|
||||
use vek::*;
|
||||
|
||||
pub struct Input {
|
||||
// TODO: Use this type to manage client input
|
||||
pub move_dir: Vec2<f32>,
|
||||
}
|
||||
|
||||
impl Default for Input {
|
||||
fn default() -> Self {
|
||||
Input {
|
||||
move_dir: Vec2::zero(),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,29 +1,38 @@
|
||||
// Standard
|
||||
use std::time::Duration;
|
||||
pub mod error;
|
||||
pub mod input;
|
||||
|
||||
// Library
|
||||
use specs::Entity as EcsEntity;
|
||||
// Reexports
|
||||
pub use specs::Entity as EcsEntity;
|
||||
pub use crate::{
|
||||
error::Error,
|
||||
input::Input,
|
||||
};
|
||||
|
||||
use std::{
|
||||
time::Duration,
|
||||
net::SocketAddr,
|
||||
};
|
||||
use vek::*;
|
||||
use threadpool;
|
||||
|
||||
// Project
|
||||
use common::{comp::phys::Vel, state::State, terrain::TerrainChunk};
|
||||
use common::{
|
||||
comp::phys::Vel,
|
||||
state::State,
|
||||
terrain::TerrainChunk,
|
||||
net::PostBox,
|
||||
msg::{ClientMsg, ServerMsg},
|
||||
};
|
||||
use world::World;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
ServerShutdown,
|
||||
Other(String),
|
||||
}
|
||||
|
||||
pub struct Input {
|
||||
// TODO: Use this type to manage client input
|
||||
pub move_dir: Vec2<f32>,
|
||||
pub enum Event {
|
||||
Chat(String),
|
||||
}
|
||||
|
||||
pub struct Client {
|
||||
thread_pool: threadpool::ThreadPool,
|
||||
|
||||
last_ping: f64,
|
||||
postbox: PostBox<ClientMsg, ServerMsg>,
|
||||
|
||||
tick: u64,
|
||||
state: State,
|
||||
player: Option<EcsEntity>,
|
||||
@ -35,25 +44,35 @@ pub struct Client {
|
||||
|
||||
impl Client {
|
||||
/// Create a new `Client`.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
#[allow(dead_code)]
|
||||
pub fn new<A: Into<SocketAddr>>(addr: A) -> Result<Self, Error> {
|
||||
let state = State::new();
|
||||
|
||||
let mut postbox = PostBox::to_server(addr)?;
|
||||
postbox.send(ClientMsg::Chat(String::from("Hello, world!")));
|
||||
|
||||
Ok(Self {
|
||||
thread_pool: threadpool::Builder::new()
|
||||
.thread_name("veloren-worker".into())
|
||||
.build(),
|
||||
|
||||
last_ping: state.get_time(),
|
||||
postbox,
|
||||
|
||||
tick: 0,
|
||||
state: State::new(),
|
||||
state,
|
||||
player: None,
|
||||
|
||||
// Testing
|
||||
world: World::new(),
|
||||
chunk: None,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Get a reference to the client's worker thread pool. This pool should be used for any
|
||||
/// computationally expensive operations that run outside of the main thread (i.e: threads that
|
||||
/// block on I/O operations are exempt).
|
||||
#[allow(dead_code)]
|
||||
pub fn thread_pool(&self) -> &threadpool::ThreadPool { &self.thread_pool }
|
||||
|
||||
// TODO: Get rid of this
|
||||
@ -70,23 +89,34 @@ impl Client {
|
||||
}
|
||||
|
||||
/// Get a reference to the client's game state.
|
||||
#[allow(dead_code)]
|
||||
pub fn state(&self) -> &State { &self.state }
|
||||
|
||||
/// Get a mutable reference to the client's game state.
|
||||
#[allow(dead_code)]
|
||||
pub fn state_mut(&mut self) -> &mut State { &mut self.state }
|
||||
|
||||
/// Get the player entity
|
||||
#[allow(dead_code)]
|
||||
pub fn player(&self) -> Option<EcsEntity> {
|
||||
self.player
|
||||
}
|
||||
|
||||
/// Get the current tick number.
|
||||
#[allow(dead_code)]
|
||||
pub fn get_tick(&self) -> u64 {
|
||||
self.tick
|
||||
}
|
||||
|
||||
/// Send a chat message to the server
|
||||
#[allow(dead_code)]
|
||||
pub fn send_chat(&mut self, msg: String) -> Result<(), Error> {
|
||||
Ok(self.postbox.send(ClientMsg::Chat(msg))?)
|
||||
}
|
||||
|
||||
/// Execute a single client tick, handle input and update the game state by the given duration
|
||||
pub fn tick(&mut self, input: Input, dt: Duration) -> Result<(), Error> {
|
||||
#[allow(dead_code)]
|
||||
pub fn tick(&mut self, input: Input, dt: Duration) -> Result<Vec<Event>, Error> {
|
||||
// This tick function is the centre of the Veloren universe. Most client-side things are
|
||||
// managed from here, and as such it's important that it stays organised. Please consult
|
||||
// the core developers before making significant changes to this code. Here is the
|
||||
@ -99,7 +129,13 @@ impl Client {
|
||||
// 4) Go through the terrain update queue and apply all changes to the terrain
|
||||
// 5) Finish the tick, passing control of the main thread back to the frontend
|
||||
|
||||
// (step 1)
|
||||
// Build up a list of events for this frame, to be passed to the frontend
|
||||
let mut frontend_events = Vec::new();
|
||||
|
||||
// Handle new messages from the server
|
||||
frontend_events.append(&mut self.handle_new_messages()?);
|
||||
|
||||
// Step 3
|
||||
if let Some(p) = self.player {
|
||||
// TODO: remove this
|
||||
const PLAYER_VELOCITY: f32 = 100.0;
|
||||
@ -113,12 +149,40 @@ impl Client {
|
||||
|
||||
// Finish the tick, pass control back to the frontend (step 6)
|
||||
self.tick += 1;
|
||||
Ok(())
|
||||
Ok(frontend_events)
|
||||
}
|
||||
|
||||
/// Clean up the client after a tick
|
||||
#[allow(dead_code)]
|
||||
pub fn cleanup(&mut self) {
|
||||
// Cleanup the local state
|
||||
self.state.cleanup();
|
||||
}
|
||||
|
||||
/// Handle new server messages
|
||||
fn handle_new_messages(&mut self) -> Result<Vec<Event>, Error> {
|
||||
let mut frontend_events = Vec::new();
|
||||
|
||||
// Step 1
|
||||
let new_msgs = self.postbox.new_messages();
|
||||
|
||||
if new_msgs.len() > 0 {
|
||||
self.last_ping = self.state.get_time();
|
||||
|
||||
for msg in new_msgs {
|
||||
match msg {
|
||||
ServerMsg::Chat(msg) => frontend_events.push(Event::Chat(msg)),
|
||||
ServerMsg::Shutdown => return Err(Error::ServerShutdown),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(frontend_events)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Client {
|
||||
fn drop(&mut self) {
|
||||
self.postbox.send(ClientMsg::Disconnect).unwrap();
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ extern crate serde_derive;
|
||||
pub mod clock;
|
||||
pub mod comp;
|
||||
pub mod figure;
|
||||
pub mod msg;
|
||||
pub mod state;
|
||||
pub mod sys;
|
||||
pub mod terrain;
|
||||
|
5
common/src/msg/client.rs
Normal file
5
common/src/msg/client.rs
Normal file
@ -0,0 +1,5 @@
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum ClientMsg {
|
||||
Chat(String),
|
||||
Disconnect,
|
||||
}
|
6
common/src/msg/mod.rs
Normal file
6
common/src/msg/mod.rs
Normal file
@ -0,0 +1,6 @@
|
||||
pub mod server;
|
||||
pub mod client;
|
||||
|
||||
// Reexports
|
||||
pub use server::ServerMsg;
|
||||
pub use client::ClientMsg;
|
5
common/src/msg/server.rs
Normal file
5
common/src/msg/server.rs
Normal file
@ -0,0 +1,5 @@
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum ServerMsg {
|
||||
Chat(String),
|
||||
Shutdown,
|
||||
}
|
@ -112,7 +112,7 @@ where
|
||||
/// Non-blocking receiver method returning an iterator over already received and deserialized objects
|
||||
/// # Errors
|
||||
/// If the other side disconnects PostBox won't realize that until you try to send something
|
||||
pub fn recv_iter(&mut self) -> impl Iterator<Item = R> {
|
||||
pub fn new_messages(&mut self) -> impl ExactSizeIterator<Item = R> {
|
||||
let mut events = Events::with_capacity(4096);
|
||||
let mut items = VecDeque::new();
|
||||
|
||||
|
@ -79,7 +79,7 @@ where
|
||||
/// Non-blocking method returning an iterator over new connections wrapped in [`PostBox`]es
|
||||
pub fn new_connections(
|
||||
&mut self,
|
||||
) -> impl Iterator<Item = PostBox<S, R>> {
|
||||
) -> impl ExactSizeIterator<Item = PostBox<S, R>> {
|
||||
let mut events = Events::with_capacity(256);
|
||||
let mut conns = VecDeque::new();
|
||||
|
||||
|
@ -72,6 +72,19 @@ impl State {
|
||||
}
|
||||
}
|
||||
|
||||
/// Register a component with the state's ECS
|
||||
pub fn with_component<T: Component>(mut self) -> Self
|
||||
where <T as Component>::Storage: Default
|
||||
{
|
||||
self.ecs_world.register::<T>();
|
||||
self
|
||||
}
|
||||
|
||||
/// Delete an entity from the state's ECS, if it exists
|
||||
pub fn delete_entity(&mut self, entity: EcsEntity) {
|
||||
let _ = self.ecs_world.delete_entity(entity);
|
||||
}
|
||||
|
||||
// TODO: Get rid of this
|
||||
pub fn new_test_player(&mut self) -> EcsEntity {
|
||||
self.ecs_world
|
||||
|
@ -1,11 +1,6 @@
|
||||
// Standard
|
||||
use std::time::Duration;
|
||||
|
||||
// Library
|
||||
use log::info;
|
||||
|
||||
// Project
|
||||
use server::{self, Server};
|
||||
use server::{Input, Event, Server};
|
||||
use common::clock::Clock;
|
||||
|
||||
const FPS: u64 = 60;
|
||||
@ -20,12 +15,21 @@ fn main() {
|
||||
let mut clock = Clock::new();
|
||||
|
||||
// Create server
|
||||
let mut server = Server::new();
|
||||
let mut server = Server::new()
|
||||
.expect("Failed to create server instance");
|
||||
|
||||
loop {
|
||||
server.tick(server::Input {}, clock.get_last_delta())
|
||||
let events = server.tick(Input::default(), clock.get_last_delta())
|
||||
.expect("Failed to tick server");
|
||||
|
||||
for event in events {
|
||||
match event {
|
||||
Event::ClientConnected { ecs_entity } => println!("Client connected!"),
|
||||
Event::ClientDisconnected { ecs_entity } => println!("Client disconnected!"),
|
||||
Event::Chat { msg, .. } => println!("[chat] {}", msg),
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up the server after a tick
|
||||
server.cleanup();
|
||||
|
||||
|
11
server/src/client.rs
Normal file
11
server/src/client.rs
Normal file
@ -0,0 +1,11 @@
|
||||
use specs::Entity as EcsEntity;
|
||||
use common::{
|
||||
msg::{ServerMsg, ClientMsg},
|
||||
net::PostBox,
|
||||
};
|
||||
|
||||
pub struct Client {
|
||||
pub ecs_entity: EcsEntity,
|
||||
pub postbox: PostBox<ServerMsg, ClientMsg>,
|
||||
pub last_ping: f64,
|
||||
}
|
13
server/src/error.rs
Normal file
13
server/src/error.rs
Normal file
@ -0,0 +1,13 @@
|
||||
use common::net::PostError;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Network(PostError),
|
||||
Other(String),
|
||||
}
|
||||
|
||||
impl From<PostError> for Error {
|
||||
fn from(err: PostError) -> Self {
|
||||
Error::Network(err)
|
||||
}
|
||||
}
|
9
server/src/input.rs
Normal file
9
server/src/input.rs
Normal file
@ -0,0 +1,9 @@
|
||||
pub struct Input {
|
||||
// TODO: Use this type to manage server input
|
||||
}
|
||||
|
||||
impl Default for Input {
|
||||
fn default() -> Self {
|
||||
Input {}
|
||||
}
|
||||
}
|
@ -1,47 +1,81 @@
|
||||
// Standard
|
||||
use std::time::Duration;
|
||||
#![feature(drain_filter)]
|
||||
|
||||
// Internal
|
||||
use common::state::State;
|
||||
pub mod client;
|
||||
pub mod error;
|
||||
pub mod input;
|
||||
|
||||
// Reexports
|
||||
pub use crate::{
|
||||
error::Error,
|
||||
input::Input,
|
||||
};
|
||||
|
||||
use std::{
|
||||
time::Duration,
|
||||
net::SocketAddr,
|
||||
};
|
||||
use specs::Entity as EcsEntity;
|
||||
use common::{
|
||||
state::State,
|
||||
net::PostOffice,
|
||||
msg::{ServerMsg, ClientMsg},
|
||||
};
|
||||
use world::World;
|
||||
use crate::client::Client;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Other(String),
|
||||
}
|
||||
const CLIENT_TIMEOUT: f64 = 5.0; // Seconds
|
||||
|
||||
pub struct Input {
|
||||
// TODO: Use this type to manage server input
|
||||
pub enum Event {
|
||||
ClientConnected {
|
||||
ecs_entity: EcsEntity,
|
||||
},
|
||||
ClientDisconnected {
|
||||
ecs_entity: EcsEntity,
|
||||
},
|
||||
Chat {
|
||||
ecs_entity: EcsEntity,
|
||||
msg: String,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct Server {
|
||||
state: State,
|
||||
world: World,
|
||||
|
||||
// TODO: Add "meta" state here
|
||||
postoffice: PostOffice<ServerMsg, ClientMsg>,
|
||||
clients: Vec<Client>,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
/// Create a new `Server`.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
#[allow(dead_code)]
|
||||
pub fn new() -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
state: State::new(),
|
||||
world: World::new(),
|
||||
}
|
||||
|
||||
postoffice: PostOffice::new(SocketAddr::from(([0; 4], 59003)))?,
|
||||
clients: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Get a reference to the server's game state.
|
||||
#[allow(dead_code)]
|
||||
pub fn state(&self) -> &State { &self.state }
|
||||
/// Get a mutable reference to the server's game state.
|
||||
#[allow(dead_code)]
|
||||
pub fn state_mut(&mut self) -> &mut State { &mut self.state }
|
||||
|
||||
/// Get a reference to the server's world.
|
||||
#[allow(dead_code)]
|
||||
pub fn world(&self) -> &World { &self.world }
|
||||
/// Get a mutable reference to the server's world.
|
||||
#[allow(dead_code)]
|
||||
pub fn world_mut(&mut self) -> &mut World { &mut self.world }
|
||||
|
||||
/// Execute a single server tick, handle input and update the game state by the given duration
|
||||
pub fn tick(&mut self, input: Input, dt: Duration) -> Result<(), Error> {
|
||||
#[allow(dead_code)]
|
||||
pub fn tick(&mut self, input: Input, dt: Duration) -> Result<Vec<Event>, Error> {
|
||||
// This tick function is the centre of the Veloren universe. Most server-side things are
|
||||
// managed from here, and as such it's important that it stays organised. Please consult
|
||||
// the core developers before making significant changes to this code. Here is the
|
||||
@ -56,16 +90,108 @@ impl Server {
|
||||
// 6) Send relevant state updates to all clients
|
||||
// 7) Finish the tick, passing control of the main thread back to the frontend
|
||||
|
||||
// Build up a list of events for this frame, to be passed to the frontend
|
||||
let mut frontend_events = Vec::new();
|
||||
|
||||
// If networking has problems, handle them
|
||||
if let Some(err) = self.postoffice.status() {
|
||||
return Err(err.into());
|
||||
}
|
||||
|
||||
// Handle new client connections (step 2)
|
||||
frontend_events.append(&mut self.handle_new_connections()?);
|
||||
|
||||
// Handle new messages from clients
|
||||
frontend_events.append(&mut self.handle_new_messages()?);
|
||||
|
||||
// Tick the client's LocalState (step 3)
|
||||
self.state.tick(dt);
|
||||
|
||||
// Finish the tick, pass control back to the frontend (step 6)
|
||||
Ok(())
|
||||
Ok(frontend_events)
|
||||
}
|
||||
|
||||
/// Clean up the server after a tick
|
||||
#[allow(dead_code)]
|
||||
pub fn cleanup(&mut self) {
|
||||
// Cleanup the local state
|
||||
self.state.cleanup();
|
||||
}
|
||||
|
||||
/// Handle new client connections
|
||||
fn handle_new_connections(&mut self) -> Result<Vec<Event>, Error> {
|
||||
let mut frontend_events = Vec::new();
|
||||
|
||||
for postbox in self.postoffice.new_connections() {
|
||||
// TODO: Don't use this method
|
||||
let ecs_entity = self.state.new_test_player();
|
||||
|
||||
frontend_events.push(Event::ClientConnected {
|
||||
ecs_entity,
|
||||
});
|
||||
|
||||
self.clients.push(Client {
|
||||
ecs_entity,
|
||||
postbox,
|
||||
last_ping: self.state.get_time(),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(frontend_events)
|
||||
}
|
||||
|
||||
/// Handle new client messages
|
||||
fn handle_new_messages(&mut self) -> Result<Vec<Event>, Error> {
|
||||
let mut frontend_events = Vec::new();
|
||||
|
||||
let state = &mut self.state;
|
||||
let mut new_chat_msgs = Vec::new();
|
||||
|
||||
self.clients.drain_filter(|client| {
|
||||
let mut disconnected = false;
|
||||
let new_msgs = client.postbox.new_messages();
|
||||
|
||||
// Update client ping
|
||||
if new_msgs.len() > 0 {
|
||||
client.last_ping = state.get_time();
|
||||
|
||||
// Process incoming messages
|
||||
for msg in new_msgs {
|
||||
match msg {
|
||||
ClientMsg::Chat(msg) => new_chat_msgs.push((client.ecs_entity, msg)),
|
||||
ClientMsg::Disconnect => disconnected = true,
|
||||
}
|
||||
}
|
||||
} else if
|
||||
state.get_time() - client.last_ping > CLIENT_TIMEOUT ||
|
||||
client.postbox.status().is_some()
|
||||
{
|
||||
disconnected = true;
|
||||
}
|
||||
|
||||
if disconnected {
|
||||
state.delete_entity(client.ecs_entity);
|
||||
frontend_events.push(Event::ClientDisconnected {
|
||||
ecs_entity: client.ecs_entity,
|
||||
});
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
// Handle new chat messages
|
||||
for (ecs_entity, msg) in new_chat_msgs {
|
||||
for client in &mut self.clients {
|
||||
let _ = client.postbox.send(ServerMsg::Chat(msg.clone()));
|
||||
}
|
||||
|
||||
frontend_events.push(Event::Chat {
|
||||
ecs_entity,
|
||||
msg,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(frontend_events)
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ impl Animation for RunAnimation {
|
||||
//skeleton.br_foot.offset = Vec3::new(0.0, wavecos_slow * 1.0, wave_slow * 2.0 + wave_dip * 1.0);
|
||||
//skeleton.br_foot.ori = Quaternion::rotation_x(0.0 + wave_slow * 10.1);
|
||||
|
||||
skeleton.bl_foot.offset = Vec3::new(0.0, 0.0, 80.0);
|
||||
skeleton.bl_foot.offset = Vec3::new(0.0, 0.0, 0.0);
|
||||
skeleton.bl_foot.ori = Quaternion::rotation_x(wave_slow * 2.0);
|
||||
//skeleton.bl_foot.offset = Vec3::new(0.0, wavecos_slow * 1.0, wave_slow * 2.0 + wave_dip * 1.0);
|
||||
//skeleton.bl_foot.ori = Quaternion::rotation_x(0.5 + wave_slow * 0.1);
|
||||
|
@ -84,7 +84,7 @@ impl Scene {
|
||||
[
|
||||
Some(load_segment("dragonhead.vox").generate_mesh(Vec3::new(2.0, -12.0, 2.0))),
|
||||
Some(load_segment("dragon_body.vox").generate_mesh(Vec3::new(0.0, 0.0, 0.0))),
|
||||
Some(load_segment("dragon_lfoot.vox").generate_mesh(Vec3::new(10.0, 10.0, -80.0))),
|
||||
Some(load_segment("dragon_lfoot.vox").generate_mesh(Vec3::new(0.0, 10.0, -4.0))),
|
||||
Some(load_segment("dragon_rfoot.vox").generate_mesh(Vec3::new(0.0, 10.0, -4.0))),
|
||||
Some(load_segment("dragon_rfoot.vox").generate_mesh(Vec3::new(0.0, -10.0, -4.0))),
|
||||
Some(load_segment("dragon_lfoot.vox").generate_mesh(Vec3::new(0.0, 0.0, 0.0))),
|
||||
|
Loading…
Reference in New Issue
Block a user