Merge master

This commit is contained in:
Adam Whitehurst 2020-03-07 12:49:15 -08:00
commit 096d3b691e
89 changed files with 1624 additions and 759 deletions

View File

@ -8,7 +8,8 @@ variables:
stages:
- optional-builds
- check-compile
- post
- build-post
- publish
before_script:
- source $HOME/.cargo/env
@ -90,30 +91,30 @@ security:
# --
# -- post build
# -- build-post
unittests:
stage: post
stage: build-post
when: delayed
start_in: 5 seconds
tags:
- veloren-docker
script:
- echo "Workaround, cargo tests fails due some rust files are already deleted, so we just stack cargo test. if its the os error, it wont appear on them all, if its a real error, it will retry and then fail"
- cargo test || cargo test || cargo test || cargo test
- cargo test || ( sleep 10 && cargo test ) || ( sleep 10 && cargo test ) || cargo test || cargo test || cargo test || cargo test || cargo test || cargo test || cargo test || cargo test || cargo test || cargo test
coverage:
stage: post
stage: build-post
when: delayed
start_in: 5 seconds
tags:
- veloren-docker
script:
- echo "Workaround, tarpaulin fails due some rust files are already deleted, so we just stack tarpaulin. if its the os error, it wont appear on them all, if its a real error, it will retry and then fail"
- cargo tarpaulin -v || cargo tarpaulin -v || cargo tarpaulin -v || cargo tarpaulin -v || cargo tarpaulin -v || cargo tarpaulin -v || cargo tarpaulin -v || cargo tarpaulin -v || cargo tarpaulin -v || cargo tarpaulin -v
- cargo tarpaulin -v || ( sleep 10 && cargo tarpaulin -v ) || ( sleep 10 && cargo tarpaulin -v ) || cargo tarpaulin -v || cargo tarpaulin -v || cargo tarpaulin -v || cargo tarpaulin -v || cargo tarpaulin -v || cargo tarpaulin -v || cargo tarpaulin -v || cargo tarpaulin -v
benchmarks:
stage: post
stage: build-post
when: delayed
start_in: 5 seconds
tags:
@ -125,7 +126,7 @@ benchmarks:
localization-status:
variables:
GIT_DEPTH: 0
stage: post
stage: build-post
when: delayed
start_in: 5 seconds
allow_failure: true
@ -135,13 +136,13 @@ localization-status:
- cargo test -q test_all_localizations -- --nocapture --ignored
linux:
stage: post
stage: build-post
when: delayed
start_in: 5 seconds
only:
refs:
- /^r[0-9]+\.[0-9]+\.[0-9]+/
- /^v[0-9]+\.[0-9]+\.[0-9]+/
- /^v[0-9]+\.[0-9]+/
- /^master$/
tags:
- veloren-docker
@ -160,13 +161,13 @@ linux:
expire_in: 1 week
windows:
stage: post
stage: build-post
when: delayed
start_in: 5 seconds
only:
refs:
- /^r[0-9]+\.[0-9]+\.[0-9]+/
- /^v[0-9]+\.[0-9]+\.[0-9]+/
- /^v[0-9]+\.[0-9]+/
- /^master$/
tags:
- veloren-docker
@ -181,4 +182,53 @@ windows:
- assets/
- LICENSE
expire_in: 1 week
macos:
stage: build-post
when: delayed
start_in: 5 seconds
only:
refs:
- /^r[0-9]+\.[0-9]+\.[0-9]+/
- /^v[0-9]+\.[0-9]+/
- /^master$/
tags:
- veloren-docker
script:
- PATH="/dockercache/osxcross/target/bin:$PATH" COREAUDIO_SDK_PATH=/dockercache/osxcross/target/SDK/MacOSX10.13.sdk CC=o64-clang CXX=o64-clang++ cargo build --target x86_64-apple-darwin --release
- cp -r target/x86_64-apple-darwin/release/veloren-server-cli $CI_PROJECT_DIR
- cp -r target/x86_64-apple-darwin/release/veloren-voxygen $CI_PROJECT_DIR
artifacts:
paths:
- veloren-server-cli
- veloren-voxygen
- assets/
- LICENSE
expire_in: 1 week
# --
# -- publish
docker:
stage: publish
when: delayed
start_in: 5 seconds
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
dependencies:
- linux
before_script:
- ls "$CI_PROJECT_DIR/server-cli/"
only:
refs:
- /^r[0-9]+\.[0-9]+\.[0-9]+/
- /^v[0-9]+\.[0-9]+/
- /^master$/
tags:
- veloren-docker
script:
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/server-cli/Dockerfile --destination "${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_NAME}-server"
# --

28
.gitlab/CODEOWNERS Normal file
View File

@ -0,0 +1,28 @@
# Defines people who should approve to certain parts of the codebase
/assets/ @assetsandvisualdesign @frontend
/chat-cli/ @frontend
/client/ @backend @networking
/common/ @backend @networking
/server/ @backend @networking
/server-cli/ @frontend
#/voxygen/ @someone
/voxygen/anim/ @animation
/voxygen/audio/ @audio
#/voxygen/hud/ @someone
#/voxygen/menu / @someone
#/voxygen/mesh/ @someone
/voxygen/render/ @rendering
#/voxygen/scene/ @someone
#/voxygen/ui/ @someone
/world/ @worldgen
# All files related to documentation or game unrelated content needs to be approved by the meta group
*.md @meta
*.nix @meta
.gitignore @meta
.gitattributes @meta
.gitlab-ci.yml @meta
rust-toolchain @meta
LICENSE @meta
.cargo/ @meta

View File

@ -19,6 +19,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added gamma setting
- Added new orc hairstyles
- Added sfx for wielding/unwielding weapons
- Fixed NPCs attacking the player forever after killing them
- Added sfx for collecting, dropping and using inventory items
- New attack animation
- weapon control system
- Game pauses when in singleplayer and pause menu
### Changed

1
Cargo.lock generated
View File

@ -3377,6 +3377,7 @@ dependencies = [
"specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
"specs-idvs 0.1.0 (git+https://gitlab.com/veloren/specs-idvs.git)",
"treeculler 0.1.0 (git+https://gitlab.com/yusdacra/treeculler.git)",
"uvth 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"vek 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)",
"veloren-client 0.5.0",
"veloren-common 0.5.0",

View File

@ -35,5 +35,59 @@
],
threshold: 1.0,
),
Inventory(Collected): (
files: [
"voxygen.audio.sfx.inventory.add_item",
],
threshold: 0.5,
),
Inventory(Swapped): (
files: [
"voxygen.audio.sfx.inventory.add_item",
],
threshold: 0.5,
),
Inventory(Given): (
files: [
"voxygen.audio.sfx.inventory.add_item",
],
threshold: 0.5,
),
Inventory(Dropped): (
files: [
"voxygen.audio.sfx.footsteps.stepgrass_4",
],
threshold: 0.5,
),
Inventory(Consumed(Potion)): (
files: [
"voxygen.audio.sfx.inventory.consumable.liquid",
],
threshold: 0.3,
),
Inventory(Consumed(PotionMinor)): (
files: [
"voxygen.audio.sfx.inventory.consumable.liquid",
],
threshold: 0.3,
),
Inventory(Consumed(Apple)): (
files: [
"voxygen.audio.sfx.inventory.consumable.apple",
],
threshold: 0.3,
),
Inventory(Consumed(Mushroom)): (
files: [
"voxygen.audio.sfx.inventory.consumable.food",
],
threshold: 0.3,
),
Inventory(Consumed(Cheese)): (
files: [
"voxygen.audio.sfx.inventory.consumable.food",
],
threshold: 0.3,
)
}
)

