ClothingPluginManager_patched

创建于 差异永不过期
1 删除
435
36 添加
468
using System;
using System;
using UnityEngine;
using UnityEngine;
using System.Collections;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Text;
using System.Text;
using SimpleJSON;
using SimpleJSON;
using MVR;
using MVR;
using MeshVR;
using MeshVR;
using System.Linq;
using System.Linq;
using Leap.Unity;
using Leap.Unity;
using MVR.FileManagementSecure;
using MVR.FileManagementSecure;
using System.Security.AccessControl;
using System.Security.AccessControl;




namespace Stopper {
namespace Stopper {
public class ClothingPluginManager : MVRScript {
public class ClothingPluginManager : MVRScript {


string fileExt = "clothingplugins";
string fileExt = "clothingplugins";


DAZDynamic dazDynamic;
DAZDynamic dazDynamic;
DAZDynamicItem dazDynamicItem;
DAZDynamicItem dazDynamicItem;
MVRPluginManager pluginManager;
MVRPluginManager pluginManager;
PresetManager presetManager;
PresetManager presetManager;
Destructor destruct;
Destructor destruct;


bool needsReload = false;
bool needsReload = false;


JSONClass sceneJson = null;
JSONClass sceneJson = null;
bool lastRestoreWasSceneRestore = false;
bool lastRestoreWasSceneRestore = false;


public override void Init() {
public override void Init() {
WalkAndGetParentItems();
WalkAndGetParentItems();
if(containingAtom == null) throw new Exception("Unable to determine containing atom.");
if(containingAtom == null) throw new Exception("Unable to determine containing atom.");
if(pluginManager == null) throw new Exception("Unable to find plugin manager.");
if(pluginManager == null) throw new Exception("Unable to find plugin manager.");
if(dazDynamicItem == null) throw new Exception("Unable to find dynamic item.");
if(dazDynamicItem == null) throw new Exception("Unable to find dynamic item.");
if(dazDynamic == null) throw new Exception("Unable to find dazDynamic item.");
if(dazDynamic == null) throw new Exception("Unable to find dazDynamic item.");


this.overrideId = $"{dazDynamic.uid}:{this.storeId}";
this.overrideId = $"{dazDynamic.uid}:{this.storeId}";


DAZCharacterSelector selector = containingAtom.GetStorableByID("geometry") as DAZCharacterSelector;
DAZCharacterSelector selector = containingAtom.GetStorableByID("geometry") as DAZCharacterSelector;
if(selector == null) throw new Exception("Unable to find CharacterSelector");
if(selector == null) throw new Exception("Unable to find CharacterSelector");




pluginManager.containingAtom = containingAtom;
pluginManager.containingAtom = containingAtom;
pluginManager.gameObject.SetActive(true);
pluginManager.gameObject.SetActive(true);
pluginManager.exclude = true;
pluginManager.exclude = true;


presetManager = dazDynamic.GetComponentInChildren<PresetManager>();
presetManager = dazDynamic.GetComponentInChildren<PresetManager>();
List<PresetManager.SpecificStorable> specificStorables = presetManager.specificStorables.ToList();
List<PresetManager.SpecificStorable> specificStorables = presetManager.specificStorables.ToList();


PresetManager.SpecificStorable specificStorable = null;
PresetManager.SpecificStorable specificStorable = null;
foreach(var storable in specificStorables) {
foreach(var storable in specificStorables) {
if(storable.specificKey == "ClothingPluginManager") {
if(storable.specificKey == "ClothingPluginManager") {
specificStorable = storable;
specificStorable = storable;
specificStorable.specificStorableBucket = this.transform;
specificStorable.specificStorableBucket = this.transform;
}
}
}
}
if(specificStorable == null) {
if(specificStorable == null) {
specificStorable = new PresetManager.SpecificStorable();
specificStorable = new PresetManager.SpecificStorable();
specificStorable.specificKey = "ClothingPluginManager";
specificStorable.specificKey = "ClothingPluginManager";
specificStorable.storeId = this.storeId;
specificStorable.storeId = this.storeId;
specificStorable.specificStorableBucket = this.transform;
specificStorable.specificStorableBucket = this.transform;
specificStorable.includeChildren = false;
specificStorable.includeChildren = false;
}
}
presetManager.specificStorables = specificStorables.ToArray();
presetManager.specificStorables = specificStorables.ToArray();
presetManager.RefreshStorables();
presetManager.RefreshStorables();


// Add the destructor to unload mods if we do a force reload
// Add the destructor to unload mods if we do a force reload
if(dazDynamicItem != selector.femaleClothingCreatorItem && dazDynamicItem != selector.maleClothingCreatorItem) {
if(dazDynamicItem != selector.femaleClothingCreatorItem && dazDynamicItem != selector.maleClothingCreatorItem) {
destruct = dazDynamic.binaryStorableBucket.gameObject.AddComponent<Destructor>();
destruct = dazDynamic.binaryStorableBucket.gameObject.AddComponent<Destructor>();
destruct.pluginManager = pluginManager;
destruct.pluginManager = pluginManager;
destruct.storedContainingAtom = containingAtom;
destruct.storedContainingAtom = containingAtom;
}
}




// If this isn't set on the plugin manager by the time we reach here, then
// If this isn't set on the plugin manager by the time we reach here, then
// this plugin will not show up in the UI. In that case we'll want to reload the plugins.
// this plugin will not show up in the UI. In that case we'll want to reload the plugins.
if(pluginManager.pluginPanelPrefab == null) {
if(pluginManager.pluginPanelPrefab == null) {
needsReload = true;
needsReload = true;
}
}
// Copy over all of the prefabs
// Copy over all of the prefabs
MVRPluginManager containingAtomPluginManager = containingAtom.GetStorableByID("PluginManager") as MVRPluginManager;
MVRPluginManager containingAtomPluginManager = containingAtom.GetStorableByID("PluginManager") as MVRPluginManager;
if(containingAtomPluginManager != null){
if(containingAtomPluginManager != null){
pluginManager.pluginPanelPrefab = containingAtomPluginManager.pluginPanelPrefab;
pluginManager.pluginPanelPrefab = containingAtomPluginManager.pluginPanelPrefab;
pluginManager.scriptControllerPanelPrefab = containingAtomPluginManager.scriptControllerPanelPrefab;
pluginManager.scriptControllerPanelPrefab = containingAtomPluginManager.scriptControllerPanelPrefab;
pluginManager.scriptUIPrefab = containingAtomPluginManager.scriptUIPrefab;
pluginManager.scriptUIPrefab = containingAtomPluginManager.scriptUIPrefab;
pluginManager.configurableSliderPrefab = containingAtomPluginManager.configurableSliderPrefab;
pluginManager.configurableSliderPrefab = containingAtomPluginManager.configurableSliderPrefab;
pluginManager.configurableTogglePrefab = containingAtomPluginManager.configurableTogglePrefab;
pluginManager.configurableTogglePrefab = containingAtomPluginManager.configurableTogglePrefab;
pluginManager.configurableColorPickerPrefab = containingAtomPluginManager.configurableColorPickerPrefab;
pluginManager.configurableColorPickerPrefab = containingAtomPluginManager.configurableColorPickerPrefab;
pluginManager.configurableButtonPrefab = containingAtomPluginManager.configurableButtonPrefab;
pluginManager.configurableButtonPrefab = containingAtomPluginManager.configurableButtonPrefab;
pluginManager.configurablePopupPrefab = containingAtomPluginManager.configurablePopupPrefab;
pluginManager.configurablePopupPrefab = containingAtomPluginManager.configurablePopupPrefab;
pluginManager.configurableScrollablePopupPrefab = containingAtomPluginManager.configurableScrollablePopupPrefab;
pluginManager.configurableScrollablePopupPrefab = containingAtomPluginManager.configurableScrollablePopupPrefab;
pluginManager.configurableFilterablePopupPrefab = containingAtomPluginManager.configurableFilterablePopupPrefab;
pluginManager.configurableFilterablePopupPrefab = containingAtomPluginManager.configurableFilterablePopupPrefab;
pluginManager.configurableTextFieldPrefab = containingAtomPluginManager.configurableTextFieldPrefab;
pluginManager.configurableTextFieldPrefab = containingAtomPluginManager.configurableTextFieldPrefab;
pluginManager.configurableSpacerPrefab = containingAtomPluginManager.configurableSpacerPrefab;
pluginManager.configurableSpacerPrefab = containingAtomPluginManager.configurableSpacerPrefab;
} else {
} else {
throw new Exception("Unable to find plugin manager for main atom.");
throw new Exception("Unable to find plugin manager for main atom.");
}
}


// If the Daz clothing item needs a post-load restore, then we are still in scene restore
// If the Daz clothing item needs a post-load restore, then we are still in scene restore
// In that case we want to load the defaults after the item loads, but before the post-load
// In that case we want to load the defaults after the item loads, but before the post-load
// restore (which will apply scene settings)
// restore (which will apply scene settings)
if(!dazDynamicItem.enabled && dazDynamicItem.needsPostLoadJSONRestore) {
if(!dazDynamicItem.enabled && dazDynamicItem.needsPostLoadJSONRestore) {
dazDynamicItem.onLoadedHandlers += PostLoad;
dazDynamicItem.onLoadedHandlers += PostLoad;
} else if (needsReload) {
} else {
// Always run PostLoad for runtime activation, not just when the UI
// needs a reload. This is what loads the default .clothingplugins
// preset; gating it on needsReload meant defaults only loaded in
// the rare case where the plugin panel prefab wasn't ready yet.
StartCoroutine("PostLoadAfterDelay");
StartCoroutine("PostLoadAfterDelay");
}
}


StartCoroutine("AddPluginTabToUI");
StartCoroutine("AddPluginTabToUI");
}
}


public void Start() {
public void Start() {
// UI
// UI


// Preset code was adapted from AcidBubbles' Collider Editor
// Preset code was adapted from AcidBubbles' Collider Editor
var savePath = dazDynamic.GetStoreFolderPath(false);
var savePath = dazDynamic.GetStoreFolderPath(false);


var savePresetUI = CreateButton("Save Plugin Presets");
var savePresetUI = CreateButton("Save Plugin Presets");
savePresetUI.button.onClick.AddListener(() =>
savePresetUI.button.onClick.AddListener(() =>
{
{
FileManagerSecure.CreateDirectory(savePath);
FileManagerSecure.CreateDirectory(savePath);
var fileBrowserUI = SuperController.singleton.fileBrowserUI;
var fileBrowserUI = SuperController.singleton.fileBrowserUI;
fileBrowserUI.SetTitle("Save Plugin Presets");
fileBrowserUI.SetTitle("Save Plugin Presets");
fileBrowserUI.fileRemovePrefix = null;
fileBrowserUI.fileRemovePrefix = null;
fileBrowserUI.hideExtension = false;
fileBrowserUI.hideExtension = false;
fileBrowserUI.keepOpen = false;
fileBrowserUI.keepOpen = false;
fileBrowserUI.fileFormat = fileExt;
fileBrowserUI.fileFormat = fileExt;
fileBrowserUI.defaultPath = savePath;
fileBrowserUI.defaultPath = savePath;
fileBrowserUI.showDirs = true;
fileBrowserUI.showDirs = true;
fileBrowserUI.shortCuts = null;
fileBrowserUI.shortCuts = null;
fileBrowserUI.browseVarFilesAsDirectories = false;
fileBrowserUI.browseVarFilesAsDirectories = false;
fileBrowserUI.SetTextEntry(true);
fileBrowserUI.SetTextEntry(true);
fileBrowserUI.Show(SavePreset);
fileBrowserUI.Show(SavePreset);
fileBrowserUI.fileEntryField.text = GetDefaultFileName() + "." + fileExt;
fileBrowserUI.fileEntryField.text = GetDefaultFileName() + "." + fileExt;
fileBrowserUI.ActivateFileNameField();
fileBrowserUI.ActivateFileNameField();
});
});
var loadPresetUI = CreateButton("Load Plugin Presets");
var loadPresetUI = CreateButton("Load Plugin Presets");
loadPresetUI.button.onClick.AddListener(() =>
loadPresetUI.button.onClick.AddListener(() =>
{
{
FileManagerSecure.CreateDirectory(savePath);
FileManagerSecure.CreateDirectory(savePath);
var shortcuts = FileManagerSecure.GetShortCutsForDirectory(savePath);
var shortcuts = FileManagerSecure.GetShortCutsForDirectory(savePath);
SuperController.singleton.GetMediaPathDialog(LoadPreset, fileExt, savePath, false, true, false, null, false, shortcuts);
SuperController.singleton.GetMediaPathDialog(LoadPreset, fileExt, savePath, false, true, false, null, false, shortcuts);
});
});
this.exclude = false;
this.exclude = false;
}
}


/*
/*
There might be a more elegant way to do this but this works for now.
There might be a more elegant way to do this but this works for now.
*/
*/
private void WalkAndGetParentItems(){
private void WalkAndGetParentItems(){
GameObject parent = this.gameObject;
GameObject parent = this.gameObject;
while(this.containingAtom == null || parent != this.containingAtom.gameObject){
while(this.containingAtom == null || parent != this.containingAtom.gameObject){
if(parent.transform.parent == null){
if(parent.transform.parent == null){
return;
return;
}
}
if(pluginManager == null){
if(pluginManager == null){
pluginManager = parent.GetComponent<MVRPluginManager>();
pluginManager = parent.GetComponent<MVRPluginManager>();
}
}
if(dazDynamic == null){
if(dazDynamic == null){
dazDynamic = parent.GetComponent<DAZDynamic>();
dazDynamic = parent.GetComponent<DAZDynamic>();
}
}
if(dazDynamicItem == null){
if(dazDynamicItem == null){
dazDynamicItem = parent.GetComponent<DAZDynamicItem>();
dazDynamicItem = parent.GetComponent<DAZDynamicItem>();
}
}
this.containingAtom = parent.GetComponent<Atom>();
this.containingAtom = parent.GetComponent<Atom>();
parent = parent.transform.parent.gameObject;
parent = parent.transform.parent.gameObject;
}
}
}
}
private void PostLoad() {
private void PostLoad() {
SyncClothSimSettings();
SyncClothSimSettings();


string namedDefaultFile = $"{dazDynamic.GetStoreFolderPath(true)}{GetDefaultFileName()}.{fileExt}";
string namedDefaultFile = $"{dazDynamic.GetStoreFolderPath(true)}{GetDefaultFileName()}.{fileExt}";
string defaultFile = $"{dazDynamic.GetStoreFolderPath(true)}default.{fileExt}";
string defaultFile = $"{dazDynamic.GetStoreFolderPath(true)}default.{fileExt}";
if(lastRestoreWasSceneRestore && sceneJson != null && sceneJson.Count > 0){
if(lastRestoreWasSceneRestore && sceneJson != null && sceneJson.Count > 0){
LoadFromJSON(sceneJson);
LoadFromJSON(sceneJson);
} else if(FileManagerSecure.FileExists(namedDefaultFile)){
} else if(FileManagerSecure.FileExists(namedDefaultFile)){
LoadPreset(namedDefaultFile);
LoadPreset(namedDefaultFile);
} else if (FileManagerSecure.FileExists(defaultFile)){
} else if (FileManagerSecure.FileExists(defaultFile)){
LoadPreset(defaultFile);
LoadPreset(defaultFile);
} else if (needsReload) {
} else if (needsReload) {
// If there is no default, we may still want to re-load plugins once now that the
// If there is no default, we may still want to re-load plugins once now that the
// plugin manager is fully set up. This is mostly to make sure that this plugin
// plugin manager is fully set up. This is mostly to make sure that this plugin
// shows up in the UI.
// shows up in the UI.
pluginManager.LateRestoreFromJSON(pluginManager.GetJSON());
pluginManager.LateRestoreFromJSON(pluginManager.GetJSON());
}
}
}
}


// From the dotnet runtime, since plugins don't have access to System.IO.Path
// From the dotnet runtime, since plugins don't have access to System.IO.Path
private static char[] GetInvalidFileNameChars() => new char[] {
private static char[] GetInvalidFileNameChars() => new char[] {
'\"', '<', '>', '|', '\0',
'\"', '<', '>', '|', '\0',
(char)1, (char)2, (char)3, (char)4, (char)5, (char)6, (char)7, (char)8, (char)9, (char)10,
(char)1, (char)2, (char)3, (char)4, (char)5, (char)6, (char)7, (char)8, (char)9, (char)10,
(char)11, (char)12, (char)13, (char)14, (char)15, (char)16, (char)17, (char)18, (char)19, (char)20,
(char)11, (char)12, (char)13, (char)14, (char)15, (char)16, (char)17, (char)18, (char)19, (char)20,
(char)21, (char)22, (char)23, (char)24, (char)25, (char)26, (char)27, (char)28, (char)29, (char)30,
(char)21, (char)22, (char)23, (char)24, (char)25, (char)26, (char)27, (char)28, (char)29, (char)30,
(char)31, ':', '*', '?', '\\', '/'
(char)31, ':', '*', '?', '\\', '/'
};
};


private string GetDefaultFileName(){
private string GetDefaultFileName(){
return String.Join("_", dazDynamicItem.displayName.Split(GetInvalidFileNameChars(), StringSplitOptions.RemoveEmptyEntries) ).TrimEnd('.') + ".default";
return String.Join("_", dazDynamicItem.displayName.Split(GetInvalidFileNameChars(), StringSplitOptions.RemoveEmptyEntries) ).TrimEnd('.') + ".default";
}
}


/*
/*
VAM has an issue on subsequent forced reloads where the ClothSimControl
VAM has an issue on subsequent forced reloads where the ClothSimControl
may get out of sync with the ClothSettings. This fixes that.
may get out of sync with the ClothSettings. This fixes that.
*/
*/
private void SyncClothSimSettings(){
private void SyncClothSimSettings(){
ClothSimControl clothSimControl = dazDynamicItem.GetComponentInChildren<ClothSimControl>();
ClothSimControl clothSimControl = dazDynamicItem.GetComponentInChildren<ClothSimControl>();
if(clothSimControl != null) {
if(clothSimControl != null) {
SyncStorable(clothSimControl, "simEnabled");
SyncStorable(clothSimControl, "simEnabled");
SyncStorable(clothSimControl, "integrateEnabled");
SyncStorable(clothSimControl, "integrateEnabled");
SyncStorable(clothSimControl, "collisionEnabled");
SyncStorable(clothSimControl, "collisionEnabled");
SyncStorable(clothSimControl, "collisionRadius");
SyncStorable(clothSimControl, "collisionRadius");
SyncStorable(clothSimControl, "drag");
SyncStorable(clothSimControl, "drag");
SyncStorable(clothSimControl, "weight");
SyncStorable(clothSimControl, "weight");
SyncStorable(clothSimControl, "distanceScale");
SyncStorable(clothSimControl, "distanceScale");
SyncStorable(clothSimControl, "stiffness");
SyncStorable(clothSimControl, "stiffness");
SyncStorable(clothSimControl, "compressionResistance");
SyncStorable(clothSimControl, "compressionResistance");
SyncStorable(clothSimControl, "friction");
SyncStorable(clothSimControl, "friction");
SyncStorable(clothSimControl, "staticMultiplier");
SyncStorable(clothSimControl, "staticMultiplier");
SyncStorable(clothSimControl, "collisionPower");
SyncStorable(clothSimControl, "collisionPower");
SyncStorable(clothSimControl, "gravityMultiplier");
SyncStorable(clothSimControl, "gravityMultiplier");
SyncStorable(clothSimControl, "iterations");
SyncStorable(clothSimControl, "iterations");
SyncStorable(clothSimControl, "allowDetach");
SyncStorable(clothSimControl, "allowDetach");
SyncStorable(clothSimControl, "detachThreshold");
SyncStorable(clothSimControl, "detachThreshold");
SyncStorable(clothSimControl, "jointStrength");
SyncStorable(clothSimControl, "jointStrength");
SyncStorable(clothSimControl, "force");
SyncStorable(clothSimControl, "force");
}
}
}
}


private void SyncStorable(JSONStorable parent, string name) {
private void SyncStorable(JSONStorable parent, string name) {
var storable = parent.GetParam(name);
var storable = parent.GetParam(name);
var storableBool = storable as JSONStorableBool;
var storableBool = storable as JSONStorableBool;
if(storableBool != null && storableBool.setCallbackFunction != null) {
if(storableBool != null && storableBool.setCallbackFunction != null) {
storableBool.setCallbackFunction(storableBool.val);
storableBool.setCallbackFunction(storableBool.val);
}
}
var storableFloat = storable as JSONStorableFloat;
var storableFloat = storable as JSONStorableFloat;
if(storableFloat != null && storableFloat.setCallbackFunction != null) {
if(storableFloat != null && storableFloat.setCallbackFunction != null) {
storableFloat.setCallbackFunction(storableFloat.val);
storableFloat.setCallbackFunction(storableFloat.val);
}
}
var storableVector = storable as JSONStorableVector3;
var storableVector = storable as JSONStorableVector3;
if(storableVector != null && storableVector.setCallbackFunction != null) {
if(storableVector != null && storableVector.setCallbackFunction != null) {
storableVector.setCallbackFunction(storableVector.val);
storableVector.setCallbackFunction(storableVector.val);
}
}
}
}


private IEnumerator PostLoadAfterDelay() {
private IEnumerator PostLoadAfterDelay() {
yield return new WaitForEndOfFrame();
yield return new WaitForEndOfFrame();


PostLoad();
PostLoad();
yield break;
yield break;
}
}


public IEnumerator AddPluginTabToUI() {
public IEnumerator AddPluginTabToUI() {
MVRPluginManager containingAtomPluginManager = containingAtom.GetStorableByID("PluginManager") as MVRPluginManager;
MVRPluginManager containingAtomPluginManager = containingAtom.GetStorableByID("PluginManager") as MVRPluginManager;
if(containingAtomPluginManager == null) throw new Exception("Cannot find plugin manager for parent atom.");
if(containingAtomPluginManager == null) throw new Exception("Cannot find plugin manager for parent atom.");
// Wait for the Person's plugin manager UI to be loaded.
// Wait for the Person's plugin manager UI to be loaded.
// This should happen when the Person's UI is first opened.
// This should happen when the Person's UI is first opened.
Transform pluginManagerUITransform = null;
Transform pluginManagerUITransform = null;
while(pluginManagerUITransform == null) {
while(pluginManagerUITransform == null) {
yield return null;
yield return null;
pluginManagerUITransform = containingAtomPluginManager.UITransform;
pluginManagerUITransform = containingAtomPluginManager.UITransform;
}
}


// Wait for the clothing item's customization UI to be created
// Wait for the clothing item's customization UI to be created
// This should happen when the user clicks 'Customize' on the clothing
// This should happen when the user clicks 'Customize' on the clothing
Transform customizationUI = dazDynamicItem.customizationUI;
Transform customizationUI = dazDynamicItem.customizationUI;
while(customizationUI == null) {
while(customizationUI == null) {
yield return null;
yield return null;
customizationUI = dazDynamicItem.customizationUI;
customizationUI = dazDynamicItem.customizationUI;
}
}


// Wait for the customization UI to be active
// Wait for the customization UI to be active
while(!customizationUI.gameObject.activeInHierarchy) {
while(!customizationUI.gameObject.activeInHierarchy) {
yield return null;
yield return null;
}
}
// This should have been initialized with the PluginManager's IO but I've seen it null here.
// This should have been initialized with the PluginManager's IO but I've seen it null here.
// Race conditions? Me being dumb? Who knows. Adding wait loop.
// Race conditions? Me being dumb? Who knows. Adding wait loop.
MVRPluginManagerUI containingAtomPluginManagerUI = pluginManagerUITransform.GetComponentInChildren<MVRPluginManagerUI>(true);
MVRPluginManagerUI containingAtomPluginManagerUI = pluginManagerUITransform.GetComponentInChildren<MVRPluginManagerUI>(true);
while(containingAtomPluginManagerUI == null) {
while(containingAtomPluginManagerUI == null) {
yield return new WaitForSeconds(0.1f);
yield return new WaitForSeconds(0.1f);
containingAtomPluginManagerUI = pluginManagerUITransform.GetComponentInChildren<MVRPluginManagerUI>(true);
containingAtomPluginManagerUI = pluginManagerUITransform.GetComponentInChildren<MVRPluginManagerUI>(true);
}
}


UIConnectorMaster uiConnectorMaster = customizationUI.GetComponent<UIConnectorMaster>();
UIConnectorMaster uiConnectorMaster = customizationUI.GetComponent<UIConnectorMaster>();
TabbedUIBuilder tabbedUIBuilder = uiConnectorMaster.GetComponentInChildren<TabbedUIBuilder>();
TabbedUIBuilder tabbedUIBuilder = uiConnectorMaster.GetComponentInChildren<TabbedUIBuilder>();


foreach(var child in tabbedUIBuilder.selector.toggleContainer.GetChildren()) {
foreach(var child in tabbedUIBuilder.selector.toggleContainer.GetChildren()) {
if(child.name == "Plugins") {
if(child.name == "Plugins") {
yield break;
yield break;
}
}
}
}
Transform pluginTabPrefab = UnityEngine.Object.Instantiate<Transform>(containingAtomPluginManagerUI.transform,tabbedUIBuilder.selector.transform);
Transform pluginTabPrefab = UnityEngine.Object.Instantiate<Transform>(containingAtomPluginManagerUI.transform,tabbedUIBuilder.selector.transform);


// Remove any plugin UIs we inadvertently copied over
// Remove any plugin UIs we inadvertently copied over
foreach(var script in pluginTabPrefab.GetComponentsInChildren<MVRScriptUI>(true)) {
foreach(var script in pluginTabPrefab.GetComponentsInChildren<MVRScriptUI>(true)) {
Destroy(script.gameObject);
Destroy(script.gameObject);
}
}


foreach(var script in pluginTabPrefab.GetComponentsInChildren<MVRPluginUI>(true)) {
foreach(var script in pluginTabPrefab.GetComponentsInChildren<MVRPluginUI>(true)) {
Destroy(script.gameObject);
Destroy(script.gameObject);
}
}


TabbedUIBuilder.Tab pluginsTab = new TabbedUIBuilder.Tab{name = "Plugins", prefab = pluginTabPrefab, color = Color.blue};
TabbedUIBuilder.Tab pluginsTab = new TabbedUIBuilder.Tab{name = "Plugins", prefab = pluginTabPrefab, color = Color.blue};
tabbedUIBuilder.AddTab(pluginsTab);
tabbedUIBuilder.AddTab(pluginsTab);


pluginManager.UITransform = pluginTabPrefab.transform;
pluginManager.UITransform = pluginTabPrefab.transform;
pluginManager.InitUI();
pluginManager.InitUI();
yield break;
yield break;
}
}


public void OnEnable() {
public void OnEnable() {
if(containingAtom != null) {
if(containingAtom != null) {
StartCoroutine("AddPluginTabToUI");
StartCoroutine("AddPluginTabToUI");
}
}
}
}


public override JSONClass GetJSON(bool includePhysical = true, bool includeAppearance = true, bool forceStore = false) {
public override JSONClass GetJSON(bool includePhysical = true, bool includeAppearance = true, bool forceStore = false) {
JSONClass jc = pluginManager.GetJSON(true,true,true);
JSONClass jc = pluginManager.GetJSON(true,true,true);
jc["id"] = this.storeId;
jc["id"] = this.storeId;


JSONArray storables = new JSONArray();
JSONArray storables = new JSONArray();
foreach(MVRScript script in pluginManager.GetComponentsInChildren<MVRScript>(true)) {
foreach(MVRScript script in pluginManager.GetComponentsInChildren<MVRScript>(true)) {
if(script != this) {
if(script != this) {
storables.Add(script.GetJSON());
storables.Add(script.GetJSON());
}
}
}
}
jc["storables"] = storables;
jc["storables"] = storables;


this.needsStore = true;
this.needsStore = true;
return jc;
return jc;
}
}




public override void RestoreFromJSON(JSONClass jc, bool restorePhysical = true, bool restoreAppearance = true, JSONArray presetAtoms = null, bool setMissingToDefault = true){
public override void RestoreFromJSON(JSONClass jc, bool restorePhysical = true, bool restoreAppearance = true, JSONArray presetAtoms = null, bool setMissingToDefault = true){
if(this.isPresetRestore) {
if(this.isPresetRestore) {
if(jc.Count > 0) {
if(jc.Count > 0) {
LoadFromJSON(jc);
LoadFromJSON(jc);
}
}
} else {
} else {
sceneJson = jc;
sceneJson = jc;
lastRestoreWasSceneRestore = SuperController.singleton.isLoading;
lastRestoreWasSceneRestore = SuperController.singleton.isLoading;
}
}
}
}


private void LoadPreset(string path) {
private void LoadPreset(string path) {
if (string.IsNullOrEmpty(path))
if (string.IsNullOrEmpty(path))
return;
return;
var presetJson = (JSONClass)LoadJSON(path);
var presetJson = (JSONClass)LoadJSON(path);
LoadFromJSON(presetJson);
LoadFromJSON(presetJson);
}
}


/*
The preset JSON is pluginManager.GetJSON(), and this plugin is itself in
that manager's plugin list. Restoring the list therefore destroys and
re-creates this very script, whose Init() schedules PostLoad(), which
loads the preset again -> infinite reload loop.

Guard: only reload plugins when the list in the JSON actually differs
from what is currently loaded. On the second pass the lists match, so
we skip straight to restoring settings and the recursion terminates.
*/
private bool PluginListMatchesJSON(JSONClass jc) {
if(jc == null || !jc.HasKey("plugins")) return false;

JSONClass target = jc["plugins"].AsObject;
JSONClass current = pluginManager.GetJSON()["plugins"] as JSONClass;

if(target == null) return false;
if(current == null) return target.Count == 0;
if(current.Count != target.Count) return false;

foreach(KeyValuePair<string, JSONNode> kv in target) {
if(current[kv.Key] == null) return false;
if(current[kv.Key].Value != kv.Value.Value) return false;
}
return true;
}

private void LoadFromJSON(JSONClass jc) {
private void LoadFromJSON(JSONClass jc) {
pluginManager.LateRestoreFromJSON(jc, true, true, false);
if(!PluginListMatchesJSON(jc)) {
pluginManager.LateRestoreFromJSON(jc, true, true, false);
}


if(jc.HasKey("storables")) {
if(jc.HasKey("storables")) {
JSONArray storables = jc["storables"].AsArray;
JSONArray storables = jc["storables"].AsArray;


foreach(MVRScript script in pluginManager.GetComponentsInChildren<MVRScript>(true)) {
foreach(MVRScript script in pluginManager.GetComponentsInChildren<MVRScript>(true)) {
foreach(JSONClass storable in storables) {
foreach(JSONClass storable in storables) {
string id = storable["id"];
string id = storable["id"];


if(id == script.storeId) {
if(id == script.storeId) {
script.RestoreFromJSON(storable);
script.RestoreFromJSON(storable);
script.LateRestoreFromJSON(storable);
script.LateRestoreFromJSON(storable);
}
}
}
}
}
}
}
}
}
}
private void SavePreset(string path) {
private void SavePreset(string path) {
SuperController.singleton.fileBrowserUI.fileFormat = null;
SuperController.singleton.fileBrowserUI.fileFormat = null;
if (string.IsNullOrEmpty(path)) {
if (string.IsNullOrEmpty(path)) {
return;
return;
}
}


if (!path.ToLower().EndsWith($".{fileExt}")) {
if (!path.ToLower().EndsWith($".{fileExt}")) {
path += $".{fileExt}";
path += $".{fileExt}";
}
}


SaveJSON(GetJSON(true,true,true), path);
SaveJSON(GetJSON(true,true,true), path);
}
}


/*
/*
A forced reload of the parent clothing will only clear specific
A forced reload of the parent clothing will only clear specific
types of components. MaterialOptions are one of them, and should
types of components. MaterialOptions are one of them, and should
otherwise be inert.
otherwise be inert.


Using this to detect that the clothing is reloading and clearing
Using this to detect that the clothing is reloading and clearing
the plugins.
the plugins.


Not doing this causes the plugin managers and plugins to accumulate.
Not doing this causes the plugin managers and plugins to accumulate.
*/
*/
public class Destructor : MaterialOptions {
public class Destructor : MaterialOptions {
public MVRPluginManager pluginManager = null;
public MVRPluginManager pluginManager = null;
public Atom storedContainingAtom = null;
public Atom storedContainingAtom = null;


public Destructor() {
public Destructor() {
this.overrideId = "ClothingPluginDestructor";
this.overrideId = "ClothingPluginDestructor";
this.paramMaterialSlots = new int[0];
this.paramMaterialSlots = new int[0];
}
}


public void OnDestroy(){
public void OnDestroy(){
if(pluginManager != null) {
if(pluginManager != null) {
foreach(var manager in pluginManager.gameObject.GetComponents<MVRPluginManager>()) {
foreach(var manager in pluginManager.gameObject.GetComponents<MVRPluginManager>()) {
if(manager != pluginManager) {
if(manager != pluginManager) {
SuperController.LogError("Multiple clothing plugin managers detected on deletion. This generally shouldn't happen. Please file a bug report.");
SuperController.LogError("Multiple clothing plugin managers detected on deletion. This generally shouldn't happen. Please file a bug report.");
}
}
manager.containingAtom = storedContainingAtom;
manager.containingAtom = storedContainingAtom;
manager.RemoveAllPlugins();
manager.RemoveAllPlugins();
Destroy(manager);
Destroy(manager);
}
}
}
}
}
}


public override void SetUI(Transform t) {
public override void SetUI(Transform t) {
// No-op
// No-op
}
}
}
}
}
}
}
}