Skip to content

Commit b41a6ca

Browse files
committed
Start work on CRC/ResMgr subsystem
1 parent b4a276d commit b41a6ca

21 files changed

Lines changed: 640 additions & 130 deletions

Cargo.toml

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ authors = ["Xiphoseer <xiphoseer@mailbox.org>"]
55
edition = "2018"
66

77
[dependencies]
8+
assembly-core = { git = "https://github.com/Xiphoseer/assembly_rs.git" }
9+
assembly-maps = { git = "https://github.com/Xiphoseer/assembly_rs.git" }
10+
assembly-pack = { git = "https://github.com/Xiphoseer/assembly_rs.git" }
11+
assembly-fdb = { git = "https://github.com/Xiphoseer/assembly_rs.git", default-features = false, features = ["serde-derives"] }
12+
assembly-xml = { git = "https://github.com/Xiphoseer/assembly_rs.git" }
813
base64 = "0.13"
914
handlebars = "3.5"
1015
pretty_env_logger = "0.4.0"
@@ -27,14 +32,6 @@ version = "0.3"
2732
features = ["tls", "multipart"]
2833
default-features = false
2934

30-
[dependencies.assembly-core]
31-
version = "0.2.1"
32-
33-
[dependencies.assembly-data]
34-
version = "0.3.0"
35-
default-features = false
36-
features = ["serde-derives"]
37-
3835
# Holds data in insertion order
3936
[dependencies.linked-hash-map]
4037
version = "0.5.3"

src/api/adapter.rs

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use std::iter::Copied;
22
use std::slice::Iter;
33
use std::{collections::BTreeMap, fmt};
44

5-
use assembly_data::xml::localization::LocaleNode;
6-
use paradox_typed_db::typed_rows::TypedRow;
5+
use assembly_xml::localization::LocaleNode;
6+
use paradox_typed_db::TypedRow;
77
use serde::{ser::SerializeMap, Serialize};
88

99
pub(crate) trait FindHash {
@@ -90,24 +90,53 @@ where
9090
}
9191
}
9292

93+
pub(crate) struct TableMultiIter<'a, 'b, R, K, F>
94+
where
95+
K: Iterator<Item = i32>,
96+
F: FindHash,
97+
R: TypedRow<'a, 'b>,
98+
{
99+
pub(crate) index: F,
100+
pub(crate) key_iter: K,
101+
pub(crate) table: &'b R::Table,
102+
pub(crate) id_col: usize,
103+
}
104+
105+
impl<'a, 'b, R, K, F> Iterator for TableMultiIter<'a, 'b, R, K, F>
106+
where
107+
K: Iterator<Item = i32>,
108+
F: FindHash,
109+
R: TypedRow<'a, 'b>,
110+
{
111+
type Item = (i32, R);
112+
113+
fn next(&mut self) -> Option<Self::Item> {
114+
for key in &mut self.key_iter {
115+
if let Some(hash) = self.index.find_hash(key) {
116+
if let Some(r) = R::get(self.table, hash, key, self.id_col) {
117+
return Some((key, r));
118+
}
119+
}
120+
}
121+
None
122+
}
123+
}
124+
93125
impl<'b, 'a: 'b, R, F, K> TypedTableIterAdapter<'a, 'b, R, F, K>
94126
where
95127
R: TypedRow<'a, 'b> + 'b,
96128
{
97-
pub(crate) fn to_iter(&self, id_col: usize) -> impl Iterator<Item = (i32, R)> + 'b
129+
pub(crate) fn to_iter(&self, id_col: usize) -> TableMultiIter<'a, 'b, R, K::IntoIter, F>
98130
where
99131
F: FindHash + Copy + 'b,
100132
K: IntoIterator<Item = i32> + Clone + 'b,
101133
{
102-
let table: &'b R::Table = self.table;
103-
let i = self.index;
104-
let iter = self.keys.clone().into_iter();
105-
let mapper = move |key| {
106-
let hash = i.find_hash(key)?;
107-
let r = R::get(table, hash, key, id_col)?;
108-
Some((key, r))
109-
};
110-
iter.filter_map(mapper)
134+
TableMultiIter {
135+
index: self.index,
136+
key_iter: self.keys.clone().into_iter(),
137+
table: self.table,
138+
id_col,
139+
}
111140
}
112141
}
113142

