Darktide Mod Manager #39
6 changed files with 87 additions and 23 deletions
|
@ -202,7 +202,7 @@ fn build_mod_data_lua(state: Arc<State>) -> String {
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn build_bundles(state: Arc<State>) -> Result<()> {
|
async fn build_bundles(state: Arc<State>) -> Result<()> {
|
||||||
let mut bundle = Bundle::new(MOD_BUNDLE_NAME.into());
|
let mut bundle = Bundle::new(MOD_BUNDLE_NAME);
|
||||||
let mut tasks = Vec::new();
|
let mut tasks = Vec::new();
|
||||||
|
|
||||||
let bundle_dir = Arc::new(state.get_game_dir().join("bundle"));
|
let bundle_dir = Arc::new(state.get_game_dir().join("bundle"));
|
||||||
|
@ -312,7 +312,7 @@ async fn build_bundles(state: Arc<State>) -> Result<()> {
|
||||||
db.add_bundle(&bundle);
|
db.add_bundle(&bundle);
|
||||||
|
|
||||||
{
|
{
|
||||||
let path = bundle_dir.join(format!("{:x}", Murmur64::hash(bundle.name())));
|
let path = bundle_dir.join(format!("{:x}", bundle.name().to_murmur64()));
|
||||||
tracing::trace!("Writing mod bundle to '{}'", path.display());
|
tracing::trace!("Writing mod bundle to '{}'", path.display());
|
||||||
fs::write(&path, bundle.to_binary()?)
|
fs::write(&path, bundle.to_binary()?)
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -50,13 +50,13 @@ where
|
||||||
|
|
||||||
match fmt {
|
match fmt {
|
||||||
OutputFormat::Text => {
|
OutputFormat::Text => {
|
||||||
println!("Bundle: {}", bundle.name());
|
println!("Bundle: {}", bundle.name().display());
|
||||||
|
|
||||||
for f in bundle.files().iter() {
|
for f in bundle.files().iter() {
|
||||||
if f.variants().len() != 1 {
|
if f.variants().len() != 1 {
|
||||||
let err = eyre::eyre!("Expected exactly one version for this file.")
|
let err = eyre::eyre!("Expected exactly one version for this file.")
|
||||||
.with_section(|| f.variants().len().to_string().header("Bundle:"))
|
.with_section(|| f.variants().len().to_string().header("Bundle:"))
|
||||||
.with_section(|| bundle.name().clone().header("Bundle:"));
|
.with_section(|| bundle.name().display().header("Bundle:"));
|
||||||
|
|
||||||
tracing::error!("{:#}", err);
|
tracing::error!("{:#}", err);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use color_eyre::eyre::{self, Context};
|
use color_eyre::eyre::{self, Context};
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use sdk::murmur::Murmur64;
|
|
||||||
use sdk::Bundle;
|
use sdk::Bundle;
|
||||||
use zip::ZipWriter;
|
use zip::ZipWriter;
|
||||||
|
|
||||||
|
@ -70,7 +69,7 @@ impl Archive {
|
||||||
map_entry.insert(file.name(false, None));
|
map_entry.insert(file.name(false, None));
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = Murmur64::hash(bundle.name().as_bytes());
|
let name = bundle.name().to_murmur64();
|
||||||
let path = base_path.join(name.to_string().to_ascii_lowercase());
|
let path = base_path.join(name.to_string().to_ascii_lowercase());
|
||||||
|
|
||||||
zip.start_file(path.to_string_lossy(), Default::default())?;
|
zip.start_file(path.to_string_lossy(), Default::default())?;
|
||||||
|
|
|
@ -38,17 +38,27 @@ pub struct BundleDatabase {
|
||||||
|
|
||||||
impl BundleDatabase {
|
impl BundleDatabase {
|
||||||
pub fn add_bundle(&mut self, bundle: &Bundle) {
|
pub fn add_bundle(&mut self, bundle: &Bundle) {
|
||||||
let hash = Murmur64::hash(bundle.name().as_bytes());
|
let hash = bundle.name().to_murmur64();
|
||||||
let name = hash.to_string();
|
let name = hash.to_string();
|
||||||
let stream = format!("{}.stream", &name);
|
let stream = format!("{}.stream", &name);
|
||||||
let file = BundleFile {
|
|
||||||
name,
|
|
||||||
stream,
|
|
||||||
file_time: 0,
|
|
||||||
platform_specific: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
self.stored_files.entry(hash).or_default().push(file);
|
{
|
||||||
|
let entry = self.stored_files.entry(hash).or_default();
|
||||||
|
let existing = entry.iter().position(|f| f.name == name);
|
||||||
|
|
||||||
|
let file = BundleFile {
|
||||||
|
name,
|
||||||
|
stream,
|
||||||
|
file_time: 0,
|
||||||
|
platform_specific: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
entry.push(file);
|
||||||
|
|
||||||
|
if let Some(pos) = existing {
|
||||||
|
entry.swap_remove(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for f in bundle.files() {
|
for f in bundle.files() {
|
||||||
let file_name = FileName {
|
let file_name = FileName {
|
||||||
|
|
|
@ -8,7 +8,7 @@ use oodle_sys::{OodleLZ_CheckCRC, OodleLZ_FuzzSafe, CHUNK_SIZE};
|
||||||
|
|
||||||
use crate::binary::sync::*;
|
use crate::binary::sync::*;
|
||||||
use crate::bundle::file::Properties;
|
use crate::bundle::file::Properties;
|
||||||
use crate::murmur::{HashGroup, Murmur64};
|
use crate::murmur::{HashGroup, IdString64, Murmur64};
|
||||||
|
|
||||||
pub(crate) mod database;
|
pub(crate) mod database;
|
||||||
pub(crate) mod file;
|
pub(crate) mod file;
|
||||||
|
@ -46,13 +46,13 @@ pub struct Bundle {
|
||||||
format: BundleFormat,
|
format: BundleFormat,
|
||||||
properties: [Murmur64; 32],
|
properties: [Murmur64; 32],
|
||||||
files: Vec<BundleFile>,
|
files: Vec<BundleFile>,
|
||||||
name: String,
|
name: IdString64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bundle {
|
impl Bundle {
|
||||||
pub fn new(name: String) -> Self {
|
pub fn new<S: Into<IdString64>>(name: S) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name: name.into(),
|
||||||
format: BundleFormat::F8,
|
format: BundleFormat::F8,
|
||||||
properties: [0.into(); 32],
|
properties: [0.into(); 32],
|
||||||
files: Vec::new(),
|
files: Vec::new(),
|
||||||
|
@ -201,7 +201,7 @@ impl Bundle {
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
name: bundle_name,
|
name: bundle_name.into(),
|
||||||
format,
|
format,
|
||||||
files,
|
files,
|
||||||
properties,
|
properties,
|
||||||
|
@ -281,7 +281,7 @@ impl Bundle {
|
||||||
Ok(w.into_inner())
|
Ok(w.into_inner())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> &String {
|
pub fn name(&self) -> &IdString64 {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -289,9 +289,9 @@ impl IdString64 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<String> for IdString64 {
|
impl<S: Into<String>> From<S> for IdString64 {
|
||||||
fn from(value: String) -> Self {
|
fn from(value: S) -> Self {
|
||||||
Self::String(value)
|
Self::String(value.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,6 +313,61 @@ impl PartialEq for IdString64 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::hash::Hash for IdString64 {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
state.write_u64(self.to_murmur64().into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serde::Serialize for IdString64 {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
serializer.serialize_u64(self.to_murmur64().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct IdString64Visitor;
|
||||||
|
|
||||||
|
impl<'de> serde::de::Visitor<'de> for IdString64Visitor {
|
||||||
|
type Value = IdString64;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str("an u64 or a string")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
Ok(IdString64::Hash(value.into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
Ok(IdString64::String(v.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
Ok(IdString64::String(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> serde::Deserialize<'de> for IdString64 {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
deserializer.deserialize_u64(IdString64Visitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct IdString64Display(String);
|
pub struct IdString64Display(String);
|
||||||
|
|
||||||
impl std::fmt::Display for IdString64Display {
|
impl std::fmt::Display for IdString64Display {
|
||||||
|
|
Loading…
Add table
Reference in a new issue