mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Create asset_migrate bin from entity_migrate
This commit is contained in:
parent
79a04c3533
commit
43b5af2980
@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
time cargo clippy --all-targets --locked --features="bin_cmd_doc_gen,bin_compression,bin_csv,bin_graphviz,bin_bot,bin_entity_migrate,asset_tweak" -- -D warnings &&
|
||||
time cargo clippy --all-targets --locked --features="bin_cmd_doc_gen,bin_compression,bin_csv,bin_graphviz,bin_bot,bin_asset_migrate,asset_tweak" -- -D warnings &&
|
||||
# Ensure that the veloren-voxygen default-publish feature builds as it excludes some default features
|
||||
time cargo clippy -p veloren-voxygen --locked --no-default-features --features="default-publish" -- -D warnings &&
|
||||
time cargo fmt --all -- --check
|
||||
|
@ -11,7 +11,7 @@ simd = ["vek/platform_intrinsics"]
|
||||
bin_csv = ["ron", "csv", "structopt"]
|
||||
bin_graphviz = ["petgraph"]
|
||||
bin_cmd_doc_gen = []
|
||||
bin_entity_migrate = ["ron"]
|
||||
bin_asset_migrate = ["ron"]
|
||||
rrt_pathfinding = ["kiddo"]
|
||||
calendar_events = []
|
||||
|
||||
@ -108,8 +108,8 @@ name = "csv_import"
|
||||
required-features = ["bin_csv"]
|
||||
|
||||
[[bin]]
|
||||
name = "entity_migrate"
|
||||
required-features = ["bin_entity_migrate"]
|
||||
name = "asset_migrate"
|
||||
required-features = ["bin_asset_migrate"]
|
||||
|
||||
[[bin]]
|
||||
name = "recipe_graphviz"
|
||||
|
146
common/src/bin/asset_migrate.rs
Normal file
146
common/src/bin/asset_migrate.rs
Normal file
@ -0,0 +1,146 @@
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use std::{
|
||||
fs, io,
|
||||
io::Write,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
/// Old version.
|
||||
mod v1 {
|
||||
use super::*;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Example {
|
||||
pub field: u8,
|
||||
}
|
||||
}
|
||||
|
||||
/// New version.
|
||||
mod v2 {
|
||||
use super::*;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Example {
|
||||
pub field: f64,
|
||||
}
|
||||
|
||||
impl From<super::v1::Example> for Example {
|
||||
fn from(old: super::v1::Example) -> Self {
|
||||
Self {
|
||||
field: f64::from(old.field),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Walk {
|
||||
File(PathBuf),
|
||||
Dir { path: PathBuf, content: Vec<Walk> },
|
||||
}
|
||||
|
||||
fn walk_tree(dir: &Path, root: &Path) -> io::Result<Vec<Walk>> {
|
||||
let mut buff = Vec::new();
|
||||
for entry in fs::read_dir(dir)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
if path.is_dir() {
|
||||
buff.push(Walk::Dir {
|
||||
path: path
|
||||
.strip_prefix(root)
|
||||
.expect("strip can't fail, this path is created from root")
|
||||
.to_owned(),
|
||||
content: walk_tree(&path, root)?,
|
||||
});
|
||||
} else {
|
||||
let filename = path
|
||||
.strip_prefix(root)
|
||||
.expect("strip can't fail, this file is created from root")
|
||||
.to_owned();
|
||||
buff.push(Walk::File(filename));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(buff)
|
||||
}
|
||||
|
||||
fn walk_with_migrate<OldV, NewV>(tree: Walk, from: &Path, to: &Path) -> std::io::Result<()>
|
||||
where
|
||||
NewV: From<OldV>,
|
||||
OldV: DeserializeOwned,
|
||||
NewV: Serialize,
|
||||
{
|
||||
match tree {
|
||||
Walk::Dir { path, content } => {
|
||||
let target_dir = to.join(path);
|
||||
fs::create_dir_all(target_dir)?;
|
||||
for entry in content {
|
||||
walk_with_migrate::<OldV, NewV>(entry, from, to)?;
|
||||
}
|
||||
},
|
||||
Walk::File(path) => {
|
||||
let source = fs::File::open(from.join(&path))?;
|
||||
let old: OldV = ron::de::from_reader(source).unwrap();
|
||||
let new: NewV = old.into();
|
||||
let target = fs::File::create(to.join(&path))?;
|
||||
let pretty_config = ron::ser::PrettyConfig::new();
|
||||
ron::ser::to_writer_pretty(target, &new, pretty_config).unwrap();
|
||||
println!("{path:?} done");
|
||||
},
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn convert_loop(from: &str, to: &str) {
|
||||
let root = Path::new(from);
|
||||
let files = Walk::Dir {
|
||||
path: Path::new("").to_owned(),
|
||||
content: walk_tree(root, root).unwrap(),
|
||||
};
|
||||
walk_with_migrate::<v1::Example, v2::Example>(files, Path::new(from), Path::new(to)).unwrap();
|
||||
}
|
||||
|
||||
fn input_string(prompt: &str) -> String { input_validated_string(prompt, &|_| true) }
|
||||
|
||||
fn input_validated_string(prompt: &str, check: &dyn Fn(&str) -> bool) -> String {
|
||||
println!("{}", prompt);
|
||||
|
||||
print!("> ");
|
||||
io::stdout().flush().unwrap();
|
||||
|
||||
let mut buff = String::new();
|
||||
io::stdin().read_line(&mut buff).unwrap();
|
||||
|
||||
while !check(buff.trim()) {
|
||||
buff.clear();
|
||||
print!("> ");
|
||||
io::stdout().flush().unwrap();
|
||||
io::stdin().read_line(&mut buff).unwrap();
|
||||
}
|
||||
|
||||
buff.trim().to_owned()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let prompt = r#"
|
||||
Stub implementation.
|
||||
If you want to migrate new assets, edit `v1` and `v2` modules.
|
||||
If you want to migrate old assets, check commit history.
|
||||
"#;
|
||||
println!("{prompt}");
|
||||
|
||||
let old_dir = input_validated_string(
|
||||
"Please input directory path with old entity configs:",
|
||||
&|path| {
|
||||
if !Path::new(path).exists() {
|
||||
eprintln!("Source directory '{path}' does not exists.");
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
},
|
||||
);
|
||||
let new_dir = input_string("Please input directory path to place new entity configs:");
|
||||
|
||||
convert_loop(&old_dir, &new_dir)
|
||||
}
|
@ -1,331 +0,0 @@
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use veloren_common::{
|
||||
comp::{inventory::loadout_builder::ItemSpec, Alignment, Body},
|
||||
lottery::LootSpec,
|
||||
};
|
||||
|
||||
use std::{
|
||||
fs, io,
|
||||
io::Write,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
/// First "stable" version.
|
||||
mod v1 {
|
||||
pub(super) use super::*;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub enum NameKind {
|
||||
Name(String),
|
||||
Automatic,
|
||||
Uninit,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub enum BodyBuilder {
|
||||
RandomWith(String),
|
||||
Exact(Body),
|
||||
Uninit,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub enum AlignmentMark {
|
||||
Alignment(Alignment),
|
||||
Uninit,
|
||||
}
|
||||
|
||||
impl Default for AlignmentMark {
|
||||
fn default() -> Self { Self::Alignment(Alignment::Wild) }
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub enum Hands {
|
||||
TwoHanded(ItemSpec),
|
||||
Paired(ItemSpec),
|
||||
Mix {
|
||||
mainhand: ItemSpec,
|
||||
offhand: ItemSpec,
|
||||
},
|
||||
Uninit,
|
||||
}
|
||||
|
||||
impl Default for Hands {
|
||||
fn default() -> Self { Self::Uninit }
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub enum Meta {
|
||||
LoadoutAsset(String),
|
||||
SkillSetAsset(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct EntityConfig {
|
||||
pub name: NameKind,
|
||||
pub body: BodyBuilder,
|
||||
pub alignment: AlignmentMark,
|
||||
pub loot: LootSpec<String>,
|
||||
pub hands: Hands,
|
||||
#[serde(default)]
|
||||
pub meta: Vec<Meta>,
|
||||
}
|
||||
}
|
||||
|
||||
/// Loadout update.
|
||||
/// 1) Added ability to randomize loadout for entity.
|
||||
/// 2) Simplified logic by squashing hands, loadout and inventory into one pack.
|
||||
mod v2 {
|
||||
pub(super) use super::*;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub enum LoadoutAsset {
|
||||
Loadout(String),
|
||||
Choice(Vec<(f32, String)>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub enum Hands {
|
||||
TwoHanded(ItemSpec),
|
||||
Paired(ItemSpec),
|
||||
Mix {
|
||||
mainhand: ItemSpec,
|
||||
offhand: ItemSpec,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub enum LoadoutKind {
|
||||
FromBody,
|
||||
Asset(LoadoutAsset),
|
||||
Hands(Hands),
|
||||
Extended {
|
||||
hands: Hands,
|
||||
base_asset: LoadoutAsset,
|
||||
inventory: Vec<(u32, String)>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub enum Meta {
|
||||
SkillSetAsset(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct EntityConfig {
|
||||
pub name: super::v1::NameKind,
|
||||
pub body: super::v1::BodyBuilder,
|
||||
pub alignment: super::v1::AlignmentMark,
|
||||
pub loadout: LoadoutKind,
|
||||
pub loot: super::v1::LootSpec<String>,
|
||||
#[serde(default)]
|
||||
pub meta: Vec<Meta>,
|
||||
}
|
||||
|
||||
impl From<super::v1::EntityConfig> for EntityConfig {
|
||||
fn from(old_config: super::v1::EntityConfig) -> Self {
|
||||
let mut loadout_asset = None;
|
||||
let mut meta = Vec::new();
|
||||
|
||||
for item in old_config.meta {
|
||||
match item {
|
||||
super::v1::Meta::SkillSetAsset(asset) => {
|
||||
meta.push(Meta::SkillSetAsset(asset));
|
||||
},
|
||||
super::v1::Meta::LoadoutAsset(asset) => {
|
||||
if loadout_asset == None {
|
||||
loadout_asset = Some(asset);
|
||||
} else {
|
||||
tracing::error!("multiple loadout assets in meta[], bad");
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
let loadout_kind = match loadout_asset {
|
||||
Some(asset) => match old_config.hands {
|
||||
super::v1::Hands::TwoHanded(spec) => LoadoutKind::Extended {
|
||||
hands: Hands::TwoHanded(spec),
|
||||
base_asset: LoadoutAsset::Loadout(asset),
|
||||
inventory: vec![],
|
||||
},
|
||||
super::v1::Hands::Paired(spec) => LoadoutKind::Extended {
|
||||
hands: Hands::Paired(spec),
|
||||
base_asset: LoadoutAsset::Loadout(asset),
|
||||
inventory: vec![],
|
||||
},
|
||||
super::v1::Hands::Mix { mainhand, offhand } => LoadoutKind::Extended {
|
||||
hands: Hands::Mix { mainhand, offhand },
|
||||
base_asset: LoadoutAsset::Loadout(asset),
|
||||
inventory: vec![],
|
||||
},
|
||||
super::v1::Hands::Uninit => LoadoutKind::Asset(LoadoutAsset::Loadout(asset)),
|
||||
},
|
||||
None => match old_config.hands {
|
||||
super::v1::Hands::TwoHanded(spec) => LoadoutKind::Hands(Hands::TwoHanded(spec)),
|
||||
super::v1::Hands::Paired(spec) => LoadoutKind::Hands(Hands::Paired(spec)),
|
||||
super::v1::Hands::Mix { mainhand, offhand } => {
|
||||
LoadoutKind::Hands(Hands::Mix { mainhand, offhand })
|
||||
},
|
||||
super::v1::Hands::Uninit => LoadoutKind::FromBody,
|
||||
},
|
||||
};
|
||||
|
||||
Self {
|
||||
name: old_config.name,
|
||||
body: old_config.body,
|
||||
alignment: old_config.alignment,
|
||||
loadout: loadout_kind,
|
||||
loot: old_config.loot,
|
||||
meta,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn input_string(prompt: &str) -> String { input_validated_string(prompt, &|_| true) }
|
||||
|
||||
fn input_validated_string(prompt: &str, check: &dyn Fn(&str) -> bool) -> String {
|
||||
println!("{}", prompt);
|
||||
|
||||
print!("> ");
|
||||
io::stdout().flush().unwrap();
|
||||
|
||||
let mut buff = String::new();
|
||||
io::stdin().read_line(&mut buff).unwrap();
|
||||
|
||||
while !check(buff.trim()) {
|
||||
buff.clear();
|
||||
print!("> ");
|
||||
io::stdout().flush().unwrap();
|
||||
io::stdin().read_line(&mut buff).unwrap();
|
||||
}
|
||||
|
||||
buff.trim().to_owned()
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Walk {
|
||||
File(PathBuf),
|
||||
Dir { path: PathBuf, content: Vec<Walk> },
|
||||
}
|
||||
|
||||
fn walk_tree(dir: &Path, root: &Path) -> io::Result<Vec<Walk>> {
|
||||
let mut buff = Vec::new();
|
||||
for entry in fs::read_dir(dir)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
if path.is_dir() {
|
||||
buff.push(Walk::Dir {
|
||||
path: path
|
||||
.strip_prefix(root)
|
||||
.expect("strip can't fail, this path is created from root")
|
||||
.to_owned(),
|
||||
content: walk_tree(&path, root)?,
|
||||
});
|
||||
} else {
|
||||
let filename = path
|
||||
.strip_prefix(root)
|
||||
.expect("strip can't fail, this file is created from root")
|
||||
.to_owned();
|
||||
buff.push(Walk::File(filename));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(buff)
|
||||
}
|
||||
|
||||
fn walk_with_migrate<OldV, NewV>(tree: Walk, from: &Path, to: &Path) -> std::io::Result<()>
|
||||
where
|
||||
NewV: From<OldV>,
|
||||
OldV: DeserializeOwned,
|
||||
NewV: Serialize,
|
||||
{
|
||||
match tree {
|
||||
Walk::Dir { path, content } => {
|
||||
let target_dir = to.join(path);
|
||||
fs::create_dir_all(target_dir)?;
|
||||
for entry in content {
|
||||
walk_with_migrate::<OldV, NewV>(entry, from, to)?;
|
||||
}
|
||||
},
|
||||
Walk::File(path) => {
|
||||
let source = fs::File::open(from.join(&path))?;
|
||||
let old: OldV = ron::de::from_reader(source).unwrap();
|
||||
let new: NewV = old.into();
|
||||
let target = fs::File::create(to.join(&path))?;
|
||||
let pretty_config = ron::ser::PrettyConfig::new();
|
||||
ron::ser::to_writer_pretty(target, &new, pretty_config).unwrap();
|
||||
println!("{path:?} done");
|
||||
},
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn convert_loop(from: &str, to: &str, old_ver: &str, new_ver: &str) {
|
||||
#[rustfmt::skip]
|
||||
println!(
|
||||
"\nRequest info:\n\
|
||||
{old_ver} -> {new_ver}.\n\
|
||||
Get data from {from} and store in {to}."
|
||||
);
|
||||
|
||||
let root = Path::new(from);
|
||||
let files = Walk::Dir {
|
||||
path: Path::new("").to_owned(),
|
||||
content: walk_tree(root, root).unwrap(),
|
||||
};
|
||||
if old_ver == "v1" && new_ver == "v2" {
|
||||
walk_with_migrate::<v1::EntityConfig, v2::EntityConfig>(
|
||||
files,
|
||||
Path::new(from),
|
||||
Path::new(to),
|
||||
)
|
||||
.unwrap();
|
||||
} else {
|
||||
eprintln!("Unexpected versions")
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!(
|
||||
r#"
|
||||
Hello, this tool can convert all your entity configs to newer version.
|
||||
Currently it supports converting from "v1" to "v2".
|
||||
"#
|
||||
);
|
||||
|
||||
let old_dir = input_validated_string(
|
||||
"Please input directory path with old entity configs:",
|
||||
&|path| {
|
||||
if !Path::new(path).exists() {
|
||||
eprintln!("Source directory '{path}' does not exists.");
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
},
|
||||
);
|
||||
let new_dir = input_string("Please input directory path to place new entity configs:");
|
||||
|
||||
let old_version =
|
||||
input_validated_string("Please input old version to migrate from:", &|version| {
|
||||
let olds = ["v1"];
|
||||
if !olds.contains(&version) {
|
||||
eprintln!("Unexpected version {version}. Available: {olds:?}");
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
let new_version = input_validated_string("Please input new version:", &|version| {
|
||||
let news = ["v2"];
|
||||
if !news.contains(&version) {
|
||||
eprintln!("Unexpected version {version}. Available: {news:?}");
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
|
||||
convert_loop(&old_dir, &new_dir, &old_version, &new_version)
|
||||
}
|
Loading…
Reference in New Issue
Block a user