src/api/files.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
use assembly_pack::pki::core::PackFileRef;
2+
use color_eyre::eyre::Context;
3+
use serde::Serialize;
4+
use std::{path::Path, sync::Arc};
5+
use tracing::error;
6+
7+
use warp::{
8+
filters::BoxedFilter,
9+
hyper::StatusCode,
10+
reply::{json, with_status, Json, WithStatus},
11+
Filter,
12+
};
13+
14+
use crate::data::fs::{Loader, Node};
15+
16+
#[derive(Serialize)]
17+
struct CRCReply<'a> {
18+
fs: Option<&'a Node>,
19+
pk: Option<&'a PackFileRef>,
20+
}
21+
22+
/// Lookup information on a CRC i.e. a file path in the client
23+
pub fn make_crc_lookup_filter(
24+
res_path: &Path,
25+
pki_path: Option<&Path>,
26+
) -> BoxedFilter<(WithStatus<Json>,)> {
27+
let mut loader = Loader::new();
28+
loader.load_dir(Path::new("client/res"), res_path);
29+
if let Some(pki_path) = pki_path {
30+
if let Err(e) = loader
31+
.load_pki(pki_path)
32+
.with_context(|| format!("Failed to load PKI file at '{}'", pki_path.display()))
33+
{
34+
error!("{}", e);
35+
}
36+
}
37+
38+
let loader = Arc::new(loader);
39+
40+
warp::path::param()
41+
.map(move |crc: u32| {
42+
let fs = loader.get(crc).map(|e| &e.public);
43+
let pk = loader.get_pki(crc);
44+
with_status(json(&CRCReply { fs, pk }), StatusCode::OK)
45+
})
46+
.boxed()
47+
}

src/api/mod.rs

Lines changed: 59 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ use std::{
22
borrow::Borrow,
33
convert::Infallible,
44
error::Error,
5+
path::Path,
56
str::{FromStr, Utf8Error},
67
sync::Arc,
78
};
89

9-
use assembly_data::{fdb::mem::Database, xml::localization::LocaleNode};
10+
use assembly_fdb::mem::Database;
11+
use assembly_xml::localization::LocaleNode;
1012
use paradox_typed_db::TypedDatabase;
1113
use percent_encoding::percent_decode_str;
1214
use warp::{
@@ -16,16 +18,18 @@ use warp::{
1618
Filter, Reply,
1719
};
1820

19-
use crate::auth::AuthKind;
21+
use crate::{auth::AuthKind, data::locale::LocaleRoot};
2022

2123
use self::{
2224
adapter::{LocaleAll, LocalePod},
25+
files::make_crc_lookup_filter,
2326
rev::{make_api_rev, ReverseLookup},
2427
tables::{make_api_tables, tables_api},
2528
};
2629

2730
pub mod adapter;
2831
mod docs;
32+
mod files;
2933
pub mod rev;
3034
pub mod tables;
3135

@@ -149,45 +153,57 @@ pub fn locale_api(lr: Arc<LocaleNode>) -> impl Fn(Tail) -> Option<warp::reply::J
149153
}
150154
}
151155

