diff --git a/Cargo.toml b/Cargo.toml index f4a8194459..41d8a76f9b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,10 +14,10 @@ members = [ # default profile for devs, fast to compile, okay enough to run, no debug information [profile.dev] opt-level = 2 -overflow-checks = true +overflow-checks = true debug-assertions = true panic = "abort" -debug = false +debug = true codegen-units = 8 lto = false incremental = true diff --git a/assets/voxygen/shaders/fluid-vert.glsl b/assets/voxygen/shaders/fluid-vert.glsl index 3386ebba06..a5317dba17 100644 --- a/assets/voxygen/shaders/fluid-vert.glsl +++ b/assets/voxygen/shaders/fluid-vert.glsl @@ -28,7 +28,8 @@ void main() { f_pos.z -= 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0); // Small waves - f_pos.z -= 0.05 + 0.05 * (sin(tick.x * 2.0 + f_pos.x * 2.0 + f_pos.y * 2.0) + 1.0) * 0.5; + f_pos.xy += 0.01; // Avoid z-fighting + f_pos.z -= 0.1 * (sin(tick.x * 2.0 + f_pos.x * 2.0 + f_pos.y * 2.0) + 1.0) * 0.5 - 0.1; f_col = vec3( float((v_col_light >> 8) & 0xFFu), diff --git a/assets/voxygen/shaders/postprocess-frag.glsl b/assets/voxygen/shaders/postprocess-frag.glsl index cd0c87a772..1a3c12cbbe 100644 --- a/assets/voxygen/shaders/postprocess-frag.glsl +++ b/assets/voxygen/shaders/postprocess-frag.glsl @@ -36,7 +36,6 @@ void main() { uv = clamp(uv + vec2(sin(uv.y * 16.0 + tick.x), sin(uv.x * 24.0 + tick.x)) * 0.005, 0, 1); } - vec4 aa_color = aa_apply(src_color, uv * screen_res.xy, screen_res.xy); //vec4 hsva_color = vec4(rgb2hsv(fxaa_color.rgb), fxaa_color.a); @@ -44,7 +43,7 @@ void main() { //hsva_color.z *= 0.85; //hsva_color.z = 1.0 - 1.0 / (1.0 * hsva_color.z + 1.0); //vec4 final_color = vec4(hsv2rgb(hsva_color.rgb), hsva_color.a); - + vec4 final_color = pow(aa_color, gamma); if (medium.x == 1u) { diff --git a/assets/world/map/veloren_0_5_0_0.bin b/assets/world/map/veloren_0_5_0_0.bin index c8cbb2cd01..804d3c85b8 100644 Binary files a/assets/world/map/veloren_0_5_0_0.bin and b/assets/world/map/veloren_0_5_0_0.bin differ diff --git a/voxygen/src/mesh/vol.rs b/voxygen/src/mesh/vol.rs index 46ea72808a..dafbee7b00 100644 --- a/voxygen/src/mesh/vol.rs +++ b/voxygen/src/mesh/vol.rs @@ -112,7 +112,7 @@ fn create_quad, Vec3, Rgb, f32, f32) -> P let darkness = darkness_ao.map(|e| e.0); let ao = darkness_ao.map(|e| e.1); - let ao_map = ao * 0.75 + 0.25; + let ao_map = ao * 0.85 + 0.15; if ao[0].min(ao[2]).min(darkness[0]).min(darkness[2]) < ao[1].min(ao[3]).min(darkness[1]).min(darkness[3]) diff --git a/world/src/civ/mod.rs b/world/src/civ/mod.rs index bf62c4a4cf..e2453a23b5 100644 --- a/world/src/civ/mod.rs +++ b/world/src/civ/mod.rs @@ -1,6 +1,9 @@ mod econ; -use std::ops::Range; +use std::{ + ops::Range, + hash::Hash, +}; use hashbrown::{HashMap, HashSet}; use vek::*; use rand::prelude::*; @@ -137,7 +140,7 @@ impl Civs { fn birth_civ(&mut self, ctx: &mut GenCtx) -> Option> { let site = attempt(5, || { let loc = find_site_loc(ctx, None)?; - self.establish_site(ctx, loc, SiteKind::Settlement(Settlement::civ_birthplace())) + self.establish_site(ctx, loc) })?; let civ = self.civs.insert(Civ { @@ -191,7 +194,7 @@ impl Civs { Some(place) } - fn establish_site(&mut self, ctx: &mut GenCtx, loc: Vec2, kind: SiteKind) -> Option> { + fn establish_site(&mut self, ctx: &mut GenCtx, loc: Vec2) -> Option> { const SITE_AREA: Range = 64..256; let place = match ctx.sim.get(loc).and_then(|site| site.place) { @@ -200,9 +203,16 @@ impl Civs { }; let site = self.sites.insert(Site { - kind, + kind: SiteKind::Settlement, center: loc, place: place, + + population: 24.0, + labor: MapVec::default(), + output: MapVec::default(), + stocks: Stocks::default(), + trade_states: Stocks::default(), + coin: 1000.0, }); // Find neighbors @@ -214,7 +224,7 @@ impl Civs { .collect::>(); nearby.sort_by_key(|(_, dist)| *dist as i32); - for (nearby, _) in nearby.into_iter() { + for (nearby, _) in nearby.into_iter().take(5) { // Find a novel path if let Some((path, cost)) = find_path(ctx, loc, self.sites.get(nearby).center) { // Find a path using existing paths @@ -242,9 +252,7 @@ impl Civs { fn tick(&mut self, ctx: &mut GenCtx, years: f32) { // Collect stocks for site in self.sites.iter_mut() { - if let SiteKind::Settlement(s) = &mut site.kind { - s.collect_stocks(years, &self.places.get(site.place).nat_res); - } + site.collect_stocks(years, &self.places.get(site.place).nat_res); } // Trade stocks @@ -253,10 +261,9 @@ impl Civs { for stock in stocks.iter().copied() { let mut sell_orders = self.sites .iter_ids() - .filter_map(|(id, site)| site.as_settlement().map(|s| (id, s))) - .map(|(id, settlement)| (id, econ::SellOrder { - quantity: settlement.trade_states[stock].surplus.min(settlement.stocks[stock]), - price: settlement.trade_states[stock].sell_belief.choose_price(ctx), + .map(|(id, site)| (id, econ::SellOrder { + quantity: site.trade_states[stock].surplus.min(site.stocks[stock]), + price: site.trade_states[stock].sell_belief.choose_price(ctx) * 1.5, // Transport cost of 1.5x q_sold: 0.0, })) .filter(|(_, order)| order.quantity > 0.0) @@ -264,15 +271,15 @@ impl Civs { let mut sites = self.sites .ids() - .filter(|id| self.sites.get(*id).as_settlement().is_some()) .collect::>(); sites.shuffle(ctx.rng); // Give all sites a chance to buy first for site in sites { let (max_spend, max_price) = { - let settlement = self.sites.get(site).as_settlement().unwrap(); + let site = self.sites.get(site); + let budget = site.coin * 0.5; ( - settlement.trade_states[stock].purchase_priority * settlement.coin, - settlement.trade_states[stock].buy_belief.price, + (site.trade_states[stock].purchase_priority * budget).min(budget), + site.trade_states[stock].buy_belief.price, ) }; let (quantity, spent) = econ::buy_units(ctx, sell_orders @@ -283,82 +290,28 @@ impl Civs { 1000000.0, // Max price TODO max_spend, ); - let mut settlement = self.sites.get_mut(site).as_settlement_mut().unwrap(); - settlement.coin -= spent; + let mut site = self.sites.get_mut(site); + site.coin -= spent; if quantity > 0.0 { - settlement.stocks[stock] += quantity; - settlement.trade_states[stock].buy_belief.update_buyer(years, spent / quantity); - println!("Belief: {:?}", settlement.trade_states[stock].buy_belief); + site.stocks[stock] += quantity; + site.trade_states[stock].buy_belief.update_buyer(years, spent / quantity); + println!("Belief: {:?}", site.trade_states[stock].buy_belief); } } for (site, order) in sell_orders { - let mut settlement = self.sites.get_mut(site).as_settlement_mut().unwrap(); - settlement.coin += order.q_sold * order.price; + let mut site = self.sites.get_mut(site); + site.coin += order.q_sold * order.price; if order.q_sold > 0.0 { - settlement.stocks[stock] -= order.q_sold; - settlement.trade_states[stock].sell_belief.update_seller(order.q_sold / order.quantity); + site.stocks[stock] -= order.q_sold; + site.trade_states[stock].sell_belief.update_seller(order.q_sold / order.quantity); } } } - // Trade stocks - /* - let mut sites = self.sites.ids().collect::>(); - sites.shuffle(ctx.rng); // Give all sites a chance to buy first - for site in sites { - let mut stocks = [FOOD, WOOD, ROCK]; - stocks.shuffle(ctx.rng); // Give each stock a chance to be traded first - for stock in stocks.iter().copied() { - if self.sites.get(site).as_settlement().is_none() { - continue; - } - - let settlement = self.sites.get(site).as_settlement().unwrap(); - let quantity_to_buy = settlement.trade_states[stock].buy_q; - let mut bought_quantity = 0.0; - let mut coin = settlement.coin; - drop(settlement); - let mut sell_orders = self - .neighbors(site) - .collect::>() - .into_iter() - .filter_map(|n| self.sites.get(n).as_settlement().map(|s| (n, s))) - .map(|(n, neighbor)| { - // TODO: Add speculation, don't use the domestic value to rationalise price - let trade_state = &neighbor.trade_states[stock]; - let sell_q = trade_state.sell_q.min(neighbor.stocks[stock]); - (n, trade_state.domestic_value, sell_q) - }) - .collect::>(); - sell_orders.sort_by_key(|(_, price, _)| (*price * 1000.0) as i64); - - for (n, price, sell_q) in sell_orders { - if bought_quantity >= quantity_to_buy { - break; - } else { - let buy_quantity = (quantity_to_buy - bought_quantity).min(sell_q).min(coin / price); - let payment = buy_quantity * price; - bought_quantity += buy_quantity; - coin -= payment; - let mut neighbor = self.sites.get_mut(n).as_settlement_mut().unwrap(); - neighbor.stocks[stock] -= buy_quantity; - neighbor.coin += payment; - } - } - - let mut settlement = self.sites.get_mut(site).as_settlement_mut().unwrap(); - settlement.stocks[stock] += bought_quantity; - settlement.coin = coin; - } - } - */ - // Consume stocks for site in self.sites.iter_mut() { - if let SiteKind::Settlement(s) = &mut site.kind { - s.consume_stocks(years); - } + site.consume_stocks(years); } } } @@ -473,7 +426,7 @@ impl NaturalResources { self.wood += chunk.tree_density; self.stone += chunk.rockiness; - self.river += if chunk.river.is_river() { 1.0 } else { 0.0 }; + self.river += if chunk.river.is_river() { 5.0 } else { 0.0 }; self.farmland += if chunk.humidity > 0.35 && chunk.temp > -0.3 && chunk.temp < 0.75 && @@ -495,81 +448,63 @@ pub struct Site { kind: SiteKind, center: Vec2, pub place: Id, -} -impl Site { - pub fn as_settlement(&self) -> Option<&Settlement> { - if let SiteKind::Settlement(s) = &self.kind { - Some(s) - } else { - None - } - } - - pub fn as_settlement_mut(&mut self) -> Option<&mut Settlement> { - if let SiteKind::Settlement(s) = &mut self.kind { - Some(s) - } else { - None - } - } -} - -#[derive(Debug)] -pub enum SiteKind { - Settlement(Settlement), -} - -#[derive(Debug)] -pub struct Settlement { population: f32, + labor: MapVec, + output: MapVec, stocks: Stocks, trade_states: Stocks, coin: f32, } -impl Settlement { - pub fn civ_birthplace() -> Self { - Self { - population: 24.0, - stocks: Stocks::default(), - trade_states: Stocks::default(), - coin: 1000.0, - } - } +#[derive(Debug)] +pub enum SiteKind { + Settlement, +} +impl Site { pub fn collect_stocks(&mut self, years: f32, nat_res: &NaturalResources) { // Per labourer, per year let collection_rate = Stocks::from_list(&[ - (FOOD, 2.0), - (ROCK, 0.6), - (WOOD, 1.5), + (FARMER, 2.0), + (LUMBERJACK, 1.5), + (MINER, 0.6), + (FISHER, 5.0), ]); - // Proportion of the population dedicated to each task - let workforce_ratios = Stocks::from_list(&[ - (FOOD, self.trade_states[FOOD].domestic_value), - (ROCK, self.trade_states[ROCK].domestic_value), - (WOOD, self.trade_states[WOOD].domestic_value), + // Proportion of the population dedicated to each task (output * price) + let labor_ratios = Stocks::from_list(&[ + (FARMER, self.output[FARMER] * self.trade_states[FOOD].domestic_value), + (LUMBERJACK, self.output[LUMBERJACK] * self.trade_states[WOOD].domestic_value), + (MINER, self.output[MINER] * self.trade_states[ROCK].domestic_value), + (FISHER, self.output[FISHER] * self.trade_states[FOOD].domestic_value), ]); - // Normalise workforce proportions - let wf_total = workforce_ratios.iter().map(|(_, r)| *r).sum::(); - let workforce = workforce_ratios.map(|stock, r| r / wf_total * self.population); - self.stocks[FOOD] += years * (workforce[FOOD] * collection_rate[FOOD] + nat_res.farmland * 0.01).min(nat_res.farmland); - self.stocks[ROCK] += years * (workforce[ROCK] * collection_rate[ROCK] + nat_res.stone * 0.01).min(nat_res.stone); - self.stocks[WOOD] += years * (workforce[WOOD] * collection_rate[WOOD] + nat_res.wood * 0.01).min(nat_res.wood); + // Normalise workforce proportions (so we aren't over-allocating our workforce) + let wf_total = labor_ratios.iter().map(|(_, r)| *r).sum::(); + if wf_total == 0.0 { // 0 output doesn't mean NaNs + let n = labor_ratios.iter().count() as f32; + self.labor = labor_ratios.map(|stock, _| self.population / n); + } else { + self.labor = labor_ratios.map(|stock, r| r / wf_total * self.population); + } - println!("{:?}", nat_res); - println!("{:?}", self.stocks); + self.output[FARMER] = (self.labor[FARMER] * collection_rate[FARMER] + nat_res.farmland * 0.01).min(nat_res.farmland); + self.output[LUMBERJACK] = (self.labor[LUMBERJACK] * collection_rate[LUMBERJACK] + nat_res.wood * 0.01).min(nat_res.wood); + self.output[MINER] = (self.labor[MINER] * collection_rate[MINER] + nat_res.stone * 0.01).min(nat_res.stone); + self.output[FISHER] = (self.labor[FISHER] * collection_rate[FISHER] + nat_res.river * 0.01).min(nat_res.river); + + self.stocks[FOOD] += years * self.output[FARMER]; + self.stocks[WOOD] += years * self.output[LUMBERJACK]; + self.stocks[ROCK] += years * self.output[MINER]; + self.stocks[FOOD] += years * self.output[FISHER]; } pub fn consume_stocks(&mut self, years: f32) { - const EAT_RATE: f32 = 0.5; + const EAT_RATE: f32 = 1.0; const USE_WOOD_RATE: f32 = 0.75; - const BIRTH_RATE: f32 = 0.1; - - self.population += years * BIRTH_RATE; + const BIRTH_RATE: f32 = 0.15; + const DEATH_RATE: f32 = 0.05; let required = Stocks::from_list(&[ (FOOD, self.population as f32 * years * EAT_RATE), @@ -583,8 +518,12 @@ impl Settlement { // Deplete stocks self.stocks.iter_mut().for_each(|(stock, v)| *v = (*v - required[stock]).max(0.0)); + // Births + self.population += years * self.population * BIRTH_RATE; + // Kill people - self.population = (self.population - deficit[FOOD] * years * EAT_RATE).max(0.0); + self.population -= years * self.population * DEATH_RATE; // Natural death rate + self.population = (self.population - deficit[FOOD] * years * EAT_RATE).max(0.0); // Starvation // If in deficit, value the stock more deficit.iter().for_each(|(stock, deficit)| { @@ -611,6 +550,12 @@ impl Settlement { } } +type Occupation = &'static str; +const FARMER: Occupation = "farmer"; +const LUMBERJACK: Occupation = "lumberjack"; +const MINER: Occupation = "miner"; +const FISHER: Occupation = "fisher"; + type Stock = &'static str; const FOOD: Stock = "food"; const WOOD: Stock = "wood"; @@ -644,15 +589,17 @@ impl Default for TradeState { } } +pub type Stocks = MapVec; + #[derive(Default, Clone, Debug)] -pub struct Stocks { - stocks: HashMap, +pub struct MapVec { + stocks: HashMap, zero: T, } -impl Stocks { - pub fn from_list<'a>(i: impl IntoIterator) -> Self - where T: 'a +impl MapVec { + pub fn from_list<'a>(i: impl IntoIterator) -> Self + where K: 'a, T: 'a { Self { stocks: i.into_iter().cloned().collect(), @@ -660,38 +607,38 @@ impl Stocks { } } - pub fn get_mut(&mut self, stock: Stock) -> &mut T { + pub fn get_mut(&mut self, stock: K) -> &mut T { self .stocks .entry(stock) .or_default() } - pub fn get(&self, stock: Stock) -> &T { + pub fn get(&self, stock: K) -> &T { self.stocks.get(&stock).unwrap_or(&self.zero) } - pub fn map(mut self, mut f: impl FnMut(Stock, T) -> T) -> Self { + pub fn map(mut self, mut f: impl FnMut(K, T) -> T) -> Self { self.stocks.iter_mut().for_each(|(s, v)| *v = f(*s, std::mem::take(v))); self } - pub fn iter(&self) -> impl Iterator + '_ { + pub fn iter(&self) -> impl Iterator + '_ { self.stocks.iter().map(|(s, v)| (*s, v)) } - pub fn iter_mut(&mut self) -> impl Iterator + '_ { + pub fn iter_mut(&mut self) -> impl Iterator + '_ { self.stocks.iter_mut().map(|(s, v)| (*s, v)) } } -impl std::ops::Index for Stocks { +impl std::ops::Index for MapVec { type Output = T; - fn index(&self, stock: Stock) -> &Self::Output { self.get(stock) } + fn index(&self, stock: K) -> &Self::Output { self.get(stock) } } -impl std::ops::IndexMut for Stocks { - fn index_mut(&mut self, stock: Stock) -> &mut Self::Output { self.get_mut(stock) } +impl std::ops::IndexMut for MapVec { + fn index_mut(&mut self, stock: K) -> &mut Self::Output { self.get_mut(stock) } } diff --git a/world/src/site/settlement/mod.rs b/world/src/site/settlement/mod.rs index 6989fb7dc6..92922f0324 100644 --- a/world/src/site/settlement/mod.rs +++ b/world/src/site/settlement/mod.rs @@ -285,7 +285,9 @@ impl Settlement { .map(|tile| tile.tower = Some(Tower::Wall)); } } - wall_path.push(wall_path[0]); + if wall_path.len() > 0 { + wall_path.push(wall_path[0]); + } self.land .write_path(&wall_path, WayKind::Wall, buildable, true); }