Finish Proto impl

This commit is contained in:
MetricExpansion 2022-10-23 17:04:54 -07:00
parent d865be3f5b
commit 96a980bba1
7 changed files with 107 additions and 21 deletions

View file

@ -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
View 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));
}
}

View file

@ -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

View file

@ -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;
}
}
}

View file

@ -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

View file

@ -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 {

View file

@ -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