152-
pub(crate) fn make_api(
153-
url: String,
154-
auth_kind: AuthKind,
155-
db: Database<'static>,
156-
tydb: &'static TypedDatabase<'static>,
157-
rev: &'static ReverseLookup,
158-
lr: Arc<LocaleNode>,
159-
) -> BoxedFilter<(WithStatus<Json>,)> {
160-
let v0_base = warp::path("v0");
161-
let v0_tables = warp::path("tables").and(make_api_tables(db));
162-
let v0_locale = warp::path("locale")
163-
.and(warp::path::tail())
164-
.map(locale_api(lr))
165-
.map(map_opt);
166-
167-
let v0_rev = warp::path("rev").and(make_api_rev(tydb, rev));
168-
let v0_openapi = docs::openapi(url, auth_kind).unwrap();
169-
let v0 = v0_base.and(
170-
v0_tables
171-
.or(v0_locale)
172-
.unify()
173-
.or(v0_rev)
174-
.unify()
175-
.or(v0_openapi)
176-
.unify(),
177-
);
178-
179-
// v1
180-
let dbf = db_filter(db);
181-
let v1_base = warp::path("v1");
182-
let v1_tables_base = dbf.and(warp::path("tables"));
183-
let v1_tables = v1_tables_base
184-
.and(warp::path::end())
185-
.map(tables_api)
186-
.map(map_res);
187-
let v1 = v1_base.and(v1_tables);
188-
189-
// catch all
190-
let catch_all = make_api_catch_all();
191-
192-
v0.or(v1).unify().or(catch_all).unify().boxed()
156+
pub(crate) struct ApiFactory<'a> {
157+
pub url: String,
158+
pub auth_kind: AuthKind,
159+
pub db: Database<'static>,
160+
pub tydb: &'static TypedDatabase<'static>,
161+
pub rev: &'static ReverseLookup,
162+
pub lr: Arc<LocaleNode>,
163+
pub res_path: &'a Path,
164+
pub pki_path: Option<&'a Path>,
165+
}
166+
167+
impl<'a> ApiFactory<'a> {
168+
pub(crate) fn make_api(self) -> BoxedFilter<(WithStatus<Json>,)> {
169+
let loc = LocaleRoot::new(self.lr.clone());
170+
171+
let v0_base = warp::path("v0");
172+
let v0_tables = warp::path("tables").and(make_api_tables(self.db));
173+
let v0_locale = warp::path("locale")
174+
.and(warp::path::tail())
175+
.map(locale_api(self.lr))
176+
.map(map_opt);
177+
178+
let v0_crc = warp::path("crc").and(make_crc_lookup_filter(self.res_path, self.pki_path));
179+
180+
let v0_rev = warp::path("rev").and(make_api_rev(self.tydb, loc, self.rev));
181+
let v0_openapi = docs::openapi(self.url, self.auth_kind).unwrap();
182+
let v0 = v0_base.and(
183+
v0_tables
184+
.or(v0_crc)
185+
.unify()
186+
.or(v0_locale)
187+
.unify()
188+
.or(v0_rev)
189+
.unify()
190+
.or(v0_openapi)
191+
.unify(),
192+
);
193+
194+
// v1
195+
let dbf = db_filter(self.db);
196+
let v1_base = warp::path("v1");
197+
let v1_tables_base = dbf.and(warp::path("tables"));
198+
let v1_tables = v1_tables_base
199+
.and(warp::path::end())
200+
.map(tables_api)
201+
.map(map_res);
202+
let v1 = v1_base.and(v1_tables);
203+
204+
// catch all
205+
let catch_all = make_api_catch_all();
206+
207+
v0.or(v1).unify().or(catch_all).unify().boxed()
208+
}
193209
}

