mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge master
This commit is contained in:
commit
096d3b691e
@ -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
28
.gitlab/CODEOWNERS
Normal 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
|
@ -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
1
Cargo.lock
generated
@ -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",
|
||||
|
@ -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
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
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
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
BIN
assets/voxygen/audio/sfx/inventory/consumable/liquid.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/frames/banner_top.png
(Stored with Git LFS)
BIN
assets/voxygen/element/frames/banner_top.png
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/misc_bg/textbox_bot.png
(Stored with Git LFS)
BIN
assets/voxygen/element/misc_bg/textbox_bot.png
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/misc_bg/textbox_mid.png
(Stored with Git LFS)
BIN
assets/voxygen/element/misc_bg/textbox_mid.png
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/misc_bg/textbox_top.png
(Stored with Git LFS)
BIN
assets/voxygen/element/misc_bg/textbox_top.png
(Stored with Git LFS)
Binary file not shown.
61
assets/voxygen/net.veloren.veloren.appdata.xml
Normal file
61
assets/voxygen/net.veloren.veloren.appdata.xml
Normal 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>
|
9
assets/voxygen/net.veloren.veloren.desktop
Normal file
9
assets/voxygen/net.veloren.veloren.desktop
Normal 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
BIN
assets/voxygen/net.veloren.veloren.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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 {
|
||||
|
@ -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>, ()>,
|
||||
|
@ -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
8
server-cli/Dockerfile
Normal 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
|
17
server-cli/docker-compose.yml
Normal file
17
server-cli/docker-compose.yml
Normal 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
3
server-cli/docker-run.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
cd /opt
|
||||
RUST_LOG=info,common=debug,common::net=info RUST_BACKTRACE=1 /opt/veloren-server-cli
|
@ -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,
|
||||
|
@ -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!(
|
||||
|
@ -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),
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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"
|
||||
|
58
voxygen/examples/character_renderer.rs
Normal file
58
voxygen/examples/character_renderer.rs
Normal 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();
|
||||
}
|
@ -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(),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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(),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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(),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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(),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -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(),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -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(),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -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(),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -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()),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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))),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -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(),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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(),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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(),
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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>) {
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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,
|
@ -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),
|
||||
|
@ -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());
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user