Compare commits
No commits in common. "master" and "feature/web" have entirely different histories.
master
...
feature/we
8 changed files with 66 additions and 68 deletions
18
package-lock.json
generated
Normal file
18
package-lock.json
generated
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "SkyrimOutfitSystemSE",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"devDependencies": {
|
||||
"@types/lodash": "^4.14.191"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.14.191",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz",
|
||||
"integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
5
package.json
Normal file
5
package.json
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"devDependencies": {
|
||||
"@types/lodash": "^4.14.191"
|
||||
}
|
||||
}
|
||||
|
|
@ -18,7 +18,6 @@ use commonlibsse::*;
|
|||
use log::*;
|
||||
use once_cell::sync::Lazy;
|
||||
use parking_lot::RwLock;
|
||||
use settings::{IntragameCaches, INTRAGAME_CACHES};
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn plugin_main(skse: *const SKSE_LoadInterface) -> bool {
|
||||
|
|
@ -105,7 +104,6 @@ pub extern "C" fn messaging_callback(message: *mut SKSE_MessagingInterface_Messa
|
|||
let mut service = OUTFIT_SERVICE_SINGLETON.write();
|
||||
service.replace_with_new();
|
||||
service.check_consistency();
|
||||
*(INTRAGAME_CACHES.write()) = IntragameCaches::new();
|
||||
}
|
||||
message_type => {
|
||||
warn!("Got unknown message type {}", message_type);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::{
|
|||
armor::{ArmorExt, ArmorLocatorExt},
|
||||
interface::ffi::{OptionalStateType, StateType, TESObjectARMOPtr, WeatherFlags},
|
||||
policy::*,
|
||||
settings::{INTRAGAME_CACHES, SETTINGS},
|
||||
settings::SETTINGS,
|
||||
stable_ptr::*,
|
||||
strings::UncasedString,
|
||||
};
|
||||
|
|
@ -161,7 +161,6 @@ impl Outfit {
|
|||
) -> Vec<*const RE_TESObjectARMO> {
|
||||
let start_time = Instant::now();
|
||||
let policy_store = &*POLICY_STORE;
|
||||
let intragame_settings = INTRAGAME_CACHES.read();
|
||||
let equipped = {
|
||||
let mut slots = [std::ptr::null(); RE_BIPED_OBJECTS_BIPED_OBJECT_kEditorTotal as usize];
|
||||
for armor in equipped {
|
||||
|
|
@ -225,7 +224,7 @@ impl Outfit {
|
|||
// First check if the equipped item is a "golden item". If so, it always wins.
|
||||
if selected_armor.is_none() {
|
||||
if let Some(equipped_item) = TESObjectARMOStablePtr::new(equipped[slot as usize]) {
|
||||
if intragame_settings.golden_items.contains(&equipped_item) {
|
||||
if SETTINGS.golden_items().contains(&equipped_item) {
|
||||
selected_armor = Some(equipped_item.as_ptr());
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
use crate::{
|
||||
settings::{IntragameCaches, INTRAGAME_CACHES},
|
||||
OUTFIT_SERVICE_SINGLETON,
|
||||
};
|
||||
use crate::OUTFIT_SERVICE_SINGLETON;
|
||||
use commonlibsse::*;
|
||||
use log::*;
|
||||
use std::ffi::c_void;
|
||||
|
|
@ -78,7 +75,6 @@ pub extern "C" fn serialization_load_callback(intfc: *mut SKSE_SerializationInte
|
|||
error!("Did not read the correct amount of data for deserialization");
|
||||
break;
|
||||
}
|
||||
*(INTRAGAME_CACHES.write()) = IntragameCaches::new();
|
||||
let mut service = OUTFIT_SERVICE_SINGLETON.write();
|
||||
if !service.replace_with_proto(&buffer, intfc) {
|
||||
error!("Failed to use proto data to instantiate");
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ use configparser::ini::Ini;
|
|||
use hash_hasher::HashedSet;
|
||||
use log::*;
|
||||
use once_cell::sync::Lazy;
|
||||
use parking_lot::RwLock;
|
||||
use std::{ffi::CString, path::PathBuf};
|
||||
|
||||
pub struct Settings {
|
||||
ini: Ini,
|
||||
golden_items: HashedSet<TESObjectARMOStablePtr>,
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
|
|
@ -28,7 +28,8 @@ impl Settings {
|
|||
} else {
|
||||
info!("Loaded INI file in {}", file.display());
|
||||
}
|
||||
Settings { ini }
|
||||
let golden_items = Self::generate_golden_items(&ini);
|
||||
Settings { ini, golden_items }
|
||||
}
|
||||
|
||||
pub fn extra_logging_enabled(&self) -> bool {
|
||||
|
|
@ -84,25 +85,15 @@ impl Settings {
|
|||
.unwrap_or_else(|_| None)
|
||||
.unwrap_or_else(|| false)
|
||||
}
|
||||
}
|
||||
|
||||
pub static SETTINGS: Lazy<Settings> = Lazy::new(|| Settings::new());
|
||||
|
||||
pub struct IntragameCaches {
|
||||
pub golden_items: HashedSet<TESObjectARMOStablePtr>,
|
||||
}
|
||||
|
||||
impl IntragameCaches {
|
||||
pub fn new() -> Self {
|
||||
let golden_items = Self::generate_golden_items(&SETTINGS.ini);
|
||||
IntragameCaches { golden_items }
|
||||
pub fn golden_items(&self) -> &HashedSet<TESObjectARMOStablePtr> {
|
||||
&self.golden_items
|
||||
}
|
||||
|
||||
fn generate_golden_items(ini: &Ini) -> HashedSet<TESObjectARMOStablePtr> {
|
||||
// Start with the set of built-in locators
|
||||
let mut locators = vec![
|
||||
("Dragonborn.esm", 0x00021739), // Dragon Aspect Armor
|
||||
];
|
||||
let mut locators = vec![];
|
||||
|
||||
// Load locators from INI file.
|
||||
let ini_string = ini
|
||||
.get("Compatibility", "GoldenItems")
|
||||
|
|
@ -120,7 +111,7 @@ impl IntragameCaches {
|
|||
if data_handler.is_null() {
|
||||
return Default::default();
|
||||
}
|
||||
let items = locators
|
||||
locators
|
||||
.into_iter()
|
||||
.flat_map(|(mod_name, local_form_id)| {
|
||||
let Ok(mod_name) = CString::new(mod_name) else { return None };
|
||||
|
|
@ -135,10 +126,8 @@ impl IntragameCaches {
|
|||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
items
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub static INTRAGAME_CACHES: Lazy<RwLock<IntragameCaches>> =
|
||||
Lazy::new(|| RwLock::new(IntragameCaches::new()));
|
||||
pub static SETTINGS: Lazy<Settings> = Lazy::new(|| Settings::new());
|
||||
|
|
|
|||
|
|
@ -1,15 +1,12 @@
|
|||
use std::{path::PathBuf, io::{Read, Cursor}};
|
||||
use log::*;
|
||||
use std::{
|
||||
io::{Cursor, Read},
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
use crate::{interface::ffi::GetRuntimeDirectory, settings::SETTINGS};
|
||||
use warp_static_zip::ZipArchive;
|
||||
use warp::Filter;
|
||||
use warp::Reply;
|
||||
use warp_static_zip::ZipArchive;
|
||||
use crate::{interface::ffi::GetRuntimeDirectory, settings::SETTINGS};
|
||||
|
||||
pub async fn web_server() {
|
||||
pub async fn web_server() {
|
||||
let get_state = warp::path!("state")
|
||||
.and(warp::get())
|
||||
.and_then(handlers::get_state);
|
||||
|
|
@ -40,7 +37,7 @@ pub async fn web_server() {
|
|||
.or(policy_info);
|
||||
|
||||
let static_asset_routes = create_zip_route();
|
||||
|
||||
|
||||
let addr = if SETTINGS.server_remote_accessible() {
|
||||
[0, 0, 0, 0]
|
||||
} else {
|
||||
|
|
@ -51,7 +48,7 @@ pub async fn web_server() {
|
|||
match binding {
|
||||
Ok((addr, sock)) => {
|
||||
info!("Server bound to {}", addr);
|
||||
sock.await;
|
||||
sock.await;
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("Could not bind address: {}", err);
|
||||
|
|
@ -69,7 +66,7 @@ fn create_zip_route() -> warp::filters::BoxedFilter<(impl Reply,)> {
|
|||
if let Err(error) = zip_data.read_to_end(&mut data) {
|
||||
error!("Failed to read web archive file: {}", error);
|
||||
};
|
||||
data
|
||||
data
|
||||
}
|
||||
Err(error) => {
|
||||
error!("Failed to read zip archive file: {}", error);
|
||||
|
|
@ -77,7 +74,7 @@ fn create_zip_route() -> warp::filters::BoxedFilter<(impl Reply,)> {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
let zip_archive = Box::leak(Box::new(ZipArchive::new(Cursor::new(&*zip_vector.leak()))));
|
||||
let static_asset_routes = {
|
||||
match zip_archive {
|
||||
|
|
@ -99,9 +96,9 @@ fn create_zip_route() -> warp::filters::BoxedFilter<(impl Reply,)> {
|
|||
|
||||
mod handlers {
|
||||
use crate::{
|
||||
outfit::Outfit,
|
||||
armor::{ArmorExt, ArmorLocatorExt},
|
||||
interface::ffi::{ArmorSearch, CreateRefreshAllArmorsTask},
|
||||
outfit::Outfit,
|
||||
policy::POLICY_STORE,
|
||||
settings::SETTINGS,
|
||||
stable_ptr::TESObjectARMOStablePtr,
|
||||
|
|
@ -210,7 +207,7 @@ mod handlers {
|
|||
let info = ArmorInfo {
|
||||
locator: locator_in,
|
||||
name,
|
||||
mask,
|
||||
mask
|
||||
};
|
||||
Ok(warp::reply::with_status(
|
||||
warp::reply::json(&info),
|
||||
|
|
@ -244,11 +241,9 @@ mod handlers {
|
|||
})?,
|
||||
name: unsafe {
|
||||
let cstr = CStr::from_ptr(armor.borrow()._base._base._base.GetName());
|
||||
cstr.to_str()
|
||||
.map(|s| s.to_owned())
|
||||
.unwrap_or_else(|_| "".to_owned())
|
||||
cstr.to_str().map(|s| s.to_owned()).unwrap_or_else(|_| "".to_owned())
|
||||
},
|
||||
mask: unsafe { armor.borrow()._base_10.GetSlotMask() } as u32,
|
||||
mask: unsafe { armor.borrow()._base_10.GetSlotMask() } as u32
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
|
|
|||
|
|
@ -8,8 +8,11 @@ use headers::{
|
|||
use http::{HeaderMap, StatusCode};
|
||||
use hyper::Body;
|
||||
use std::future::ready;
|
||||
use std::{
|
||||
path::{PathBuf},
|
||||
time::SystemTime,
|
||||
};
|
||||
use std::io::{Read, Seek};
|
||||
use std::{path::PathBuf, time::SystemTime};
|
||||
use warp::{
|
||||
filters::header::headers_cloned,
|
||||
path::{tail, Tail},
|
||||
|
|
@ -26,7 +29,8 @@ pub use once_cell::sync::Lazy;
|
|||
|
||||
#[doc(hidden)]
|
||||
pub fn failed() -> impl Filter<Extract = (Response,), Error = Rejection> + Clone + 'static {
|
||||
warp::get().and_then(move || ready(Err(reject::not_found())))
|
||||
warp::get()
|
||||
.and_then(move || ready(Err(reject::not_found())))
|
||||
}
|
||||
|
||||
/// Creates a [Filter][warp::Filter] that serves an included directory.
|
||||
|
|
@ -68,20 +72,13 @@ pub fn file<'a, R: Read + Seek + Clone + Send + Sync>(
|
|||
.and_then(move |path, conds| ready(reply(dir, path, conds)))
|
||||
}
|
||||
|
||||
fn parse_path<R: Read + Seek + Clone>(
|
||||
tail: &str,
|
||||
dir: &ZipArchive<R>,
|
||||
) -> Result<String, Rejection> {
|
||||
let mut path_str = urlencoding::decode(tail).map_err(|_| reject::not_found())?;
|
||||
|
||||
fn parse_path<R: Read + Seek + Clone>(tail: &str, dir: &ZipArchive<R>) -> Result<String, Rejection> {
|
||||
let mut path_str = urlencoding::decode(tail)
|
||||
.map_err(|_| reject::not_found())?;
|
||||
let path: PathBuf = path_str.split('/').collect();
|
||||
|
||||
if path.parent().is_none()
|
||||
|| dir
|
||||
.clone()
|
||||
.by_name(&path_str)
|
||||
.map(|v| v.is_dir())
|
||||
.unwrap_or(false)
|
||||
{
|
||||
if path.parent().is_none() || dir.clone().by_name(&path_str).map(|v| v.is_dir()).unwrap_or(false) {
|
||||
log::debug!("appending index.html to {:?}", path);
|
||||
path_str += "/index.html";
|
||||
}
|
||||
|
|
@ -154,11 +151,7 @@ fn bytes_range(range: Range, max_len: u64) -> Option<(u64, u64)> {
|
|||
}
|
||||
}
|
||||
|
||||
fn reply<R: Read + Seek + Clone>(
|
||||
dir: &ZipArchive<R>,
|
||||
path: String,
|
||||
conds: Conditionals,
|
||||
) -> Result<Response, Rejection> {
|
||||
fn reply<R: Read + Seek + Clone>(dir: &ZipArchive<R>, path: String, conds: Conditionals) -> Result<Response, Rejection> {
|
||||
let mut contents = Vec::new();
|
||||
if let Ok(mut file) = dir.clone().by_name(&path) {
|
||||
file.read_to_end(&mut contents).unwrap();
|
||||
|
|
@ -201,7 +194,12 @@ fn reply_full(buf: Vec<u8>, path: &str, last_mod: LastModified) -> Response {
|
|||
resp
|
||||
}
|
||||
|
||||
fn reply_range(buf: Vec<u8>, (s, e): (u64, u64), path: &str, last_mod: LastModified) -> Response {
|
||||
fn reply_range(
|
||||
buf: Vec<u8>,
|
||||
(s, e): (u64, u64),
|
||||
path: &str,
|
||||
last_mod: LastModified,
|
||||
) -> Response {
|
||||
let len = e - s;
|
||||
let buf = (&buf[s as usize..e as usize]).to_owned();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue