mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Began adding rtsim2 NPCs, scale command
This commit is contained in:
parent
9d3dadfaba
commit
87a6143375
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -6949,9 +6949,11 @@ dependencies = [
|
|||||||
"atomic_refcell",
|
"atomic_refcell",
|
||||||
"enum-map",
|
"enum-map",
|
||||||
"hashbrown 0.12.3",
|
"hashbrown 0.12.3",
|
||||||
|
"rand 0.8.5",
|
||||||
"rmp-serde",
|
"rmp-serde",
|
||||||
"ron 0.8.0",
|
"ron 0.8.0",
|
||||||
"serde",
|
"serde",
|
||||||
|
"slotmap 1.0.6",
|
||||||
"tracing",
|
"tracing",
|
||||||
"vek 0.15.8",
|
"vek 0.15.8",
|
||||||
"veloren-common",
|
"veloren-common",
|
||||||
|
@ -298,6 +298,7 @@ pub enum ServerChatCommand {
|
|||||||
RevokeBuildAll,
|
RevokeBuildAll,
|
||||||
Safezone,
|
Safezone,
|
||||||
Say,
|
Say,
|
||||||
|
Scale,
|
||||||
ServerPhysics,
|
ServerPhysics,
|
||||||
SetMotd,
|
SetMotd,
|
||||||
Ship,
|
Ship,
|
||||||
@ -727,6 +728,9 @@ impl ServerChatCommand {
|
|||||||
ServerChatCommand::Lightning => {
|
ServerChatCommand::Lightning => {
|
||||||
cmd(vec![], "Lightning strike at current position", Some(Admin))
|
cmd(vec![], "Lightning strike at current position", Some(Admin))
|
||||||
},
|
},
|
||||||
|
ServerChatCommand::Scale => {
|
||||||
|
cmd(vec![Float("factor", 1.0, Required)], "Scale your character", Some(Admin))
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -808,6 +812,7 @@ impl ServerChatCommand {
|
|||||||
ServerChatCommand::DeleteLocation => "delete_location",
|
ServerChatCommand::DeleteLocation => "delete_location",
|
||||||
ServerChatCommand::WeatherZone => "weather_zone",
|
ServerChatCommand::WeatherZone => "weather_zone",
|
||||||
ServerChatCommand::Lightning => "lightning",
|
ServerChatCommand::Lightning => "lightning",
|
||||||
|
ServerChatCommand::Scale => "scale",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,10 @@ impl RtSimController {
|
|||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, enum_map::Enum)]
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize, enum_map::Enum)]
|
||||||
pub enum ChunkResource {
|
pub enum ChunkResource {
|
||||||
|
#[serde(rename = "0")]
|
||||||
Grass,
|
Grass,
|
||||||
|
#[serde(rename = "1")]
|
||||||
Flax,
|
Flax,
|
||||||
|
#[serde(rename = "2")]
|
||||||
Cotton,
|
Cotton,
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use crate::{
|
|||||||
ActiveAbilities, Beam, Body, CharacterState, Combo, ControlAction, Controller,
|
ActiveAbilities, Beam, Body, CharacterState, Combo, ControlAction, Controller,
|
||||||
ControllerInputs, Density, Energy, Health, InputAttr, InputKind, Inventory,
|
ControllerInputs, Density, Energy, Health, InputAttr, InputKind, Inventory,
|
||||||
InventoryAction, Mass, Melee, Ori, PhysicsState, Pos, SkillSet, Stance, StateUpdate, Stats,
|
InventoryAction, Mass, Melee, Ori, PhysicsState, Pos, SkillSet, Stance, StateUpdate, Stats,
|
||||||
Vel,
|
Vel, Scale,
|
||||||
},
|
},
|
||||||
link::Is,
|
link::Is,
|
||||||
mounting::Rider,
|
mounting::Rider,
|
||||||
@ -123,6 +123,7 @@ pub struct JoinData<'a> {
|
|||||||
pub pos: &'a Pos,
|
pub pos: &'a Pos,
|
||||||
pub vel: &'a Vel,
|
pub vel: &'a Vel,
|
||||||
pub ori: &'a Ori,
|
pub ori: &'a Ori,
|
||||||
|
pub scale: Option<&'a Scale>,
|
||||||
pub mass: &'a Mass,
|
pub mass: &'a Mass,
|
||||||
pub density: &'a Density,
|
pub density: &'a Density,
|
||||||
pub dt: &'a DeltaTime,
|
pub dt: &'a DeltaTime,
|
||||||
@ -155,6 +156,7 @@ pub struct JoinStruct<'a> {
|
|||||||
pub pos: &'a mut Pos,
|
pub pos: &'a mut Pos,
|
||||||
pub vel: &'a mut Vel,
|
pub vel: &'a mut Vel,
|
||||||
pub ori: &'a mut Ori,
|
pub ori: &'a mut Ori,
|
||||||
|
pub scale: Option<&'a Scale>,
|
||||||
pub mass: &'a Mass,
|
pub mass: &'a Mass,
|
||||||
pub density: FlaggedAccessMut<'a, &'a mut Density, Density>,
|
pub density: FlaggedAccessMut<'a, &'a mut Density, Density>,
|
||||||
pub energy: FlaggedAccessMut<'a, &'a mut Energy, Energy>,
|
pub energy: FlaggedAccessMut<'a, &'a mut Energy, Energy>,
|
||||||
@ -191,6 +193,7 @@ impl<'a> JoinData<'a> {
|
|||||||
pos: j.pos,
|
pos: j.pos,
|
||||||
vel: j.vel,
|
vel: j.vel,
|
||||||
ori: j.ori,
|
ori: j.ori,
|
||||||
|
scale: j.scale,
|
||||||
mass: j.mass,
|
mass: j.mass,
|
||||||
density: &j.density,
|
density: &j.density,
|
||||||
energy: &j.energy,
|
energy: &j.energy,
|
||||||
|
@ -122,10 +122,10 @@ impl CharacterBehavior for Data {
|
|||||||
// Apply Vertical Climbing Movement
|
// Apply Vertical Climbing Movement
|
||||||
match climb {
|
match climb {
|
||||||
Climb::Down => {
|
Climb::Down => {
|
||||||
update.vel.0.z += data.dt.0 * (GRAVITY - self.static_data.movement_speed.powi(2))
|
update.vel.0.z += data.dt.0 * (GRAVITY - self.static_data.movement_speed.powi(2) * data.scale.map_or(1.0, |s| s.0))
|
||||||
},
|
},
|
||||||
Climb::Up => {
|
Climb::Up => {
|
||||||
update.vel.0.z += data.dt.0 * (GRAVITY + self.static_data.movement_speed.powi(2))
|
update.vel.0.z += data.dt.0 * (GRAVITY + self.static_data.movement_speed.powi(2) * data.scale.map_or(1.0, |s| s.0))
|
||||||
},
|
},
|
||||||
Climb::Hold => update.vel.0.z += data.dt.0 * GRAVITY,
|
Climb::Hold => update.vel.0.z += data.dt.0 * GRAVITY,
|
||||||
}
|
}
|
||||||
|
@ -385,7 +385,10 @@ fn basic_move(data: &JoinData<'_>, update: &mut StateUpdate, efficiency: f32) {
|
|||||||
|
|
||||||
let accel = if let Some(block) = data.physics.on_ground {
|
let accel = if let Some(block) = data.physics.on_ground {
|
||||||
// FRIC_GROUND temporarily used to normalize things around expected values
|
// FRIC_GROUND temporarily used to normalize things around expected values
|
||||||
data.body.base_accel() * block.get_traction() * block.get_friction() / FRIC_GROUND
|
data.body.base_accel()
|
||||||
|
* data.scale.map_or(1.0, |s| s.0)
|
||||||
|
* block.get_traction()
|
||||||
|
* block.get_friction() / FRIC_GROUND
|
||||||
} else {
|
} else {
|
||||||
data.body.air_accel()
|
data.body.air_accel()
|
||||||
} * efficiency;
|
} * efficiency;
|
||||||
@ -435,7 +438,7 @@ pub fn handle_forced_movement(
|
|||||||
data.body.base_accel() * block.get_traction() * block.get_friction() / FRIC_GROUND
|
data.body.base_accel() * block.get_traction() * block.get_friction() / FRIC_GROUND
|
||||||
}) {
|
}) {
|
||||||
update.vel.0 +=
|
update.vel.0 +=
|
||||||
Vec2::broadcast(data.dt.0) * accel * Vec2::from(*data.ori) * strength;
|
Vec2::broadcast(data.dt.0) * accel * data.scale.map_or(1.0, |s| s.0) * Vec2::from(*data.ori) * strength;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ForcedMovement::Reverse(strength) => {
|
ForcedMovement::Reverse(strength) => {
|
||||||
@ -445,7 +448,7 @@ pub fn handle_forced_movement(
|
|||||||
data.body.base_accel() * block.get_traction() * block.get_friction() / FRIC_GROUND
|
data.body.base_accel() * block.get_traction() * block.get_friction() / FRIC_GROUND
|
||||||
}) {
|
}) {
|
||||||
update.vel.0 +=
|
update.vel.0 +=
|
||||||
Vec2::broadcast(data.dt.0) * accel * -Vec2::from(*data.ori) * strength;
|
Vec2::broadcast(data.dt.0) * accel * data.scale.map_or(1.0, |s| s.0) * -Vec2::from(*data.ori) * strength;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ForcedMovement::Sideways(strength) => {
|
ForcedMovement::Sideways(strength) => {
|
||||||
@ -467,7 +470,7 @@ pub fn handle_forced_movement(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
update.vel.0 += Vec2::broadcast(data.dt.0) * accel * direction * strength;
|
update.vel.0 += Vec2::broadcast(data.dt.0) * accel * data.scale.map_or(1.0, |s| s.0) * direction * strength;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ForcedMovement::DirectedReverse(strength) => {
|
ForcedMovement::DirectedReverse(strength) => {
|
||||||
@ -516,6 +519,7 @@ pub fn handle_forced_movement(
|
|||||||
dir.y,
|
dir.y,
|
||||||
vertical,
|
vertical,
|
||||||
)
|
)
|
||||||
|
* data.scale.map_or(1.0, |s| s.0)
|
||||||
// Multiply decreasing amount linearly over time (with average of 1)
|
// Multiply decreasing amount linearly over time (with average of 1)
|
||||||
* 2.0 * progress
|
* 2.0 * progress
|
||||||
// Apply direction
|
// Apply direction
|
||||||
@ -528,8 +532,9 @@ pub fn handle_forced_movement(
|
|||||||
* (1.0 - data.inputs.look_dir.z.abs());
|
* (1.0 - data.inputs.look_dir.z.abs());
|
||||||
},
|
},
|
||||||
ForcedMovement::Hover { move_input } => {
|
ForcedMovement::Hover { move_input } => {
|
||||||
update.vel.0 = Vec3::new(data.vel.0.x, data.vel.0.y, 0.0)
|
update.vel.0 = Vec3::new(data.vel.0.x, data.vel.0.y, 0.0) + move_input
|
||||||
+ move_input * data.inputs.move_dir.try_normalized().unwrap_or_default();
|
* data.scale.map_or(1.0, |s| s.0)
|
||||||
|
* data.inputs.move_dir.try_normalized().unwrap_or_default();
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -570,6 +575,7 @@ pub fn handle_orientation(
|
|||||||
};
|
};
|
||||||
// unit is multiples of 180°
|
// unit is multiples of 180°
|
||||||
let half_turns_per_tick = data.body.base_ori_rate()
|
let half_turns_per_tick = data.body.base_ori_rate()
|
||||||
|
/ data.scale.map_or(1.0, |s| s.0)
|
||||||
* efficiency
|
* efficiency
|
||||||
* if data.physics.on_ground.is_some() {
|
* if data.physics.on_ground.is_some() {
|
||||||
1.0
|
1.0
|
||||||
@ -605,7 +611,7 @@ fn swim_move(
|
|||||||
) -> bool {
|
) -> bool {
|
||||||
let efficiency = efficiency * data.stats.move_speed_modifier * data.stats.friction_modifier;
|
let efficiency = efficiency * data.stats.move_speed_modifier * data.stats.friction_modifier;
|
||||||
if let Some(force) = data.body.swim_thrust() {
|
if let Some(force) = data.body.swim_thrust() {
|
||||||
let force = efficiency * force;
|
let force = efficiency * force * data.scale.map_or(1.0, |s| s.0);
|
||||||
let mut water_accel = force / data.mass.0;
|
let mut water_accel = force / data.mass.0;
|
||||||
|
|
||||||
if let Ok(level) = data.skill_set.skill_level(Skill::Swim(SwimSkill::Speed)) {
|
if let Ok(level) = data.skill_set.skill_level(Skill::Swim(SwimSkill::Speed)) {
|
||||||
@ -1068,7 +1074,9 @@ pub fn handle_jump(
|
|||||||
.map(|impulse| {
|
.map(|impulse| {
|
||||||
output_events.emit_local(LocalEvent::Jump(
|
output_events.emit_local(LocalEvent::Jump(
|
||||||
data.entity,
|
data.entity,
|
||||||
strength * impulse / data.mass.0 * data.stats.move_speed_modifier,
|
strength * impulse / data.mass.0
|
||||||
|
* data.scale.map_or(1.0, |s| s.0.sqrt())
|
||||||
|
* data.stats.move_speed_modifier,
|
||||||
));
|
));
|
||||||
})
|
})
|
||||||
.is_some()
|
.is_some()
|
||||||
|
@ -10,7 +10,7 @@ use common::{
|
|||||||
inventory::item::{tool::AbilityMap, MaterialStatManifest},
|
inventory::item::{tool::AbilityMap, MaterialStatManifest},
|
||||||
ActiveAbilities, Beam, Body, CharacterState, Combo, Controller, Density, Energy, Health,
|
ActiveAbilities, Beam, Body, CharacterState, Combo, Controller, Density, Energy, Health,
|
||||||
Inventory, InventoryManip, Mass, Melee, Ori, PhysicsState, Poise, Pos, SkillSet, Stance,
|
Inventory, InventoryManip, Mass, Melee, Ori, PhysicsState, Poise, Pos, SkillSet, Stance,
|
||||||
StateUpdate, Stats, Vel,
|
StateUpdate, Stats, Vel, Scale,
|
||||||
},
|
},
|
||||||
event::{EventBus, LocalEvent, ServerEvent},
|
event::{EventBus, LocalEvent, ServerEvent},
|
||||||
link::Is,
|
link::Is,
|
||||||
@ -37,6 +37,7 @@ pub struct ReadData<'a> {
|
|||||||
healths: ReadStorage<'a, Health>,
|
healths: ReadStorage<'a, Health>,
|
||||||
bodies: ReadStorage<'a, Body>,
|
bodies: ReadStorage<'a, Body>,
|
||||||
masses: ReadStorage<'a, Mass>,
|
masses: ReadStorage<'a, Mass>,
|
||||||
|
scales: ReadStorage<'a, Scale>,
|
||||||
physics_states: ReadStorage<'a, PhysicsState>,
|
physics_states: ReadStorage<'a, PhysicsState>,
|
||||||
melee_attacks: ReadStorage<'a, Melee>,
|
melee_attacks: ReadStorage<'a, Melee>,
|
||||||
beams: ReadStorage<'a, Beam>,
|
beams: ReadStorage<'a, Beam>,
|
||||||
@ -116,7 +117,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
health,
|
health,
|
||||||
body,
|
body,
|
||||||
physics,
|
physics,
|
||||||
(stat, skill_set, active_abilities, is_rider),
|
(scale, stat, skill_set, active_abilities, is_rider),
|
||||||
combo,
|
combo,
|
||||||
) in (
|
) in (
|
||||||
&read_data.entities,
|
&read_data.entities,
|
||||||
@ -134,6 +135,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
&read_data.bodies,
|
&read_data.bodies,
|
||||||
&read_data.physics_states,
|
&read_data.physics_states,
|
||||||
(
|
(
|
||||||
|
read_data.scales.maybe(),
|
||||||
&read_data.stats,
|
&read_data.stats,
|
||||||
&read_data.skill_sets,
|
&read_data.skill_sets,
|
||||||
read_data.active_abilities.maybe(),
|
read_data.active_abilities.maybe(),
|
||||||
@ -183,6 +185,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
pos,
|
pos,
|
||||||
vel,
|
vel,
|
||||||
ori,
|
ori,
|
||||||
|
scale,
|
||||||
mass,
|
mass,
|
||||||
density,
|
density,
|
||||||
energy,
|
energy,
|
||||||
|
@ -1350,19 +1350,15 @@ fn box_voxel_collision<T: BaseVol<Vox = Block> + ReadVol>(
|
|||||||
read: &PhysicsRead,
|
read: &PhysicsRead,
|
||||||
ori: &Ori,
|
ori: &Ori,
|
||||||
) {
|
) {
|
||||||
// FIXME: Review these
|
let scale = read.scales.get(entity).map_or(1.0, |s| s.0);
|
||||||
#![allow(
|
|
||||||
clippy::cast_precision_loss,
|
|
||||||
clippy::cast_possible_truncation,
|
|
||||||
clippy::cast_sign_loss
|
|
||||||
)]
|
|
||||||
//prof_span!("box_voxel_collision");
|
//prof_span!("box_voxel_collision");
|
||||||
|
|
||||||
// Convience function to compute the player aabb
|
// Convience function to compute the player aabb
|
||||||
fn player_aabb(pos: Vec3<f32>, radius: f32, z_range: Range<f32>) -> Aabb<f32> {
|
fn player_aabb(pos: Vec3<f32>, radius: f32, z_range: Range<f32>, scale: f32) -> Aabb<f32> {
|
||||||
Aabb {
|
Aabb {
|
||||||
min: pos + Vec3::new(-radius, -radius, z_range.start),
|
min: pos + Vec3::new(-radius, -radius, z_range.start) * scale,
|
||||||
max: pos + Vec3::new(radius, radius, z_range.end),
|
max: pos + Vec3::new(radius, radius, z_range.end) * scale,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1383,8 +1379,9 @@ fn box_voxel_collision<T: BaseVol<Vox = Block> + ReadVol>(
|
|||||||
near_aabb: Aabb<i32>,
|
near_aabb: Aabb<i32>,
|
||||||
radius: f32,
|
radius: f32,
|
||||||
z_range: Range<f32>,
|
z_range: Range<f32>,
|
||||||
|
scale: f32,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let player_aabb = player_aabb(pos, radius, z_range);
|
let player_aabb = player_aabb(pos, radius, z_range, scale);
|
||||||
|
|
||||||
// Calculate the world space near aabb
|
// Calculate the world space near aabb
|
||||||
let near_aabb = move_aabb(near_aabb, pos);
|
let near_aabb = move_aabb(near_aabb, pos);
|
||||||
@ -1451,7 +1448,7 @@ fn box_voxel_collision<T: BaseVol<Vox = Block> + ReadVol>(
|
|||||||
let try_colliding_block = |pos: &Pos| {
|
let try_colliding_block = |pos: &Pos| {
|
||||||
//prof_span!("most colliding check");
|
//prof_span!("most colliding check");
|
||||||
// Calculate the player's AABB
|
// Calculate the player's AABB
|
||||||
let player_aabb = player_aabb(pos.0, radius, z_range.clone());
|
let player_aabb = player_aabb(pos.0, radius, z_range.clone(), scale);
|
||||||
|
|
||||||
// Determine the block that we are colliding with most
|
// Determine the block that we are colliding with most
|
||||||
// (based on minimum collision axis)
|
// (based on minimum collision axis)
|
||||||
@ -1501,7 +1498,7 @@ fn box_voxel_collision<T: BaseVol<Vox = Block> + ReadVol>(
|
|||||||
.flatten()
|
.flatten()
|
||||||
{
|
{
|
||||||
// Calculate the player's AABB
|
// Calculate the player's AABB
|
||||||
let player_aabb = player_aabb(pos.0, radius, z_range.clone());
|
let player_aabb = player_aabb(pos.0, radius, z_range.clone(), scale);
|
||||||
|
|
||||||
// Find the intrusion vector of the collision
|
// Find the intrusion vector of the collision
|
||||||
let dir = player_aabb.collision_vector_with_aabb(block_aabb);
|
let dir = player_aabb.collision_vector_with_aabb(block_aabb);
|
||||||
@ -1547,6 +1544,7 @@ fn box_voxel_collision<T: BaseVol<Vox = Block> + ReadVol>(
|
|||||||
near_aabb,
|
near_aabb,
|
||||||
radius,
|
radius,
|
||||||
z_range.clone(),
|
z_range.clone(),
|
||||||
|
scale,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// ...and there is a collision with a block beneath our current hitbox...
|
// ...and there is a collision with a block beneath our current hitbox...
|
||||||
@ -1559,6 +1557,7 @@ fn box_voxel_collision<T: BaseVol<Vox = Block> + ReadVol>(
|
|||||||
near_aabb,
|
near_aabb,
|
||||||
radius,
|
radius,
|
||||||
z_range.clone(),
|
z_range.clone(),
|
||||||
|
scale,
|
||||||
)
|
)
|
||||||
} {
|
} {
|
||||||
// ...block-hop!
|
// ...block-hop!
|
||||||
@ -1613,6 +1612,7 @@ fn box_voxel_collision<T: BaseVol<Vox = Block> + ReadVol>(
|
|||||||
near_aabb,
|
near_aabb,
|
||||||
radius,
|
radius,
|
||||||
z_range.clone(),
|
z_range.clone(),
|
||||||
|
scale,
|
||||||
)
|
)
|
||||||
} {
|
} {
|
||||||
//prof_span!("snap!!");
|
//prof_span!("snap!!");
|
||||||
@ -1630,7 +1630,7 @@ fn box_voxel_collision<T: BaseVol<Vox = Block> + ReadVol>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find liquid immersion and wall collision all in one round of iteration
|
// Find liquid immersion and wall collision all in one round of iteration
|
||||||
let player_aabb = player_aabb(pos.0, radius, z_range.clone());
|
let player_aabb = player_aabb(pos.0, radius, z_range.clone(), scale);
|
||||||
// Calculate the world space near_aabb
|
// Calculate the world space near_aabb
|
||||||
let near_aabb = move_aabb(near_aabb, pos.0);
|
let near_aabb = move_aabb(near_aabb, pos.0);
|
||||||
|
|
||||||
|
@ -15,3 +15,5 @@ rmp-serde = "1.1.0"
|
|||||||
anymap2 = "0.13"
|
anymap2 = "0.13"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
atomic_refcell = "0.1"
|
atomic_refcell = "0.1"
|
||||||
|
slotmap = { version = "1.0.6", features = ["serde"] }
|
||||||
|
rand = { version = "0.8", features = ["small_rng"] }
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
use hashbrown::HashMap;
|
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
|
||||||
pub struct ActorId {
|
|
||||||
pub idx: u32,
|
|
||||||
pub gen: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
|
||||||
pub struct Actor {}
|
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
|
||||||
pub struct Actors {
|
|
||||||
pub actors: HashMap<ActorId, Actor>,
|
|
||||||
}
|
|
@ -1,19 +1,30 @@
|
|||||||
pub mod actor;
|
pub mod npc;
|
||||||
pub mod nature;
|
pub mod nature;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
actor::{Actor, ActorId, Actors},
|
npc::{Npc, NpcId, Npcs},
|
||||||
nature::Nature,
|
nature::Nature,
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::helper::Latest;
|
use enum_map::{EnumMap, EnumArray, enum_map};
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize, ser, de};
|
||||||
use std::io::{Read, Write};
|
use std::{
|
||||||
|
io::{Read, Write},
|
||||||
|
marker::PhantomData,
|
||||||
|
cmp::PartialEq,
|
||||||
|
fmt,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||||
|
pub enum Actor {
|
||||||
|
Npc(NpcId),
|
||||||
|
Character(common::character::CharacterId),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub struct Data {
|
pub struct Data {
|
||||||
pub nature: Nature,
|
pub nature: Nature,
|
||||||
pub actors: Actors,
|
pub npcs: Npcs,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ReadError = rmp_serde::decode::Error;
|
pub type ReadError = rmp_serde::decode::Error;
|
||||||
@ -25,6 +36,57 @@ impl Data {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_to<W: Write>(&self, mut writer: W) -> Result<(), WriteError> {
|
pub fn write_to<W: Write>(&self, mut writer: W) -> Result<(), WriteError> {
|
||||||
rmp_serde::encode::write(&mut writer, self)
|
rmp_serde::encode::write_named(&mut writer, self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fn rugged_ser_enum_map<K: EnumArray<V> + Serialize, V: PartialEq + Default + Serialize, S: ser::Serializer>(map: &EnumMap<K, V>, mut ser: S) -> Result<S::Ok, S::Error> {
|
||||||
|
// ser.collect_map(map
|
||||||
|
// .iter()
|
||||||
|
// .filter(|(k, v)| v != &&V::default())
|
||||||
|
// .map(|(k, v)| (k, v)))
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn rugged_ser_enum_map<
|
||||||
|
K: EnumArray<V> + Serialize,
|
||||||
|
V: From<i16> + PartialEq + Serialize,
|
||||||
|
S: ser::Serializer,
|
||||||
|
const DEFAULT: i16,
|
||||||
|
>(map: &EnumMap<K, V>, ser: S) -> Result<S::Ok, S::Error> {
|
||||||
|
ser.collect_map(map
|
||||||
|
.iter()
|
||||||
|
.filter(|(k, v)| v != &&V::from(DEFAULT))
|
||||||
|
.map(|(k, v)| (k, v)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rugged_de_enum_map<
|
||||||
|
'a,
|
||||||
|
K: EnumArray<V> + EnumArray<Option<V>> + Deserialize<'a>,
|
||||||
|
V: From<i16> + Deserialize<'a>,
|
||||||
|
D: de::Deserializer<'a>,
|
||||||
|
const DEFAULT: i16,
|
||||||
|
>(mut de: D) -> Result<EnumMap<K, V>, D::Error> {
|
||||||
|
struct Visitor<K, V, const DEFAULT: i16>(PhantomData<(K, V)>);
|
||||||
|
|
||||||
|
impl<'de, K, V, const DEFAULT: i16> de::Visitor<'de> for Visitor<K, V, DEFAULT>
|
||||||
|
where
|
||||||
|
K: EnumArray<V> + EnumArray<Option<V>> + Deserialize<'de>,
|
||||||
|
V: From<i16> + Deserialize<'de>,
|
||||||
|
{
|
||||||
|
type Value = EnumMap<K, V>;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(formatter, "a map")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_map<M: de::MapAccess<'de>>(self, mut access: M) -> Result<Self::Value, M::Error> {
|
||||||
|
let mut entries = EnumMap::default();
|
||||||
|
while let Some((key, value)) = access.next_entry()? {
|
||||||
|
entries[key] = Some(value);
|
||||||
|
}
|
||||||
|
Ok(enum_map! { key => entries[key].take().unwrap_or_else(|| V::from(DEFAULT)) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
de.deserialize_map(Visitor::<_, _, DEFAULT>(PhantomData))
|
||||||
|
}
|
||||||
|
@ -9,6 +9,9 @@ use vek::*;
|
|||||||
|
|
||||||
/// Represents the state of 'natural' elements of the world such as plant/animal/resource populations, weather systems,
|
/// Represents the state of 'natural' elements of the world such as plant/animal/resource populations, weather systems,
|
||||||
/// etc.
|
/// etc.
|
||||||
|
///
|
||||||
|
/// Where possible, this data does not define the state of natural aspects of the world, but instead defines
|
||||||
|
/// 'modifications' that sit on top of the world data generated by initial generation.
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub struct Nature {
|
pub struct Nature {
|
||||||
chunks: Grid<Chunk>,
|
chunks: Grid<Chunk>,
|
||||||
@ -43,5 +46,17 @@ impl Nature {
|
|||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub struct Chunk {
|
pub struct Chunk {
|
||||||
/// Represent the 'naturally occurring' resource proportion that exists in this chunk.
|
/// Represent the 'naturally occurring' resource proportion that exists in this chunk.
|
||||||
|
///
|
||||||
|
/// 0.0 => None of the resources generated by terrain generation should be present
|
||||||
|
/// 1.0 => All of the resources generated by terrain generation should be present
|
||||||
|
///
|
||||||
|
/// It's important to understand this this number does not represent the total amount of a resource present in a
|
||||||
|
/// chunk, nor is it even proportional to the amount of the resource present. To get the total amount of the
|
||||||
|
/// resource in a chunk, one must first multiply this factor by the amount of 'natural' resources given by terrain
|
||||||
|
/// generation. This value represents only the variable 'depletion' factor of that resource, which shall change
|
||||||
|
/// over time as the world evolves and players interact with it.
|
||||||
|
#[serde(rename = "r")]
|
||||||
|
#[serde(serialize_with = "crate::data::rugged_ser_enum_map::<_, _, _, 1>")]
|
||||||
|
#[serde(deserialize_with = "crate::data::rugged_de_enum_map::<_, _, _, 1>")]
|
||||||
res: EnumMap<ChunkResource, f32>,
|
res: EnumMap<ChunkResource, f32>,
|
||||||
}
|
}
|
||||||
|
50
rtsim/src/data/npc.rs
Normal file
50
rtsim/src/data/npc.rs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
use hashbrown::HashMap;
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
use slotmap::HopSlotMap;
|
||||||
|
use vek::*;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
use common::uid::Uid;
|
||||||
|
|
||||||
|
slotmap::new_key_type! { pub struct NpcId; }
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Npc {
|
||||||
|
pub wpos: Vec3<f32>,
|
||||||
|
#[serde(skip_serializing, skip_deserializing)]
|
||||||
|
pub mode: NpcMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Npc {
|
||||||
|
pub fn at(wpos: Vec3<f32>) -> Self {
|
||||||
|
Self { wpos, mode: NpcMode::Simulated }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Default)]
|
||||||
|
pub enum NpcMode {
|
||||||
|
/// The NPC is unloaded and is being simulated via rtsim.
|
||||||
|
#[default]
|
||||||
|
Simulated,
|
||||||
|
/// The NPC has been loaded into the game world as an ECS entity.
|
||||||
|
Loaded,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Npcs {
|
||||||
|
pub npcs: HopSlotMap<NpcId, Npc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Npcs {
|
||||||
|
pub fn spawn(&mut self, npc: Npc) -> NpcId {
|
||||||
|
self.npcs.insert(npc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Npcs {
|
||||||
|
type Target = HopSlotMap<NpcId, Npc>;
|
||||||
|
fn deref(&self) -> &Self::Target { &self.npcs }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for Npcs {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.npcs }
|
||||||
|
}
|
@ -1,14 +1,42 @@
|
|||||||
use crate::data::{Actors, Data, Nature};
|
use crate::data::{Npcs, Npc, Data, Nature};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use world::World;
|
use rand::prelude::*;
|
||||||
|
use world::{
|
||||||
|
site::SiteKind,
|
||||||
|
IndexRef,
|
||||||
|
World,
|
||||||
|
};
|
||||||
|
|
||||||
impl Data {
|
impl Data {
|
||||||
pub fn generate(world: &World) -> Self {
|
pub fn generate(index: IndexRef, world: &World) -> Self {
|
||||||
Self {
|
let mut seed = [0; 32];
|
||||||
|
seed.iter_mut().zip(&mut index.seed.to_le_bytes()).for_each(|(dst, src)| *dst = *src);
|
||||||
|
let mut rng = SmallRng::from_seed(seed);
|
||||||
|
|
||||||
|
let mut this = Self {
|
||||||
nature: Nature::generate(world),
|
nature: Nature::generate(world),
|
||||||
actors: Actors {
|
npcs: Npcs { npcs: Default::default() },
|
||||||
actors: HashMap::default(),
|
};
|
||||||
},
|
|
||||||
|
for (site_id, site) in world
|
||||||
|
.civs()
|
||||||
|
.sites
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(site_id, site)| site.site_tmp.map(|id| (site_id, &index.sites[id])))
|
||||||
|
{
|
||||||
|
match &site.kind {
|
||||||
|
SiteKind::Refactor(site2) => {
|
||||||
|
let wpos = site.get_origin()
|
||||||
|
.map(|e| e as f32 + 0.5)
|
||||||
|
.with_z(world.sim().get_alt_approx(site.get_origin()).unwrap_or(0.0));
|
||||||
|
// TODO: Better API
|
||||||
|
this.npcs.spawn(Npc::at(wpos));
|
||||||
|
println!("Spawned rtsim NPC at {:?}", wpos);
|
||||||
|
}
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,6 +196,7 @@ fn do_command(
|
|||||||
ServerChatCommand::DeleteLocation => handle_delete_location,
|
ServerChatCommand::DeleteLocation => handle_delete_location,
|
||||||
ServerChatCommand::WeatherZone => handle_weather_zone,
|
ServerChatCommand::WeatherZone => handle_weather_zone,
|
||||||
ServerChatCommand::Lightning => handle_lightning,
|
ServerChatCommand::Lightning => handle_lightning,
|
||||||
|
ServerChatCommand::Scale => handle_scale,
|
||||||
};
|
};
|
||||||
|
|
||||||
handler(server, client, target, args, cmd)
|
handler(server, client, target, args, cmd)
|
||||||
@ -3835,3 +3836,26 @@ fn handle_body(
|
|||||||
Err(action.help_string())
|
Err(action.help_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_scale(
|
||||||
|
server: &mut Server,
|
||||||
|
client: EcsEntity,
|
||||||
|
target: EcsEntity,
|
||||||
|
args: Vec<String>,
|
||||||
|
action: &ServerChatCommand,
|
||||||
|
) -> CmdResult<()> {
|
||||||
|
if let Some(scale) = parse_cmd_args!(args, f32) {
|
||||||
|
let _ = server
|
||||||
|
.state
|
||||||
|
.ecs_mut()
|
||||||
|
.write_storage::<comp::Scale>()
|
||||||
|
.insert(target, comp::Scale(scale));
|
||||||
|
server.notify_client(
|
||||||
|
client,
|
||||||
|
ServerGeneral::server_msg(ChatType::CommandInfo, format!("Set scale to {}", scale)),
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(action.help_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -564,7 +564,7 @@ impl Server {
|
|||||||
// Init rtsim, loading it from disk if possible
|
// Init rtsim, loading it from disk if possible
|
||||||
#[cfg(feature = "worldgen")]
|
#[cfg(feature = "worldgen")]
|
||||||
{
|
{
|
||||||
match rtsim2::RtSim::new(&world, data_dir.to_owned()) {
|
match rtsim2::RtSim::new(index.as_index_ref(), &world, data_dir.to_owned()) {
|
||||||
Ok(rtsim) => state.ecs_mut().insert(rtsim),
|
Ok(rtsim) => state.ecs_mut().insert(rtsim),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("Failed to load rtsim: {}", err);
|
error!("Failed to load rtsim: {}", err);
|
||||||
|
@ -27,7 +27,7 @@ use std::{
|
|||||||
use enum_map::EnumMap;
|
use enum_map::EnumMap;
|
||||||
use tracing::{error, warn, info, debug};
|
use tracing::{error, warn, info, debug};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
use world::World;
|
use world::{IndexRef, World};
|
||||||
|
|
||||||
pub struct RtSim {
|
pub struct RtSim {
|
||||||
file_path: PathBuf,
|
file_path: PathBuf,
|
||||||
@ -36,43 +36,47 @@ pub struct RtSim {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RtSim {
|
impl RtSim {
|
||||||
pub fn new(world: &World, data_dir: PathBuf) -> Result<Self, ron::Error> {
|
pub fn new(index: IndexRef, world: &World, data_dir: PathBuf) -> Result<Self, ron::Error> {
|
||||||
let file_path = Self::get_file_path(data_dir);
|
let file_path = Self::get_file_path(data_dir);
|
||||||
|
|
||||||
info!("Looking for rtsim data in {}...", file_path.display());
|
info!("Looking for rtsim data in {}...", file_path.display());
|
||||||
let data = 'load: {
|
let data = 'load: {
|
||||||
match File::open(&file_path) {
|
if std::env::var("RTSIM_NOLOAD").map_or(true, |v| v != "1") {
|
||||||
Ok(file) => {
|
match File::open(&file_path) {
|
||||||
info!("Rtsim data found. Attempting to load...");
|
Ok(file) => {
|
||||||
match Data::from_reader(io::BufReader::new(file)) {
|
info!("Rtsim data found. Attempting to load...");
|
||||||
Ok(data) => { info!("Rtsim data loaded."); break 'load data },
|
match Data::from_reader(io::BufReader::new(file)) {
|
||||||
Err(e) => {
|
Ok(data) => { info!("Rtsim data loaded."); break 'load data },
|
||||||
error!("Rtsim data failed to load: {}", e);
|
Err(e) => {
|
||||||
let mut i = 0;
|
error!("Rtsim data failed to load: {}", e);
|
||||||
loop {
|
let mut i = 0;
|
||||||
let mut backup_path = file_path.clone();
|
loop {
|
||||||
backup_path.set_extension(if i == 0 {
|
let mut backup_path = file_path.clone();
|
||||||
format!("backup_{}", i)
|
backup_path.set_extension(if i == 0 {
|
||||||
} else {
|
format!("backup_{}", i)
|
||||||
"ron_backup".to_string()
|
} else {
|
||||||
});
|
"ron_backup".to_string()
|
||||||
if !backup_path.exists() {
|
});
|
||||||
fs::rename(&file_path, &backup_path)?;
|
if !backup_path.exists() {
|
||||||
warn!("Failed rtsim data was moved to {}", backup_path.display());
|
fs::rename(&file_path, &backup_path)?;
|
||||||
info!("A fresh rtsim data will now be generated.");
|
warn!("Failed rtsim data was moved to {}", backup_path.display());
|
||||||
break;
|
info!("A fresh rtsim data will now be generated.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
}
|
}
|
||||||
i += 1;
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
Err(e) if e.kind() == io::ErrorKind::NotFound =>
|
||||||
},
|
info!("No rtsim data found. Generating from world..."),
|
||||||
Err(e) if e.kind() == io::ErrorKind::NotFound =>
|
Err(e) => return Err(e.into()),
|
||||||
info!("No rtsim data found. Generating from world..."),
|
}
|
||||||
Err(e) => return Err(e.into()),
|
} else {
|
||||||
|
warn!("'RTSIM_NOLOAD' is set, skipping loading of rtsim state (old state will be overwritten).");
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = Data::generate(&world);
|
let data = Data::generate(index, &world);
|
||||||
info!("Rtsim data generated.");
|
info!("Rtsim data generated.");
|
||||||
data
|
data
|
||||||
};
|
};
|
||||||
|
@ -10,6 +10,7 @@ use common::{
|
|||||||
slowjob::SlowJobPool,
|
slowjob::SlowJobPool,
|
||||||
};
|
};
|
||||||
use common_ecs::{Job, Origin, Phase, System};
|
use common_ecs::{Job, Origin, Phase, System};
|
||||||
|
use rtsim2::data::npc::NpcMode;
|
||||||
use specs::{Join, Read, ReadExpect, ReadStorage, WriteExpect, WriteStorage};
|
use specs::{Join, Read, ReadExpect, ReadStorage, WriteExpect, WriteStorage};
|
||||||
use std::{sync::Arc, time::Duration};
|
use std::{sync::Arc, time::Duration};
|
||||||
|
|
||||||
@ -32,8 +33,9 @@ impl<'a> System<'a> for Sys {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
_job: &mut Job<Self>,
|
_job: &mut Job<Self>,
|
||||||
(dt, time, server_event_bus, mut rtsim, world, index, slow_jobs): Self::SystemData,
|
(dt, time, mut server_event_bus, mut rtsim, world, index, slow_jobs): Self::SystemData,
|
||||||
) {
|
) {
|
||||||
|
let mut emitter = server_event_bus.emitter();
|
||||||
let rtsim = &mut *rtsim;
|
let rtsim = &mut *rtsim;
|
||||||
|
|
||||||
rtsim.state.tick(dt.0);
|
rtsim.state.tick(dt.0);
|
||||||
@ -42,6 +44,38 @@ impl<'a> System<'a> for Sys {
|
|||||||
rtsim.save(&slow_jobs);
|
rtsim.save(&slow_jobs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let chunk_states = rtsim.state.resource::<ChunkStates>();
|
||||||
|
for (npc_id, npc) in rtsim.state.data_mut().npcs.iter_mut() {
|
||||||
|
let chunk = npc.wpos
|
||||||
|
.xy()
|
||||||
|
.map2(TerrainChunk::RECT_SIZE, |e, sz| (e as i32).div_euclid(sz as i32));
|
||||||
|
|
||||||
|
// Load the NPC into the world if it's in a loaded chunk and is not already loaded
|
||||||
|
if matches!(npc.mode, NpcMode::Simulated) && chunk_states.0.get(chunk).map_or(false, |c| c.is_some()) {
|
||||||
|
npc.mode = NpcMode::Loaded;
|
||||||
|
|
||||||
|
println!("Loading in rtsim NPC at {:?}", npc.wpos);
|
||||||
|
|
||||||
|
let body = comp::Body::Object(comp::object::Body::Scarecrow);
|
||||||
|
emitter.emit(ServerEvent::CreateNpc {
|
||||||
|
pos: comp::Pos(npc.wpos),
|
||||||
|
stats: comp::Stats::new("Rtsim NPC".to_string()),
|
||||||
|
skill_set: comp::SkillSet::default(),
|
||||||
|
health: None,
|
||||||
|
poise: comp::Poise::new(body),
|
||||||
|
inventory: comp::Inventory::with_empty(),
|
||||||
|
body,
|
||||||
|
agent: None,
|
||||||
|
alignment: comp::Alignment::Wild,
|
||||||
|
scale: comp::Scale(10.0),
|
||||||
|
anchor: None,
|
||||||
|
loot: Default::default(),
|
||||||
|
rtsim_entity: None, // For now, the old one is used!
|
||||||
|
projectile: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// rtsim.tick += 1;
|
// rtsim.tick += 1;
|
||||||
|
|
||||||
// Update unloaded rtsim entities, in groups at a time
|
// Update unloaded rtsim entities, in groups at a time
|
||||||
|
@ -776,7 +776,7 @@ impl FigureMgr {
|
|||||||
.enumerate()
|
.enumerate()
|
||||||
{
|
{
|
||||||
// Velocity relative to the current ground
|
// Velocity relative to the current ground
|
||||||
let rel_vel = anim::vek::Vec3::<f32>::from(vel.0 - physics.ground_vel);
|
let rel_vel = anim::vek::Vec3::<f32>::from(vel.0 - physics.ground_vel) / scale.map_or(1.0, |s| s.0);
|
||||||
|
|
||||||
let look_dir = controller.map(|c| c.inputs.look_dir).unwrap_or_default();
|
let look_dir = controller.map(|c| c.inputs.look_dir).unwrap_or_default();
|
||||||
let is_viewpoint = scene_data.viewpoint_entity == entity;
|
let is_viewpoint = scene_data.viewpoint_entity == entity;
|
||||||
@ -1005,7 +1005,7 @@ impl FigureMgr {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Average velocity relative to the current ground
|
// Average velocity relative to the current ground
|
||||||
let rel_avg_vel = state.avg_vel - physics.ground_vel;
|
let rel_avg_vel = (state.avg_vel - physics.ground_vel) / scale;
|
||||||
|
|
||||||
let (character, last_character) = match (character, last_character) {
|
let (character, last_character) = match (character, last_character) {
|
||||||
(Some(c), Some(l)) => (c, l),
|
(Some(c), Some(l)) => (c, l),
|
||||||
@ -6157,6 +6157,7 @@ impl FigureMgr {
|
|||||||
None,
|
None,
|
||||||
entity,
|
entity,
|
||||||
body,
|
body,
|
||||||
|
scale.copied(),
|
||||||
inventory,
|
inventory,
|
||||||
false,
|
false,
|
||||||
pos.0,
|
pos.0,
|
||||||
@ -6238,6 +6239,7 @@ impl FigureMgr {
|
|||||||
character_state,
|
character_state,
|
||||||
entity,
|
entity,
|
||||||
body,
|
body,
|
||||||
|
scale.copied(),
|
||||||
inventory,
|
inventory,
|
||||||
false,
|
false,
|
||||||
pos.0,
|
pos.0,
|
||||||
@ -6273,9 +6275,10 @@ impl FigureMgr {
|
|||||||
let character_state = character_state_storage.get(player_entity);
|
let character_state = character_state_storage.get(player_entity);
|
||||||
let items = ecs.read_storage::<Item>();
|
let items = ecs.read_storage::<Item>();
|
||||||
|
|
||||||
if let (Some(pos), Some(body)) = (
|
if let (Some(pos), Some(body), scale) = (
|
||||||
ecs.read_storage::<Pos>().get(player_entity),
|
ecs.read_storage::<Pos>().get(player_entity),
|
||||||
ecs.read_storage::<Body>().get(player_entity),
|
ecs.read_storage::<Body>().get(player_entity),
|
||||||
|
ecs.read_storage::<Scale>().get(player_entity),
|
||||||
) {
|
) {
|
||||||
let healths = state.read_storage::<Health>();
|
let healths = state.read_storage::<Health>();
|
||||||
let health = healths.get(player_entity);
|
let health = healths.get(player_entity);
|
||||||
@ -6292,6 +6295,7 @@ impl FigureMgr {
|
|||||||
character_state,
|
character_state,
|
||||||
player_entity,
|
player_entity,
|
||||||
body,
|
body,
|
||||||
|
scale.copied(),
|
||||||
inventory,
|
inventory,
|
||||||
true,
|
true,
|
||||||
pos.0,
|
pos.0,
|
||||||
@ -6325,6 +6329,7 @@ impl FigureMgr {
|
|||||||
character_state: Option<&CharacterState>,
|
character_state: Option<&CharacterState>,
|
||||||
entity: EcsEntity,
|
entity: EcsEntity,
|
||||||
body: &Body,
|
body: &Body,
|
||||||
|
scale: Option<Scale>,
|
||||||
inventory: Option<&Inventory>,
|
inventory: Option<&Inventory>,
|
||||||
is_viewpoint: bool,
|
is_viewpoint: bool,
|
||||||
pos: Vec3<f32>,
|
pos: Vec3<f32>,
|
||||||
@ -6702,8 +6707,8 @@ impl FigureMgr {
|
|||||||
} {
|
} {
|
||||||
let model_entry = model_entry?;
|
let model_entry = model_entry?;
|
||||||
|
|
||||||
let figure_low_detail_distance = figure_lod_render_distance * 0.75;
|
let figure_low_detail_distance = figure_lod_render_distance * scale.map_or(1.0, |s| s.0) * 0.75;
|
||||||
let figure_mid_detail_distance = figure_lod_render_distance * 0.5;
|
let figure_mid_detail_distance = figure_lod_render_distance * scale.map_or(1.0, |s| s.0) * 0.5;
|
||||||
|
|
||||||
let model = if pos.distance_squared(cam_pos) > figure_low_detail_distance.powi(2) {
|
let model = if pos.distance_squared(cam_pos) > figure_low_detail_distance.powi(2) {
|
||||||
model_entry.lod_model(2)
|
model_entry.lod_model(2)
|
||||||
@ -7092,7 +7097,7 @@ impl<S: Skeleton> FigureState<S> {
|
|||||||
|
|
||||||
self.last_ori = Lerp::lerp(self.last_ori, *ori, 15.0 * dt).normalized();
|
self.last_ori = Lerp::lerp(self.last_ori, *ori, 15.0 * dt).normalized();
|
||||||
|
|
||||||
self.state_time += dt * state_animation_rate;
|
self.state_time += dt * state_animation_rate / scale;
|
||||||
|
|
||||||
let mat = {
|
let mat = {
|
||||||
let scale_mat = anim::vek::Mat4::scaling_3d(anim::vek::Vec3::from(*scale));
|
let scale_mat = anim::vek::Mat4::scaling_3d(anim::vek::Vec3::from(*scale));
|
||||||
@ -7254,7 +7259,7 @@ impl<S: Skeleton> FigureState<S> {
|
|||||||
|
|
||||||
// Can potentially overflow
|
// Can potentially overflow
|
||||||
if self.avg_vel.magnitude_squared() != 0.0 {
|
if self.avg_vel.magnitude_squared() != 0.0 {
|
||||||
self.acc_vel += (self.avg_vel - *ground_vel).magnitude() * dt;
|
self.acc_vel += (self.avg_vel - *ground_vel).magnitude() * dt / scale;
|
||||||
} else {
|
} else {
|
||||||
self.acc_vel = 0.0;
|
self.acc_vel = 0.0;
|
||||||
}
|
}
|
||||||
|
@ -526,7 +526,30 @@ impl Scene {
|
|||||||
.get(scene_data.viewpoint_entity)
|
.get(scene_data.viewpoint_entity)
|
||||||
.map_or(Quaternion::identity(), |ori| ori.to_quat());
|
.map_or(Quaternion::identity(), |ori| ori.to_quat());
|
||||||
|
|
||||||
let (is_humanoid, viewpoint_height, viewpoint_eye_height) = ecs
|
let viewpoint_scale = ecs
|
||||||
|
.read_storage::<comp::Scale>()
|
||||||
|
.get(scene_data.viewpoint_entity)
|
||||||
|
.map_or(1.0, |scale| scale.0);
|
||||||
|
|
||||||
|
let viewpoint_rolling = ecs
|
||||||
|
.read_storage::<comp::CharacterState>()
|
||||||
|
.get(scene_data.viewpoint_entity)
|
||||||
|
.map_or(false, |cs| cs.is_dodge());
|
||||||
|
|
||||||
|
let is_running = ecs
|
||||||
|
.read_storage::<comp::Vel>()
|
||||||
|
.get(scene_data.viewpoint_entity)
|
||||||
|
.map(|v| v.0.magnitude_squared() > RUNNING_THRESHOLD.powi(2))
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
let on_ground = ecs
|
||||||
|
.read_storage::<comp::PhysicsState>()
|
||||||
|
.get(scene_data.viewpoint_entity)
|
||||||
|
.map(|p| p.on_ground.is_some());
|
||||||
|
|
||||||
|
let (is_humanoid, viewpoint_height, viewpoint_eye_height) = scene_data
|
||||||
|
.state
|
||||||
|
.ecs()
|
||||||
.read_storage::<comp::Body>()
|
.read_storage::<comp::Body>()
|
||||||
.get(scene_data.viewpoint_entity)
|
.get(scene_data.viewpoint_entity)
|
||||||
.map_or((false, 1.0, 0.0), |b| {
|
.map_or((false, 1.0, 0.0), |b| {
|
||||||
@ -602,10 +625,10 @@ impl Scene {
|
|||||||
let tilt = self.camera.get_orientation().y;
|
let tilt = self.camera.get_orientation().y;
|
||||||
let dist = self.camera.get_distance();
|
let dist = self.camera.get_distance();
|
||||||
|
|
||||||
Vec3::unit_z() * (up - tilt.min(0.0).sin() * dist * 0.6)
|
Vec3::unit_z() * (up * viewpoint_scale - tilt.min(0.0).sin() * dist * 0.6)
|
||||||
} else {
|
} else {
|
||||||
self.figure_mgr
|
self.figure_mgr
|
||||||
.viewpoint_offset(scene_data, scene_data.viewpoint_entity)
|
.viewpoint_offset(scene_data, scene_data.viewpoint_entity) * viewpoint_scale
|
||||||
};
|
};
|
||||||
|
|
||||||
match self.camera.get_mode() {
|
match self.camera.get_mode() {
|
||||||
|
Loading…
Reference in New Issue
Block a user