2021-05-28 18:42:29 +00:00
|
|
|
use common::{
|
|
|
|
terrain::BiomeKind,
|
|
|
|
trade::{Good, SitePrices},
|
|
|
|
};
|
|
|
|
use rayon::ThreadPoolBuilder;
|
|
|
|
use rusqlite::{Connection, ToSql};
|
|
|
|
use std::error::Error;
|
|
|
|
use strum::IntoEnumIterator;
|
|
|
|
use vek::Vec2;
|
|
|
|
use veloren_world::{
|
|
|
|
index::Index,
|
|
|
|
sim::{FileOpts, WorldOpts, DEFAULT_WORLD_MAP},
|
|
|
|
World,
|
|
|
|
};
|
|
|
|
|
|
|
|
fn good_pricing_csv(world: &World, index: &Index) -> Result<(), Box<dyn Error>> {
|
|
|
|
let mut csv = csv::Writer::from_path("good_pricing.csv")?;
|
|
|
|
csv.write_record(&[
|
|
|
|
"Site",
|
|
|
|
"XCoord",
|
|
|
|
"YCoord",
|
|
|
|
"Flour",
|
|
|
|
"Meat",
|
|
|
|
"Transportation",
|
|
|
|
"Food",
|
|
|
|
"Wood",
|
|
|
|
"Stone",
|
|
|
|
"Tools",
|
|
|
|
"Armor",
|
|
|
|
"Ingredients",
|
|
|
|
"Potions",
|
|
|
|
"Coin",
|
|
|
|
"RoadSecurity",
|
|
|
|
])?;
|
|
|
|
|
|
|
|
for civsite in world.civs().sites() {
|
|
|
|
if let Some(site_id) = civsite.site_tmp {
|
|
|
|
let site = index.sites.get(site_id);
|
|
|
|
if site.do_economic_simulation() {
|
|
|
|
let prices = site.economy.get_site_prices();
|
|
|
|
//println!("{:?}: {:?} {:?}", site.name(), civsite.center, prices);
|
|
|
|
csv.write_record(&[
|
|
|
|
site.name(),
|
|
|
|
&format!("{}", civsite.center.x),
|
|
|
|
&format!("{}", civsite.center.y),
|
|
|
|
&format!("{}", prices.values.get(&Good::Flour).unwrap_or(&0.0)),
|
|
|
|
&format!("{}", prices.values.get(&Good::Meat).unwrap_or(&0.0)),
|
|
|
|
&format!(
|
|
|
|
"{}",
|
|
|
|
prices.values.get(&Good::Transportation).unwrap_or(&0.0)
|
|
|
|
),
|
|
|
|
&format!("{}", prices.values.get(&Good::Food).unwrap_or(&0.0)),
|
|
|
|
&format!("{}", prices.values.get(&Good::Wood).unwrap_or(&0.0)),
|
|
|
|
&format!("{}", prices.values.get(&Good::Stone).unwrap_or(&0.0)),
|
|
|
|
&format!("{}", prices.values.get(&Good::Tools).unwrap_or(&0.0)),
|
|
|
|
&format!("{}", prices.values.get(&Good::Armor).unwrap_or(&0.0)),
|
|
|
|
&format!("{}", prices.values.get(&Good::Ingredients).unwrap_or(&0.0)),
|
|
|
|
&format!("{}", prices.values.get(&Good::Potions).unwrap_or(&0.0)),
|
|
|
|
&format!("{}", prices.values.get(&Good::Coin).unwrap_or(&0.0)),
|
|
|
|
&format!("{}", prices.values.get(&Good::RoadSecurity).unwrap_or(&0.0)),
|
|
|
|
])?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn economy_sqlite(world: &World, index: &Index) -> Result<(), Box<dyn Error>> {
|
|
|
|
let conn = Connection::open("economy.sqlite")?;
|
|
|
|
#[rustfmt::skip]
|
|
|
|
conn.execute_batch("
|
2021-05-28 20:14:31 +00:00
|
|
|
DROP TABLE IF EXISTS site;
|
|
|
|
CREATE TABLE site (
|
2021-05-28 18:42:29 +00:00
|
|
|
xcoord INTEGER NOT NULL,
|
2021-06-28 19:02:57 +00:00
|
|
|
ycoord INTEGER NOT NULL,
|
2021-05-28 18:42:29 +00:00
|
|
|
name TEXT NOT NULL
|
|
|
|
);
|
2021-05-28 20:14:31 +00:00
|
|
|
CREATE UNIQUE INDEX site_position ON site(xcoord, ycoord);
|
|
|
|
DROP TABLE IF EXISTS site_price;
|
|
|
|
CREATE TABLE site_price (
|
2021-05-28 18:42:29 +00:00
|
|
|
xcoord INTEGER NOT NULL,
|
|
|
|
ycoord INTEGER NOT NULL,
|
|
|
|
good TEXT NOT NULL,
|
|
|
|
price REAL NOT NULL
|
|
|
|
);
|
2021-05-28 20:14:31 +00:00
|
|
|
CREATE UNIQUE INDEX site_good on site_price(xcoord, ycoord, good);
|
2021-05-28 18:42:29 +00:00
|
|
|
")?;
|
|
|
|
let mut all_goods = Vec::new();
|
|
|
|
for good in Good::iter() {
|
|
|
|
match good {
|
|
|
|
Good::Territory(_) => {
|
|
|
|
for biome in BiomeKind::iter() {
|
|
|
|
all_goods.push(Good::Territory(biome));
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Good::Terrain(_) => {
|
|
|
|
for biome in BiomeKind::iter() {
|
|
|
|
all_goods.push(Good::Terrain(biome));
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
all_goods.push(good);
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut good_columns = String::new();
|
|
|
|
let mut good_exprs = String::new();
|
|
|
|
for good in all_goods.iter() {
|
|
|
|
good_columns += &format!(", '{:?}'", good);
|
|
|
|
good_exprs += &format!(
|
|
|
|
", MAX(CASE WHEN site_price.good = '{:?}' THEN site_price.price END)",
|
|
|
|
good
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[rustfmt::skip]
|
|
|
|
let create_view = format!("
|
2021-05-28 20:14:31 +00:00
|
|
|
DROP VIEW IF EXISTS site_price_tr;
|
|
|
|
CREATE VIEW site_price_tr (xcoord, ycoord {})
|
2021-05-28 18:42:29 +00:00
|
|
|
AS SELECT xcoord, ycoord {}
|
|
|
|
FROM site NATURAL JOIN site_price
|
2021-05-28 20:14:31 +00:00
|
|
|
GROUP BY xcoord, ycoord;
|
2021-05-28 18:42:29 +00:00
|
|
|
", good_columns, good_exprs);
|
|
|
|
conn.execute_batch(&create_view)?;
|
|
|
|
let mut insert_price_stmt = conn
|
|
|
|
.prepare("REPLACE INTO site_price (xcoord, ycoord, good, price) VALUES (?1, ?2, ?3, ?4)")?;
|
|
|
|
let mut insert_price = move |center: Vec2<i32>, good: Good, prices: &SitePrices| {
|
|
|
|
let price = prices.values.get(&good).unwrap_or(&0.0);
|
|
|
|
insert_price_stmt.execute(&[
|
|
|
|
¢er.x as &dyn ToSql,
|
|
|
|
¢er.y,
|
|
|
|
&format!("{:?}", good),
|
|
|
|
&(*price as f64),
|
|
|
|
])
|
|
|
|
};
|
|
|
|
for civsite in world.civs().sites() {
|
|
|
|
if let Some(site_id) = civsite.site_tmp {
|
|
|
|
let site = index.sites.get(site_id);
|
|
|
|
if site.do_economic_simulation() {
|
|
|
|
let prices = site.economy.get_site_prices();
|
|
|
|
conn.execute(
|
|
|
|
"REPLACE INTO site (xcoord, ycoord, name) VALUES (?1, ?2, ?3)",
|
|
|
|
&[
|
|
|
|
&civsite.center.x as &dyn ToSql,
|
|
|
|
&civsite.center.y,
|
|
|
|
&site.name(),
|
|
|
|
],
|
|
|
|
)?;
|
|
|
|
for good in all_goods.iter() {
|
|
|
|
insert_price(civsite.center, *good, &prices)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
common_frontend::init_stdout(None);
|
|
|
|
println!("Loading world");
|
|
|
|
let pool = ThreadPoolBuilder::new().build().unwrap();
|
|
|
|
let (world, index) = World::generate(
|
|
|
|
59686,
|
|
|
|
WorldOpts {
|
|
|
|
seed_elements: true,
|
|
|
|
world_file: FileOpts::LoadAsset(DEFAULT_WORLD_MAP.into()),
|
|
|
|
},
|
|
|
|
&pool,
|
|
|
|
);
|
|
|
|
println!("Loaded world");
|
|
|
|
|
|
|
|
if let Err(e) = good_pricing_csv(&world, &index) {
|
|
|
|
println!("Error generating goodpricing csv: {:?}", e);
|
|
|
|
}
|
|
|
|
if let Err(e) = economy_sqlite(&world, &index) {
|
|
|
|
println!("Error generating economy sqlite db: {:?}", e);
|
|
|
|
}
|
|
|
|
}
|