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
|
#!/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
|
# 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 clippy -p veloren-voxygen --locked --no-default-features --features="default-publish" -- -D warnings &&
|
||||||
time cargo fmt --all -- --check
|
time cargo fmt --all -- --check
|
||||||
|
@ -11,7 +11,7 @@ simd = ["vek/platform_intrinsics"]
|
|||||||
bin_csv = ["ron", "csv", "structopt"]
|
bin_csv = ["ron", "csv", "structopt"]
|
||||||
bin_graphviz = ["petgraph"]
|
bin_graphviz = ["petgraph"]
|
||||||
bin_cmd_doc_gen = []
|
bin_cmd_doc_gen = []
|
||||||
bin_entity_migrate = ["ron"]
|
bin_asset_migrate = ["ron"]
|
||||||
rrt_pathfinding = ["kiddo"]
|
rrt_pathfinding = ["kiddo"]
|
||||||
calendar_events = []
|
calendar_events = []
|
||||||
|
|
||||||
@ -108,8 +108,8 @@ name = "csv_import"
|
|||||||
required-features = ["bin_csv"]
|
required-features = ["bin_csv"]
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "entity_migrate"
|
name = "asset_migrate"
|
||||||
required-features = ["bin_entity_migrate"]
|
required-features = ["bin_asset_migrate"]
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "recipe_graphviz"
|
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