Track almost all collectable sprites, added resource replenishment

This commit is contained in:
Joshua Barretto 2023-01-06 01:16:15 +00:00
parent 94390331e0
commit bb96e92362
10 changed files with 205 additions and 15 deletions

View File

@ -312,6 +312,7 @@ pub enum ServerChatCommand {
Tp,
TpNpc,
NpcInfo,
RtsimChunk,
Unban,
Version,
Waypoint,
@ -691,6 +692,11 @@ impl ServerChatCommand {
"Display information about an rtsim NPC",
Some(Moderator),
),
ServerChatCommand::RtsimChunk => cmd(
vec![],
"Display information about the current chunk from rtsim",
Some(Moderator),
),
ServerChatCommand::Unban => cmd(
vec![PlayerName(Required)],
"Remove the ban for the given username",
@ -815,6 +821,7 @@ impl ServerChatCommand {
ServerChatCommand::Tp => "tp",
ServerChatCommand::TpNpc => "tp_npc",
ServerChatCommand::NpcInfo => "npc_info",
ServerChatCommand::RtsimChunk => "rtsim_chunk",
ServerChatCommand::Unban => "unban",
ServerChatCommand::Version => "version",
ServerChatCommand::Waypoint => "waypoint",

View File

@ -94,9 +94,25 @@ pub enum ChunkResource {
#[serde(rename = "0")]
Grass,
#[serde(rename = "1")]
Flax,
Flower,
#[serde(rename = "2")]
Cotton,
Fruit,
#[serde(rename = "3")]
Vegetable,
#[serde(rename = "4")]
Mushroom,
#[serde(rename = "5")]
Loot, // Chests, boxes, potions, etc.
#[serde(rename = "6")]
Plant, // Flax, cotton, wheat, corn, etc.
#[serde(rename = "7")]
Stone,
#[serde(rename = "8")]
Wood, // Twigs, logs, bamboo, etc.
#[serde(rename = "9")]
Gem, // Amethyst, diamond, etc.
#[serde(rename = "a")]
Ore, // Iron, copper, etc.
}
#[derive(Clone, Debug, Serialize, Deserialize)]

View File

@ -200,6 +200,37 @@ impl Block {
#[inline]
pub fn get_rtsim_resource(&self) -> Option<rtsim::ChunkResource> {
match self.get_sprite()? {
SpriteKind::Stones => Some(rtsim::ChunkResource::Stone),
SpriteKind::Twigs
| SpriteKind::Wood
| SpriteKind::Bamboo
| SpriteKind::Hardwood
| SpriteKind::Ironwood
| SpriteKind::Frostwood
| SpriteKind::Eldwood => Some(rtsim::ChunkResource::Wood),
SpriteKind::Amethyst
| SpriteKind::Ruby
| SpriteKind::Sapphire
| SpriteKind::Emerald
| SpriteKind::Topaz
| SpriteKind::Diamond
| SpriteKind::AmethystSmall
| SpriteKind::TopazSmall
| SpriteKind::DiamondSmall
| SpriteKind::RubySmall
| SpriteKind::EmeraldSmall
| SpriteKind::SapphireSmall
| SpriteKind::CrystalHigh
| SpriteKind::CrystalLow => Some(rtsim::ChunkResource::Gem),
SpriteKind::Bloodstone
| SpriteKind::Coal
| SpriteKind::Cobalt
| SpriteKind::Copper
| SpriteKind::Iron
| SpriteKind::Tin
| SpriteKind::Silver
| SpriteKind::Gold => Some(rtsim::ChunkResource::Ore),
SpriteKind::LongGrass
| SpriteKind::MediumGrass
| SpriteKind::ShortGrass
@ -209,9 +240,48 @@ impl Block {
| SpriteKind::SavannaGrass
| SpriteKind::TallSavannaGrass
| SpriteKind::RedSavannaGrass
| SpriteKind::JungleRedGrass => Some(rtsim::ChunkResource::Grass),
SpriteKind::WildFlax => Some(rtsim::ChunkResource::Flax),
SpriteKind::Cotton => Some(rtsim::ChunkResource::Cotton),
| SpriteKind::JungleRedGrass
| SpriteKind::Fern => Some(rtsim::ChunkResource::Grass),
SpriteKind::BlueFlower
| SpriteKind::PinkFlower
| SpriteKind::PurpleFlower
| SpriteKind::RedFlower
| SpriteKind::WhiteFlower
| SpriteKind::YellowFlower
| SpriteKind::Sunflower
| SpriteKind::Moonbell
| SpriteKind::Pyrebloom => Some(rtsim::ChunkResource::Flower),
SpriteKind::Reed
| SpriteKind::Flax
| SpriteKind::WildFlax
| SpriteKind::Cotton
| SpriteKind::Corn
| SpriteKind::WheatYellow
| SpriteKind::WheatGreen => Some(rtsim::ChunkResource::Plant),
SpriteKind::Apple
| SpriteKind::Pumpkin
| SpriteKind::Beehive // TODO: Not a fruit, but kind of acts like one
| SpriteKind::Coconut => Some(rtsim::ChunkResource::Fruit),
SpriteKind::Cabbage
| SpriteKind::Carrot
| SpriteKind::Tomato
| SpriteKind::Radish
| SpriteKind::Turnip => Some(rtsim::ChunkResource::Vegetable),
SpriteKind::Mushroom
| SpriteKind::CaveMushroom
| SpriteKind::CeilingMushroom => Some(rtsim::ChunkResource::Mushroom),
SpriteKind::Chest
| SpriteKind::ChestBuried
| SpriteKind::PotionMinor
| SpriteKind::DungeonChest0
| SpriteKind::DungeonChest1
| SpriteKind::DungeonChest2
| SpriteKind::DungeonChest3
| SpriteKind::DungeonChest4
| SpriteKind::DungeonChest5
| SpriteKind::CoralChest
| SpriteKind::Crate => Some(rtsim::ChunkResource::Loot),
_ => None,
}
}

View File

@ -62,6 +62,7 @@ impl RtState {
fn start_default_rules(&mut self) {
info!("Starting default rtsim rules...");
self.start_rule::<rule::setup::Setup>();
self.start_rule::<rule::replenish_resources::ReplenishResources>();
self.start_rule::<rule::simulate_npcs::SimulateNpcs>();
self.start_rule::<rule::npc_ai::NpcAi>();
}

View File

@ -1,4 +1,5 @@
pub mod npc_ai;
pub mod replenish_resources;
pub mod setup;
pub mod simulate_npcs;

View File

@ -0,0 +1,41 @@
use crate::{event::OnTick, RtState, Rule, RuleError};
use common::{terrain::TerrainChunkSize, vol::RectVolSize};
use rand::prelude::*;
use tracing::info;
use vek::*;
pub struct ReplenishResources;
/// Take 1 hour to replenish resources entirely. Makes farming unviable, but
/// probably still poorly balanced.
// TODO: Different rates for different resources?
// TODO: Non-renewable resources?
pub const REPLENISH_TIME: f32 = 60.0 * 60.0;
/// How many chunks should be replenished per tick?
pub const REPLENISH_PER_TICK: usize = 100000;
impl Rule for ReplenishResources {
fn start(rtstate: &mut RtState) -> Result<Self, RuleError> {
rtstate.bind::<Self, OnTick>(|ctx| {
let world_size = ctx.world.sim().get_size();
let mut data = ctx.state.data_mut();
// How much should be replenished for each chosen chunk to hit our target
// replenishment rate?
let replenish_amount = world_size.product() as f32 * ctx.event.dt
/ REPLENISH_TIME
/ REPLENISH_PER_TICK as f32;
for _ in 0..REPLENISH_PER_TICK {
let key = world_size.map(|e| thread_rng().gen_range(0..e as i32));
let mut res = data.nature.get_chunk_resources(key);
for (_, res) in &mut res {
*res = (*res + replenish_amount).clamp(0.0, 1.0);
}
data.nature.set_chunk_resources(key, res);
}
});
Ok(Self)
}
}

View File

@ -186,6 +186,7 @@ fn do_command(
ServerChatCommand::Tp => handle_tp,
ServerChatCommand::TpNpc => handle_tp_npc,
ServerChatCommand::NpcInfo => handle_npc_info,
ServerChatCommand::RtsimChunk => handle_rtsim_chunk,
ServerChatCommand::Unban => handle_unban,
ServerChatCommand::Version => handle_version,
ServerChatCommand::Waypoint => handle_waypoint,
@ -1262,6 +1263,61 @@ fn handle_npc_info(
}
}
fn handle_rtsim_chunk(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
args: Vec<String>,
action: &ServerChatCommand,
) -> CmdResult<()> {
use crate::rtsim2::{ChunkStates, RtSim};
let pos = position(server, target, "target")?;
let chunk_key = pos.0.xy().map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| {
e as i32 / sz as i32
});
let rtsim = server.state.ecs().read_resource::<RtSim>();
let data = rtsim.state().data();
let chunk_states = rtsim.state().resource::<ChunkStates>();
let chunk_state = match chunk_states.0.get(chunk_key) {
Some(Some(chunk_state)) => chunk_state,
Some(None) => return Err(format!("Chunk {}, {} not loaded", chunk_key.x, chunk_key.y)),
None => {
return Err(format!(
"Chunk {}, {} not within map bounds",
chunk_key.x, chunk_key.y
));
},
};
let mut info = String::new();
let _ = writeln!(
&mut info,
"-- Chunk {}, {} Resources --",
chunk_key.x, chunk_key.y
);
for (res, frac) in data.nature.get_chunk_resources(chunk_key) {
let total = chunk_state.max_res[res];
let _ = writeln!(
&mut info,
"{:?}: {} / {} ({}%)",
res,
frac * total as f32,
total,
frac * 100.0
);
}
server.notify_client(
client,
ServerGeneral::server_msg(ChatType::CommandInfo, info),
);
Ok(())
}
fn handle_spawn(
server: &mut Server,
client: EcsEntity,

View File

@ -208,11 +208,11 @@ impl RtSim {
pub fn state(&self) -> &RtState { &self.state }
}
struct ChunkStates(pub Grid<Option<LoadedChunkState>>);
pub struct ChunkStates(pub Grid<Option<LoadedChunkState>>);
struct LoadedChunkState {
pub struct LoadedChunkState {
// The maximum possible number of each resource in this chunk
max_res: EnumMap<ChunkResource, usize>,
pub max_res: EnumMap<ChunkResource, usize>,
}
pub fn add_server_systems(dispatch_builder: &mut DispatcherBuilder) {

View File

@ -1,14 +1,11 @@
use crate::rtsim2::{event::OnBlockChange, ChunkStates};
use common::{terrain::TerrainChunk, vol::RectRasterableVol};
use rtsim2::{RtState, Rule, RuleError};
use tracing::info;
pub struct DepleteResources;
impl Rule for DepleteResources {
fn start(rtstate: &mut RtState) -> Result<Self, RuleError> {
info!("Hello from the resource depletion rule!");
rtstate.bind::<Self, OnBlockChange>(|ctx| {
let key = ctx
.event
@ -35,7 +32,7 @@ impl Rule for DepleteResources {
/ chunk_state.max_res[res] as f32;
}
}
println!("Chunk resources = {:?}", chunk_res);
//println!("Chunk resources = {:?}", chunk_res);
ctx.state
.data_mut()
.nature

View File

@ -1,4 +1,4 @@
use crate::{column::ColumnSample, sim::SimChunk, Canvas, CONFIG};
use crate::{column::ColumnSample, sim::SimChunk, util::RandomField, Canvas, CONFIG};
use common::{
calendar::{Calendar, CalendarEvent},
terrain::{Block, BlockKind, SpriteKind},
@ -13,7 +13,7 @@ pub fn close(x: f32, tgt: f32, falloff: f32) -> f32 {
(1.0 - (x - tgt).abs() / falloff).max(0.0).powf(0.125)
}
/// Returns a decimal value between 0 and 1.
/// Returns a decimal value between 0 and 1.
/// The density is maximum at the middle of the highest and the lowest allowed
/// altitudes, and zero otherwise. Quadratic curve.
///
@ -1071,7 +1071,8 @@ pub fn apply_scatter_to(canvas: &mut Canvas, rng: &mut impl Rng, calendar: Optio
})
.unwrap_or(density);
if density > 0.0
&& rng.gen::<f32>() < density //RandomField::new(i as u32).chance(Vec3::new(wpos2d.x, wpos2d.y, 0), density)
// Now deterministic, chunk resources are tracked by rtsim
&& /*rng.gen::<f32>() < density*/ RandomField::new(i as u32).chance(Vec3::new(wpos2d.x, wpos2d.y, 0), density)
&& matches!(&water_mode, Underwater | Floating) == underwater
{
Some((*kind, water_mode))