mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Implement migration script for LoadoutSpec
This commit is contained in:
parent
3f7bfff8d7
commit
b81904efd1
@ -1,33 +1,155 @@
|
|||||||
|
use hashbrown::HashMap;
|
||||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
fs, io,
|
fs, io,
|
||||||
io::Write,
|
io::Write,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
use veloren_common::comp::inventory::{
|
||||||
|
loadout_builder::ItemSpec,
|
||||||
|
slot::{ArmorSlot, EquipSlot},
|
||||||
|
};
|
||||||
|
|
||||||
/// Old version.
|
/// Old version.
|
||||||
mod v1 {
|
mod v1 {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
pub type Config = LoadoutSpec;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Debug, Deserialize, Clone)]
|
||||||
pub struct Example {
|
pub struct LoadoutSpec(pub HashMap<EquipSlot, ItemSpec>);
|
||||||
pub field: u8,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// New version.
|
/// New version.
|
||||||
mod v2 {
|
mod v2 {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
type OldConfig = super::v1::Config;
|
||||||
pub struct Example {
|
pub type Config = LoadoutSpecNew;
|
||||||
pub field: f64,
|
type Weight = u8;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||||
|
enum Base {
|
||||||
|
Asset(String),
|
||||||
|
/// NOTE: If you have the same item in multiple configs,
|
||||||
|
/// first one will have the priority
|
||||||
|
Combine(Vec<Base>),
|
||||||
|
Choice(Vec<(Weight, Base)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<super::v1::Example> for Example {
|
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||||
fn from(old: super::v1::Example) -> Self {
|
pub enum ItemSpecNew {
|
||||||
|
Item(String),
|
||||||
|
Choice(Vec<(Weight, Option<ItemSpecNew>)>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||||
|
pub enum Hands {
|
||||||
|
/// Allows to specify one pair
|
||||||
|
// TODO: add link to tests with example
|
||||||
|
InHands((Option<ItemSpecNew>, Option<ItemSpecNew>)),
|
||||||
|
/// Allows specify range of choices
|
||||||
|
// TODO: add link to tests with example
|
||||||
|
Choice(Vec<(Weight, Hands)>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, Clone, Default)]
|
||||||
|
pub struct LoadoutSpecNew {
|
||||||
|
// Meta fields
|
||||||
|
inherit: Option<Base>,
|
||||||
|
// Armor
|
||||||
|
head: Option<ItemSpecNew>,
|
||||||
|
neck: Option<ItemSpecNew>,
|
||||||
|
shoulders: Option<ItemSpecNew>,
|
||||||
|
chest: Option<ItemSpecNew>,
|
||||||
|
gloves: Option<ItemSpecNew>,
|
||||||
|
ring1: Option<ItemSpecNew>,
|
||||||
|
ring2: Option<ItemSpecNew>,
|
||||||
|
back: Option<ItemSpecNew>,
|
||||||
|
belt: Option<ItemSpecNew>,
|
||||||
|
legs: Option<ItemSpecNew>,
|
||||||
|
feet: Option<ItemSpecNew>,
|
||||||
|
tabard: Option<ItemSpecNew>,
|
||||||
|
bag1: Option<ItemSpecNew>,
|
||||||
|
bag2: Option<ItemSpecNew>,
|
||||||
|
bag3: Option<ItemSpecNew>,
|
||||||
|
bag4: Option<ItemSpecNew>,
|
||||||
|
lantern: Option<ItemSpecNew>,
|
||||||
|
glider: Option<ItemSpecNew>,
|
||||||
|
// Weapons
|
||||||
|
active_hands: Option<Hands>,
|
||||||
|
inactive_hands: Option<Hands>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(Option<ItemSpec>, Option<ItemSpec>)> for Hands {
|
||||||
|
fn from((mainhand, offhand): (Option<ItemSpec>, Option<ItemSpec>)) -> Self {
|
||||||
|
Hands::InHands((mainhand.map(|i| i.into()), offhand.map(|i| i.into())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ItemSpec> for ItemSpecNew {
|
||||||
|
fn from(old: ItemSpec) -> Self {
|
||||||
|
match old {
|
||||||
|
ItemSpec::Item(s) => ItemSpecNew::Item(s),
|
||||||
|
ItemSpec::Choice(choices) => {
|
||||||
|
let smallest = choices
|
||||||
|
.iter()
|
||||||
|
.map(|(w, i)| *w)
|
||||||
|
.min_by(|x, y| x.partial_cmp(y).expect("floats are evil"))
|
||||||
|
.expect("choice shouldn't empty");
|
||||||
|
// Very imprecise algo, but it works
|
||||||
|
let new_choices = choices
|
||||||
|
.into_iter()
|
||||||
|
.map(|(w, i)| ((w / smallest) as u8, i.map(|i| i.into())))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
ItemSpecNew::Choice(new_choices)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<OldConfig> for Config {
|
||||||
|
fn from(old: OldConfig) -> Self {
|
||||||
|
let super::v1::LoadoutSpec(old) = old;
|
||||||
|
let to_new_item = |slot: &EquipSlot| -> Option<ItemSpecNew> {
|
||||||
|
old.get(slot).cloned().map(|i| i.into())
|
||||||
|
};
|
||||||
|
|
||||||
|
let active_mainhand = old.get(&EquipSlot::ActiveMainhand).cloned();
|
||||||
|
let active_offhand = old.get(&EquipSlot::ActiveOffhand).cloned();
|
||||||
|
let inactive_mainhand = old.get(&EquipSlot::InactiveMainhand).cloned();
|
||||||
|
let inactive_offhand = old.get(&EquipSlot::InactiveOffhand).cloned();
|
||||||
|
|
||||||
|
let to_hands =
|
||||||
|
|mainhand: Option<ItemSpec>, offhand: Option<ItemSpec>| -> Option<Hands> {
|
||||||
|
if mainhand.is_none() && offhand.is_none() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some((mainhand, offhand).into())
|
||||||
|
}
|
||||||
|
};
|
||||||
Self {
|
Self {
|
||||||
field: f64::from(old.field),
|
inherit: None,
|
||||||
|
head: to_new_item(&EquipSlot::Armor(ArmorSlot::Head)),
|
||||||
|
neck: to_new_item(&EquipSlot::Armor(ArmorSlot::Neck)),
|
||||||
|
shoulders: to_new_item(&EquipSlot::Armor(ArmorSlot::Shoulders)),
|
||||||
|
chest: to_new_item(&EquipSlot::Armor(ArmorSlot::Chest)),
|
||||||
|
gloves: to_new_item(&EquipSlot::Armor(ArmorSlot::Hands)),
|
||||||
|
ring1: to_new_item(&EquipSlot::Armor(ArmorSlot::Ring1)),
|
||||||
|
ring2: to_new_item(&EquipSlot::Armor(ArmorSlot::Ring2)),
|
||||||
|
back: to_new_item(&EquipSlot::Armor(ArmorSlot::Back)),
|
||||||
|
belt: to_new_item(&EquipSlot::Armor(ArmorSlot::Belt)),
|
||||||
|
legs: to_new_item(&EquipSlot::Armor(ArmorSlot::Legs)),
|
||||||
|
feet: to_new_item(&EquipSlot::Armor(ArmorSlot::Feet)),
|
||||||
|
tabard: to_new_item(&EquipSlot::Armor(ArmorSlot::Tabard)),
|
||||||
|
bag1: to_new_item(&EquipSlot::Armor(ArmorSlot::Bag1)),
|
||||||
|
bag2: to_new_item(&EquipSlot::Armor(ArmorSlot::Bag2)),
|
||||||
|
bag3: to_new_item(&EquipSlot::Armor(ArmorSlot::Bag3)),
|
||||||
|
bag4: to_new_item(&EquipSlot::Armor(ArmorSlot::Bag4)),
|
||||||
|
lantern: to_new_item(&EquipSlot::Lantern),
|
||||||
|
glider: to_new_item(&EquipSlot::Glider),
|
||||||
|
active_hands: to_hands(active_mainhand, active_offhand),
|
||||||
|
inactive_hands: to_hands(inactive_mainhand, inactive_offhand),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,7 +219,7 @@ fn convert_loop(from: &str, to: &str) {
|
|||||||
path: Path::new("").to_owned(),
|
path: Path::new("").to_owned(),
|
||||||
content: walk_tree(root, root).unwrap(),
|
content: walk_tree(root, root).unwrap(),
|
||||||
};
|
};
|
||||||
walk_with_migrate::<v1::Example, v2::Example>(files, Path::new(from), Path::new(to)).unwrap();
|
walk_with_migrate::<v1::Config, v2::Config>(files, Path::new(from), Path::new(to)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_string(prompt: &str) -> String { input_validated_string(prompt, &|_| true) }
|
fn input_string(prompt: &str) -> String { input_validated_string(prompt, &|_| true) }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user