BIN
assets/voxygen/audio/sfx/inventory/add_item.wav (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/voxygen/audio/sfx/inventory/consumable/apple.wav (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/voxygen/audio/sfx/inventory/consumable/food.wav (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/voxygen/audio/sfx/inventory/consumable/liquid.wav (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright 2019 Artem Polishchuk <ego.cordatus@gmail.com> -->
<component type="desktop-application">
<id>net.veloren.veloren.desktop</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0-or-later</project_license>
<content_rating type="oars-1.0">
<content_attribute id="social-chat">intense</content_attribute>
<content_attribute id="social-info">mild</content_attribute>
<content_attribute id="violence-cartoon">mild</content_attribute>
<content_attribute id="violence-fantasy">mild</content_attribute>
</content_rating>
<name>Veloren</name>
<summary>
Veloren is a multiplayer voxel RPG written in Rust. It is inspired
by games such as Cube World, Legend of Zelda: Breath of the Wild,
Dwarf Fortress and Minecraft.
</summary>
<description>
<p>
Welcome To Veloren!
</p><p>
Veloren is a multiplayer voxel RPG written in Rust. Veloren takes
inspiration from games such as Cube World, Minecraft and Dwarf
Fortress. The game is currently under heavy development, but is
playable.
</p><p>
Development
</p><p>
Currently the communication of contributors happens mainly on our
official Discord server (https://discord.gg/kjwJwjK). You can join
it to keep up with the development, talk to us or contribute
something yourself. Anyone who shows genuine effort to help is
welcome in our team. You don't have to know how to program to
contribute!
</p>
</description>
<screenshots>
<screenshot type="default">
<image>https://media.discordapp.net/attachments/634860358623821835/643034796548947968/screenshot_1573381825305.png</image>
</screenshot>
<screenshot>
<image>https://media.discordapp.net/attachments/597826574095613962/643102462781423616/screenshot_1573397958545.png</image>
</screenshot>
<screenshot>
<image>https://cdn.discordapp.com/attachments/634860358623821835/646518917577310219/screenshot_1574211401431.png</image>
</screenshot>
</screenshots>
<keywords>
<keyword>sandbox</keyword>
<keyword>world</keyword>
<keyword>multiplayer</keyword>
</keywords>
<url type="homepage">https://veloren.net</url>
<url type="bugtracker">https://gitlab.com/veloren/veloren/issues</url>
<url type="faq">https://gitlab.com/veloren/veloren#faq</url>
<url type="help">https://book.veloren.net/</url>
<provides>
<binary>veloren-voxygen</binary>
</provides>
</component>

View File

@ -0,0 +1,9 @@
[Desktop Entry]
Type=Application
Name=Veloren
Comment=Veloren is a multiplayer voxel RPG written in Rust
Exec=veloren-voxygen
Categories=Game;Simulation;
Keywords=veloren;sandbox;world;blocks;nodes;multiplayer;roleplaying;
Icon=net.veloren.veloren.png
Terminal=false

BIN
assets/voxygen/net.veloren.veloren.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -14,6 +14,7 @@ pub use specs::{
use byteorder::{ByteOrder, LittleEndian};
use common::{
comp::{self, ControlEvent, Controller, ControllerInputs, InventoryManip},
event::{EventBus, SfxEvent, SfxEventItem},
msg::{
validate_chat_msg, ChatMsgValidationError, ClientMsg, ClientState, PlayerListUpdate,
RequestStateError, ServerError, ServerInfo, ServerMsg, MAX_BYTES_CHAT_MSG,
@ -39,11 +40,11 @@ use vek::*;
// The duration of network inactivity until the player is kicked
// @TODO: in the future, this should be configurable on the server
// and be provided to the client
const SERVER_TIMEOUT: Duration = Duration::from_secs(20);
const SERVER_TIMEOUT: f64 = 20.0;
// After this duration has elapsed, the user will begin getting kick warnings in
// their chat window
const SERVER_TIMEOUT_GRACE_PERIOD: Duration = Duration::from_secs(14);
const SERVER_TIMEOUT_GRACE_PERIOD: f64 = 14.0;
pub enum Event {
Chat {
@ -63,8 +64,8 @@ pub struct Client {
postbox: PostBox<ClientMsg, ServerMsg>,
last_server_ping: Instant,
last_server_pong: Instant,
last_server_ping: f64,
last_server_pong: f64,
last_ping_delta: f64,
tick: u64,
@ -151,8 +152,8 @@ impl Client {
postbox,
last_server_ping: Instant::now(),
last_server_pong: Instant::now(),
last_server_ping: 0.0,
last_server_pong: 0.0,
last_ping_delta: 0.0,
tick: 0,
@ -377,6 +378,7 @@ impl Client {
}
}
}
// Handle new messages from the server.
frontend_events.append(&mut self.handle_new_messages()?);
@ -479,9 +481,9 @@ impl Client {
}
// Send a ping to the server once every second
if Instant::now().duration_since(self.last_server_ping) > Duration::from_secs(1) {
if self.state.get_time() - self.last_server_ping > 1. {
self.postbox.send_message(ClientMsg::Ping);
self.last_server_ping = Instant::now();
self.last_server_ping = self.state.get_time();
}
// 6) Update the server about the player's physics attributes.
@ -526,16 +528,14 @@ impl Client {
// Check that we have an valid connection.
// Use the last ping time as a 1s rate limiter, we only notify the user once per
// second
if Instant::now().duration_since(self.last_server_ping) > Duration::from_secs(1) {
let duration_since_last_pong = Instant::now().duration_since(self.last_server_pong);
if self.state.get_time() - self.last_server_ping > 1. {
let duration_since_last_pong = self.state.get_time() - self.last_server_pong;
// Dispatch a notification to the HUD warning they will be kicked in {n} seconds
if duration_since_last_pong.as_secs() >= SERVER_TIMEOUT_GRACE_PERIOD.as_secs() {
if let Some(seconds_until_kick) =
SERVER_TIMEOUT.checked_sub(duration_since_last_pong)
{
if duration_since_last_pong >= SERVER_TIMEOUT_GRACE_PERIOD {
if self.state.get_time() - duration_since_last_pong > 0. {
frontend_events.push(Event::DisconnectionNotification(
seconds_until_kick.as_secs(),
(self.state.get_time() - duration_since_last_pong).round() as u64,
));
}
}
@ -589,11 +589,10 @@ impl Client {
ServerMsg::Ping => self.postbox.send_message(ClientMsg::Pong),
ServerMsg::Pong => {
self.last_server_pong = Instant::now();
self.last_server_pong = self.state.get_time();
self.last_ping_delta = Instant::now()
.duration_since(self.last_server_ping)
.as_secs_f64();
self.last_ping_delta =
(self.state.get_time() - self.last_server_ping).round();
},
ServerMsg::ChatMsg { message, chat_type } => {
frontend_events.push(Event::Chat { message, chat_type })
@ -669,8 +668,14 @@ impl Client {
self.state.write_component(entity, character_state);
}
},
ServerMsg::InventoryUpdate(inventory) => {
self.state.write_component(self.entity, inventory)
ServerMsg::InventoryUpdate(inventory, event) => {
self.state.write_component(self.entity, inventory);
self.state
.ecs()
.read_resource::<EventBus<SfxEventItem>>()
.emitter()
.emit(SfxEventItem::at_player_position(SfxEvent::Inventory(event)));
},
ServerMsg::TerrainChunkUpdate { key, chunk } => {
if let Ok(chunk) = chunk {
@ -704,7 +709,7 @@ impl Client {
} else if let Some(err) = self.postbox.error() {
return Err(err.into());
// We regularily ping in the tick method
} else if Instant::now().duration_since(self.last_server_pong) > SERVER_TIMEOUT {
} else if self.state.get_time() - self.last_server_pong > SERVER_TIMEOUT {
return Err(Error::ServerTimeout);
}
Ok(frontend_events)

View File

@ -70,8 +70,7 @@ pub enum Armor {
Necklace,
}
//TODO: Do we even need this?
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Consumable {
Apple,
Cheese,

View File

@ -1,10 +1,11 @@
pub mod item;
// Reexports
pub use item::{Debug, Item, ItemKind, SwordKind, ToolData, ToolKind};
pub use item::{Consumable, Debug, Item, ItemKind, Tool};
use crate::assets;
use specs::{Component, HashMapStorage, NullStorage};
use specs::{Component, FlaggedStorage, HashMapStorage};
use specs_idvs::IDVStorage;
use std::ops::Not;
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
@ -136,12 +137,37 @@ impl Component for Inventory {
type Storage = HashMapStorage<Self>;
}
// ForceUpdate
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
pub enum InventoryUpdateEvent {
Init,
Used,
Consumed(Consumable),
Gave,
Given,
Swapped,
Dropped,
Collected,
Possession,
Debug,
}
impl Default for InventoryUpdateEvent {
fn default() -> Self { Self::Init }
}
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
pub struct InventoryUpdate;
pub struct InventoryUpdate {
event: InventoryUpdateEvent,
}
impl InventoryUpdate {
pub fn new(event: InventoryUpdateEvent) -> Self { Self { event } }
pub fn event(&self) -> InventoryUpdateEvent { self.event }
}
impl Component for InventoryUpdate {
type Storage = NullStorage<Self>;
type Storage = FlaggedStorage<Self, IDVStorage<Self>>;
}
#[cfg(test)] mod test;

View File

@ -31,7 +31,8 @@ pub use controller::{
pub use energy::{Energy, EnergySource};
pub use inputs::CanBuild;
pub use inventory::{
item, Inventory, InventoryUpdate, Item, ItemKind, SwordKind, ToolData, ToolKind,
item, Inventory, InventoryUpdate, InventoryUpdateEvent, Item, ItemKind, SwordKind, ToolData,
ToolKind,
};
pub use last::Last;
pub use location::{Waypoint, WaypointArea};

View File

@ -1,4 +1,5 @@
use crate::{comp, sync::Uid};
use comp::{item::Tool, InventoryUpdateEvent};
use parking_lot::Mutex;
use serde::Deserialize;
use specs::Entity as EcsEntity;
@ -39,8 +40,9 @@ pub enum SfxEvent {
Fall,
ExperienceGained,
LevelUp,
Wield(comp::item::ToolKind),
Unwield(comp::item::ToolKind),
Wield(Tool),
Unwield(Tool),
Inventory(InventoryUpdateEvent),
}
pub enum LocalEvent {

View File

@ -71,7 +71,7 @@ pub enum ServerMsg {
entity: u64,
character_state: comp::CharacterState,
},
InventoryUpdate(comp::Inventory),
InventoryUpdate(comp::Inventory, comp::InventoryUpdateEvent),
TerrainChunkUpdate {
key: Vec2<i32>,
chunk: Result<Box<TerrainChunk>, ()>,

View File

@ -153,7 +153,7 @@ impl<'a> System<'a> for Sys {
been_close,
..
} => {
if let (Some(tgt_pos), _tgt_stats, tgt_alignment) = (
if let (Some(tgt_pos), Some(tgt_stats), tgt_alignment) = (
positions.get(*target),
stats.get(*target),
alignments
@ -164,7 +164,8 @@ impl<'a> System<'a> for Sys {
// Don't attack entities we are passive towards
// TODO: This is here, it's a bit of a hack
if let Some(alignment) = alignment {
if (*alignment).passive_towards(tgt_alignment) {
if (*alignment).passive_towards(tgt_alignment) || tgt_stats.is_dead
{
do_idle = true;
break 'activity;
}

8
server-cli/Dockerfile Normal file
View File

@ -0,0 +1,8 @@
FROM debian:stable-slim
ARG PROJECTNAME=server-cli
COPY ./server-cli/docker-run.sh /opt/docker-run.sh
COPY ./veloren-server-cli /opt/veloren-server-cli
COPY ./assets/common /opt/assets/common
COPY ./assets/world /opt/assets/world

View File

@ -0,0 +1,17 @@
version: "3.7"
services:
game-server:
image: registry.gitlab.com/veloren/veloren:master-server
ports:
- "14004:14004"
- "14005:14005"
deploy:
replicas: 1
update_config:
parallelism: 2
delay: 10s
order: stop-first
failure_action: rollback
restart_policy:
condition: on-failure

3
server-cli/docker-run.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
cd /opt
RUST_LOG=info,common=debug,common::net=info RUST_BACKTRACE=1 /opt/veloren-server-cli

View File

@ -262,6 +262,7 @@ lazy_static! {
),
];
}
fn handle_give(server: &mut Server, entity: EcsEntity, args: String, _action: &ChatCommand) {
if let Ok(item) = assets::load_cloned(&args) {
server
@ -274,7 +275,10 @@ fn handle_give(server: &mut Server, entity: EcsEntity, args: String, _action: &C
.state
.ecs()
.write_storage::<comp::InventoryUpdate>()
.insert(entity, comp::InventoryUpdate);
.insert(
entity,
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Given),
);
} else {
server.notify_client(entity, ServerMsg::private(String::from("Invalid item!")));
}
@ -1113,7 +1117,10 @@ fn handle_debug(server: &mut Server, entity: EcsEntity, _args: String, _action:
.state
.ecs()
.write_storage::<comp::InventoryUpdate>()
.insert(entity, comp::InventoryUpdate);
.insert(
entity,
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Debug),
);
} else {
server.notify_client(
entity,

View File

@ -106,7 +106,10 @@ pub fn handle_possess(server: &Server, possessor_uid: Uid, possesse_uid: Uid) {
}
}
ecs.write_storage::<comp::InventoryUpdate>()
.insert(possesse, comp::InventoryUpdate)
.insert(
possesse,
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Possession),
)
.err()
.map(|e| {
error!(

View File

@ -48,7 +48,10 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
}
}
state.write_component(entity, comp::InventoryUpdate);
state.write_component(
entity,
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Collected),
);
},
comp::InventoryManip::Collect(pos) => {
@ -76,6 +79,8 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
.get_mut(entity)
.and_then(|inv| inv.remove(slot));
let mut event = comp::InventoryUpdateEvent::Used;
if let Some(item) = item_opt {
match item.kind {
comp::ItemKind::Tool { .. } => {
@ -94,7 +99,8 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
stats.equipment.main = Some(item);
}
},
comp::ItemKind::Consumable { effect, .. } => {
comp::ItemKind::Consumable { kind, effect } => {
event = comp::InventoryUpdateEvent::Consumed(kind);
state.apply_effect(entity, effect);
},
comp::ItemKind::Utility { kind } => match kind {
@ -168,7 +174,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
}
}
state.write_component(entity, comp::InventoryUpdate);
state.write_component(entity, comp::InventoryUpdate::new(event));
},
comp::InventoryManip::Swap(a, b) => {
@ -177,7 +183,10 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
.write_storage::<comp::Inventory>()
.get_mut(entity)
.map(|inv| inv.swap_slots(a, b));
state.write_component(entity, comp::InventoryUpdate);
state.write_component(
entity,
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Swapped),
);
},
comp::InventoryManip::Drop(slot) => {
@ -201,7 +210,10 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
item,
));
}
state.write_component(entity, comp::InventoryUpdate);
state.write_component(
entity,
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Dropped),
);
},
}

View File

@ -282,7 +282,10 @@ impl Server {
state.write_component(entity, comp::CharacterState::default());
state.write_component(entity, comp::Alignment::Owned(entity));
state.write_component(entity, comp::Inventory::default());
state.write_component(entity, comp::InventoryUpdate);
state.write_component(
entity,
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::default()),
);
state.write_component(entity, comp::AbilityPool::default());
// Make sure physics are accepted.
state.write_component(entity, comp::ForceUpdate);
@ -576,6 +579,8 @@ impl Server {
.get(entity)
.is_some()
}
pub fn number_of_players(&self) -> i64 { self.metrics.player_online.get() }
}
impl Drop for Server {
@ -607,7 +612,10 @@ impl StateExt for State {
.map(|inv| inv.push(item).is_none())
.unwrap_or(false);
if success {
self.write_component(entity, comp::InventoryUpdate);
self.write_component(
entity,
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Collected),
);
}
success
}

View File

@ -328,8 +328,11 @@ impl<'a> System<'a> for Sys {
// TODO: Sync clients that don't have a position?
// Sync inventories
for (client, inventory, _) in (&mut clients, &inventories, &inventory_updates).join() {
client.notify(ServerMsg::InventoryUpdate(inventory.clone()));
for (client, inventory, update) in (&mut clients, &inventories, &inventory_updates).join() {
client.notify(ServerMsg::InventoryUpdate(
inventory.clone(),
update.event(),
));
}
// Remove all force flags.

View File

@ -63,6 +63,7 @@ chrono = "0.4.9"
rust-argon2 = "0.5"
bincode = "1.2"
deunicode = "1.0"
uvth = "3.1.1"
[target.'cfg(target_os = "macos")'.dependencies]
dispatch = "0.1.4"
@ -74,6 +75,7 @@ winres = "0.1"
criterion = "0.3"
git2 = "0.10"
world = { package = "veloren-world", path = "../world" }
gfx_window_glutin = { version = "0.31.0", features = ["headless"] }
[[bench]]
name = "meshing_benchmark"

View File

@ -0,0 +1,58 @@
use common::{assets, comp};
use gfx_window_glutin::init_headless;
use vek::*;
use veloren_voxygen::{render, scene::simple as scene};
fn main() {
// Setup renderer
let dim = (200u16, 300u16, 1, gfx::texture::AaMode::Single);
let events_loop = glutin::EventsLoop::new();
let context = glutin::ContextBuilder::new()
.with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
.build_headless(&events_loop, (dim.0 as u32, dim.1 as u32).into())
.expect("Failed to build headless context");
let (_context, device, factory, color_view, depth_view) = init_headless(context, dim);
let mut renderer = render::Renderer::new(
device,
factory,
color_view,
depth_view,
render::AaMode::SsaaX4,
render::CloudMode::Regular,
render::FluidMode::Shiny,
)
.unwrap();
// Create character
let body = comp::humanoid::Body::random();
const STARTER_BOW: &str = "common.items.weapons.starter_bow";
let equipment = comp::Equipment {
main: assets::load_cloned(STARTER_BOW).ok(),
alt: None,
};
// Setup scene (using the character selection screen `Scene`)
let mut scene = scene::Scene::new(&mut renderer, None);
let scene_data = scene::SceneData {
time: 1.0,
delta_time: 1.0,
tick: 0,
body: Some(body.clone()),
gamma: 1.0,
};
scene.camera_mut().set_focus_pos(Vec3::unit_z() * 0.8);
scene.camera_mut().set_distance(1.5);
scene.camera_mut().update(0.0);
scene.maintain(&mut renderer, scene_data);
// Render
renderer.clear();
scene.render(&mut renderer, 0, Some(body), &equipment);
renderer.flush();
// Get image
let img = renderer.create_screenshot().unwrap();
img.save("character.png").unwrap();
}

View File

@ -47,7 +47,7 @@ impl BipedLargeSkeleton {
impl Skeleton for BipedLargeSkeleton {
type Attr = SkeletonAttr;
fn compute_matrices(&self) -> [FigureBoneData; 16] {
fn compute_matrices(&self) -> [FigureBoneData; 18] {
let upper_torso_mat = self.upper_torso.compute_base_matrix();
let shoulder_l_mat = self.shoulder_l.compute_base_matrix();
let shoulder_r_mat = self.shoulder_r.compute_base_matrix();
@ -78,6 +78,8 @@ impl Skeleton for BipedLargeSkeleton {
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
]
}

View File

@ -33,7 +33,7 @@ impl Animation for IdleAnimation {
* 0.25,
);
next.head.offset = Vec3::new(0.0, skeleton_attr.head.0, skeleton_attr.head.1) / 11.0;
next.head.offset = Vec3::new(0.0, skeleton_attr.head.0, skeleton_attr.head.1);
next.head.ori = Quaternion::rotation_z(duck_head_look.x)
* Quaternion::rotation_x(-duck_head_look.y.abs() + wave_slow_cos * 0.03);
next.head.scale = Vec3::one();
@ -46,7 +46,7 @@ impl Animation for IdleAnimation {
next.torso.ori = Quaternion::rotation_y(wave_slow * 0.03);
next.torso.scale = Vec3::one() / 11.0;
next.tail.offset = Vec3::new(0.0, skeleton_attr.tail.0, skeleton_attr.tail.1) / 11.0;
next.tail.offset = Vec3::new(0.0, skeleton_attr.tail.0, skeleton_attr.tail.1);
next.tail.ori = Quaternion::rotation_x(wave_slow_cos * 0.03);
next.tail.scale = Vec3::one();
@ -54,7 +54,7 @@ impl Animation for IdleAnimation {
-skeleton_attr.wing.0,
skeleton_attr.wing.1,
skeleton_attr.wing.2,
) / 11.0;
);
next.wing_l.ori = Quaternion::rotation_z(0.0);
next.wing_l.scale = Vec3::one() * 1.05;
@ -62,7 +62,7 @@ impl Animation for IdleAnimation {
skeleton_attr.wing.0,
skeleton_attr.wing.1,
skeleton_attr.wing.2,
) / 11.0;
);
next.wing_r.ori = Quaternion::rotation_y(0.0);
next.wing_r.scale = Vec3::one() * 1.05;

View File

@ -27,15 +27,15 @@ impl BirdMediumSkeleton {
impl Skeleton for BirdMediumSkeleton {
type Attr = SkeletonAttr;
fn compute_matrices(&self) -> [FigureBoneData; 16] {
fn compute_matrices(&self) -> [FigureBoneData; 18] {
let torso_mat = self.torso.compute_base_matrix();
[
FigureBoneData::new(self.head.compute_base_matrix() * torso_mat),
FigureBoneData::new(torso_mat * self.head.compute_base_matrix()),
FigureBoneData::new(torso_mat),
FigureBoneData::new(self.tail.compute_base_matrix() * torso_mat),
FigureBoneData::new(self.wing_l.compute_base_matrix() * torso_mat),
FigureBoneData::new(self.wing_r.compute_base_matrix() * torso_mat),
FigureBoneData::new(torso_mat * self.tail.compute_base_matrix()),
FigureBoneData::new(torso_mat * self.wing_l.compute_base_matrix()),
FigureBoneData::new(torso_mat * self.wing_r.compute_base_matrix()),
FigureBoneData::new(self.leg_l.compute_base_matrix()),
FigureBoneData::new(self.leg_r.compute_base_matrix()),
FigureBoneData::default(),
@ -47,6 +47,8 @@ impl Skeleton for BirdMediumSkeleton {
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
]
}

View File

@ -28,7 +28,7 @@ impl Animation for RunAnimation {
0.0,
skeleton_attr.head.0,
skeleton_attr.head.1 + center * 0.5,
) / 11.0;
);
next.head.ori = Quaternion::rotation_z(0.0) * Quaternion::rotation_x(0.0 + center * 0.03);
next.head.scale = Vec3::one();
@ -44,7 +44,7 @@ impl Animation for RunAnimation {
0.0,
skeleton_attr.tail.0,
skeleton_attr.tail.1 + centeroffset * 0.6,
) / 11.0;
);
next.tail.ori = Quaternion::rotation_x(center * 0.03);
next.tail.scale = Vec3::one();
@ -52,16 +52,16 @@ impl Animation for RunAnimation {
-skeleton_attr.wing.0,
skeleton_attr.wing.1,
skeleton_attr.wing.2,
) / 11.0;
next.wing_l.ori = Quaternion::rotation_y(footl * 0.3);
);
next.wing_l.ori = Quaternion::rotation_y(footl * 0.1);
next.wing_l.scale = Vec3::one() * 1.05;
next.wing_r.offset = Vec3::new(
skeleton_attr.wing.0,
skeleton_attr.wing.1,
skeleton_attr.wing.2,
) / 11.0;
next.wing_r.ori = Quaternion::rotation_y(footr * 0.3);
);
next.wing_r.ori = Quaternion::rotation_y(footr * 0.1);
next.wing_r.scale = Vec3::one() * 1.05;
next.leg_l.offset = Vec3::new(

View File

@ -31,7 +31,7 @@ impl BirdSmallSkeleton {
impl Skeleton for BirdSmallSkeleton {
type Attr = SkeletonAttr;
fn compute_matrices(&self) -> [FigureBoneData; 16] {
fn compute_matrices(&self) -> [FigureBoneData; 18] {
let torso_mat = self.torso.compute_base_matrix();
[
@ -51,6 +51,8 @@ impl Skeleton for BirdSmallSkeleton {
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
]
}

View File

@ -21,60 +21,65 @@ impl Animation for AttackAnimation {
) -> Self::Skeleton {
let mut next = (*skeleton).clone();
let slow = (anim_time as f32 * 9.0).sin();
let accel_med = 1.0 - (anim_time as f32 * 16.0).cos();
let accel_slow = 1.0 - (anim_time as f32 * 12.0).cos();
let accel_fast = 1.0 - (anim_time as f32 * 24.0).cos();
let decel = (anim_time as f32 * 16.0).min(PI / 2.0).sin();
let lab = 1.0;
let accel_med = 1.0 - (anim_time as f32 * 16.0 * lab as f32).cos();
let accel_slow = 1.0 - (anim_time as f32 * 12.0 * lab as f32).cos();
let accel_fast = 1.0 - (anim_time as f32 * 24.0 * lab as f32).cos();
let decel = (anim_time as f32 * 16.0 * lab as f32).min(PI / 2.0).sin();
let slow = (((5.0)
/ (1.1 + 3.9 * ((anim_time as f32 * lab as f32 * 12.4).sin()).powf(2.0 as f32)))
.sqrt())
* ((anim_time as f32 * lab as f32 * 12.4).sin());
next.head.offset = Vec3::new(
0.0 + skeleton_attr.neck_right,
-2.0 + skeleton_attr.neck_forward,
-2.0 + skeleton_attr.neck_forward + decel * 0.8,
skeleton_attr.neck_height + 21.0,
);
next.head.ori = Quaternion::rotation_z(decel * -0.25)
* Quaternion::rotation_x(0.0 + decel * -0.1)
* Quaternion::rotation_y(decel * 0.1);
next.head.ori = Quaternion::rotation_z(decel * 0.25)
* Quaternion::rotation_x(0.0 + decel * 0.1)
* Quaternion::rotation_y(decel * -0.1);
next.head.scale = Vec3::one() * skeleton_attr.head_scale;
next.chest.offset = Vec3::new(0.0, 0.0, 7.0);
next.chest.ori = Quaternion::rotation_x(0.0);
next.chest.ori = Quaternion::rotation_z(decel * -0.2)
* Quaternion::rotation_x(0.0 + decel * -0.2)
* Quaternion::rotation_y(decel * 0.2);
next.chest.scale = Vec3::one();
next.belt.offset = Vec3::new(0.0, 0.0, 5.0);
next.belt.ori = Quaternion::rotation_x(0.0);
next.belt.ori = Quaternion::rotation_z(decel * -0.1)
* Quaternion::rotation_x(0.0 + decel * -0.1)
* Quaternion::rotation_y(decel * 0.1);
next.belt.scale = Vec3::one();
next.shorts.offset = Vec3::new(0.0, 0.0, 2.0);
next.shorts.ori = Quaternion::rotation_x(0.0);
next.belt.ori = Quaternion::rotation_z(decel * -0.08)
* Quaternion::rotation_x(0.0 + decel * -0.08)
* Quaternion::rotation_y(decel * 0.08);
next.shorts.scale = Vec3::one();
match active_tool_kind {
//TODO: Inventory
Some(ToolKind::Sword(_)) => {
next.l_hand.offset =
Vec3::new(-8.0 + accel_slow * 10.0, 8.0 + accel_fast * 3.0, 0.0);
next.l_hand.ori = Quaternion::rotation_z(-0.8)
* Quaternion::rotation_x(0.0 + accel_med * -0.8)
* Quaternion::rotation_y(0.0 + accel_med * -0.4);
next.l_hand.scale = Vec3::one() * 1.01;
next.r_hand.offset =
Vec3::new(-8.0 + accel_slow * 10.0, 8.0 + accel_fast * 3.0, -2.0);
next.r_hand.ori = Quaternion::rotation_z(-0.8)
* Quaternion::rotation_x(0.0 + accel_med * -0.8)
* Quaternion::rotation_y(0.0 + accel_med * -0.4);
next.r_hand.scale = Vec3::one() * 1.01;
next.main.offset = Vec3::new(
-8.0 + accel_slow * 10.0 + skeleton_attr.weapon_x,
8.0 + accel_fast * 3.0,
0.0,
);
next.main.ori = Quaternion::rotation_z(-0.8)
* Quaternion::rotation_x(0.0 + accel_med * -0.8)
* Quaternion::rotation_y(0.0 + accel_med * -0.4);
Some(Tool::Sword(_)) => {
next.l_hand.offset = Vec3::new(0.0, 1.0, 0.0);
next.l_hand.ori = Quaternion::rotation_x(1.27);
next.l_hand.scale = Vec3::one() * 1.04;
next.r_hand.offset = Vec3::new(0.0, 0.0, -3.0);
next.r_hand.ori = Quaternion::rotation_x(1.27);
next.r_hand.scale = Vec3::one() * 1.05;
next.main.offset = Vec3::new(0.0, 6.0, -1.0);
next.main.ori = Quaternion::rotation_x(-0.3)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(0.0);
next.main.scale = Vec3::one();
next.control.offset = Vec3::new(-8.0 - slow * 1.0, 3.0 - slow * 5.0, 0.0);
next.control.ori = Quaternion::rotation_x(-1.2)
* Quaternion::rotation_y(slow * 1.5)
* Quaternion::rotation_z(1.4 + slow * 0.5);
next.control.scale = Vec3::one();
},
Some(ToolKind::Axe) => {
next.l_hand.offset =
@ -266,10 +271,17 @@ impl Animation for AttackAnimation {
next.lantern.scale = Vec3::one() * 0.0;
next.torso.offset = Vec3::new(0.0, -0.2, 0.1) * skeleton_attr.scaler;
next.torso.ori = Quaternion::rotation_z(decel * -0.2)
* Quaternion::rotation_x(0.0 + decel * -0.2)
* Quaternion::rotation_y(decel * 0.2);
next.torso.ori =
Quaternion::rotation_z(0.0) * Quaternion::rotation_x(0.0) * Quaternion::rotation_y(0.0);
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
next.l_control.offset = Vec3::new(0.0, 0.0, 0.0);
next.l_control.ori = Quaternion::rotation_x(0.0);
next.l_control.scale = Vec3::one();
next.r_control.offset = Vec3::new(0.0, 0.0, 0.0);
next.r_control.ori = Quaternion::rotation_x(0.0);
next.r_control.scale = Vec3::one();
next
}
}

View File

@ -62,22 +62,24 @@ impl Animation for BlockAnimation {
match active_tool_kind {
//TODO: Inventory
Some(ToolKind::Sword(_)) => {
next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0 + wave_ultra_slow * 1.0);
next.l_hand.ori = Quaternion::rotation_x(-0.3);
next.l_hand.scale = Vec3::one() * 1.01;
next.r_hand.offset = Vec3::new(-6.0, 3.0, -2.0);
next.r_hand.ori = Quaternion::rotation_x(-0.3);
next.r_hand.scale = Vec3::one() * 1.01;
next.main.offset = Vec3::new(
-6.0 + skeleton_attr.weapon_x,
4.5 + skeleton_attr.weapon_y,
0.0,
);
Some(Tool::Sword(_)) => {
next.l_hand.offset = Vec3::new(0.0, -5.0, -5.0);
next.l_hand.ori = Quaternion::rotation_x(1.27);
next.l_hand.scale = Vec3::one() * 1.04;
next.r_hand.offset = Vec3::new(0.0, -6.0, -8.0);
next.r_hand.ori = Quaternion::rotation_x(1.27);
next.r_hand.scale = Vec3::one() * 1.05;
next.main.offset = Vec3::new(0.0, 0.0, -6.0);
next.main.ori = Quaternion::rotation_x(-0.3)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(0.0);
next.main.scale = Vec3::one();
next.control.offset = Vec3::new(-8.0, 13.0, 8.0);
next.control.ori = Quaternion::rotation_x(0.2)
* Quaternion::rotation_y(0.4)
* Quaternion::rotation_z(-1.57);
next.control.scale = Vec3::one();
},
Some(ToolKind::Axe) => {
next.l_hand.offset = Vec3::new(

View File

@ -61,22 +61,24 @@ impl Animation for BlockIdleAnimation {
match active_tool_kind {
//TODO: Inventory
Some(ToolKind::Sword(_)) => {
next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0 + wave_ultra_slow * 1.0);
next.l_hand.ori = Quaternion::rotation_x(-0.3);
next.l_hand.scale = Vec3::one() * 1.01;
next.r_hand.offset = Vec3::new(-6.0, 3.0, -2.0);
next.r_hand.ori = Quaternion::rotation_x(-0.3);
next.r_hand.scale = Vec3::one() * 1.01;
next.main.offset = Vec3::new(
-6.0 + skeleton_attr.weapon_x,
4.5 + skeleton_attr.weapon_y,
0.0,
);
Some(Tool::Sword(_)) => {
next.l_hand.offset = Vec3::new(0.0, -5.0, -5.0);
next.l_hand.ori = Quaternion::rotation_x(1.27);
next.l_hand.scale = Vec3::one() * 1.04;
next.r_hand.offset = Vec3::new(0.0, -6.0, -8.0);
next.r_hand.ori = Quaternion::rotation_x(1.27);
next.r_hand.scale = Vec3::one() * 1.05;
next.main.offset = Vec3::new(0.0, 0.0, -6.0);
next.main.ori = Quaternion::rotation_x(-0.3)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(0.0);
next.main.scale = Vec3::one();
next.control.offset = Vec3::new(-8.0, 13.0, 8.0);
next.control.ori = Quaternion::rotation_x(0.2)
* Quaternion::rotation_y(0.4)
* Quaternion::rotation_z(-1.57);
next.control.scale = Vec3::one();
},
Some(ToolKind::Axe) => {
next.l_hand.offset = Vec3::new(

View File

@ -103,6 +103,11 @@ impl Animation for ChargeAnimation {
next.torso.ori =
Quaternion::rotation_z(0.0) * Quaternion::rotation_x(0.0) * Quaternion::rotation_y(0.0);
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
next.control.offset = Vec3::new(0.0, 0.0, 0.0);
next.control.ori = Quaternion::rotation_x(0.0);
next.control.scale = Vec3::one();
next
}
}

View File

@ -22,7 +22,7 @@ impl Animation for CidleAnimation {
) -> Self::Skeleton {
let mut next = (*skeleton).clone();
let wave_ultra_slow = (anim_time as f32 * 3.0 + PI).sin();
let wave_ultra_slow = (anim_time as f32 * 0.5 + PI).sin();
let wave_ultra_slow_cos = (anim_time as f32 * 3.0 + PI).cos();
let wave_slow_cos = (anim_time as f32 * 6.0 + PI).cos();
let wave_slow = (anim_time as f32 * 6.0 + PI).sin();
@ -62,30 +62,24 @@ impl Animation for CidleAnimation {
match active_tool_kind {
//TODO: Inventory
Some(ToolKind::Sword(_)) => {
next.l_hand.offset = Vec3::new(
-6.0 + wave_ultra_slow_cos * 1.0,
-2.0 + wave_ultra_slow_cos * 0.5,
1.0 + wave_ultra_slow * 1.0,
);
next.l_hand.ori = Quaternion::rotation_x(1.27);
next.l_hand.scale = Vec3::one() * 1.0;
next.r_hand.offset = Vec3::new(
-6.0 + wave_ultra_slow_cos * 1.0,
-2.5 + wave_ultra_slow_cos * 0.5,
-1.0 + wave_ultra_slow * 1.0,
);
next.r_hand.ori = Quaternion::rotation_x(1.27);
next.r_hand.scale = Vec3::one() * 1.01;
next.main.offset = Vec3::new(
-6.0 + skeleton_attr.weapon_x + wave_ultra_slow_cos * 1.0,
5.5 + skeleton_attr.weapon_y + wave_ultra_slow_cos * 0.5,
1.0 + wave_ultra_slow * 1.0,
);
next.main.ori = Quaternion::rotation_x(-0.3)
Some(Tool::Sword(_)) => {
next.l_hand.offset = Vec3::new(-0.25, -5.0, -5.0);
next.l_hand.ori = Quaternion::rotation_x(1.47) * Quaternion::rotation_y(-0.2);
next.l_hand.scale = Vec3::one() * 1.04;
next.r_hand.offset = Vec3::new(1.25, -5.5, -8.0);
next.r_hand.ori = Quaternion::rotation_x(1.47) * Quaternion::rotation_y(0.3);
next.r_hand.scale = Vec3::one() * 1.05;
next.main.offset = Vec3::new(0.0, 0.0, -6.0);
next.main.ori = Quaternion::rotation_x(-0.1)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(0.0);
next.main.scale = Vec3::one();
next.control.offset = Vec3::new(-7.0, 6.0, 6.0);
next.control.ori = Quaternion::rotation_x(0.0)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(0.0);
next.control.scale = Vec3::one();
},
Some(ToolKind::Axe) => {
next.l_hand.offset = Vec3::new(

View File

@ -59,11 +59,11 @@ impl Animation for ClimbAnimation {
* Quaternion::rotation_y(wave_test * 0.10);
next.shorts.scale = Vec3::one();
next.l_hand.offset = Vec3::new(-6.0, -0.25 + wave_testc * 1.5, 5.0 - wave_test * 4.0);
next.l_hand.offset = Vec3::new(-6.0, -0.25 + wave_testc * 1.5, 6.0 - wave_test * 4.0);
next.l_hand.ori = Quaternion::rotation_x(2.2 + wave_testc * 0.5);
next.l_hand.scale = Vec3::one();
next.r_hand.offset = Vec3::new(6.0, -0.25 - wave_testc * 1.5, 5.0 + wave_test * 4.0);
next.r_hand.offset = Vec3::new(6.0, -0.25 - wave_testc * 1.5, 6.0 + wave_test * 4.0);
next.r_hand.ori = Quaternion::rotation_x(2.2 - wave_testc * 0.5);
next.r_hand.scale = Vec3::one();
@ -75,15 +75,6 @@ impl Animation for ClimbAnimation {
next.r_foot.ori = Quaternion::rotation_x(0.2 + wave_testc * 0.5);
next.r_foot.scale = Vec3::one();
next.main.offset = Vec3::new(
-7.0 + skeleton_attr.weapon_x,
-5.0 + skeleton_attr.weapon_y,
15.0,
);
next.main.ori =
Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57 + wave_cos * 0.25);
next.main.scale = Vec3::one();
next.l_shoulder.offset = Vec3::new(-5.0, 0.0, 4.7);
next.l_shoulder.ori = Quaternion::rotation_x(wave_cos * 0.15);
next.l_shoulder.scale = Vec3::one() * 1.1;
@ -96,6 +87,23 @@ impl Animation for ClimbAnimation {
next.glider.ori = Quaternion::rotation_y(0.0);
next.glider.scale = Vec3::one() * 0.0;
next.main.offset = Vec3::new(
-7.0 + skeleton_attr.weapon_x,
-5.0 + skeleton_attr.weapon_y,
18.0,
);
next.main.ori =
Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57 + wave_cos * 0.25);
next.main.scale = Vec3::one();
next.second.offset = Vec3::new(
0.0 + skeleton_attr.weapon_x,
0.0 + skeleton_attr.weapon_y,
0.0,
);
next.second.ori = Quaternion::rotation_y(0.0);
next.second.scale = Vec3::one() * 0.0;
next.lantern.offset = Vec3::new(0.0, 0.0, 0.0);
next.lantern.ori = Quaternion::rotation_x(0.0);
next.lantern.scale = Vec3::one() * 0.0;
@ -104,6 +112,17 @@ impl Animation for ClimbAnimation {
next.torso.ori = Quaternion::rotation_x(0.0) * Quaternion::rotation_y(0.0);
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
next.control.offset = Vec3::new(0.0, 0.0, 0.0);
next.control.ori = Quaternion::rotation_x(0.0);
next.control.scale = Vec3::one();
next.l_control.offset = Vec3::new(0.0, 0.0, 0.0);
next.l_control.ori = Quaternion::rotation_x(0.0);
next.l_control.scale = Vec3::one();
next.r_control.offset = Vec3::new(0.0, 0.0, 0.0);
next.r_control.ori = Quaternion::rotation_x(0.0);
next.r_control.scale = Vec3::one();
next
}
}

View File

@ -1,17 +1,13 @@
use super::{
super::{Animation, },
CharacterSkeleton,SkeletonAttr
};
use super::{super::Animation, CharacterSkeleton, SkeletonAttr};
use common::comp::item::ToolKind;
use std::f32::consts::PI;
use std::ops::Mul;
use std::{f32::consts::PI, ops::Mul};
use vek::*;
pub struct WieldAnimation;
impl Animation for WieldAnimation {
type Skeleton = CharacterSkeleton;
type Dependency = (f32, f64);
type Skeleton = CharacterSkeleton;
fn update_skeleton(
skeleton: &Self::Skeleton,
@ -43,23 +39,25 @@ impl Animation for WieldAnimation {
match Tool::Bow {
//TODO: Inventory
Tool::Sword(_) => {
next.l_hand.offset = Vec3::new(-6.0, 3.75, 0.25);
next.l_hand.ori = Quaternion::rotation_x(-0.3);
next.l_hand.scale = Vec3::one() * 1.01;
next.r_hand.offset = Vec3::new(-6.0, 3.0, -2.0);
next.r_hand.ori = Quaternion::rotation_x(-0.3);
next.r_hand.scale = Vec3::one() * 1.01;
next.weapon.offset = Vec3::new(
-6.0 + skeleton_attr.weapon_x,
4.0 + skeleton_attr.weapon_y,
0.0,
);
next.weapon.ori = Quaternion::rotation_x(-0.3)
Some(Tool::Sword(_)) => {
next.l_hand.offset = Vec3::new(0.0, -5.0, -5.0);
next.l_hand.ori = Quaternion::rotation_x(1.27);
next.l_hand.scale = Vec3::one() * 1.04;
next.r_hand.offset = Vec3::new(0.0, -6.0, -8.0);
next.r_hand.ori = Quaternion::rotation_x(1.27);
next.r_hand.scale = Vec3::one() * 1.05;
next.main.offset = Vec3::new(0.0, 0.0, -6.0);
next.main.ori = Quaternion::rotation_x(-0.3)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(0.0);
next.weapon.scale = Vec3::one();
}
next.main.scale = Vec3::one();
next.control.offset = Vec3::new(-8.0, 4.0, 6.0);
next.control.ori = Quaternion::rotation_x(0.0)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(0.0);
next.control.scale = Vec3::one();
},
Tool::Axe => {
next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0);
next.l_hand.ori = Quaternion::rotation_x(-0.3);
@ -76,7 +74,7 @@ impl Animation for WieldAnimation {
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(0.0);
next.weapon.scale = Vec3::one();
}
},
Tool::Hammer => {
next.l_hand.offset = Vec3::new(-7.0, 8.25, 3.0);
next.l_hand.ori = Quaternion::rotation_x(-0.3)
@ -97,7 +95,7 @@ impl Animation for WieldAnimation {
* Quaternion::rotation_y(-1.2)
* Quaternion::rotation_z(wave * -0.25);
next.weapon.scale = Vec3::one();
}
},
Tool::Staff => {
next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0);
next.l_hand.ori = Quaternion::rotation_x(-0.3);
@ -114,7 +112,7 @@ impl Animation for WieldAnimation {
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(0.0);
next.weapon.scale = Vec3::one();
}
},
Tool::SwordShield => {
next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0);
next.l_hand.ori = Quaternion::rotation_x(-0.3);
@ -131,7 +129,7 @@ impl Animation for WieldAnimation {
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(0.0);
next.weapon.scale = Vec3::one();
}
},
Tool::Bow => {
next.l_hand.offset = Vec3::new(-4.0, 5.0, 0.0);
next.l_hand.ori = Quaternion::rotation_x(0.0)
@ -152,7 +150,7 @@ impl Animation for WieldAnimation {
* Quaternion::rotation_y(-1.7)
* Quaternion::rotation_z(0.85 + 3.14);
next.weapon.scale = Vec3::one();
}
},
Tool::Daggers => {
next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0);
next.l_hand.ori = Quaternion::rotation_x(-0.3);
@ -169,7 +167,7 @@ impl Animation for WieldAnimation {
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(0.0);
next.weapon.scale = Vec3::one();
}
},
}
next

View File

@ -105,14 +105,6 @@ impl Animation for GlidingAnimation {
);
next.r_foot.scale = Vec3::one();
next.main.offset = Vec3::new(
-7.0 + skeleton_attr.weapon_x,
-5.0 + skeleton_attr.weapon_y,
15.0,
);
next.main.ori = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
next.main.scale = Vec3::one();
next.l_shoulder.offset = Vec3::new(-5.0, 0.0, 4.7);
next.l_shoulder.ori = Quaternion::rotation_x(0.0);
next.l_shoulder.scale = Vec3::one() * 1.1;
@ -126,6 +118,22 @@ impl Animation for GlidingAnimation {
Quaternion::rotation_x(1.0) * Quaternion::rotation_y(wave_very_slow_cos * 0.04);
next.glider.scale = Vec3::one();
next.main.offset = Vec3::new(
-7.0 + skeleton_attr.weapon_x,
-5.0 + skeleton_attr.weapon_y,
15.0,
);
next.main.ori = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
next.main.scale = Vec3::one();
next.second.offset = Vec3::new(
0.0 + skeleton_attr.weapon_x,
0.0 + skeleton_attr.weapon_y,
0.0,
);
next.second.ori = Quaternion::rotation_y(0.0);
next.second.scale = Vec3::one() * 0.0;
next.lantern.offset = Vec3::new(0.0, 0.0, 0.0);
next.lantern.ori = Quaternion::rotation_x(0.0);
next.lantern.scale = Vec3::one() * 0.0;
@ -135,6 +143,17 @@ impl Animation for GlidingAnimation {
* Quaternion::rotation_y(tilt * 16.0);
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
next.control.offset = Vec3::new(0.0, 0.0, 0.0);
next.control.ori = Quaternion::rotation_x(0.0);
next.control.scale = Vec3::one();
next.l_control.offset = Vec3::new(0.0, 0.0, 0.0);
next.l_control.ori = Quaternion::rotation_x(0.0);
next.l_control.scale = Vec3::one();
next.r_control.offset = Vec3::new(0.0, 0.0, 0.0);
next.r_control.ori = Quaternion::rotation_x(0.0);
next.r_control.scale = Vec3::one();
next
}
}

View File

@ -56,7 +56,7 @@ impl Animation for IdleAnimation {
next.shorts.scale = Vec3::one();
next.l_hand.offset = Vec3::new(
-6.0,
-7.0,
-0.25 + wave_ultra_slow_cos * 0.15,
5.0 + wave_ultra_slow * 0.5,
);
@ -65,7 +65,7 @@ impl Animation for IdleAnimation {
next.l_hand.scale = Vec3::one();
next.r_hand.offset = Vec3::new(
6.0,
7.0,
-0.25 + wave_ultra_slow_cos * 0.15,
5.0 + wave_ultra_slow * 0.5 + wave_ultra_slow_abs * -0.05,
);
@ -80,14 +80,6 @@ impl Animation for IdleAnimation {
next.r_foot.ori = Quaternion::identity();
next.r_foot.scale = Vec3::one();
next.main.offset = Vec3::new(
-7.0 + skeleton_attr.weapon_x,
-5.0 + skeleton_attr.weapon_y,
15.0,
);
next.main.ori = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
next.main.scale = Vec3::one() + wave_ultra_slow_abs * -0.05;
next.l_shoulder.offset = Vec3::new(-5.0, 0.0, 5.0);
next.l_shoulder.ori = Quaternion::rotation_x(0.0);
next.l_shoulder.scale = (Vec3::one() + wave_ultra_slow_abs * -0.05) * 1.15;
@ -100,6 +92,22 @@ impl Animation for IdleAnimation {
next.glider.ori = Quaternion::rotation_y(0.0);
next.glider.scale = Vec3::one() * 0.0;
next.main.offset = Vec3::new(
-7.0 + skeleton_attr.weapon_x,
-5.0 + skeleton_attr.weapon_y,
18.0,
);
next.main.ori = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
next.main.scale = Vec3::one() + wave_ultra_slow_abs * -0.05;
next.second.offset = Vec3::new(
0.0 + skeleton_attr.weapon_x,
0.0 + skeleton_attr.weapon_y,
0.0,
);
next.second.ori = Quaternion::rotation_y(0.0);
next.second.scale = Vec3::one() * 0.0;
next.lantern.offset = Vec3::new(0.0, 0.0, 0.0);
next.lantern.ori = Quaternion::rotation_x(0.0);
next.lantern.scale = Vec3::one() * 0.0;
@ -108,6 +116,17 @@ impl Animation for IdleAnimation {
next.torso.ori = Quaternion::rotation_x(0.0);
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
next.control.offset = Vec3::new(0.0, 0.0, 0.0);
next.control.ori = Quaternion::rotation_x(0.0);
next.control.scale = Vec3::one();
next.l_control.offset = Vec3::new(0.0, 0.0, 0.0);
next.l_control.ori = Quaternion::rotation_x(0.0);
next.l_control.scale = Vec3::one();
next.r_control.offset = Vec3::new(0.0, 0.0, 0.0);
next.r_control.ori = Quaternion::rotation_x(0.0);
next.r_control.scale = Vec3::one();
next
}
}

View File

@ -68,14 +68,6 @@ impl Animation for JumpAnimation {
next.r_foot.ori = Quaternion::rotation_x(wave_stop * 1.2 + wave_slow * 0.2);
next.r_foot.scale = Vec3::one();
next.main.offset = Vec3::new(
-7.0 + skeleton_attr.weapon_x,
-5.0 + skeleton_attr.weapon_y,
15.0,
);
next.main.ori = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
next.main.scale = Vec3::one();
next.l_shoulder.offset = Vec3::new(-5.0, 0.0, 4.7);
next.l_shoulder.ori = Quaternion::rotation_x(wave_stop_alt * 0.3);
next.l_shoulder.scale = Vec3::one() * 1.1;
@ -88,6 +80,22 @@ impl Animation for JumpAnimation {
next.glider.ori = Quaternion::rotation_y(0.0);
next.glider.scale = Vec3::one() * 0.0;
next.main.offset = Vec3::new(
-7.0 + skeleton_attr.weapon_x,
-5.0 + skeleton_attr.weapon_y,
15.0,
);
next.main.ori = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
next.main.scale = Vec3::one();
next.second.offset = Vec3::new(
0.0 + skeleton_attr.weapon_x,
0.0 + skeleton_attr.weapon_y,
0.0,
);
next.second.ori = Quaternion::rotation_y(0.0);
next.second.scale = Vec3::one() * 0.0;
next.lantern.offset = Vec3::new(0.0, 0.0, 0.0);
next.lantern.ori = Quaternion::rotation_x(0.0);
next.lantern.scale = Vec3::one() * 0.0;
@ -96,6 +104,17 @@ impl Animation for JumpAnimation {
next.torso.ori = Quaternion::rotation_x(-0.2);
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
next.control.offset = Vec3::new(0.0, 0.0, 0.0);
next.control.ori = Quaternion::rotation_x(0.0);
next.control.scale = Vec3::one();
next.l_control.offset = Vec3::new(0.0, 0.0, 0.0);
next.l_control.ori = Quaternion::rotation_x(0.0);
next.l_control.scale = Vec3::one();
next.r_control.offset = Vec3::new(0.0, 0.0, 0.0);
next.r_control.ori = Quaternion::rotation_x(0.0);
next.r_control.scale = Vec3::one();
next
}
}

View File

@ -37,12 +37,16 @@ pub struct CharacterSkeleton {
r_hand: Bone,
l_foot: Bone,
r_foot: Bone,
main: Bone,
l_shoulder: Bone,
r_shoulder: Bone,
glider: Bone,
main: Bone,
second: Bone,
lantern: Bone,
torso: Bone,
control: Bone,
l_control: Bone,
r_control: Bone,
}
impl CharacterSkeleton {
@ -52,11 +56,16 @@ impl CharacterSkeleton {
impl Skeleton for CharacterSkeleton {
type Attr = SkeletonAttr;
fn compute_matrices(&self) -> [FigureBoneData; 16] {
fn compute_matrices(&self) -> [FigureBoneData; 18] {
let chest_mat = self.chest.compute_base_matrix();
let torso_mat = self.torso.compute_base_matrix();
let l_hand_mat = self.l_hand.compute_base_matrix();
let r_hand_mat = self.r_hand.compute_base_matrix();
let control_mat = self.control.compute_base_matrix();
let l_control_mat = self.l_control.compute_base_matrix();
let r_control_mat = self.r_control.compute_base_matrix();
let main_mat = self.main.compute_base_matrix();
let second_mat = self.second.compute_base_matrix();
let head_mat = self.head.compute_base_matrix();
[
@ -64,18 +73,20 @@ impl Skeleton for CharacterSkeleton {
FigureBoneData::new(torso_mat * chest_mat),
FigureBoneData::new(torso_mat * self.belt.compute_base_matrix()),
FigureBoneData::new(torso_mat * self.shorts.compute_base_matrix()),
FigureBoneData::new(torso_mat * chest_mat * l_hand_mat),
FigureBoneData::new(torso_mat * chest_mat * self.r_hand.compute_base_matrix()),
FigureBoneData::new(torso_mat * chest_mat * control_mat * l_control_mat * l_hand_mat),
FigureBoneData::new(torso_mat * chest_mat * control_mat * r_control_mat * r_hand_mat),
FigureBoneData::new(torso_mat * self.l_foot.compute_base_matrix()),
FigureBoneData::new(torso_mat * self.r_foot.compute_base_matrix()),
FigureBoneData::new(torso_mat * chest_mat * main_mat),
FigureBoneData::new(torso_mat * chest_mat * self.l_shoulder.compute_base_matrix()),
FigureBoneData::new(torso_mat * chest_mat * self.r_shoulder.compute_base_matrix()),
FigureBoneData::new(torso_mat * self.glider.compute_base_matrix()),
FigureBoneData::new(torso_mat * chest_mat * control_mat * l_control_mat * main_mat),
FigureBoneData::new(torso_mat * chest_mat * control_mat * r_control_mat * second_mat),
FigureBoneData::new(torso_mat * chest_mat * self.lantern.compute_base_matrix()),
FigureBoneData::new(torso_mat),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::new(control_mat),
FigureBoneData::new(l_control_mat),
FigureBoneData::new(r_control_mat),
]
}
@ -88,12 +99,16 @@ impl Skeleton for CharacterSkeleton {
self.r_hand.interpolate(&target.r_hand, dt);
self.l_foot.interpolate(&target.l_foot, dt);
self.r_foot.interpolate(&target.r_foot, dt);
self.main.interpolate(&target.main, dt);
self.l_shoulder.interpolate(&target.l_shoulder, dt);
self.r_shoulder.interpolate(&target.r_shoulder, dt);
self.glider.interpolate(&target.glider, dt);
self.main.interpolate(&target.main, dt);
self.second.interpolate(&target.second, dt);
self.lantern.interpolate(&target.lantern, dt);
self.torso.interpolate(&target.torso, dt);
self.control.interpolate(&target.control, dt);
self.l_control.interpolate(&target.l_control, dt);
self.r_control.interpolate(&target.r_control, dt);
}
}

View File

@ -86,16 +86,6 @@ impl Animation for RollAnimation {
next.r_foot.ori = Quaternion::rotation_x(wave * -0.4);
next.r_foot.scale = Vec3::one();
next.main.offset = Vec3::new(
-7.0 + skeleton_attr.weapon_x,
-5.0 + skeleton_attr.weapon_y,
15.0,
);
next.main.ori = Quaternion::rotation_y(2.5)
* Quaternion::rotation_z(1.57)
* Quaternion::rotation_x(0.0);
next.main.scale = Vec3::one();
next.l_shoulder.offset = Vec3::new(-5.0, 0.0, 4.7);
next.l_shoulder.ori = Quaternion::rotation_x(0.0);
next.l_shoulder.scale = Vec3::one() * 1.1;
@ -108,6 +98,24 @@ impl Animation for RollAnimation {
next.glider.ori = Quaternion::rotation_y(0.0);
next.glider.scale = Vec3::one() * 0.0;
next.main.offset = Vec3::new(
-7.0 + skeleton_attr.weapon_x,
-5.0 + skeleton_attr.weapon_y,
15.0,
);
next.main.ori = Quaternion::rotation_y(2.5)
* Quaternion::rotation_z(1.57)
* Quaternion::rotation_x(0.0);
next.main.scale = Vec3::one();
next.second.offset = Vec3::new(
0.0 + skeleton_attr.weapon_x,
0.0 + skeleton_attr.weapon_y,
0.0,
);
next.second.ori = Quaternion::rotation_y(0.0);
next.second.scale = Vec3::one() * 0.0;
next.lantern.offset = Vec3::new(0.0, 0.0, 0.0);
next.lantern.ori = Quaternion::rotation_x(0.0);
next.lantern.scale = Vec3::one() * 0.0;
@ -116,6 +124,18 @@ impl Animation for RollAnimation {
Vec3::new(0.0, 0.0, 0.1 + wave_dub * 16.0) / 11.0 * skeleton_attr.scaler;
next.torso.ori = Quaternion::rotation_x(wave_slow * 6.5) * Quaternion::rotation_y(tilt);
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
next.control.offset = Vec3::new(0.0, 0.0, 0.0);
next.control.ori = Quaternion::rotation_x(0.0);
next.control.scale = Vec3::one();
next.l_control.offset = Vec3::new(0.0, 0.0, 0.0);
next.l_control.ori = Quaternion::rotation_x(0.0);
next.l_control.scale = Vec3::one();
next.r_control.offset = Vec3::new(0.0, 0.0, 0.0);
next.r_control.ori = Quaternion::rotation_x(0.0);
next.r_control.scale = Vec3::one();
next
}
}

View File

@ -21,29 +21,38 @@ impl Animation for RunAnimation {
let speed = Vec2::<f32>::from(velocity).magnitude();
*rate = speed;
let constant = 1.0;
let wave = (((5.0)
/ (1.1 + 3.9 * ((anim_time as f32 * constant as f32 * 4.2).sin()).powf(2.0 as f32)))
let lab = 1.0;
let long = (((5.0)
/ (1.5 + 3.5 * ((anim_time as f32 * lab as f32 * 0.66).sin()).powf(2.0 as f32)))
.sqrt())
* ((anim_time as f32 * constant as f32 * 1.2).sin());
let wave_cos = (((5.0)
/ (1.1 + 3.9 * ((anim_time as f32 * constant as f32 * 2.4).sin()).powf(2.0 as f32)))
.sqrt())
* ((anim_time as f32 * constant as f32 * 1.5).sin());
let wave_cos_dub = (((5.0)
/ (1.1 + 3.9 * ((anim_time as f32 * constant as f32 * 4.8).sin()).powf(2.0 as f32)))
.sqrt())
* ((anim_time as f32 * constant as f32 * 1.5).sin());
* ((anim_time as f32 * lab as f32 * 0.66).sin());
let short = (((5.0)
/ (1.5 + 3.5 * ((anim_time as f32 * lab as f32 * 1.32).sin()).powf(2.0 as f32)))
.sqrt())
* ((anim_time as f32 * lab as f32 * 1.32).sin());
let shortalt = (((5.0)
/ (1.5
+ 3.5
* ((anim_time as f32 * lab as f32 * 1.32 + PI / 2.0).sin()).powf(2.0 as f32)))
.sqrt())
* ((anim_time as f32 * lab as f32 * 1.32 + PI / 2.0).sin());
let foot = (((5.0)
/ (1.1 + 3.9 * ((anim_time as f32 * lab as f32 * 1.32).sin()).powf(2.0 as f32)))
.sqrt())
* ((anim_time as f32 * lab as f32 * 1.32).sin());
let wave_stop = (anim_time as f32 * 2.6).min(PI / 2.0 / 2.0).sin();
let wave_diff = (anim_time as f32 * 0.6).sin();
let wave_stop = (anim_time as f32 * 2.6).min(PI / 2.0).sin();
let head_look = Vec2::new(
((global_time + anim_time) as f32 / 4.0)
((global_time + anim_time) as f32 / 18.0)
.floor()
.mul(7331.0)
.sin()
* 0.2,
((global_time + anim_time) as f32 / 4.0)
((global_time + anim_time) as f32 / 18.0)
.floor()
.mul(1337.0)
.sin()
@ -67,81 +76,100 @@ impl Animation for RunAnimation {
next.head.offset = Vec3::new(
0.0,
-3.0 + skeleton_attr.neck_forward,
skeleton_attr.neck_height + 20.0 + wave_cos * 1.3,
skeleton_attr.neck_height + 20.0 + short * 1.3,
);
next.head.ori = Quaternion::rotation_z(head_look.x + wave * 0.1)
next.head.ori = Quaternion::rotation_z(head_look.x + long * 0.1)
* Quaternion::rotation_x(head_look.y + 0.35);
next.head.scale = Vec3::one() * skeleton_attr.head_scale;
next.chest.offset = Vec3::new(0.0, 0.0, 7.0 + wave_cos * 1.1);
next.chest.ori = Quaternion::rotation_z(wave * 0.2);
next.chest.offset = Vec3::new(0.0, 0.0, 7.0 + short * 1.1);
next.chest.ori = Quaternion::rotation_z(short * 0.2);
next.chest.scale = Vec3::one();
next.belt.offset = Vec3::new(0.0, 0.0, 5.0 + wave_cos * 1.1);
next.belt.ori = Quaternion::rotation_z(wave * 0.35);
next.belt.offset = Vec3::new(0.0, 0.0, 5.0 + short * 1.1);
next.belt.ori = Quaternion::rotation_z(short * 0.35);
next.belt.scale = Vec3::one();
next.shorts.offset = Vec3::new(0.0, 0.0, 2.0 + wave_cos * 1.1);
next.shorts.ori = Quaternion::rotation_z(wave * 0.6);
next.shorts.offset = Vec3::new(0.0, 0.0, 2.0 + short * 1.1);
next.shorts.ori = Quaternion::rotation_z(short * 0.6);
next.shorts.scale = Vec3::one();
next.l_hand.offset = Vec3::new(
-6.0 + wave_stop * -1.0,
-0.25 + wave_cos * 2.0,
5.0 - wave * 1.5,
-0.25 + short * 2.0,
5.0 + short * -1.5,
);
next.l_hand.ori =
Quaternion::rotation_x(0.8 + wave_cos * 1.2) * Quaternion::rotation_y(wave_stop * 0.1);
Quaternion::rotation_x(0.8 + short * 1.2) * Quaternion::rotation_y(wave_stop * 0.1);
next.l_hand.scale = Vec3::one();
next.r_hand.offset = Vec3::new(
6.0 + wave_stop * 1.0,
-0.25 - wave_cos * 2.0,
5.0 + wave * 1.5,
-0.25 + short * -2.0,
5.0 + short * 1.5,
);
next.r_hand.ori = Quaternion::rotation_x(0.8 + wave_cos * -1.2)
* Quaternion::rotation_y(wave_stop * -0.1);
next.r_hand.ori =
Quaternion::rotation_x(0.8 + short * -1.2) * Quaternion::rotation_y(wave_stop * -0.1);
next.r_hand.scale = Vec3::one();
next.l_foot.offset = Vec3::new(-3.4, 0.0 + wave_cos * 1.0, 6.0 - wave_cos_dub * 0.7);
next.l_foot.ori = Quaternion::rotation_x(-0.0 - wave_cos * 1.2);
next.l_foot.offset = Vec3::new(-3.4, foot * 1.0, 6.0);
next.l_foot.ori = Quaternion::rotation_x(foot * -1.2);
next.l_foot.scale = Vec3::one();
next.r_foot.offset = Vec3::new(3.4, 0.0 - wave_cos * 1.0, 6.0 - wave_cos_dub * 0.7);
next.r_foot.ori = Quaternion::rotation_x(-0.0 + wave_cos * 1.2);
next.r_foot.offset = Vec3::new(3.4, foot * -1.0, 6.0);
next.r_foot.ori = Quaternion::rotation_x(foot * 1.2);
next.r_foot.scale = Vec3::one();
next.main.offset = Vec3::new(
-7.0 + skeleton_attr.weapon_x,
-5.0 + skeleton_attr.weapon_y,
15.0,
);
next.main.ori =
Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57 + wave_cos * 0.25);
next.main.scale = Vec3::one();
next.l_shoulder.offset = Vec3::new(-5.0, 0.0, 4.7);
next.l_shoulder.ori = Quaternion::rotation_x(wave_cos * 0.15);
next.l_shoulder.offset = Vec3::new(-5.0, -1.0, 4.7);
next.l_shoulder.ori = Quaternion::rotation_x(short * 0.15);
next.l_shoulder.scale = Vec3::one() * 1.1;
next.r_shoulder.offset = Vec3::new(5.0, 0.0, 4.7);
next.r_shoulder.ori = Quaternion::rotation_x(wave * 0.15);
next.r_shoulder.offset = Vec3::new(5.0, -1.0, 4.7);
next.r_shoulder.ori = Quaternion::rotation_x(short * -0.15);
next.r_shoulder.scale = Vec3::one() * 1.1;
next.glider.offset = Vec3::new(0.0, 5.0, 0.0);
next.glider.ori = Quaternion::rotation_y(0.0);
next.glider.scale = Vec3::one() * 0.0;
next.main.offset = Vec3::new(
-7.0 + skeleton_attr.weapon_x,
-5.0 + skeleton_attr.weapon_y,
15.0,
);
next.main.ori = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57 + short * 0.25);
next.main.scale = Vec3::one();
next.second.offset = Vec3::new(
0.0 + skeleton_attr.weapon_x,
0.0 + skeleton_attr.weapon_y,
0.0,
);
next.second.ori = Quaternion::rotation_y(0.0);
next.second.scale = Vec3::one() * 0.0;
next.lantern.offset = Vec3::new(0.0, 5.0, 0.0);
next.lantern.ori = Quaternion::rotation_y(0.0);
next.lantern.scale = Vec3::one() * 0.0;
next.torso.offset = Vec3::new(0.0, -0.3 + wave * -0.08, 0.4) * skeleton_attr.scaler;
next.torso.offset = Vec3::new(0.0, -0.3 + shortalt * -0.065, 0.4) * skeleton_attr.scaler;
next.torso.ori =
Quaternion::rotation_x(wave_stop * speed * -0.06 + wave_diff * speed * -0.005)
Quaternion::rotation_x(wave_stop * speed * -0.05 + wave_stop * speed * -0.005)
* Quaternion::rotation_y(tilt);
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
next.control.offset = Vec3::new(0.0, 0.0, 0.0);
next.control.ori = Quaternion::rotation_x(0.0);
next.control.scale = Vec3::one();
next.l_control.offset = Vec3::new(0.0, 0.0, 0.0);
next.l_control.ori = Quaternion::rotation_x(0.0);
next.l_control.scale = Vec3::one();
next.r_control.offset = Vec3::new(0.0, 0.0, 0.0);
next.r_control.ori = Quaternion::rotation_x(0.0);
next.r_control.scale = Vec3::one();
next
}
}

View File

@ -95,14 +95,6 @@ impl Animation for SitAnimation {
);
next.r_foot.scale = Vec3::one();
next.main.offset = Vec3::new(
-7.0 + skeleton_attr.weapon_x,
-5.0 + skeleton_attr.weapon_y,
15.0,
);
next.main.ori = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
next.main.scale = Vec3::one() + wave_slow_abs * -0.05;
next.l_shoulder.offset = Vec3::new(-5.0, 0.0, 4.7);
next.l_shoulder.ori = Quaternion::rotation_x(0.0);
next.l_shoulder.scale = (Vec3::one() + wave_slow_abs * -0.05) * 1.15;
@ -115,6 +107,22 @@ impl Animation for SitAnimation {
next.glider.ori = Quaternion::rotation_y(0.0);
next.glider.scale = Vec3::one() * 0.0;
next.main.offset = Vec3::new(
-7.0 + skeleton_attr.weapon_x,
-5.0 + skeleton_attr.weapon_y,
15.0,
);
next.main.ori = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
next.main.scale = Vec3::one() + wave_slow_abs * -0.05;
next.second.offset = Vec3::new(
0.0 + skeleton_attr.weapon_x,
0.0 + skeleton_attr.weapon_y,
0.0,
);
next.second.ori = Quaternion::rotation_y(0.0);
next.second.scale = Vec3::one() * 0.0;
next.lantern.offset = Vec3::new(0.0, 0.0, 0.0);
next.lantern.ori = Quaternion::rotation_x(0.0);
next.lantern.scale = Vec3::one() * 0.0;
@ -122,6 +130,18 @@ impl Animation for SitAnimation {
next.torso.offset = Vec3::new(0.0, -0.2, wave_stop * -0.16) * skeleton_attr.scaler;
next.torso.ori = Quaternion::rotation_x(0.0);
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
next.control.offset = Vec3::new(0.0, 0.0, 0.0);
next.control.ori = Quaternion::rotation_x(0.0);
next.control.scale = Vec3::one();
next.l_control.offset = Vec3::new(0.0, 0.0, 0.0);
next.l_control.ori = Quaternion::rotation_x(0.0);
next.l_control.scale = Vec3::one();
next.r_control.offset = Vec3::new(0.0, 0.0, 0.0);
next.r_control.ori = Quaternion::rotation_x(0.0);
next.r_control.scale = Vec3::one();
next
}
}

View File

@ -1,6 +1,6 @@
use super::{super::Animation, CharacterSkeleton, SkeletonAttr};
use common::comp::item::ToolKind;
use std::{f32::consts::PI, ops::Mul};
use common::comp::item::Tool;
use std::ops::Mul;
use vek::*;
pub struct StandAnimation;
@ -18,9 +18,8 @@ impl Animation for StandAnimation {
) -> Self::Skeleton {
let mut next = (*skeleton).clone();
let wave_ultra_slow = (anim_time as f32 * 1.0 + PI).sin();
let wave_ultra_slow_cos = (anim_time as f32 * 1.0 + PI).cos();
let wave_ultra_slow_abs = ((anim_time as f32 * 0.5 + PI).sin()) + 1.0;
let slow = (anim_time as f32 * 1.0).sin();
let breathe = ((anim_time as f32 * 0.5).sin()).abs();
let head_look = Vec2::new(
((global_time + anim_time) as f32 / 12.0)
@ -37,40 +36,32 @@ impl Animation for StandAnimation {
next.head.offset = Vec3::new(
0.0 + skeleton_attr.neck_right,
-3.0 + skeleton_attr.neck_forward,
skeleton_attr.neck_height + 21.0 + wave_ultra_slow * 0.3,
skeleton_attr.neck_height + 21.0 + slow * 0.3,
);
next.head.ori =
Quaternion::rotation_z(head_look.x) * Quaternion::rotation_x(head_look.y.abs());
next.head.scale = Vec3::one() * skeleton_attr.head_scale;
next.chest.offset = Vec3::new(0.0, 0.0, 7.0 + wave_ultra_slow * 0.3);
next.chest.ori = Quaternion::rotation_x(0.0);
next.chest.scale = Vec3::one() * 1.01 + wave_ultra_slow_abs * 0.05;
next.chest.offset = Vec3::new(0.0, 0.0, 7.0 + slow * 0.3);
next.chest.ori = Quaternion::rotation_z(head_look.x * 0.6);
next.chest.scale = Vec3::one() * 1.01;
next.belt.offset = Vec3::new(0.0, 0.0, 5.0 + wave_ultra_slow * 0.3);
next.belt.ori = Quaternion::rotation_x(0.0);
next.belt.scale = Vec3::one() + wave_ultra_slow_abs * 0.05;
next.belt.offset = Vec3::new(0.0, 0.0, 5.0 + slow * 0.3);
next.belt.ori = Quaternion::rotation_z(head_look.x * 0.4);
next.belt.scale = Vec3::one() + breathe * 0.05;
next.shorts.offset = Vec3::new(0.0, 0.0, 2.0 + wave_ultra_slow * 0.3);
next.shorts.offset = Vec3::new(0.0, 0.0, 2.0 + slow * 0.3);
next.shorts.ori = Quaternion::rotation_x(0.0);
next.shorts.scale = Vec3::one();
next.l_hand.offset = Vec3::new(
-6.0,
-0.25 + wave_ultra_slow_cos * 0.15,
5.0 + wave_ultra_slow * 0.5,
);
next.l_hand.offset = Vec3::new(-7.0, -0.25 + slow * 0.15, 5.0 + slow * 0.5);
next.l_hand.ori = Quaternion::rotation_x(0.0 + wave_ultra_slow * -0.06);
next.l_hand.ori = Quaternion::rotation_x(0.0 + slow * -0.06);
next.l_hand.scale = Vec3::one();
next.r_hand.offset = Vec3::new(
6.0,
-0.25 + wave_ultra_slow_cos * 0.15,
5.0 + wave_ultra_slow * 0.5 + wave_ultra_slow_abs * -0.05,
);
next.r_hand.ori = Quaternion::rotation_x(0.0 + wave_ultra_slow * -0.06);
next.r_hand.scale = Vec3::one() + wave_ultra_slow_abs * -0.05;
next.r_hand.offset = Vec3::new(7.0, -0.25 + slow * 0.15, 5.0 + slow * 0.5);
next.r_hand.ori = Quaternion::rotation_x(0.0 + slow * -0.06);
next.r_hand.scale = Vec3::one();
next.l_foot.offset = Vec3::new(-3.4, -0.1, 8.0);
next.l_foot.ori = Quaternion::identity();
@ -80,26 +71,34 @@ impl Animation for StandAnimation {
next.r_foot.ori = Quaternion::identity();
next.r_foot.scale = Vec3::one();
next.main.offset = Vec3::new(
-7.0 + skeleton_attr.weapon_x,
-5.0 + skeleton_attr.weapon_y,
15.0,
);
next.main.ori = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
next.main.scale = Vec3::one() + wave_ultra_slow_abs * -0.05;
next.l_shoulder.offset = Vec3::new(-5.0, 0.0, 5.0);
next.l_shoulder.ori = Quaternion::rotation_x(0.0);
next.l_shoulder.scale = (Vec3::one() + wave_ultra_slow_abs * -0.05) * 1.15;
next.l_shoulder.scale = (Vec3::one() + breathe * -0.05) * 1.15;
next.r_shoulder.offset = Vec3::new(5.0, 0.0, 5.0);
next.r_shoulder.ori = Quaternion::rotation_x(0.0);
next.r_shoulder.scale = (Vec3::one() + wave_ultra_slow_abs * -0.05) * 1.15;
next.r_shoulder.scale = (Vec3::one() + breathe * -0.05) * 1.15;
next.glider.offset = Vec3::new(0.0, 5.0, 0.0);
next.glider.ori = Quaternion::rotation_y(0.0);
next.glider.scale = Vec3::one() * 0.0;
next.main.offset = Vec3::new(
-7.0 + skeleton_attr.weapon_x,
-5.0 + skeleton_attr.weapon_y,
18.0,
);
next.main.ori = Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57);
next.main.scale = Vec3::one();
next.second.offset = Vec3::new(
0.0 + skeleton_attr.weapon_x,
0.0 + skeleton_attr.weapon_y,
0.0,
);
next.second.ori = Quaternion::rotation_y(0.0);
next.second.scale = Vec3::one() * 0.0;
next.lantern.offset = Vec3::new(0.0, 0.0, 0.0);
next.lantern.ori = Quaternion::rotation_x(0.0);
next.lantern.scale = Vec3::one() * 0.0;
@ -108,6 +107,17 @@ impl Animation for StandAnimation {
next.torso.ori = Quaternion::rotation_x(0.0);
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
next.control.offset = Vec3::new(0.0, 0.0, 0.0);
next.control.ori = Quaternion::rotation_x(0.0);
next.control.scale = Vec3::one();
next.l_control.offset = Vec3::new(0.0, 0.0, 0.0);
next.l_control.ori = Quaternion::rotation_x(0.0);
next.l_control.scale = Vec3::one();
next.r_control.offset = Vec3::new(0.0, 0.0, 0.0);
next.r_control.ori = Quaternion::rotation_x(0.0);
next.r_control.scale = Vec3::one();
next
}
}

View File

@ -95,15 +95,6 @@ impl Animation for SwimAnimation {
next.r_foot.ori = Quaternion::rotation_x(-0.0 + wave_cos * 1.5);
next.r_foot.scale = Vec3::one();
next.main.offset = Vec3::new(
-7.0 + skeleton_attr.weapon_x,
-5.0 + skeleton_attr.weapon_y,
15.0,
);
next.main.ori =
Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57 + wave_cos * 0.25);
next.main.scale = Vec3::one();
next.l_shoulder.offset = Vec3::new(-5.0, 0.0, 4.7);
next.l_shoulder.ori = Quaternion::rotation_x(wave_cos * 0.15);
next.l_shoulder.scale = Vec3::one() * 1.1;
@ -116,6 +107,23 @@ impl Animation for SwimAnimation {
next.glider.ori = Quaternion::rotation_y(0.0);
next.glider.scale = Vec3::one() * 0.0;
next.main.offset = Vec3::new(
-7.0 + skeleton_attr.weapon_x,
-5.0 + skeleton_attr.weapon_y,
18.0,
);
next.main.ori =
Quaternion::rotation_y(2.5) * Quaternion::rotation_z(1.57 + wave_cos * 0.25);
next.main.scale = Vec3::one();
next.second.offset = Vec3::new(
0.0 + skeleton_attr.weapon_x,
0.0 + skeleton_attr.weapon_y,
0.0,
);
next.second.ori = Quaternion::rotation_y(0.0);
next.second.scale = Vec3::one() * 0.0;
next.lantern.offset = Vec3::new(0.0, 5.0, 0.0);
next.lantern.ori = Quaternion::rotation_y(0.0);
next.lantern.scale = Vec3::one() * 0.0;
@ -126,6 +134,17 @@ impl Animation for SwimAnimation {
* Quaternion::rotation_y(0.0);
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
next.control.offset = Vec3::new(0.0, 0.0, 0.0);
next.control.ori = Quaternion::rotation_x(0.0);
next.control.scale = Vec3::one();
next.l_control.offset = Vec3::new(0.0, 0.0, 0.0);
next.l_control.ori = Quaternion::rotation_x(0.0);
next.l_control.scale = Vec3::one();
next.r_control.offset = Vec3::new(0.0, 0.0, 0.0);
next.r_control.ori = Quaternion::rotation_x(0.0);
next.r_control.scale = Vec3::one();
next
}
}

View File

@ -29,22 +29,24 @@ impl Animation for WieldAnimation {
let wave_stop = (anim_time as f32 * 2.6).min(PI / 2.0).sin();
match active_tool_kind {
//TODO: Inventory
Some(ToolKind::Sword(_)) => {
next.l_hand.offset = Vec3::new(-6.0, -2.0, 1.0);
Some(Tool::Sword(_)) => {
next.l_hand.offset = Vec3::new(0.0, -5.0, -5.0);
next.l_hand.ori = Quaternion::rotation_x(1.27);
next.l_hand.scale = Vec3::one() * 1.00;
next.r_hand.offset = Vec3::new(-6.0, -2.5, -1.0);
next.l_hand.scale = Vec3::one() * 1.04;
next.r_hand.offset = Vec3::new(0.0, -6.0, -8.0);
next.r_hand.ori = Quaternion::rotation_x(1.27);
next.r_hand.scale = Vec3::one() * 1.01;
next.main.offset = Vec3::new(
-6.0 + skeleton_attr.weapon_x,
5.5 + skeleton_attr.weapon_y,
1.0,
);
next.r_hand.scale = Vec3::one() * 1.05;
next.main.offset = Vec3::new(0.0, 0.0, -6.0);
next.main.ori = Quaternion::rotation_x(-0.3)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(0.0);
next.main.scale = Vec3::one();
next.control.offset = Vec3::new(-8.0, 4.0, 6.0);
next.control.ori = Quaternion::rotation_x(0.0)
* Quaternion::rotation_y(0.0)
* Quaternion::rotation_z(0.0);
next.control.scale = Vec3::one();
},
Some(ToolKind::Axe) => {
next.l_hand.offset = Vec3::new(-6.5, -0.5, 6.0);
@ -200,6 +202,14 @@ impl Animation for WieldAnimation {
next.torso.offset = Vec3::new(0.0, 0.3 + wave * -0.08, 0.4) * skeleton_attr.scaler;
next.torso.ori = Quaternion::rotation_x(wave_stop * -0.2);
next.torso.scale = Vec3::one() / 11.0 * skeleton_attr.scaler;
next.l_control.offset = Vec3::new(0.0, 0.0, 0.0);
next.l_control.ori = Quaternion::rotation_x(0.0);
next.l_control.scale = Vec3::one();
next.r_control.offset = Vec3::new(0.0, 0.0, 0.0);
next.r_control.ori = Quaternion::rotation_x(0.0);
next.r_control.scale = Vec3::one();
next
}
}

View File

@ -32,7 +32,7 @@ impl CritterSkeleton {
impl Skeleton for CritterSkeleton {
type Attr = CritterAttr;
fn compute_matrices(&self) -> [FigureBoneData; 16] {
fn compute_matrices(&self) -> [FigureBoneData; 18] {
[
FigureBoneData::new(self.head.compute_base_matrix()),
FigureBoneData::new(self.chest.compute_base_matrix()),
@ -50,6 +50,8 @@ impl Skeleton for CritterSkeleton {
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
]
}

View File

@ -49,7 +49,7 @@ impl DragonSkeleton {
impl Skeleton for DragonSkeleton {
type Attr = SkeletonAttr;
fn compute_matrices(&self) -> [FigureBoneData; 16] {
fn compute_matrices(&self) -> [FigureBoneData; 18] {
let chest_front_mat = self.chest_front.compute_base_matrix();
let wing_in_l_mat = self.wing_in_l.compute_base_matrix();
let wing_in_r_mat = self.wing_in_r.compute_base_matrix();
@ -72,6 +72,8 @@ impl Skeleton for DragonSkeleton {
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
]
}

View File

@ -35,7 +35,7 @@ impl FishMediumSkeleton {
impl Skeleton for FishMediumSkeleton {
type Attr = SkeletonAttr;
fn compute_matrices(&self) -> [FigureBoneData; 16] {
fn compute_matrices(&self) -> [FigureBoneData; 18] {
let torso_mat = self.torso.compute_base_matrix();
let rear_mat = self.rear.compute_base_matrix();
@ -56,6 +56,8 @@ impl Skeleton for FishMediumSkeleton {
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
]
}

View File

@ -27,7 +27,7 @@ impl FishSmallSkeleton {
impl Skeleton for FishSmallSkeleton {
type Attr = SkeletonAttr;
fn compute_matrices(&self) -> [FigureBoneData; 16] {
fn compute_matrices(&self) -> [FigureBoneData; 18] {
let torso_mat = self.torso.compute_base_matrix();
[
@ -47,6 +47,8 @@ impl Skeleton for FishSmallSkeleton {
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
]
}

View File

@ -13,7 +13,7 @@ impl FixtureSkeleton {
impl Skeleton for FixtureSkeleton {
type Attr = SkeletonAttr;
fn compute_matrices(&self) -> [FigureBoneData; 16] {
fn compute_matrices(&self) -> [FigureBoneData; 18] {
[
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
@ -31,6 +31,8 @@ impl Skeleton for FixtureSkeleton {
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
FigureBoneData::new(vek::Mat4::identity()),
]
}

View File

@ -52,7 +52,7 @@ impl Bone {
pub trait Skeleton: Send + Sync + 'static {
type Attr;
fn compute_matrices(&self) -> [FigureBoneData; 16];
fn compute_matrices(&self) -> [FigureBoneData; 18];
/// Change the current skeleton to be more like `target`.
fn interpolate(&mut self, target: &Self, dt: f32);

View File

@ -15,7 +15,7 @@ const SCALE: f32 = 1.0 / 11.0;
impl Skeleton for ObjectSkeleton {
type Attr = SkeletonAttr;
fn compute_matrices(&self) -> [FigureBoneData; 16] {
fn compute_matrices(&self) -> [FigureBoneData; 18] {
[
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
@ -33,6 +33,8 @@ impl Skeleton for ObjectSkeleton {
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
FigureBoneData::new(Mat4::scaling_3d(Vec3::broadcast(SCALE))),
]
}

View File

@ -31,7 +31,7 @@ impl QuadrupedMediumSkeleton {
impl Skeleton for QuadrupedMediumSkeleton {
type Attr = SkeletonAttr;
fn compute_matrices(&self) -> [FigureBoneData; 16] {
fn compute_matrices(&self) -> [FigureBoneData; 18] {
let ears_mat = self.ears.compute_base_matrix();
let head_upper_mat = self.head_upper.compute_base_matrix();
let head_lower_mat = self.head_lower.compute_base_matrix();
@ -53,6 +53,8 @@ impl Skeleton for QuadrupedMediumSkeleton {
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
]
}

View File

@ -17,11 +17,10 @@ impl Animation for IdleAnimation {
) -> Self::Skeleton {
let mut next = (*skeleton).clone();
let wave = (anim_time as f32 * 14.0).sin();
let wave_slow = (anim_time as f32 * 3.5 + PI).sin();
let wave_slow_cos = (anim_time as f32 * 3.5 + PI).cos();
let slow = (anim_time as f32 * 3.5).sin();
let slow_alt = (anim_time as f32 * 3.5 + PI).sin();
let pig_head_look = Vec2::new(
let head_look = Vec2::new(
((global_time + anim_time) as f32 / 8.0)
.floor()
.mul(7331.0)
@ -35,17 +34,17 @@ impl Animation for IdleAnimation {
);
next.head.offset =
Vec3::new(0.0, skeleton_attr.head.0, skeleton_attr.head.1 + wave * 0.2) / 11.0;
next.head.ori = Quaternion::rotation_z(pig_head_look.x)
* Quaternion::rotation_x(pig_head_look.y + wave_slow_cos * 0.03);
Vec3::new(0.0, skeleton_attr.head.0, skeleton_attr.head.1 + slow * 0.2) / 11.0;
next.head.ori = Quaternion::rotation_z(head_look.x)
* Quaternion::rotation_x(head_look.y + slow_alt * 0.03);
next.head.scale = Vec3::one() / 10.5;
next.chest.offset = Vec3::new(
wave_slow * 0.05,
slow * 0.05,
skeleton_attr.chest.0,
skeleton_attr.chest.1 + wave_slow_cos * 0.2,
skeleton_attr.chest.1 + slow_alt * 0.2,
) / 11.0;
next.chest.ori = Quaternion::rotation_y(wave_slow * 0.05);
next.chest.ori = Quaternion::rotation_y(slow * 0.05);
next.chest.scale = Vec3::one() / 11.0;
next.leg_lf.offset = Vec3::new(
@ -53,7 +52,7 @@ impl Animation for IdleAnimation {
skeleton_attr.feet_f.1,
skeleton_attr.feet_f.2,
) / 11.0;
next.leg_lf.ori = Quaternion::rotation_x(wave_slow * 0.08);
next.leg_lf.ori = Quaternion::rotation_x(slow * 0.08);
next.leg_lf.scale = Vec3::one() / 11.0;
next.leg_rf.offset = Vec3::new(
@ -61,7 +60,7 @@ impl Animation for IdleAnimation {
skeleton_attr.feet_f.1,
skeleton_attr.feet_f.2,
) / 11.0;
next.leg_rf.ori = Quaternion::rotation_x(wave_slow_cos * 0.08);
next.leg_rf.ori = Quaternion::rotation_x(slow_alt * 0.08);
next.leg_rf.scale = Vec3::one() / 11.0;
next.leg_lb.offset = Vec3::new(
@ -69,7 +68,7 @@ impl Animation for IdleAnimation {
skeleton_attr.feet_b.1,
skeleton_attr.feet_b.2,
) / 11.0;
next.leg_lb.ori = Quaternion::rotation_x(wave_slow_cos * 0.08);
next.leg_lb.ori = Quaternion::rotation_x(slow_alt * 0.08);
next.leg_lb.scale = Vec3::one() / 11.0;
next.leg_rb.offset = Vec3::new(
@ -77,7 +76,7 @@ impl Animation for IdleAnimation {
skeleton_attr.feet_b.1,
skeleton_attr.feet_b.2,
) / 11.0;
next.leg_rb.ori = Quaternion::rotation_x(wave_slow * 0.08);
next.leg_rb.ori = Quaternion::rotation_x(slow * 0.08);
next.leg_rb.scale = Vec3::one() / 11.0;
next

View File

@ -26,7 +26,7 @@ impl QuadrupedSmallSkeleton {
impl Skeleton for QuadrupedSmallSkeleton {
type Attr = SkeletonAttr;
fn compute_matrices(&self) -> [FigureBoneData; 16] {
fn compute_matrices(&self) -> [FigureBoneData; 18] {
[
FigureBoneData::new(self.head.compute_base_matrix()),
FigureBoneData::new(self.chest.compute_base_matrix()),
@ -44,6 +44,8 @@ impl Skeleton for QuadrupedSmallSkeleton {
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
FigureBoneData::default(),
]
}

View File

@ -1,4 +1,5 @@
use super::{super::Animation, QuadrupedSmallSkeleton, SkeletonAttr};
use std::f32::consts::PI;
use vek::*;
pub struct RunAnimation;
@ -16,55 +17,55 @@ impl Animation for RunAnimation {
) -> Self::Skeleton {
let mut next = (*skeleton).clone();
let wave = (anim_time as f32 * 14.0).sin();
let wave_quick = (anim_time as f32 * 20.0).sin();
let wave_quick_cos = (anim_time as f32 * 20.0).cos();
let wave_cos = (anim_time as f32 * 14.0).cos();
let slow = (anim_time as f32 * 14.0).sin();
let fast = (anim_time as f32 * 20.0).sin();
let fast_alt = (anim_time as f32 * 20.0 + PI / 2.0).sin();
let slow_alt = (anim_time as f32 * 14.0 + PI / 2.0).sin();
next.head.offset =
Vec3::new(0.0, skeleton_attr.head.0, skeleton_attr.head.1 + wave * 1.5) / 11.0;
Vec3::new(0.0, skeleton_attr.head.0, skeleton_attr.head.1 + slow * 1.5) / 11.0;
next.head.ori =
Quaternion::rotation_x(0.2 + wave * 0.05) * Quaternion::rotation_y(wave_cos * 0.03);
Quaternion::rotation_x(0.2 + slow * 0.05) * Quaternion::rotation_y(slow_alt * 0.03);
next.head.scale = Vec3::one() / 10.5;
next.chest.offset = Vec3::new(
0.0,
skeleton_attr.chest.0,
skeleton_attr.chest.1 + wave_cos * 1.2,
skeleton_attr.chest.1 + slow_alt * 1.2,
) / 11.0;
next.chest.ori = Quaternion::rotation_x(wave * 0.1);
next.chest.ori = Quaternion::rotation_x(slow * 0.1);
next.chest.scale = Vec3::one() / 11.0;
next.leg_lf.offset = Vec3::new(
-skeleton_attr.feet_f.0,
skeleton_attr.feet_f.1 + wave_quick * 0.8,
skeleton_attr.feet_f.2 + wave_quick_cos * 1.5,
skeleton_attr.feet_f.1 + fast * 0.8,
skeleton_attr.feet_f.2 + fast_alt * 1.5,
) / 11.0;
next.leg_lf.ori = Quaternion::rotation_x(wave_quick * 0.3);
next.leg_lf.ori = Quaternion::rotation_x(fast * 0.3);
next.leg_lf.scale = Vec3::one() / 11.0;
next.leg_rf.offset = Vec3::new(
skeleton_attr.feet_f.0,
skeleton_attr.feet_f.1 - wave_quick_cos * 0.8,
skeleton_attr.feet_f.2 + wave_quick * 1.5,
skeleton_attr.feet_f.1 + fast_alt * -0.8,
skeleton_attr.feet_f.2 + fast * 1.5,
) / 11.0;
next.leg_rf.ori = Quaternion::rotation_x(wave_quick_cos * -0.3);
next.leg_rf.ori = Quaternion::rotation_x(fast_alt * -0.3);
next.leg_rf.scale = Vec3::one() / 11.0;
next.leg_lb.offset = Vec3::new(
-skeleton_attr.feet_b.0,
skeleton_attr.feet_b.1 - wave_quick_cos * 0.8,
skeleton_attr.feet_b.2 + wave_quick * 1.5,
skeleton_attr.feet_b.1 + fast_alt * -0.8,
skeleton_attr.feet_b.2 + fast * 1.5,
) / 11.0;
next.leg_lb.ori = Quaternion::rotation_x(wave_quick_cos * -0.3);
next.leg_lb.ori = Quaternion::rotation_x(fast_alt * -0.3);
next.leg_lb.scale = Vec3::one() / 11.0;
next.leg_rb.offset = Vec3::new(
skeleton_attr.feet_b.0,
skeleton_attr.feet_b.1 + wave_quick * 0.8,
skeleton_attr.feet_b.2 + wave_quick_cos * 1.5,
skeleton_attr.feet_b.1 + fast * 0.8,
skeleton_attr.feet_b.2 + fast_alt * 1.5,
) / 11.0;
next.leg_rb.ori = Quaternion::rotation_x(wave_quick * 0.3);
next.leg_rb.ori = Quaternion::rotation_x(fast * 0.3);
next.leg_rb.scale = Vec3::one() / 11.0;
next

View File

@ -1,6 +1,5 @@
use crate::audio::AudioFrontend;
use client::Client;
use common::assets;
use common::{assets, state::State};
use rand::{seq::IteratorRandom, thread_rng};
use serde::Deserialize;
use std::time::Instant;
@ -44,18 +43,18 @@ impl MusicMgr {
}
}
pub fn maintain(&mut self, audio: &mut AudioFrontend, client: &Client) {
pub fn maintain(&mut self, audio: &mut AudioFrontend, state: &State) {
if audio.music_enabled()
&& self.began_playing.elapsed().as_secs_f64() > self.next_track_change
{
self.play_random_track(audio, client);
self.play_random_track(audio, state);
}
}
fn play_random_track(&mut self, audio: &mut AudioFrontend, client: &Client) {
fn play_random_track(&mut self, audio: &mut AudioFrontend, state: &State) {
const SILENCE_BETWEEN_TRACKS_SECONDS: f64 = 45.0;
let game_time = (client.state().get_time_of_day() as u64 % 86400) as u32;
let game_time = (state.get_time_of_day() as u64 % 86400) as u32;
let current_period_of_day = Self::get_current_day_period(game_time);
let mut rng = thread_rng();

View File

@ -1,11 +1,12 @@
pub mod movement;
pub mod progression;
mod movement;
mod progression;
use common::state::State;
use movement::MovementEventMapper;
use progression::ProgressionEventMapper;
use super::SfxTriggers;
use client::Client;
pub struct SfxEventMapper {
progression_event_mapper: ProgressionEventMapper,
@ -20,8 +21,15 @@ impl SfxEventMapper {
}
}
pub fn maintain(&mut self, client: &Client, triggers: &SfxTriggers) {
self.progression_event_mapper.maintain(client, triggers);
self.movement_event_mapper.maintain(client, triggers);
pub fn maintain(
&mut self,
state: &State,
player_entity: specs::Entity,
triggers: &SfxTriggers,
) {
self.progression_event_mapper
.maintain(state, player_entity, triggers);
self.movement_event_mapper
.maintain(state, player_entity, triggers);
}
}

View File

@ -3,10 +3,10 @@
/// from
use crate::audio::sfx::{SfxTriggerItem, SfxTriggers};
use client::Client;
use common::{
comp::{Body, CharacterState, Item, ItemKind, PhysicsState, Pos, Stats, ToolData, Vel},
event::{EventBus, SfxEvent, SfxEventItem},
state::State,
};
use hashbrown::HashMap;
use specs::{Entity as EcsEntity, Join, WorldExt};
@ -43,13 +43,13 @@ impl MovementEventMapper {
}
}
pub fn maintain(&mut self, client: &Client, triggers: &SfxTriggers) {
pub fn maintain(&mut self, state: &State, player_entity: EcsEntity, triggers: &SfxTriggers) {
const SFX_DIST_LIMIT_SQR: f32 = 20000.0;
let ecs = client.state().ecs();
let ecs = state.ecs();
let player_position = ecs
.read_storage::<Pos>()
.get(client.entity())
.get(player_entity)
.map_or(Vec3::zero(), |pos| pos.0);
for (entity, pos, vel, body, stats, physics, character) in (
@ -108,7 +108,7 @@ impl MovementEventMapper {
}
}
self.cleanup(client.entity());
self.cleanup(player_entity);
}
/// As the player explores the world, we track the last event of the nearby
@ -167,31 +167,42 @@ impl MovementEventMapper {
}) = stats.equipment.main
{
if let Some(wield_event) = match (
previous_state.weapon_drawn,
Self::weapon_drawn(character_state),
previous_event.weapon_drawn,
current_event.action.is_roll(),
Self::has_weapon_drawn(current_event.action),
) {
(false, true) => Some(SfxEvent::Wield(kind)),
(true, false) => Some(SfxEvent::Unwield(kind)),
(false, false, true) => Some(SfxEvent::Wield(kind)),
(true, false, false) => Some(SfxEvent::Unwield(kind)),
_ => None,
} {
return wield_event;
}
}
// Match the fall/land and jump states based on the on_ground status
// They may also have landed on the ground with the glider (!jump)
if let Some(jump_or_fall_event) = match (physics_state.on_ground, previous_state.on_ground)
{
(true, false) => {
if previous_state.event == SfxEvent::Glide {
Some(SfxEvent::GliderClose)
// Match all other Movemement and Action states
match (
current_event.movement,
current_event.action,
previous_event.event.clone(),
) {
(_, ActionState::Roll { .. }, _) => SfxEvent::Roll,
(MovementState::Climb, ..) => SfxEvent::Climb,
(MovementState::Swim, ..) => SfxEvent::Swim,
(MovementState::Run, ..) => {
// If the entitys's velocity is very low, they may be stuck, or walking into a
// solid object. We should not trigger the run SFX in this case,
// even if their move state indicates running. The 0.1 value is
// an approximation from playtesting scenarios where this can occur.
if vel.magnitude() > 0.1 {
SfxEvent::Run
} else {
Some(SfxEvent::Run)
}
},
(false, true) => Some(SfxEvent::Jump),
_ => None,
} {
}
{
return jump_or_fall_event;
}

View File

@ -2,10 +2,10 @@
/// and experience and emits associated SFX
use crate::audio::sfx::SfxTriggers;
use client::Client;
use common::{
comp::Stats,
event::{EventBus, SfxEvent, SfxEventItem},
state::State,
};
use specs::WorldExt;
@ -30,13 +30,18 @@ impl ProgressionEventMapper {
}
}
pub fn maintain(&mut self, client: &Client, triggers: &SfxTriggers) {
let ecs = client.state().ecs();
pub fn maintain(
&mut self,
state: &State,
player_entity: specs::Entity,
triggers: &SfxTriggers,
) {
let ecs = state.ecs();
// level and exp changes
let next_state =
ecs.read_storage::<Stats>()
.get(client.entity())
.get(player_entity)
.map_or(self.state.clone(), |stats| ProgressionState {
level: stats.level.level(),
exp: stats.exp.current(),

View File

@ -4,11 +4,11 @@
mod event_mapper;
use crate::audio::AudioFrontend;
use client::Client;
use common::{
assets,
comp::{Ori, Pos},
event::{EventBus, SfxEvent, SfxEventItem},
state::State,
};
use event_mapper::SfxEventMapper;
use hashbrown::HashMap;
@ -50,23 +50,29 @@ impl SfxMgr {
}
}
pub fn maintain(&mut self, audio: &mut AudioFrontend, client: &Client) {
pub fn maintain(
&mut self,
audio: &mut AudioFrontend,
state: &State,
player_entity: specs::Entity,
) {
if !audio.sfx_enabled() {
return;
}
self.event_mapper.maintain(client, &self.triggers);
self.event_mapper
.maintain(state, player_entity, &self.triggers);
let ecs = client.state().ecs();
let ecs = state.ecs();
let player_position = ecs
.read_storage::<Pos>()
.get(client.entity())
.get(player_entity)
.map_or(Vec3::zero(), |pos| pos.0);
let player_ori = ecs
.read_storage::<Ori>()
.get(client.entity())
.get(player_entity)
.map_or(Vec3::zero(), |pos| pos.0);
audio.set_listener_pos(&player_position, &player_ori);

View File

@ -258,6 +258,7 @@ impl<'a> Widget for Bag<'a> {
if let Some(to_drop) = state.selected_slot {
if ui.widget_input(ui.window).clicks().left().next().is_some() {
event = Some(Event::HudEvent(HudEvent::DropInventorySlot(to_drop)));
state.update(|s| s.selected_slot = None);
}
}

View File

@ -38,7 +38,7 @@ use crate::{
ecs::comp as vcomp,
i18n::{i18n_asset_key, LanguageMetadata, VoxygenLocalization},
render::{AaMode, CloudMode, Consts, FluidMode, Globals, Renderer},
scene::camera::Camera,
scene::camera::{self, Camera},
ui::{fonts::ConrodVoxygenFonts, Graphic, Ingameable, ScaleMode, Ui},
window::{Event as WinEvent, GameInput},
GlobalState,
@ -357,7 +357,7 @@ impl Show {
fn toggle_ui(&mut self) { self.ui = !self.ui; }
fn toggle_windows(&mut self) {
fn toggle_windows(&mut self, global_state: &mut GlobalState) {
if self.bag
|| self.esc_menu
|| self.map
@ -379,9 +379,19 @@ impl Show {
self.character_window = false;
self.open_windows = Windows::None;
self.want_grab = true;
// Unpause the game if we are on singleplayer
if let Some(singleplayer) = global_state.singleplayer.as_ref() {
singleplayer.pause(false);
};
} else {
self.esc_menu = true;
self.want_grab = false;
// Pause the game if we are on singleplayer
if let Some(singleplayer) = global_state.singleplayer.as_ref() {
singleplayer.pause(true);
};
}
}
@ -1725,7 +1735,14 @@ impl Hud {
settings_window::Event::ToggleHelp => self.show.help = !self.show.help,
settings_window::Event::ToggleDebug => self.show.debug = !self.show.debug,
settings_window::Event::ChangeTab(tab) => self.show.open_setting_tab(tab),
settings_window::Event::Close => self.show.settings(false),
settings_window::Event::Close => {
// Unpause the game if we are on singleplayer so that we can logout
if let Some(singleplayer) = global_state.singleplayer.as_ref() {
singleplayer.pause(false);
};
self.show.settings(false)
},
settings_window::Event::AdjustMousePan(sensitivity) => {
events.push(Event::AdjustMousePan(sensitivity));
},
@ -1917,12 +1934,29 @@ impl Hud {
self.show.esc_menu = false;
self.show.want_grab = false;
self.force_ungrab = true;
// Unpause the game if we are on singleplayer
if let Some(singleplayer) = global_state.singleplayer.as_ref() {
singleplayer.pause(false);
};
},
Some(esc_menu::Event::Logout) => {
// Unpause the game if we are on singleplayer so that we can logout
if let Some(singleplayer) = global_state.singleplayer.as_ref() {
singleplayer.pause(false);
};
events.push(Event::Logout);
},
Some(esc_menu::Event::Quit) => events.push(Event::Quit),
Some(esc_menu::Event::CharacterSelection) => events.push(Event::CharacterSelection),
Some(esc_menu::Event::CharacterSelection) => {
// Unpause the game if we are on singleplayer so that we can logout
if let Some(singleplayer) = global_state.singleplayer.as_ref() {
singleplayer.pause(false);
};
events.push(Event::CharacterSelection)
},
None => {},
}
}
@ -1992,7 +2026,7 @@ impl Hud {
self.ui.focus_widget(None);
} else {
// Close windows on esc
self.show.toggle_windows();
self.show.toggle_windows(global_state);
}
true
},
@ -2078,9 +2112,13 @@ impl Hud {
self.ui.focus_widget(maybe_id);
}
let events = self.update_layout(client, global_state, debug_info, dt);
let (v_mat, p_mat, _) = camera.compute_dependents(client);
self.ui
.maintain(&mut global_state.window.renderer_mut(), Some(p_mat * v_mat));
let camera::Dependents {
view_mat, proj_mat, ..
} = camera.dependents();
self.ui.maintain(
&mut global_state.window.renderer_mut(),
Some(proj_mat * view_mat),
);
// Check if item images need to be reloaded
self.item_imgs.reload_if_changed(&mut self.ui);

View File

@ -1,6 +1,82 @@
/// Used by benchmarks
pub mod mesh;
pub mod render;
#![deny(unsafe_code)]
#![feature(drain_filter)]
#![recursion_limit = "2048"]
// Used by tests
#[macro_use]
pub mod ui;
pub mod anim;
pub mod audio;
mod ecs;
pub mod error;
pub mod hud;
pub mod i18n;
pub mod key_state;
pub mod logging;
pub mod menu;
pub mod mesh;
pub mod meta;
pub mod render;
pub mod scene;
pub mod session;
pub mod settings;
#[cfg(feature = "singleplayer")]
pub mod singleplayer;
pub mod window;
// Reexports
pub use crate::error::Error;
use crate::{
audio::AudioFrontend, meta::Meta, settings::Settings, singleplayer::Singleplayer,
window::Window,
};
/// A type used to store state that is shared between all play states.
pub struct GlobalState {
pub settings: Settings,
pub meta: Meta,
pub window: Window,
pub audio: AudioFrontend,
pub info_message: Option<String>,
pub singleplayer: Option<Singleplayer>,
}
impl GlobalState {
/// Called after a change in play state has occurred (usually used to
/// reverse any temporary effects a state may have made).
pub fn on_play_state_changed(&mut self) {
self.window.grab_cursor(false);
self.window.needs_refresh_resize();
}
pub fn maintain(&mut self, dt: f32) { self.audio.maintain(dt); }
}
pub enum Direction {
Forwards,
Backwards,
}
/// States can either close (and revert to a previous state), push a new state
/// on top of themselves, or switch to a totally different state.
pub enum PlayStateResult {
/// Pop all play states in reverse order and shut down the program.
Shutdown,
/// Close the current play state and pop it from the play state stack.
Pop,
/// Push a new play state onto the play state stack.
Push(Box<dyn PlayState>),
/// Switch the current play state with a new play state.
Switch(Box<dyn PlayState>),
}
/// A trait representing a playable game state. This may be a menu, a game
/// session, the title screen, etc.
pub trait PlayState {
/// Play the state until some change of state is required (i.e: a menu is
/// opened or the game is closed).
fn play(&mut self, direction: Direction, global_state: &mut GlobalState) -> PlayStateResult;
/// Get a descriptive name for this state type.
fn name(&self) -> &'static str;
}

View File

@ -1,4 +1,5 @@
use fern::colors::{Color, ColoredLevelConfig};
use std::fs;
use crate::settings::Settings;
@ -39,12 +40,20 @@ pub fn init(
))
});
// Try to create the log file.
// Incase of it failing we simply print it out to the console.
let mut log_file_created = Ok(());
match fern::log_file(&format!("voxygen-{}.log", time.format("%Y-%m-%d-%H"))) {
Ok(log_file) => file_cfg = file_cfg.chain(log_file),
Err(e) => log_file_created = Err(e),
// Try to create the logs file parent directories.
let mut log_file_created = fs::create_dir_all(&settings.log.logs_path);
if log_file_created.is_ok() {
// Try to create the log file.
match fern::log_file(
settings
.log
.logs_path
.join(&format!("voxygen-{}.log", time.format("%Y-%m-%d-%H"))),
) {
Ok(log_file) => file_cfg = file_cfg.chain(log_file),
Err(e) => log_file_created = Err(e),
}
}
let stdout_cfg = fern::Dispatch::new()
@ -65,6 +74,7 @@ pub fn init(
.apply()
.expect("Failed to setup logging!");
// Incase that the log file creation failed simply print it to the console
if let Err(e) = log_file_created {
log::error!("Failed to create log file! {}", e);
}

View File

@ -1,92 +1,21 @@
#![deny(unsafe_code)]
#![feature(drain_filter)]
#![recursion_limit = "2048"]
#[macro_use]
pub mod ui;
pub mod anim;
pub mod audio;
mod ecs;
pub mod error;
pub mod hud;
pub mod i18n;
pub mod key_state;
mod logging;
pub mod menu;
pub mod mesh;
pub mod meta;
pub mod render;
pub mod scene;
pub mod session;
pub mod settings;
#[cfg(feature = "singleplayer")]
pub mod singleplayer;
pub mod window;
// Reexports
pub use crate::error::Error;
use crate::{
audio::AudioFrontend,
i18n::{i18n_asset_key, VoxygenLocalization},
use veloren_voxygen::{
audio::{self, AudioFrontend},
i18n::{self, i18n_asset_key, VoxygenLocalization},
logging,
menu::main::MainMenuState,
meta::Meta,
settings::Settings,
window::Window,
Direction, GlobalState, PlayState, PlayStateResult,
};
use common::assets::{load, load_expect};
use log::{debug, error};
use std::{mem, panic, str::FromStr};
/// A type used to store state that is shared between all play states.
pub struct GlobalState {
settings: Settings,
meta: Meta,
window: Window,
audio: AudioFrontend,
info_message: Option<String>,
}
impl GlobalState {
/// Called after a change in play state has occurred (usually used to
/// reverse any temporary effects a state may have made).
pub fn on_play_state_changed(&mut self) {
self.window.grab_cursor(false);
self.window.needs_refresh_resize();
}
pub fn maintain(&mut self, dt: f32) { self.audio.maintain(dt); }
}
pub enum Direction {
Forwards,
Backwards,
}
/// States can either close (and revert to a previous state), push a new state
/// on top of themselves, or switch to a totally different state.
pub enum PlayStateResult {
/// Pop all play states in reverse order and shut down the program.
Shutdown,
/// Close the current play state and pop it from the play state stack.
Pop,
/// Push a new play state onto the play state stack.
Push(Box<dyn PlayState>),
/// Switch the current play state with a new play state.
Switch(Box<dyn PlayState>),
}
/// A trait representing a playable game state. This may be a menu, a game
/// session, the title screen, etc.
pub trait PlayState {
/// Play the state until some change of state is required (i.e: a menu is
/// opened or the game is closed).
fn play(&mut self, direction: Direction, global_state: &mut GlobalState) -> PlayStateResult;
/// Get a descriptive name for this state type.
fn name(&self) -> &'static str;
}
fn main() {
// Initialize logging.
let term_log_level = std::env::var_os("VOXYGEN_LOG")
@ -135,6 +64,7 @@ fn main() {
settings,
meta,
info_message: None,
singleplayer: None,
};
// Try to load the localization and log missing entries

View File

@ -1,16 +1,16 @@
mod scene;
mod ui;
use crate::{
i18n::{i18n_asset_key, VoxygenLocalization},
scene::simple::{self as scene, Scene},
session::SessionState,
window::Event as WinEvent,
Direction, GlobalState, PlayState, PlayStateResult,
};
use client::{self, Client};
use common::{assets, clock::Clock, comp, msg::ClientState};
use common::{assets, clock::Clock, comp, msg::ClientState, state::DeltaTime};
use log::error;
use scene::Scene;
use specs::WorldExt;
use std::{cell::RefCell, rc::Rc, time::Duration};
use ui::CharSelectionUi;
@ -26,7 +26,10 @@ impl CharSelectionState {
Self {
char_selection_ui: CharSelectionUi::new(global_state),
client,
scene: Scene::new(global_state.window.renderer_mut()),
scene: Scene::new(
global_state.window.renderer_mut(),
Some("fixture.selection_bg"),
),
}
}
}
@ -95,17 +98,23 @@ impl PlayState for CharSelectionState {
});
// Maintain the scene.
self.scene.maintain(
global_state.window.renderer_mut(),
&self.client.borrow(),
humanoid_body.clone(),
global_state.settings.graphics.gamma,
);
{
let client = self.client.borrow();
let scene_data = scene::SceneData {
time: client.state().get_time(),
delta_time: client.state().ecs().read_resource::<DeltaTime>().0,
tick: client.get_tick(),
body: humanoid_body.clone(),
gamma: global_state.settings.graphics.gamma,
};
self.scene
.maintain(global_state.window.renderer_mut(), scene_data);
}
// Render the scene.
self.scene.render(
global_state.window.renderer_mut(),
&self.client.borrow(),
self.client.borrow().get_tick(),
humanoid_body.clone(),
&comp::Equipment {
main: self

View File

@ -18,7 +18,6 @@ use ui::{Event as MainMenuEvent, MainMenuUi};
pub struct MainMenuState {
main_menu_ui: MainMenuUi,
singleplayer: Option<Singleplayer>,
}
impl MainMenuState {
@ -26,7 +25,6 @@ impl MainMenuState {
pub fn new(global_state: &mut GlobalState) -> Self {
Self {
main_menu_ui: MainMenuUi::new(global_state),
singleplayer: None,
}
}
}
@ -47,7 +45,7 @@ impl PlayState for MainMenuState {
}
// Reset singleplayer server if it was running already
self.singleplayer = None;
global_state.singleplayer = None;
loop {
// Handle window events.
@ -119,7 +117,7 @@ impl PlayState for MainMenuState {
// client_init contains Some(ClientInit), which spawns a thread which
// contains a TcpStream::connect() call This call is
// blocking TODO fix when the network rework happens
self.singleplayer = None;
global_state.singleplayer = None;
client_init = None;
self.main_menu_ui.cancel_connection();
},
@ -127,7 +125,7 @@ impl PlayState for MainMenuState {
MainMenuEvent::StartSingleplayer => {
let (singleplayer, server_settings) = Singleplayer::new(None); // TODO: Make client and server use the same thread pool
self.singleplayer = Some(singleplayer);
global_state.singleplayer = Some(singleplayer);
attempt_login(
global_state,

View File

@ -1,4 +1,3 @@
use client::Client;
use common::vol::{ReadVol, Vox};
use std::f32::consts::PI;
use treeculler::Frustum;
@ -22,6 +21,13 @@ impl Default for CameraMode {
fn default() -> Self { Self::ThirdPerson }
}
#[derive(Clone)]
pub struct Dependents {
pub view_mat: Mat4<f32>,
pub proj_mat: Mat4<f32>,
pub cam_pos: Vec3<f32>,
}
pub struct Camera {
tgt_focus: Vec3<f32>,
focus: Vec3<f32>,
@ -33,6 +39,8 @@ pub struct Camera {
mode: CameraMode,
last_time: Option<f64>,
dependents: Dependents,
}
impl Camera {
@ -49,12 +57,18 @@ impl Camera {
mode,
last_time: None,
dependents: Dependents {
view_mat: Mat4::identity(),
proj_mat: Mat4::identity(),
cam_pos: Vec3::zero(),
},
}
}
/// Compute the transformation matrices (view matrix and projection matrix)
/// and position of the camera.
pub fn compute_dependents(&self, client: &Client) -> (Mat4<f32>, Mat4<f32>, Vec3<f32>) {
pub fn compute_dependents(&mut self, terrain: &impl ReadVol) {
let dist = {
let (start, end) = (
self.focus
@ -66,9 +80,7 @@ impl Camera {
self.focus,
);
match client
.state()
.terrain()
match terrain
.ray(start, end)
.ignore_error()
.max_iter(500)
@ -82,7 +94,7 @@ impl Camera {
.max(0.0)
};
let view_mat = Mat4::<f32>::identity()
self.dependents.view_mat = Mat4::<f32>::identity()
* Mat4::translation_3d(-Vec3::unit_z() * dist)
* Mat4::rotation_z(self.ori.z)
* Mat4::rotation_x(self.ori.y)
@ -90,20 +102,21 @@ impl Camera {
* Mat4::rotation_3d(PI / 2.0, -Vec4::unit_x())
* Mat4::translation_3d(-self.focus);
let proj_mat = Mat4::perspective_rh_no(self.fov, self.aspect, NEAR_PLANE, FAR_PLANE);
self.dependents.proj_mat =
Mat4::perspective_rh_no(self.fov, self.aspect, NEAR_PLANE, FAR_PLANE);
// TODO: Make this more efficient.
let cam_pos = Vec3::from(view_mat.inverted() * Vec4::unit_w());
(view_mat, proj_mat, cam_pos)
self.dependents.cam_pos = Vec3::from(self.dependents.view_mat.inverted() * Vec4::unit_w());
}
pub fn frustum(&self, client: &Client) -> Frustum<f32> {
let (view_mat, proj_mat, _) = self.compute_dependents(client);
Frustum::from_modelview_projection((proj_mat * view_mat).into_col_arrays())
pub fn frustum(&self) -> Frustum<f32> {
Frustum::from_modelview_projection(
(self.dependents.proj_mat * self.dependents.view_mat).into_col_arrays(),
)
}
pub fn dependents(&self) -> Dependents { self.dependents.clone() }
/// Rotate the camera about its focus by the given delta, limiting the input
/// accordingly.
pub fn rotate_by(&mut self, delta: Vec3<f32>) {

View File

@ -167,21 +167,6 @@ impl<Skel: Skeleton> FigureModelCache<Skel> {
},
CameraMode::FirstPerson => None,
},
if camera_mode != CameraMode::FirstPerson
|| character_state
.map(|cs| match cs {
CharacterState::BasicAttack { .. }
| CharacterState::BasicBlock { .. }
| CharacterState::Equipping { .. }
| CharacterState::Wielding { .. } => true,
_ => false,
})
.unwrap_or_default()
{
Some(mesh_main(equipment.and_then(|e| e.main.as_ref())))
} else {
None
},
match camera_mode {
CameraMode::ThirdPerson => Some(
humanoid_armor_shoulder_spec.mesh_left_shoulder(&body),
@ -195,6 +180,19 @@ impl<Skel: Skeleton> FigureModelCache<Skel> {
CameraMode::FirstPerson => None,
},
Some(mesh_glider()),
if camera_mode != CameraMode::FirstPerson
|| character_state
.map(|cs| {
cs.action.is_attack()
|| cs.action.is_block()
|| cs.action.is_wield()
})
.unwrap_or_default()
{
Some(mesh_main(equipment.and_then(|e| e.main.as_ref())))
} else {
None
},
Some(mesh_lantern()),
None,
None,

View File

@ -1,5 +1,5 @@
mod cache;
mod load;
pub mod load;
pub use cache::FigureModelCache;
pub use load::load_mesh; // TODO: Don't make this public.
@ -13,13 +13,16 @@ use crate::{
quadruped_small::QuadrupedSmallSkeleton, Animation, Skeleton,
},
render::{Consts, FigureBoneData, FigureLocals, Globals, Light, Renderer, Shadow},
scene::camera::{Camera, CameraMode},
scene::{
camera::{Camera, CameraMode},
SceneData,
},
};
use client::Client;
use common::{
comp::{
Body, CharacterState, ItemKind, Last, Ori, PhysicsState, Pos, Scale, Stats, ToolData, Vel,
},
state::State,
terrain::TerrainChunk,
vol::RectRasterableVol,
};
@ -95,17 +98,18 @@ impl FigureMgr {
self.biped_large_model_cache.clean(tick);
}
pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client, camera: &Camera) {
let time = client.state().get_time();
let tick = client.get_tick();
let ecs = client.state().ecs();
let view_distance = client.view_distance().unwrap_or(1);
let dt = client.state().get_delta_time();
let frustum = camera.frustum(client);
pub fn maintain(&mut self, renderer: &mut Renderer, scene_data: &SceneData, camera: &Camera) {
let state = scene_data.state;
let time = state.get_time();
let tick = scene_data.tick;
let ecs = state.ecs();
let view_distance = scene_data.view_distance;
let dt = state.get_delta_time();
let frustum = camera.frustum();
// Get player position.
let player_pos = ecs
.read_storage::<Pos>()
.get(client.entity())
.get(scene_data.player_entity)
.map_or(Vec3::zero(), |pos| pos.0);
for (entity, pos, vel, ori, scale, body, character, last_character, physics, stats) in (
@ -1252,7 +1256,7 @@ impl FigureMgr {
}
}
// Clear states that have dead entities.
// Clear states that have deleted entities.
self.character_states
.retain(|entity, _| ecs.entities().is_alive(*entity));
self.quadruped_small_states
@ -1280,19 +1284,18 @@ impl FigureMgr {
pub fn render(
&mut self,
renderer: &mut Renderer,
client: &mut Client,
state: &State,
player_entity: EcsEntity,
tick: u64,
globals: &Consts<Globals>,
lights: &Consts<Light>,
shadows: &Consts<Shadow>,
camera: &Camera,
) {
let tick = client.get_tick();
let ecs = client.state().ecs();
let ecs = state.ecs();
let character_state_storage = client
.state()
.read_storage::<common::comp::CharacterState>();
let character_state = character_state_storage.get(client.entity());
let character_state_storage = state.read_storage::<common::comp::CharacterState>();
let character_state = character_state_storage.get(player_entity);
for (entity, _, _, body, stats, _) in (
&ecs.entities(),
@ -1306,7 +1309,7 @@ impl FigureMgr {
// Don't render dead entities
.filter(|(_, _, _, _, stats, _)| stats.map_or(true, |s| !s.is_dead))
{
let is_player = entity == client.entity();
let is_player = entity == player_entity;
let player_camera_mode = if is_player {
camera.get_mode()
} else {

View File

@ -1,29 +1,29 @@
pub mod camera;
pub mod figure;
pub mod simple;
pub mod terrain;
use self::{
camera::{Camera, CameraMode},
figure::FigureMgr,
music::MusicMgr,
terrain::Terrain,
};
use crate::{
anim::character::SkeletonAttr,
audio::{music, sfx::SfxMgr, AudioFrontend},
audio::{music::MusicMgr, sfx::SfxMgr, AudioFrontend},
render::{
create_pp_mesh, create_skybox_mesh, Consts, Globals, Light, Model, PostProcessLocals,
PostProcessPipeline, Renderer, Shadow, SkyboxLocals, SkyboxPipeline,
},
window::Event,
};
use client::Client;
use common::{
comp,
state::State,
terrain::{BlockKind, TerrainChunk},
vol::ReadVol,
};
use specs::{Join, WorldExt};
use specs::{Entity as EcsEntity, Join, WorldExt};
use vek::*;
// TODO: Don't hard-code this.
@ -62,6 +62,15 @@ pub struct Scene {
music_mgr: MusicMgr,
}
pub struct SceneData<'a> {
pub state: &'a State,
pub player_entity: specs::Entity,
pub loaded_distance: f32,
pub view_distance: u32,
pub tick: u64,
pub thread_pool: &'a uvth::ThreadPool,
}
impl Scene {
/// Create a new `Scene` with default parameters.
pub fn new(renderer: &mut Renderer) -> Self {
@ -148,29 +157,29 @@ impl Scene {
&mut self,
renderer: &mut Renderer,
audio: &mut AudioFrontend,
client: &Client,
scene_data: &SceneData,
gamma: f32,
) {
// Get player position.
let player_pos = client
.state()
let player_pos = scene_data
.state
.ecs()
.read_storage::<comp::Pos>()
.get(client.entity())
.get(scene_data.player_entity)
.map_or(Vec3::zero(), |pos| pos.0);
let player_rolling = client
.state()
let player_rolling = scene_data
.state
.ecs()
.read_storage::<comp::CharacterState>()
.get(client.entity())
.map_or(false, |cs| cs.is_dodge());
.get(scene_data.player_entity)
.map_or(false, |cs| cs.action.is_roll());
let player_scale = match client
.state()
let player_scale = match scene_data
.state
.ecs()
.read_storage::<comp::Body>()
.get(client.entity())
.get(scene_data.player_entity)
{
Some(comp::Body::Humanoid(body)) => SkeletonAttr::calculate_scale(body),
_ => 1_f32,
@ -196,25 +205,30 @@ impl Scene {
);
// Tick camera for interpolation.
self.camera.update(client.state().get_time());
self.camera.update(scene_data.state.get_time());
// Compute camera matrices.
let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents(client);
self.camera.compute_dependents(&*scene_data.state.terrain());
let camera::Dependents {
view_mat,
proj_mat,
cam_pos,
} = self.camera.dependents();
// Update chunk loaded distance smoothly for nice shader fog
let loaded_distance = client.loaded_distance();
self.loaded_distance = (0.98 * self.loaded_distance + 0.02 * loaded_distance).max(0.01);
self.loaded_distance =
(0.98 * self.loaded_distance + 0.02 * scene_data.loaded_distance).max(0.01);
// Update light constants
let mut lights = (
&client.state().ecs().read_storage::<comp::Pos>(),
client.state().ecs().read_storage::<comp::Ori>().maybe(),
client
.state()
&scene_data.state.ecs().read_storage::<comp::Pos>(),
scene_data.state.ecs().read_storage::<comp::Ori>().maybe(),
scene_data
.state
.ecs()
.read_storage::<crate::ecs::comp::Interpolated>()
.maybe(),
&client.state().ecs().read_storage::<comp::LightEmitter>(),
&scene_data.state.ecs().read_storage::<comp::LightEmitter>(),
)
.join()
.filter(|(pos, _, _, _)| {
@ -247,15 +261,15 @@ impl Scene {
// Update shadow constants
let mut shadows = (
&client.state().ecs().read_storage::<comp::Pos>(),
client
.state()
&scene_data.state.ecs().read_storage::<comp::Pos>(),
scene_data
.state
.ecs()
.read_storage::<crate::ecs::comp::Interpolated>()
.maybe(),
client.state().ecs().read_storage::<comp::Scale>().maybe(),
&client.state().ecs().read_storage::<comp::Body>(),
&client.state().ecs().read_storage::<comp::Stats>(),
scene_data.state.ecs().read_storage::<comp::Scale>().maybe(),
&scene_data.state.ecs().read_storage::<comp::Body>(),
&scene_data.state.ecs().read_storage::<comp::Stats>(),
)
.join()
.filter(|(_, _, _, _, stats)| !stats.is_dead)
@ -285,13 +299,13 @@ impl Scene {
cam_pos,
self.camera.get_focus_pos(),
self.loaded_distance,
client.state().get_time_of_day(),
client.state().get_time(),
scene_data.state.get_time_of_day(),
scene_data.state.get_time(),
renderer.get_resolution(),
lights.len(),
shadows.len(),
client
.state()
scene_data
.state
.terrain()
.get(cam_pos.map(|e| e.floor() as i32))
.map(|b| b.kind())
@ -304,7 +318,7 @@ impl Scene {
// Maintain the terrain.
self.terrain.maintain(
renderer,
client,
&scene_data,
self.camera.get_focus_pos(),
self.loaded_distance,
view_mat,
@ -312,22 +326,31 @@ impl Scene {
);
// Maintain the figures.
self.figure_mgr.maintain(renderer, client, &self.camera);
self.figure_mgr.maintain(renderer, scene_data, &self.camera);
// Remove unused figures.
self.figure_mgr.clean(client.get_tick());
self.figure_mgr.clean(scene_data.tick);
// Maintain audio
self.sfx_mgr.maintain(audio, client);
self.music_mgr.maintain(audio, client);
self.sfx_mgr
.maintain(audio, scene_data.state, scene_data.player_entity);
self.music_mgr.maintain(audio, scene_data.state);
}
/// Render the scene using the provided `Renderer`.
pub fn render(&mut self, renderer: &mut Renderer, client: &mut Client) {
pub fn render(
&mut self,
renderer: &mut Renderer,
state: &State,
player_entity: EcsEntity,
tick: u64,
) {
// Render terrain and figures.
self.figure_mgr.render(
renderer,
client,
state,
player_entity,
tick,
&self.globals,
&self.lights,
&self.shadows,

View File

@ -9,21 +9,37 @@ use crate::{
PostProcessLocals, PostProcessPipeline, Renderer, Shadow, SkyboxLocals, SkyboxPipeline,
},
scene::{
camera::{Camera, CameraMode},
camera::{self, Camera, CameraMode},
figure::{load_mesh, FigureModelCache, FigureState},
},
window::{Event, PressState},
};
use client::Client;
use common::{
comp::{humanoid, Body, Equipment},
state::DeltaTime,
terrain::BlockKind,
vol::{BaseVol, ReadVol, Vox},
};
use log::error;
use specs::WorldExt;
use vek::*;
#[derive(PartialEq, Eq, Copy, Clone)]
struct VoidVox;
impl Vox for VoidVox {
fn empty() -> Self { VoidVox }
fn is_empty(&self) -> bool { true }
fn or(self, _other: Self) -> Self { VoidVox }
}
struct VoidVol;
impl BaseVol for VoidVol {
type Error = ();
type Vox = VoidVox;
}
impl ReadVol for VoidVol {
fn get<'a>(&'a self, _pos: Vec3<i32>) -> Result<&'a Self::Vox, Self::Error> { Ok(&VoidVox) }
}
struct Skybox {
model: Model<SkyboxPipeline>,
locals: Consts<SkyboxLocals>,
@ -42,8 +58,7 @@ pub struct Scene {
skybox: Skybox,
postprocess: PostProcess,
backdrop_model: Model<FigurePipeline>,
backdrop_state: FigureState<FixtureSkeleton>,
backdrop: Option<(Model<FigurePipeline>, FigureState<FixtureSkeleton>)>,
figure_model_cache: FigureModelCache,
figure_state: FigureState<CharacterSkeleton>,
@ -52,15 +67,28 @@ pub struct Scene {
char_ori: f32,
}
pub struct SceneData {
pub time: f64,
pub delta_time: f32,
pub tick: u64,
pub body: Option<humanoid::Body>,
pub gamma: f32,
}
impl Scene {
pub fn new(renderer: &mut Renderer) -> Self {
pub fn new(renderer: &mut Renderer, backdrop: Option<&str>) -> Self {
let resolution = renderer.get_resolution().map(|e| e as f32);
let mut camera = Camera::new(resolution.x / resolution.y, CameraMode::ThirdPerson);
camera.set_focus_pos(Vec3::unit_z() * 1.5);
camera.set_distance(3.0); // 4.2
camera.set_orientation(Vec3::new(0.0, 0.0, 0.0));
Self {
globals: renderer.create_consts(&[Globals::default()]).unwrap(),
lights: renderer.create_consts(&[Light::default(); 32]).unwrap(),
shadows: renderer.create_consts(&[Shadow::default(); 32]).unwrap(),
camera: Camera::new(resolution.x / resolution.y, CameraMode::ThirdPerson),
camera,
skybox: Skybox {
model: renderer.create_model(&create_skybox_mesh()).unwrap(),
@ -75,13 +103,14 @@ impl Scene {
figure_model_cache: FigureModelCache::new(),
figure_state: FigureState::new(renderer, CharacterSkeleton::new()),
backdrop_model: renderer
.create_model(&load_mesh(
"fixture.selection_bg",
Vec3::new(-55.0, -49.5, -2.0),
))
.unwrap(),
backdrop_state: FigureState::new(renderer, FixtureSkeleton::new()),
backdrop: backdrop.map(|specifier| {
(
renderer
.create_model(&load_mesh(specifier, Vec3::new(-55.0, -49.5, -2.0)))
.unwrap(),
FigureState::new(renderer, FixtureSkeleton::new()),
)
}),
turning: false,
char_ori: 0.0,
@ -90,6 +119,8 @@ impl Scene {
pub fn globals(&self) -> &Consts<Globals> { &self.globals }
pub fn camera_mut(&mut self) -> &mut Camera { &mut self.camera }
/// Handle an incoming user input event (e.g.: cursor moved, key pressed,
/// window closed).
///
@ -114,22 +145,17 @@ impl Scene {
}
}
pub fn maintain(
&mut self,
renderer: &mut Renderer,
client: &Client,
body: Option<humanoid::Body>,
gamma: f32,
) {
self.camera.set_focus_pos(Vec3::unit_z() * 1.5);
self.camera.update(client.state().get_time());
self.camera.set_distance(3.0); // 4.2
self.camera
.set_orientation(Vec3::new(client.state().get_time() as f32 * 0.0, 0.0, 0.0));
pub fn maintain(&mut self, renderer: &mut Renderer, scene_data: SceneData) {
self.camera.update(scene_data.time);
let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents(client);
const VD: f32 = 115.0; //View Distance
const TIME: f64 = 43200.0; // hours*3600 seconds
self.camera.compute_dependents(&VoidVol);
let camera::Dependents {
view_mat,
proj_mat,
cam_pos,
} = self.camera.dependents();
const VD: f32 = 115.0; // View Distance
const TIME: f64 = 43200.0; // 12 hours*3600 seconds
if let Err(err) = renderer.update_consts(&mut self.globals, &[Globals::new(
view_mat,
proj_mat,
@ -137,31 +163,30 @@ impl Scene {
self.camera.get_focus_pos(),
VD,
TIME,
client.state().get_time(),
scene_data.time,
renderer.get_resolution(),
0,
0,
BlockKind::Air,
None,
gamma,
scene_data.gamma,
)]) {
error!("Renderer failed to update: {:?}", err);
}
self.figure_model_cache.clean(client.get_tick());
self.figure_model_cache.clean(scene_data.tick);
if let Some(body) = body {
if let Some(body) = scene_data.body {
let tgt_skeleton = IdleAnimation::update_skeleton(
self.figure_state.skeleton_mut(),
client.state().get_time(),
client.state().get_time(),
scene_data.time,
scene_data.time,
&mut 0.0,
&SkeletonAttr::from(&body),
);
self.figure_state.skeleton_mut().interpolate(
&tgt_skeleton,
client.state().ecs().read_resource::<DeltaTime>().0,
);
self.figure_state
.skeleton_mut()
.interpolate(&tgt_skeleton, scene_data.delta_time);
}
self.figure_state.update(
@ -181,7 +206,7 @@ impl Scene {
pub fn render(
&mut self,
renderer: &mut Renderer,
client: &Client,
tick: u64,
body: Option<humanoid::Body>,
equipment: &Equipment,
) {
@ -194,7 +219,7 @@ impl Scene {
renderer,
Body::Humanoid(body),
Some(equipment),
client.get_tick(),
tick,
CameraMode::default(),
None,
)
@ -210,14 +235,16 @@ impl Scene {
);
}
renderer.render_figure(
&self.backdrop_model,
&self.globals,
self.backdrop_state.locals(),
self.backdrop_state.bone_consts(),
&self.lights,
&self.shadows,
);
if let Some((model, state)) = &self.backdrop {
renderer.render_figure(
model,
&self.globals,
state.locals(),
state.bone_consts(),
&self.lights,
&self.shadows,
);
}
renderer.render_post_process(
&self.postprocess.model,

View File

@ -6,7 +6,7 @@ use crate::{
},
};
use client::Client;
use super::SceneData;
use common::{
assets,
figure::Segment,
@ -1083,26 +1083,26 @@ impl<V: RectRasterableVol> Terrain<V> {
pub fn maintain(
&mut self,
renderer: &mut Renderer,
client: &Client,
scene_data: &SceneData,
focus_pos: Vec3<f32>,
loaded_distance: f32,
view_mat: Mat4<f32>,
proj_mat: Mat4<f32>,
) {
let current_tick = client.get_tick();
let current_time = client.state().get_time();
let current_tick = scene_data.tick;
let current_time = scene_data.state.get_time();
// Add any recently created or changed chunks to the list of chunks to be
// meshed.
for (modified, pos) in client
.state()
for (modified, pos) in scene_data
.state
.terrain_changes()
.modified_chunks
.iter()
.map(|c| (true, c))
.chain(
client
.state()
scene_data
.state
.terrain_changes()
.new_chunks
.iter()
@ -1121,8 +1121,8 @@ impl<V: RectRasterableVol> Terrain<V> {
let mut neighbours = true;
for i in -1..2 {
for j in -1..2 {
neighbours &= client
.state()
neighbours &= scene_data
.state
.terrain()
.get_key(pos + Vec2::new(i, j))
.is_some();
@ -1143,20 +1143,20 @@ impl<V: RectRasterableVol> Terrain<V> {
// Add the chunks belonging to recently changed blocks to the list of chunks to
// be meshed
for pos in client
.state()
for pos in scene_data
.state
.terrain_changes()
.modified_blocks
.iter()
.map(|(p, _)| *p)
{
let chunk_pos = client.state().terrain().pos_key(pos);
let chunk_pos = scene_data.state.terrain().pos_key(pos);
// Only mesh if this chunk has all its neighbors
let mut neighbours = true;
for i in -1..2 {
for j in -1..2 {
neighbours &= client
.state()
neighbours &= scene_data
.state
.terrain()
.get_key(chunk_pos + Vec2::new(i, j))
.is_some();
@ -1178,15 +1178,15 @@ impl<V: RectRasterableVol> Terrain<V> {
for x in -1..2 {
for y in -1..2 {
let neighbour_pos = pos + Vec3::new(x, y, 0);
let neighbour_chunk_pos = client.state().terrain().pos_key(neighbour_pos);
let neighbour_chunk_pos = scene_data.state.terrain().pos_key(neighbour_pos);
if neighbour_chunk_pos != chunk_pos {
// Only remesh if this chunk has all its neighbors
let mut neighbours = true;
for i in -1..2 {
for j in -1..2 {
neighbours &= client
.state()
neighbours &= scene_data
.state
.terrain()
.get_key(neighbour_chunk_pos + Vec2::new(i, j))
.is_some();
@ -1205,7 +1205,7 @@ impl<V: RectRasterableVol> Terrain<V> {
}
// Remove any models for chunks that have been recently removed.
for pos in &client.state().terrain_changes().removed_chunks {
for pos in &scene_data.state.terrain_changes().removed_chunks {
self.chunks.remove(pos);
self.mesh_todo.remove(pos);
}
@ -1220,7 +1220,7 @@ impl<V: RectRasterableVol> Terrain<V> {
})
.min_by_key(|todo| todo.active_worker.unwrap_or(todo.started_tick))
{
if client.thread_pool().queued_jobs() > 0 {
if scene_data.thread_pool.queued_jobs() > 0 {
break;
}
@ -1239,7 +1239,7 @@ impl<V: RectRasterableVol> Terrain<V> {
// Copy out the chunk data we need to perform the meshing. We do this by taking
// a sample of the terrain that includes both the chunk we want and
// its neighbours.
let volume = match client.state().terrain().sample(aabr) {
let volume = match scene_data.state.terrain().sample(aabr) {
Ok(sample) => sample,
// Either this chunk or its neighbours doesn't yet exist, so we keep it in the
// queue to be processed at a later date when we have its neighbours.
@ -1266,7 +1266,7 @@ impl<V: RectRasterableVol> Terrain<V> {
// Queue the worker thread.
let started_tick = todo.started_tick;
client.thread_pool().execute(move || {
scene_data.thread_pool.execute(move || {
let _ = send.send(mesh_worker(
pos,
(min_z as f32, max_z as f32),

View File

@ -4,7 +4,7 @@ use crate::{
i18n::{i18n_asset_key, VoxygenLocalization},
key_state::KeyState,
render::Renderer,
scene::Scene,
scene::{camera, Scene, SceneData},
window::{Event, GameInput},
Direction, Error, GlobalState, PlayState, PlayStateResult,
};
@ -108,7 +108,11 @@ impl SessionState {
renderer.clear();
// Render the screen using the global renderer
self.scene.render(renderer, &mut self.client.borrow_mut());
{
let client = self.client.borrow();
self.scene
.render(renderer, client.state(), client.entity(), client.get_tick());
}
// Draw the UI to the screen
self.hud.render(renderer, self.scene.globals());
@ -145,10 +149,12 @@ impl PlayState for SessionState {
let mut current_client_state = self.client.borrow().get_client_state();
while let ClientState::Pending | ClientState::Character = current_client_state {
// Compute camera data
let (view_mat, _, cam_pos) = self
.scene
.camera()
.compute_dependents(&self.client.borrow());
self.scene
.camera_mut()
.compute_dependents(&*self.client.borrow().state().terrain());
let camera::Dependents {
view_mat, cam_pos, ..
} = self.scene.camera().dependents();
let cam_dir: Vec3<f32> = Vec3::from(view_mat.inverted() * -Vec4::unit_z());
// Check to see whether we're aiming at anything
@ -368,18 +374,27 @@ impl PlayState for SessionState {
self.inputs.look_dir = cam_dir;
// Perform an in-game tick.
if let Err(err) = self.tick(clock.get_avg_delta()) {
global_state.info_message =
Some(localized_strings.get("common.connection_lost").to_owned());
error!("[session] Failed to tick the scene: {:?}", err);
// Runs if either in a multiplayer server or the singleplayer server is unpaused
if global_state.singleplayer.is_none()
|| !global_state.singleplayer.as_ref().unwrap().is_paused()
{
// Perform an in-game tick.
if let Err(err) = self.tick(clock.get_avg_delta()) {
global_state.info_message =
Some(localized_strings.get("common.connection_lost").to_owned());
error!("[session] Failed to tick the scene: {:?}", err);
return PlayStateResult::Pop;
return PlayStateResult::Pop;
}
}
// Maintain global state.
global_state.maintain(clock.get_last_delta().as_secs_f32());
// Recompute dependents just in case some input modified the camera
self.scene
.camera_mut()
.compute_dependents(&*self.client.borrow().state().terrain());
// Extract HUD events ensuring the client borrow gets dropped.
let mut hud_events = self.hud.maintain(
&self.client.borrow(),
@ -539,6 +554,9 @@ impl PlayState for SessionState {
global_state.settings.graphics.fov = new_fov;
global_state.settings.save_to_file_warn();
self.scene.camera_mut().set_fov_deg(new_fov);
self.scene
.camera_mut()
.compute_dependents(&*self.client.borrow().state().terrain());
},
HudEvent::ChangeGamma(new_gamma) => {
global_state.settings.graphics.gamma = new_gamma;
@ -598,13 +616,26 @@ impl PlayState for SessionState {
}
}
// Maintain the scene.
self.scene.maintain(
global_state.window.renderer_mut(),
&mut global_state.audio,
&self.client.borrow(),
global_state.settings.graphics.gamma,
);
// Runs if either in a multiplayer server or the singleplayer server is unpaused
if global_state.singleplayer.is_none()
|| !global_state.singleplayer.as_ref().unwrap().is_paused()
{
let client = self.client.borrow();
let scene_data = SceneData {
state: client.state(),
player_entity: client.entity(),
loaded_distance: client.loaded_distance(),
view_distance: client.view_distance().unwrap_or(1),
tick: client.get_tick(),
thread_pool: client.thread_pool(),
};
self.scene.maintain(
global_state.window.renderer_mut(),
&mut global_state.audio,
&scene_data,
global_state.settings.graphics.gamma,
);
}
// Render the session.
self.render(global_state.window.renderer_mut());

View File

@ -5,7 +5,7 @@ use crate::{
ui::ScaleMode,
window::KeyMouse,
};
use directories::ProjectDirs;
use directories::{ProjectDirs, UserDirs};
use glutin::{MouseButton, VirtualKeyCode};
use log::warn;
use serde_derive::{Deserialize, Serialize};
@ -177,10 +177,28 @@ pub struct Log {
// Whether to create a log file or not.
// Default is to create one.
pub log_to_file: bool,
// The path on which the logs will be stored
pub logs_path: PathBuf,
}
impl Default for Log {
fn default() -> Self { Self { log_to_file: true } }
fn default() -> Self {
let proj_dirs = ProjectDirs::from("net", "veloren", "voxygen")
.expect("System's $HOME directory path not found!");
// Chooses a path to store the logs by the following order:
// - The VOXYGEN_LOGS environment variable
// - The ProjectsDirs data local directory
// This only selects if there isn't already an entry in the settings file
let logs_path = std::env::var_os("VOXYGEN_LOGS")
.map(PathBuf::from)
.unwrap_or(proj_dirs.data_local_dir().join("logs"));
Self {
log_to_file: true,
logs_path,
}
}
}
/// `GraphicsSettings` contains settings related to framerate and in-game
@ -273,10 +291,26 @@ pub struct Settings {
// TODO: Remove at a later date, for dev testing
pub logon_commands: Vec<String>,
pub language: LanguageSettings,
pub screenshots_path: PathBuf,
}
impl Default for Settings {
fn default() -> Self {
let user_dirs = UserDirs::new().expect("System's $HOME directory path not found!");
// Chooses a path to store the screenshots by the following order:
// - The VOXYGEN_SCREENSHOT environment variable
// - The user's picture directory
// - The executable's directory
// This only selects if there isn't already an entry in the settings file
let screenshots_path = std::env::var_os("VOXYGEN_SCREENSHOT")
.map(PathBuf::from)
.or(user_dirs.picture_dir().map(|dir| dir.join("veloren")))
.or(std::env::current_exe()
.ok()
.and_then(|dir| dir.parent().map(|val| PathBuf::from(val))))
.expect("Couldn't choose a place to store the screenshots");
Settings {
controls: ControlSettings::default(),
gameplay: GameplaySettings::default(),
@ -288,6 +322,7 @@ impl Default for Settings {
send_logon_commands: false,
logon_commands: Vec::new(),
language: LanguageSettings::default(),
screenshots_path,
}
}
}

View File

@ -4,6 +4,10 @@ use crossbeam::channel::{unbounded, Receiver, Sender, TryRecvError};
use log::info;
use server::{Event, Input, Server, ServerSettings};
use std::{
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
thread::{self, JoinHandle},
time::Duration,
};
@ -19,6 +23,8 @@ enum Msg {
pub struct Singleplayer {
_server_thread: JoinHandle<()>,
sender: Sender<Msg>,
// Wether the server is stopped or not
paused: Arc<AtomicBool>,
}
impl Singleplayer {
@ -31,6 +37,9 @@ impl Singleplayer {
let thread_pool = client.map(|c| c.thread_pool().clone());
let settings2 = settings.clone();
let paused = Arc::new(AtomicBool::new(false));
let paused1 = paused.clone();
let thread = thread::spawn(move || {
let server = Server::new(settings2).expect("Failed to create server instance!");
@ -39,17 +48,25 @@ impl Singleplayer {
None => server,
};
run_server(server, receiver);
run_server(server, receiver, paused1);
});
(
Singleplayer {
_server_thread: thread,
sender,
paused,
},
settings,
)
}
/// Returns wether or not the server is paused
pub fn is_paused(&self) -> bool { self.paused.load(Ordering::SeqCst) }
/// Pauses if true is passed and unpauses if false (Does nothing if in that
/// state already)
pub fn pause(&self, state: bool) { self.paused.store(state, Ordering::SeqCst); }
}
impl Drop for Singleplayer {
@ -59,13 +76,34 @@ impl Drop for Singleplayer {
}
}
fn run_server(mut server: Server, rec: Receiver<Msg>) {
fn run_server(mut server: Server, rec: Receiver<Msg>, paused: Arc<AtomicBool>) {
info!("Starting server-cli...");
// Set up an fps clock
let mut clock = Clock::start();
loop {
// Check any event such as stopping and pausing
match rec.try_recv() {
Ok(msg) => match msg {
Msg::Stop => break,
},
Err(err) => match err {
TryRecvError::Empty => (),
TryRecvError::Disconnected => break,
},
}
// Wait for the next tick.
clock.tick(Duration::from_millis(1000 / TPS));
// Skip updating the server if it's paused
if paused.load(Ordering::SeqCst) && server.number_of_players() < 2 {
continue;
} else if server.number_of_players() > 1 {
paused.store(false, Ordering::SeqCst);
}
let events = server
.tick(Input::default(), clock.get_last_delta())
.expect("Failed to tick server!");
@ -80,16 +118,5 @@ fn run_server(mut server: Server, rec: Receiver<Msg>) {
// Clean up the server after a tick.
server.cleanup();
match rec.try_recv() {
Ok(_msg) => break,
Err(err) => match err {
TryRecvError::Empty => (),
TryRecvError::Disconnected => break,
},
}
// Wait for the next tick.
clock.tick(Duration::from_millis(1000 / TPS));
}
}

View File

@ -114,7 +114,12 @@ pub struct Rotations {
/// corresponding ImgIds and create a struct with all of them.
///
/// Example usage:
/// ```
/// ```ignore
/// use veloren_voxygen::{
/// image_ids,
/// ui::img_ids::{BlankGraphic, ImageGraphic, VoxelGraphic},
/// };
///
/// image_ids! {
/// pub struct Imgs {
/// <VoxelGraphic>

View File

@ -594,7 +594,7 @@ impl Window {
});
if take_screenshot {
self.take_screenshot();
self.take_screenshot(&settings);
}
if toggle_fullscreen {
@ -659,15 +659,16 @@ impl Window {
pub fn send_supplement_event(&mut self, event: Event) { self.supplement_events.push(event) }
pub fn take_screenshot(&mut self) {
pub fn take_screenshot(&mut self, settings: &Settings) {
match self.renderer.create_screenshot() {
Ok(img) => {
let mut path = settings.screenshots_path.clone();
std::thread::spawn(move || {
use std::{path::PathBuf, time::SystemTime};
use std::time::SystemTime;
// Check if folder exists and create it if it does not
let mut path = PathBuf::from("./screenshots");
if !path.exists() {
if let Err(err) = std::fs::create_dir(&path) {
if let Err(err) = std::fs::create_dir_all(&path) {
warn!("Couldn't create folder for screenshot: {:?}", err);
}
}