Commit 2c83e7b6 authored by Ruby's avatar Ruby
Browse files

Refactor to remove references to Rc::get_mut_unchecked, since that doesn't...

Refactor to remove references to Rc::get_mut_unchecked, since that doesn't look like it'll be stabilized anytime soon
parent 5f6c90ec
Pipeline #220190991 passed with stages
in 4 minutes and 18 seconds
......@@ -37,8 +37,6 @@ Once you have everything set, simply run:
And this will do the magic. I recommend release mode while you're not debugging as it parses much faster.
**Note:** Version 2.0.0 forward require a nightly version of Rust for the time being.
## Output
The description of the JSON output files can be found in the [data dictionary](docs/index.md).
......
......@@ -2,7 +2,6 @@ use super::*;
use crate::structs::{
Archetype, CharacterAttributes, CharacterAttributesTable, Keyed, NameKey, NamedTable,
};
use std::rc::Rc;
/// Reads all of the archetypes in the current .bin file.
///
......@@ -34,8 +33,8 @@ where
for _ in 0..at_size {
let mut archetype = read_archetype(reader, strings, messages)?;
archetype.is_villain = is_villain;
if let Some(class_key) = &archetype.class_key {
archetypes.insert(class_key.clone(), Rc::new(archetype));
if let Some(class_key) = archetype.class_key.clone() {
archetypes.insert(class_key, archetype);
}
}
......
use super::*;
use crate::structs::{BoostList, BoostSet, BoostSetBonus, Keyed, NameKey};
use std::rc::Rc;
/// Reads all of the boost sets in the current .bin file.
///
......@@ -29,8 +28,8 @@ where
let bs_size: usize = bin_read(reader)?;
for _ in 0..bs_size {
let boost_set = read_boost_set(reader, strings, messages)?;
if let Some(name) = &boost_set.pch_name {
boost_sets.insert(name.clone(), Rc::new(boost_set));
if let Some(name) = boost_set.pch_name.clone() {
boost_sets.insert(name, boost_set);
}
}
......
use super::*;
use crate::structs::{Keyed, PowerCategory};
use std::rc::Rc;
/// Reads all of the power categories in the current .bin file.
///
......@@ -31,8 +30,8 @@ where
let pcat_size: usize = bin_read(reader)?;
for _ in 0..pcat_size {
let powercat = read_power_category(reader, strings, messages)?;
if let Some(powercat_name) = &powercat.pch_name {
powercats.insert(powercat_name.clone(), Rc::new(powercat));
if let Some(powercat_name) = powercat.pch_name.clone() {
powercats.insert(powercat_name, powercat);
}
}
......
use super::*;
use crate::structs::*;
use std::cell::RefCell;
use std::rc::Rc;
const MAX_ATTRIBMOD_FX: usize = 4;
......@@ -33,8 +34,8 @@ where
let mut powers = Keyed::<_>::new();
for _ in 0..pbp_size {
let power = read_base_power(reader, strings, messages)?;
if let Some(power_name) = &power.pch_full_name {
powers.insert(power_name.clone(), Rc::new(power));
if let Some(power_name) = power.pch_full_name.clone() {
powers.insert(power_name, power);
}
}
verify_struct_length(powers, expected_bytes, begin_pos, reader)
......@@ -232,12 +233,12 @@ where
)?;
bin_read_arr_fn(
&mut power.pp_effects,
|re| Ok(Rc::new(read_effect_group(re, strings, messages)?)),
|re| Ok(Rc::new(RefCell::new(read_effect_group(re, strings, messages)?))),
reader,
)?;
bin_read_arr_fn(
&mut power.pp_activation_effects,
|re| Ok(Rc::new(read_effect_group(re, strings, messages)?)),
|re| Ok(Rc::new(RefCell::new(read_effect_group(re, strings, messages)?))),
reader,
)?;
......
use super::*;
use crate::structs::{BasePowerSet, Keyed};
use std::rc::Rc;
/// Reads all of the power sets in the current .bin file.
///
......@@ -30,8 +29,8 @@ where
let mut powersets = Keyed::<_>::new();
for _ in 0..pbps_size {
let powerset = read_base_powerset(reader, strings, messages)?;
if let Some(powerset_name) = &powerset.pch_full_name {
powersets.insert(powerset_name.clone(), Rc::new(powerset));
if let Some(powerset_name) = powerset.pch_full_name.clone() {
powersets.insert(powerset_name, powerset);
}
}
......
......@@ -3,7 +3,6 @@ use crate::structs::{
Keyed, PetCommandStrings, PowerNameRef, VillainDef, VillainDefFlags, VillainExclusion,
VillainLevelDef,
};
use std::rc::Rc;
/// Reads all of the villain definitions in the current .bin file.
///
......@@ -33,8 +32,8 @@ where
let mut villains = Keyed::<_>::new();
for _ in 0..v_size {
let villain = read_villain_def(reader, strings, messages)?;
if let Some(villain_name) = &villain.name {
villains.insert(villain_name.clone(), Rc::new(villain));
if let Some(villain_name) = villain.name.clone() {
villains.insert(villain_name, villain);
}
}
......
This diff is collapsed.
#![feature(get_mut_unchecked)]
#[macro_use]
extern crate bitflags;
extern crate chrono;
......
......@@ -2,14 +2,13 @@ mod structs;
use crate::structs::config::{OutputStyleConfig, PowersConfig};
use crate::structs::{
Archetype, AttribNames, BasePowerSet, Keyed, PowerCategory, PowersDictionary,
Archetype, AttribNames, BasePowerSet, Keyed, ObjRef, PowerCategory, PowersDictionary,
};
use std::fs;
use std::io;
use std::io::prelude::*;
use std::io::{Error, ErrorKind};
use std::path::Path;
use std::rc::Rc;
use structs::*;
/// Default name for the .json files.
......@@ -64,19 +63,19 @@ pub fn write_powers_dictionary(
write_archetypes(&powers_dict.archetypes, config)?;
// write all of the categories
for category in &powers_dict.power_categories {
for category in powers_dict.power_categories.iter().map(|c| c.borrow()) {
if !category.include_in_output {
continue;
}
write_power_category(category, config)?;
write_power_category(&*category, config)?;
if let Some(pcat_name) = category.pch_name.as_ref() {
// write the category's power sets
for set in &category.pp_power_sets {
for set in category.pp_power_sets.iter().map(|p| p.borrow()) {
if set.include_in_output {
write_power_set(
Some(pcat_name.get_string()),
set,
&*set,
&powers_dict.attrib_names,
config,
)?;
......@@ -89,7 +88,10 @@ pub fn write_powers_dictionary(
}
/// Writes the root .json file.
fn write_root(power_categories: &Vec<Rc<PowerCategory>>, config: &PowersConfig) -> io::Result<()> {
fn write_root(
power_categories: &Vec<ObjRef<PowerCategory>>,
config: &PowersConfig,
) -> io::Result<()> {
let output_file = config.join_to_output_path(JSON_FILE);
println!("Writing: {} ...", output_file.display());
let mut f = fs::File::create(output_file)?;
......@@ -149,11 +151,7 @@ fn write_power_set(
println!("\tWriting: {} ...", output_file.display());
let mut f = fs::File::create(output_file)?;
let pset = PowerSetOutput::from_base_power_set(
power_set,
attrib_names,
config,
);
let pset = PowerSetOutput::from_base_power_set(power_set, attrib_names, config);
match config.output_style {
OutputStyleConfig::Pretty => serde_json::to_writer_pretty(&mut f, &pset)?,
OutputStyleConfig::Compact => serde_json::to_writer(&mut f, &pset)?,
......
......@@ -116,7 +116,7 @@ impl AttribModParamOutput {
if let Some(villain) = &e.villain_def {
let mut display_name = None;
let mut powers = Vec::new();
if let Some(level_def) = villain.levels.get(config.at_level as usize) {
if let Some(level_def) = villain.borrow().levels.get(config.at_level as usize) {
display_name = level_def.display_names.get(0).cloned();
}
for power in &e.power_refs {
......@@ -319,7 +319,7 @@ impl AttribModOutput {
fn from_attrib_mod_template(
attrib_mod: &AttribModTemplate,
attrib_names: &AttribNames,
archetypes: &Vec<Rc<Archetype>>,
archetypes: &Vec<ObjRef<Archetype>>,
config: &PowersConfig,
) -> Self {
let mut output = AttribModOutput {
......@@ -453,11 +453,11 @@ impl AttribModOutput {
fn add_effect_scales(
&mut self,
attrib_mod: &AttribModTemplate,
archetypes: &Vec<Rc<Archetype>>,
archetypes: &Vec<ObjRef<Archetype>>,
at_level: i32,
) {
if let Some(table_name) = &attrib_mod.pch_table {
for at in archetypes {
for at in archetypes.iter().map(|at| at.borrow()) {
// calculate scaled effect for each archetype attached to this power
if let Some(named_table) = at.pp_named_tables.get(&table_name.to_lowercase()) {
let base_value = named_table.pf_values[(at_level - 1) as usize];
......@@ -514,7 +514,7 @@ impl EffectGroupOutput {
effect: &EffectGroup,
attrib_names: &AttribNames,
base_power: &BasePower,
archetypes: &Vec<Rc<Archetype>>,
archetypes: &Vec<ObjRef<Archetype>>,
config: &PowersConfig,
) -> Self {
let mut group = EffectGroupOutput {
......@@ -644,18 +644,19 @@ fn calculate_damage(
/// If `effect` has no requirements, all archetypes passed in will be returned.
fn filter_archetypes_eg(
effect: &EffectGroup,
archetypes: &Vec<Rc<Archetype>>,
) -> Vec<Rc<Archetype>> {
archetypes: &Vec<ObjRef<Archetype>>,
) -> Vec<ObjRef<Archetype>> {
// filter out the MLCrit and BossCrit effects, they use arch to test for NPC archetypes
if !is_critical_by_tags(&effect.ppch_tags)
// pets sometimes check for the "owner" which can confuse this rule
&& !archetypes.iter().any(|at| at.is_villain)
&& !archetypes.iter().any(|at| at.borrow().is_villain)
&& effect.ppch_requires.iter().any(|rule| rule == "arch")
{
// second form of this rule compares to the latter half of the class key
archetypes
.iter()
.filter(|at| {
let at = at.borrow();
if let Some(class_key) = &at.class_key {
if let Some(class_name) = &at.pch_name {
effect.ppch_requires.iter().any(|rule| {
......
......@@ -9,7 +9,6 @@ use powers::PowerOutput;
use serde::Serialize;
use std::borrow::Cow;
use std::collections::HashMap;
use std::rc::Rc;
/// Used when joining parts of an URL together.
const URL_SEP: char = '/';
......@@ -127,7 +126,7 @@ impl ArchetypesOutput {
};
for at in ats.values() {
ats_out.archetypes.push(ArchetypeOutput::from_archetype(
at,
&*at.borrow(),
&PrimarySecondary::None,
true,
config,
......@@ -161,14 +160,14 @@ impl RootOutput {
///
/// Arguments:
///
/// * `power_categories` - A `Vec<Rc<PowerCategory>>`.
/// * `power_categories` - A `Vec<ObjRef<PowerCategory>>`.
/// * `config` - Configuration information.
///
/// Returns:
///
/// A `RootOutput`.
pub fn from_power_categories(
power_categories: &Vec<Rc<PowerCategory>>,
power_categories: &Vec<ObjRef<PowerCategory>>,
config: &PowersConfig,
) -> Self {
let mut at_url = String::new();
......@@ -185,7 +184,7 @@ impl RootOutput {
archetypes: at_url,
power_categories: Vec::new(),
};
for pcat in power_categories {
for pcat in power_categories.iter().map(|p| p.borrow()) {
if !pcat.top_level || !pcat.include_in_output {
continue;
}
......@@ -208,7 +207,7 @@ impl RootOutput {
if pcat.archetypes.len() == 1 {
// if there's only 1 archetype attached, then this is a group of sets intended for that archetype
rpc.archetype = Some(ArchetypeOutput::from_archetype(
&pcat.archetypes[0],
&*pcat.archetypes[0].borrow(),
&pcat.pri_sec,
false,
config,
......@@ -261,15 +260,14 @@ impl PowerCategoryOutput {
if power_category.archetypes.len() == 1 {
// if there's only 1 archetype attached, then this is a group of sets intended for that archetype
pcat.archetype = Some(ArchetypeOutput::from_archetype(
&power_category.archetypes[0],
&*power_category.archetypes[0].borrow(),
&power_category.pri_sec,
false,
config,
));
}
for pset in &power_category.pp_power_sets {
if !pset.include_in_output
{
for pset in power_category.pp_power_sets.iter().map(|p| p.borrow()) {
if !pset.include_in_output {
continue;
}
let mut url = String::new();
......@@ -374,14 +372,11 @@ impl PowerSetOutput {
power_set.pch_set_buy_requires_failed_text.clone();
}
// map individual powers
for power in &power_set.pp_powers {
for power in power_set.pp_powers.iter().map(|p| p.borrow()) {
// skip disabled powers
if power.include_in_output {
pset.powers.push(PowerOutput::from_base_power(
power,
attrib_names,
config,
));
pset.powers
.push(PowerOutput::from_base_power(&*power, attrib_names, config));
}
}
// copy minimum levels
......@@ -658,4 +653,3 @@ where
}
None
}
......@@ -420,7 +420,7 @@ impl PowerOutput {
// effect groups
for effect_group in &power.pp_effects {
pwr.effect_groups.push(EffectGroupOutput::from_effect_group(
effect_group,
&*effect_group.borrow(),
attrib_names,
power,
&archetypes,
......@@ -430,7 +430,7 @@ impl PowerOutput {
for effect_group in &power.pp_activation_effects {
pwr.activate_effect_groups
.push(EffectGroupOutput::from_effect_group(
effect_group,
&*effect_group.borrow(),
attrib_names,
power,
&archetypes,
......@@ -450,7 +450,7 @@ impl PowerOutput {
/// Filters the archetypes vector based on any purchase requirements specified in `power`.
/// If `power` has no requirements, all archetypes passed in will be returned.
fn filter_archetypes_pwr(power: &BasePower, archetypes: &Vec<Rc<Archetype>>) -> Vec<Rc<Archetype>> {
fn filter_archetypes_pwr(power: &BasePower, archetypes: &Vec<ObjRef<Archetype>>) -> Vec<ObjRef<Archetype>> {
if power
.ppch_buy_requires
.iter()
......@@ -460,7 +460,7 @@ fn filter_archetypes_pwr(power: &BasePower, archetypes: &Vec<Rc<Archetype>>) ->
archetypes
.iter()
.filter(|at| {
if let Some(class_key) = &at.class_key {
if let Some(class_key) = &at.borrow().class_key {
power
.ppch_buy_requires
.iter()
......
......@@ -55,18 +55,18 @@ pub fn write_powers_dictionary(
// write powers
let mut fx_cache = HashSet::new();
let mut file_count = 0;
for power_cat in &powers_dict.power_categories {
for power_cat in powers_dict.power_categories.iter().map(|p| p.borrow()) {
if power_cat.include_in_output {
write_power_category(power_cat, config)?;
write_power_category(&*power_cat, config)?;
file_count += 1;
for power_set in &power_cat.pp_power_sets {
for power_set in power_cat.pp_power_sets.iter().map(|p| p.borrow()) {
if power_set.include_in_output {
write_power_set(power_set, config)?;
write_power_set(&*power_set, config)?;
file_count += 1;
let powers: Vec<_> = power_set
.pp_powers
.iter()
.filter(|p| p.include_in_output)
.filter(|p| p.borrow().include_in_output)
.collect();
if powers.len() > 0 {
// write all powers in the power set
......@@ -74,33 +74,27 @@ pub fn write_powers_dictionary(
file_count += 1;
// write all the FX blocks, checking for duplicates
for fx in powers
.iter()
.filter(|p| p.p_fx.is_some())
.map(|p| p.p_fx.as_ref().unwrap())
{
if let Some(source) = &fx.pch_source_file {
let source = source.to_lowercase();
if !fx_cache.contains(&source) {
fx_cache.insert(source);
write_fx(fx, config)?;
file_count += 1;
for p in powers.iter().map(|p| p.borrow()) {
if let Some(fx) = &p.p_fx {
if let Some(source) = &fx.pch_source_file {
let source = source.to_lowercase();
if !fx_cache.contains(&source) {
fx_cache.insert(source);
write_fx(fx, config)?;
file_count += 1;
}
}
}
}
for custom_fx in powers
.iter()
.map(|p| &p.pp_custom_fx)
.flatten()
.filter(|cfx| cfx.p_fx.is_some())
.map(|cfx| cfx.p_fx.as_ref().unwrap())
{
if let Some(source) = &custom_fx.pch_source_file {
let source = source.to_lowercase();
if !fx_cache.contains(&source) {
fx_cache.insert(source);
write_fx(custom_fx, config)?;
file_count += 1;
for cfx in &p.pp_custom_fx {
if let Some(custom_fx) = &cfx.p_fx {
if let Some(source) = &custom_fx.pch_source_file {
let source = source.to_lowercase();
if !fx_cache.contains(&source) {
fx_cache.insert(source);
write_fx(custom_fx, config)?;
file_count += 1;
}
}
}
}
}
......@@ -114,7 +108,7 @@ pub fn write_powers_dictionary(
// the original has everything in one def file, but that results in a massive unwieldy
// file because of all the computed tables that end up in the bin
for archetype in powers_dict.archetypes.values() {
write_archetype(archetype, config)?;
write_archetype(&*archetype.borrow(), config)?;
file_count += 1;
}
......@@ -165,11 +159,12 @@ fn write_power_set(power_set: &BasePowerSet, config: &PowersConfig) -> io::Resul
Ok(())
}
fn write_powers(powers: &Vec<&std::rc::Rc<BasePower>>, config: &PowersConfig) -> io::Result<()> {
fn write_powers(powers: &Vec<&ObjRef<BasePower>>, config: &PowersConfig) -> io::Result<()> {
// NOTE: is it true that all powers in a set share same the source file?
let source_file = powers
.first()
.unwrap()
.borrow()
.source_file
.as_ref()
.unwrap()
......
#![allow(dead_code)]
#![allow(non_camel_case_types)]
use super::{NameKey, Vec3, VillainDef};
use super::{NameKey, ObjRef, Vec3, VillainDef};
use num_enum::TryFromPrimitive;
use serde::Serialize;
use std::rc::Rc;
macro_rules! default_new {
($type:ty) => {
......@@ -618,7 +617,7 @@ pub struct AttribModParam_EntCreate {
pub redirects: Vec<NameKey>,
/// reference to full Villain Def (not inline)
#[serde(skip)]
pub villain_def: Option<Rc<VillainDef>>,
pub villain_def: Option<ObjRef<VillainDef>>,
/// reference to entity's powers (not inline)
#[serde(skip)]
pub power_refs: Vec<NameKey>,
......
......@@ -39,6 +39,7 @@ pub use enums::*;
pub use flags::*;
pub use namekey::*;
use serde::{Serialize, Serializer};
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::default::Default;
use std::fmt;
......@@ -46,7 +47,65 @@ use std::rc::Rc;
pub use strings::*;
pub use villains::*;
pub type Keyed<T> = HashMap<NameKey, Rc<T>>;
/// Short-hand for shareable references.
pub type ObjRef<T> = Rc<RefCell<T>>;
/// Dictionary that maps `NameKey` values to their objects (powers, power sets, etc.).
#[derive(Debug)]
pub struct Keyed<T>(pub HashMap<NameKey, ObjRef<T>>);
impl<T> Keyed<T> {
/// Create a new `Keyed<T>` dictionary.
pub fn new() -> Self {
Keyed(HashMap::new())
}
/// Get the object named by `key`, if any.
///
/// # Arguments
/// * `key` - The `NameKey` that references the desired object.
///
/// # Returns
/// An `ObjRef<T>` to the object if found, otherwise `None`.
pub fn get(&self, key: &NameKey) -> Option<&ObjRef<T>> {
self.0.get(key)
}
/// Insert a new object into the dictionary.
///
/// # Arguments
/// * `key` - The `NameKey` that references `value`.
/// * `value` - The object to store. It will automatically be wrapped as an `ObjRef<T>`.
pub fn insert(&mut self, key: NameKey, value: T) {
self.0.insert(key, Rc::new(RefCell::new(value)));
}
/// Gets the number of items in this dictionary.
///
/// # Returns
/// A `usize` value.
pub fn len(&self) -> usize {
self.0.len()
}
/// Gets a visitor that iterates over all values in the dictionary.
///
/// # Returns
/// An iterator with element type `ObjRef<T>`.
pub fn values<'a>(&'a self) -> std::collections::hash_map::Values<'a, NameKey, ObjRef<T>> {
self.0.values()
}
/// Gets a visitor that iterates over all values mutably in the dictionary.
///
/// # Returns
/// An iterator with mutable element type `ObjRef<T>`.
pub fn values_mut<'a>(
&'a mut self,
) -> std::collections::hash_map::ValuesMut<'a, NameKey, ObjRef<T>> {
self.0.values_mut()
}
}
#[derive(Debug, Default, Serialize)]
pub struct NamedTable {
......@@ -207,7 +266,7 @@ pub struct BasePowerSet {
pub pch_set_buy_requires_failed_text: Option<String>,
/// The list of powers which are part of this power set.
#[serde(skip)]
pub pp_powers: Vec<Rc<BasePower>>,
pub pp_powers: Vec<ObjRef<BasePower>>,
/// The array of names of included powers.
pub pp_power_names: Vec<NameKey>,
/// How old the set has to be (in levels) before the power becomes available.
......@@ -843,10 +902,10 @@ pub struct BasePower {
/// List of redirections for this power.
pub pp_redirect: Vec<PowerRedirect>,
/// Effects of this power.
/// Stored as `Rc` because I need to make references to these for effects pulled in by `pp_redirect`.