Compare commits

..

No commits in common. "a0150caa56bda21f7a622e0f4b6724d8cdf519c6" and "4972986feec372235db62ac2546ad1d55a976179" have entirely different histories.

6 changed files with 53 additions and 44 deletions

View file

@ -36,10 +36,7 @@ fn main() -> Result<(), anyhow::Error> {
rom_bytes.resize(4 * 1024 * 1024, 0); rom_bytes.resize(4 * 1024 * 1024, 0);
let mut symbols_file = File::open(&symbols_path)?; let symbols = asar::load_symbols(Path::new(&symbols_path))?;
let mut symbols_text = String::new();
symbols_file.read_to_string(&mut symbols_text)?;
let symbols = asar::load_symbols(&symbols_text)?;
let mut rom = RomData::new(symbols, rom_bytes); let mut rom = RomData::new(symbols, rom_bytes);

View file

@ -1,34 +1,43 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::Path;
pub type Symbols = HashMap<String, usize>; pub type Symbols = HashMap<String, usize>;
pub fn load_symbols(contents: &str) -> anyhow::Result<Symbols> { pub fn load_symbols(filename: &Path) -> anyhow::Result<Symbols> {
let symbols = contents let file = File::open(filename)?;
let reader = BufReader::new(file);
let symbols = reader
.lines() .lines()
.filter_map(|line| { .filter_map(|l| {
let mut words = line.split_ascii_whitespace(); l.ok()
match (words.next(), words.next(), words.next()) { .and_then(|line| {
// Get only two-word lines. let mut words = line.split_ascii_whitespace();
(Some(address), Some(symbol), None) => { match (words.next(), words.next(), words.next()) {
Some((symbol.to_owned(), address.to_owned())) // Get only two-word lines.
} (Some(address), Some(symbol), None) => {
Some((symbol.to_owned(), address.to_owned()))
}
_ => None, _ => None,
} }
})
.and_then(|(symbol, mut address)| {
if let Some(colon_at) = address.find(':') {
address.remove(colon_at);
}
// Filter out the ones that don't have a hexadecimal number as the first word.
let snes_address = u32::from_str_radix(&address, 16).ok()?;
let pc_address = snes_to_pc_address(snes_address);
Some((symbol, pc_address))
})
}) })
.filter_map(|(symbol, mut address)| { .collect();
if let Some(colon_at) = address.find(':') {
address.remove(colon_at);
}
// Filter out the ones that don't have a hexadecimal number as the first word.
let snes_address = u32::from_str_radix(&address, 16).ok()?;
let pc_address = snes_to_pc_address(snes_address);
Some((symbol, pc_address))
})
.collect();
Ok(symbols) Ok(symbols)
} }

View file

@ -19,13 +19,11 @@ pub mod rom;
pub struct InvalidEnumError<T>(PhantomData<T>); pub struct InvalidEnumError<T>(PhantomData<T>);
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Patch { pub struct Patch {
pub address: usize, pub address: usize,
pub patch_data: Vec<u8>, pub patch_data: Vec<u8>,
} }
#[derive(Default)]
pub struct PatchSet { pub struct PatchSet {
filename: PathBuf, filename: PathBuf,
patches: Vec<Patch>, patches: Vec<Patch>,

View file

@ -1,15 +1,15 @@
use std::fs::File; use std::fs::File;
use std::io::prelude::*; use std::io::prelude::*;
use std::path::PathBuf; use std::path::{Path, PathBuf};
use std::time::Instant; use std::time::Instant;
use anyhow::ensure; use anyhow::{bail, ensure};
use clap::Parser; use clap::Parser;
use enemize::{asar, rom::RomData}; use enemize::{asar, rom::RomData};
const ASAR_SYMBOLS: &'static str = include_str!("../../asar_symbols.txt"); const ASAR_SYMBOLS: &'static str = "asar_symbols.txt";
const ENEMIZER_BASE_PATCH: &'static str = include_str!("../../enemizer_base_patch.json"); const ENEMIZER_BASE_PATCH: &'static str = "enemizer_base_patch.json";
/// Randomizes enemy placements in The Legend of Zelda: A Link to the Past for the Super Nintendo /// Randomizes enemy placements in The Legend of Zelda: A Link to the Past for the Super Nintendo
/// Entertainment System /// Entertainment System
@ -65,7 +65,7 @@ fn main() -> anyhow::Result<()> {
// (That is, 2 out of 2 billion instead of 1.) // (That is, 2 out of 2 billion instead of 1.)
let seed = args.seed.unwrap_or_else(|| rand::random()).saturating_abs(); let seed = args.seed.unwrap_or_else(|| rand::random()).saturating_abs();
rom.randomize(ENEMIZER_BASE_PATCH, options, seed)?; rom.randomize(Path::new(ENEMIZER_BASE_PATCH), options, seed)?;
let mut out_file = File::create(&args.output)?; let mut out_file = File::create(&args.output)?;
@ -84,5 +84,12 @@ fn main() -> anyhow::Result<()> {
} }
fn load_symbols() -> anyhow::Result<asar::Symbols> { fn load_symbols() -> anyhow::Result<asar::Symbols> {
asar::load_symbols(ASAR_SYMBOLS) if let Err(_) = std::fs::metadata(ASAR_SYMBOLS) {
bail!(
"Could not find symbols at {}. Did you run prepare.sh?",
ASAR_SYMBOLS
);
}
asar::load_symbols(Path::new(ASAR_SYMBOLS))
} }

View file

@ -1,13 +1,15 @@
use std::path::Path;
use anyhow::ensure; use anyhow::ensure;
use crate::option_flags::OptionFlags; use crate::option_flags::OptionFlags;
use crate::rom::RomData; use crate::rom::RomData;
use crate::{Patch, PatchSet}; use crate::PatchSet;
impl RomData { impl RomData {
pub fn randomize( pub fn randomize(
&mut self, &mut self,
base_patch: &str, base_patch: &Path,
option_flags: OptionFlags, option_flags: OptionFlags,
seed: i32, seed: i32,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
@ -27,11 +29,8 @@ impl RomData {
self.expand_rom(); self.expand_rom();
self.set_info_flags(option_flags)?; self.set_info_flags(option_flags)?;
let patches: Vec<Patch> = serde_json::from_str(base_patch)?; let patches = PatchSet::load(base_patch)?;
patches.patch_rom(self);
let mut patch_set = PatchSet::default();
patch_set.add_patches(patches);
patch_set.patch_rom(self);
Ok(()) Ok(())
} }

View file

@ -6,4 +6,3 @@ fi
if [[ ! -s enemizer_base_patch.json ]]; then if [[ ! -s enemizer_base_patch.json ]]; then
cargo run -p base_patch_generator -- "$1" base_patch.json asar_symbols.txt enemizer_base_patch.json cargo run -p base_patch_generator -- "$1" base_patch.json asar_symbols.txt enemizer_base_patch.json
fi fi
cp enemizer_base_patch.json target/debug/enemizerBasePatch.json