src/api/rev/behaviors.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use assembly_core::buffer::CastError;
22
use paradox_typed_db::{
3-
typed_rows::{BehaviorTemplateRow, TypedRow},
4-
typed_tables::{BehaviorParameterTable, BehaviorTemplateTable},
5-
TypedDatabase,
3+
columns::BehaviorTemplateColumn,
4+
rows::BehaviorTemplateRow,
5+
tables::{BehaviorParameterTable, BehaviorTemplateTable},
6+
TypedDatabase, TypedRow,
67
};
78
use serde::ser::SerializeMap;
89
use serde::Serialize;
@@ -56,14 +57,18 @@ impl Serialize for EmbeddedBehaviors<'_, '_> {
5657
S: serde::Serializer,
5758
{
5859
let mut m = serializer.serialize_map(Some(self.keys.len()))?;
60+
let col_behavior_id = self
61+
.table_templates
62+
.get_col(BehaviorTemplateColumn::BehaviorId)
63+
.unwrap();
5964
for &behavior_id in self.keys {
6065
m.serialize_key(&behavior_id)?;
6166
let b = Behavior {
6267
template: BehaviorTemplateRow::get(
6368
self.table_templates,
6469
behavior_id,
6570
behavior_id,
66-
self.table_templates.col_behavior_id,
71+
col_behavior_id,
6772
),
6873
parameters: BehaviorParameters {
6974
key: behavior_id,

src/api/rev/common.rs

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
use std::collections::HashMap;
22

3+
use assembly_fdb::common::Latin1Str;
34
use paradox_typed_db::{
4-
typed_rows::{MissionTaskRow, ObjectsRef},
5-
typed_tables::MissionTasksTable,
5+
columns::ObjectsColumn,
6+
rows::{MissionTasksRow, ObjectsRow},
7+
tables::{MissionTasksTable, ObjectsTable},
68
};
79
use serde::Serialize;
810

9-
use crate::api::adapter::{FindHash, I32Slice, IdentityHash, TypedTableIterAdapter};
11+
use crate::api::adapter::{
12+
FindHash, I32Slice, IdentityHash, TableMultiIter, TypedTableIterAdapter,
13+
};
1014

1115
use super::data::MissionTaskUIDLookup;
1216

@@ -16,8 +20,40 @@ pub struct MapFilter<'a, E> {
1620
keys: &'a [i32],
1721
}
1822

19-
pub(super) type ObjectsRefAdapter<'a, 'b> =
20-
TypedTableIterAdapter<'a, 'b, ObjectsRef<'a, 'b>, IdentityHash, I32Slice<'b>>;
23+
#[derive(Clone)]
24+
pub struct ObjectsRefAdapter<'a, 'b> {
25+
table: &'b ObjectsTable<'a>,
26+
keys: &'b [i32],
27+
}
28+
29+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize)]
30+
struct ObjectRefData<'a> {
31+
name: &'a Latin1Str,
32+
}
33+
34+
impl<'a, 'b> ObjectsRefAdapter<'a, 'b> {
35+
pub fn new(table: &'b ObjectsTable<'a>, keys: &'b [i32]) -> Self {
36+
Self { table, keys }
37+
}
38+
}
39+
40+
impl<'a, 'b> serde::Serialize for ObjectsRefAdapter<'a, 'b> {
41+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
42+
where
43+
S: serde::Serializer,
44+
{
45+
let id_col = self.table.get_col(ObjectsColumn::Id).unwrap();
46+
serializer.collect_map(
47+
TableMultiIter {
48+
index: IdentityHash,
49+
key_iter: self.keys.iter().copied(),
50+
table: self.table,
51+
id_col,
52+
}
53+
.map(|(id, row): (i32, ObjectsRow)| (id, ObjectRefData { name: row.name() })),
54+
)
55+
}
56+
}
2157

2258
#[derive(Serialize)]
2359
pub(super) struct ObjectTypeEmbedded<'a, 'b> {
@@ -44,7 +80,7 @@ impl<'a, E: Serialize> Serialize for MapFilter<'a, E> {
4480
pub(super) type MissionTaskHash<'b> = &'b HashMap<i32, MissionTaskUIDLookup>;
4581

4682
pub(super) type MissionTasks<'a, 'b> =
47-
TypedTableIterAdapter<'a, 'b, MissionTaskRow<'a, 'b>, MissionTaskHash<'b>, I32Slice<'b>>;
83+
TypedTableIterAdapter<'a, 'b, MissionTasksRow<'a, 'b>, MissionTaskHash<'b>, I32Slice<'b>>;
4884

4985
pub(super) struct MissionTaskIconsAdapter<'a, 'b> {
5086
table: &'b MissionTasksTable<'a>,

0 commit comments

Comments
 (0)