Finish Proto impl
This commit is contained in:
parent
d865be3f5b
commit
96a980bba1
7 changed files with 107 additions and 21 deletions
|
|
@ -133,7 +133,8 @@ add_library(SkyrimOutfitSystemSE SHARED
|
|||
src/hooking/Patches.cpp
|
||||
src/Utility.cpp
|
||||
include/RE/REAugments.h
|
||||
src/RE/REAugments.cpp)
|
||||
src/RE/REAugments.cpp
|
||||
src/RustSymbols.cpp)
|
||||
|
||||
set(ROOT_NAMESPACE SkyrimOutfitSystemSE)
|
||||
|
||||
|
|
|
|||
9
src/RustSymbols.cpp
Normal file
9
src/RustSymbols.cpp
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
//
|
||||
// Created by m on 10/23/2022.
|
||||
//
|
||||
|
||||
namespace RE {
|
||||
TESObjectARMO* ResolveARMOFormID(FormID id) {
|
||||
return skyrim_cast<RE::TESObjectARMO*>(RE::TESForm::LookupByID(id));
|
||||
}
|
||||
}
|
||||
|
|
@ -6,11 +6,11 @@
|
|||
#define SKYRIMOUTFITSYSTEMSE_SRC_RUST_COMMONLIBSSE_SRC_CUSTOMIZE_H
|
||||
|
||||
#include <RE/Skyrim.h>
|
||||
#include <SKSE/SKSE.h>
|
||||
|
||||
namespace RE {
|
||||
using BipedObjectSlot = BIPED_MODEL::BipedObjectSlot;
|
||||
PlayerCharacter* PlayerCharacter_GetSingleton() {
|
||||
return RE::PlayerCharacter::GetSingleton();
|
||||
}
|
||||
TESObjectARMO* ResolveARMOFormID(FormID id);
|
||||
}
|
||||
|
||||
#endif //SKYRIMOUTFITSYSTEMSE_SRC_RUST_COMMONLIBSSE_SRC_CUSTOMIZE_H
|
||||
|
|
|
|||
|
|
@ -92,25 +92,28 @@ pub mod ffi {
|
|||
unsafe extern "C++" {
|
||||
include!("commonlibsse/include/customize.h");
|
||||
pub type TESObjectARMO;
|
||||
pub fn ResolveARMOFormID(id: u32) -> *mut TESObjectARMO;
|
||||
pub fn GetSlotMask(self: &TESObjectARMO) -> BipedObjectSlot;
|
||||
pub fn GetFormID(self: &TESObjectARMO) -> u32;
|
||||
pub type BipedObjectSlot;
|
||||
pub type BIPED_OBJECT;
|
||||
pub type PlayerCharacter;
|
||||
pub fn PlayerCharacter_GetSingleton() -> *mut PlayerCharacter;
|
||||
#[namespace = "SKSE"]
|
||||
pub type SerializationInterface;
|
||||
pub fn ResolveFormID(self: &SerializationInterface, old_form: u32, new_form: &mut u32) -> bool;
|
||||
pub fn ResolveHandle(self: &SerializationInterface, old_handle: u64, new_handle: &mut u64) -> bool;
|
||||
}
|
||||
}
|
||||
|
||||
impl BIPED_OBJECT {
|
||||
pub const MAX_IN_GAME: usize = BIPED_OBJECT::kHandToHandMelee.repr as usize;
|
||||
pub const MAX_IN_GAME: u32 = BIPED_OBJECT::kHandToHandMelee.repr;
|
||||
}
|
||||
|
||||
impl TESObjectARMO {
|
||||
pub fn assign_using_mask(&mut self, dest: &mut [*mut TESObjectARMO; BIPED_OBJECT::MAX_IN_GAME]) {
|
||||
pub fn assign_using_mask(&mut self, dest: &mut [*mut TESObjectARMO; BIPED_OBJECT::MAX_IN_GAME as usize]) {
|
||||
let mask = self.GetSlotMask().repr;
|
||||
for slot in 0..BIPED_OBJECT::MAX_IN_GAME {
|
||||
if mask & (1 << slot) != 0 {
|
||||
dest[slot] = self;
|
||||
dest[slot as usize] = self;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,4 @@
|
|||
#ifndef SKYRIMOUTFITSYSTEMSE_SRC_RUST_COMMONLIBSSE_SRC_CUSTOMIZE_H
|
||||
#define SKYRIMOUTFITSYSTEMSE_SRC_RUST_COMMONLIBSSE_SRC_CUSTOMIZE_H
|
||||
|
||||
namespace RE {
|
||||
class PlayerCharacter;
|
||||
}
|
||||
|
||||
#endif //SKYRIMOUTFITSYSTEMSE_SRC_RUST_COMMONLIBSSE_SRC_CUSTOMIZE_H
|
||||
|
|
|
|||
|
|
@ -59,8 +59,6 @@ mod ffi {
|
|||
#[namespace = "RE"]
|
||||
extern "C++" {
|
||||
include!("sos/include/customize.h");
|
||||
type PlayerCharacter = commonlibsse::ffi::PlayerCharacter;
|
||||
|
||||
}
|
||||
extern "Rust" {
|
||||
type OutfitService;
|
||||
|
|
@ -114,6 +112,8 @@ impl ffi::Policy {
|
|||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
pub const MAX: u8 = (Self::XEOO.repr + 1);
|
||||
}
|
||||
|
||||
pub enum PolicySelection {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
use std::ptr::null_mut;
|
||||
use uncased::{Uncased, UncasedStr};
|
||||
use commonlibsse::{BIPED_OBJECT, TESObjectARMO};
|
||||
use commonlibsse::{BIPED_OBJECT, SerializationInterface, TESObjectARMO, ResolveARMOFormID};
|
||||
use crate::{PolicySelection, UncasedString};
|
||||
use crate::ffi::{WeatherFlags, LocationType, Policy};
|
||||
use crate::outfit::slot_policy::Policies;
|
||||
|
|
@ -23,6 +23,40 @@ impl Outfit {
|
|||
}
|
||||
}
|
||||
|
||||
fn from_proto_data(input: &protos::outfit::Outfit, infc: &SerializationInterface) -> Self {
|
||||
let mut outfit = Outfit {
|
||||
name: Uncased::new(input.name.as_str()).into_owned(),
|
||||
armors: Default::default(),
|
||||
favorite: input.is_favorite,
|
||||
slot_policies: Policies {
|
||||
slot_policies: Default::default(),
|
||||
blanket_slot_policy: Policy::XXXX
|
||||
}
|
||||
};
|
||||
for armor in &input.armors {
|
||||
let mut form_id = 0;
|
||||
if (*infc).ResolveFormID(*armor, &mut form_id) {
|
||||
let armor = ResolveARMOFormID(form_id);
|
||||
if !armor.is_null() {
|
||||
outfit.armors.insert(armor);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (slot, policy) in &input.slot_policies {
|
||||
let policy = *policy as u8;
|
||||
if *slot >= BIPED_OBJECT::MAX_IN_GAME || policy >= Policy::MAX {
|
||||
continue
|
||||
}
|
||||
let slot = BIPED_OBJECT { repr: *slot };
|
||||
let policy = Policy { repr: policy };
|
||||
outfit.slot_policies.slot_policies.insert(slot, policy);
|
||||
}
|
||||
if (input.slot_policy as u8) < Policy::MAX {
|
||||
outfit.slot_policies.blanket_slot_policy = Policy { repr: input.slot_policy as u8 };
|
||||
}
|
||||
outfit
|
||||
}
|
||||
|
||||
unsafe fn conflicts_with(&self, armor: *mut TESObjectARMO) -> bool {
|
||||
if armor.is_null() { return false }
|
||||
let mask = (*armor).GetSlotMask();
|
||||
|
|
@ -36,14 +70,14 @@ impl Outfit {
|
|||
|
||||
unsafe fn compute_display_set(&self, equipped: Vec<*mut TESObjectARMO>) -> Vec<*mut TESObjectARMO> {
|
||||
let equipped = {
|
||||
let mut slots = [null_mut(); BIPED_OBJECT::MAX_IN_GAME];
|
||||
let mut slots = [null_mut(); BIPED_OBJECT::MAX_IN_GAME as usize];
|
||||
for armor in equipped {
|
||||
(*armor).assign_using_mask(&mut slots);
|
||||
}
|
||||
slots
|
||||
};
|
||||
let outfit = {
|
||||
let mut slots = [null_mut(); BIPED_OBJECT::MAX_IN_GAME];
|
||||
let mut slots = [null_mut(); BIPED_OBJECT::MAX_IN_GAME as usize];
|
||||
for armor in &self.armors {
|
||||
(**armor).assign_using_mask(&mut slots);
|
||||
}
|
||||
|
|
@ -57,11 +91,13 @@ impl Outfit {
|
|||
.slot_policies.get(&BIPED_OBJECT { repr: slot as u32 })
|
||||
.unwrap_or_else(|| &self.slot_policies.blanket_slot_policy)
|
||||
.clone();
|
||||
let selection = policy.select(!equipped[slot].is_null(), !outfit[slot].is_null());
|
||||
let selection = policy.select(
|
||||
!equipped[slot as usize].is_null(),
|
||||
!outfit[slot as usize].is_null());
|
||||
let selected_armor = match selection {
|
||||
None => None,
|
||||
Some(PolicySelection::Equipped) => Some(equipped[slot]),
|
||||
Some(PolicySelection::Outfit) => Some(outfit[slot]),
|
||||
Some(PolicySelection::Equipped) => Some(equipped[slot as usize]),
|
||||
Some(PolicySelection::Outfit) => Some(outfit[slot as usize]),
|
||||
};
|
||||
if let Some(selected_armor) = selected_armor {
|
||||
mask |= (*selected_armor).GetSlotMask().repr;
|
||||
|
|
@ -129,6 +165,47 @@ impl OutfitService {
|
|||
location_switching_enabled: false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_proto_data(data: Vec<u8>, infc: &SerializationInterface) -> Option<Self> {
|
||||
use protobuf::Message;
|
||||
let mut new = OutfitService::new();
|
||||
let input = protos::outfit::OutfitSystem::parse_from_bytes(&data).ok()?;
|
||||
new.enabled = input.enabled;
|
||||
let mut actor_assignments = BTreeMap::new();
|
||||
for (actor_handle, assignments) in &input.actor_outfit_assignments {
|
||||
let mut new_handle = *actor_handle;
|
||||
if !(*infc).ResolveHandle(*actor_handle, &mut new_handle) {
|
||||
continue
|
||||
}
|
||||
let mut assignments_out = ActorAssignments {
|
||||
current: None,
|
||||
location_based: Default::default()
|
||||
};
|
||||
assignments_out.current = if assignments.current_outfit_name.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(Uncased::from(assignments.current_outfit_name.as_str()).into_owned())
|
||||
};
|
||||
for (location, assignment) in assignments.location_based_outfits.iter() {
|
||||
let value = if assignment.is_empty() {
|
||||
continue
|
||||
} else {
|
||||
Uncased::from(assignment.as_str()).into_owned()
|
||||
};
|
||||
let location = LocationType { repr: *location };
|
||||
assignments_out.location_based.insert(location, value);
|
||||
}
|
||||
actor_assignments.insert(new_handle as u32, assignments_out);
|
||||
}
|
||||
new.actor_assignments = actor_assignments;
|
||||
for outfit in input.outfits {
|
||||
new.outfits.insert(Uncased::from(outfit.name.as_str()).into_owned(),
|
||||
Outfit::from_proto_data(&outfit, infc));
|
||||
}
|
||||
new.location_switching_enabled = input.location_based_auto_switch_enabled;
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn get_outfit_ptr(&mut self, name: &str) -> *mut Outfit {
|
||||
if let Some(reference) = self.get_mut_outfit(name) {
|
||||
reference
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue