-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move ROEngines partmodules into ROLib... again
- Loading branch information
Showing
3 changed files
with
361 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,356 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Reflection; | ||
using UnityEngine; | ||
using KSPShaderTools; | ||
|
||
namespace ROLib | ||
{ | ||
[SuppressMessage("ReSharper", "InvertIf")] | ||
public class ModuleRORCS : PartModule, IRecolorable | ||
{ | ||
private const string GroupDisplayName = "RO-RCS"; | ||
private const string GroupName = "ModuleRORCS"; | ||
|
||
[KSPField] public string rcsThrustTransformName = string.Empty; | ||
[KSPField] public bool allowRescale = true; | ||
[KSPField] public float scaleLargeStep = 0.1f; | ||
[KSPField] public float scaleSmallStep = 0.1f; | ||
[KSPField] public float scaleSlideStep = 0.001f; | ||
[KSPField] public float minScale = 0.1f; | ||
[KSPField] public float maxScale = 100.0f; | ||
|
||
[KSPField(isPersistant = true, guiActiveEditor = true, groupDisplayName = GroupDisplayName, groupName = GroupName, guiName = "Scale"), | ||
UI_FloatEdit(sigFigs = 3, suppressEditorShipModified = true)] | ||
public float currentScale = 1f; | ||
|
||
[KSPField(isPersistant = true, guiActiveEditor = true, groupName = GroupName, guiName = "Type"), | ||
UI_ChooseOption(suppressEditorShipModified = true)] | ||
public string currentType = "Default"; | ||
|
||
[KSPField(isPersistant = true, guiActiveEditor = true, groupName = GroupName, guiName = "RCS Model"), | ||
UI_ChooseOption(suppressEditorShipModified = true)] | ||
public string currentRCSModel = "Default"; | ||
|
||
[KSPField(isPersistant = true, guiActiveEditor = true, groupName = GroupName, guiName = "RCS Texture"), | ||
UI_ChooseOption(suppressEditorShipModified = true)] | ||
public string currentRCSModelTexture = "Default"; | ||
|
||
[KSPField(isPersistant = true, guiActiveEditor = true, groupName = GroupName, guiName = "Base"), | ||
UI_ChooseOption(suppressEditorShipModified = true)] | ||
public string currentBase = "Default"; | ||
|
||
[KSPField(isPersistant = true, guiActiveEditor = true, groupName = GroupName, guiName = "Base Texture"), | ||
UI_ChooseOption(suppressEditorShipModified = true)] | ||
public string currentBaseTexture = "Default"; | ||
|
||
[KSPField(isPersistant = true, guiActiveEditor = true, groupName = GroupName, guiName = "Layout"), | ||
UI_ChooseOption(suppressEditorShipModified = true)] | ||
public string currentLayout = "Default"; | ||
|
||
[KSPField(isPersistant = true)] public string rcsModelModulePersistentData = string.Empty; | ||
[KSPField(isPersistant = true)] public string baseModulePersistentData = string.Empty; | ||
[Persistent] public string configNodeData = string.Empty; | ||
|
||
private bool initialized = false; | ||
internal ROLModelModule<ModuleRORCS> rcsModelModule; | ||
internal ROLModelModule<ModuleRORCS> baseModule; | ||
|
||
private Transform baseRotatedRoot; | ||
private Transform baseTransform; | ||
private Transform rcsModelRotatedRoot; | ||
private Transform rcsModelTransform; | ||
|
||
private static MethodInfo MEC_ApplyDynamicPatch; | ||
private static MethodInfo MEC_GetNonDynamicPatchedConfiguration; | ||
private static bool reflectionInitialized = false; | ||
|
||
private PartModule mec; | ||
private ModuleRCSFX rcsfx; | ||
|
||
private readonly Dictionary<string, ModelDefinitionVariantSet> variantSets = new Dictionary<string, ModelDefinitionVariantSet>(); | ||
|
||
private ModelDefinitionVariantSet GetVariantSet(string name) | ||
{ | ||
if (!variantSets.TryGetValue(name, out ModelDefinitionVariantSet set)) | ||
{ | ||
set = new ModelDefinitionVariantSet(name); | ||
variantSets.Add(name, set); | ||
} | ||
return set; | ||
} | ||
|
||
internal ModelDefinitionLayoutOptions[] rcsModelDefs; | ||
internal ModelDefinitionLayoutOptions[] baseDefs; | ||
|
||
internal void ModelChangedHandler(bool pushNodes) | ||
{ | ||
UpdateModelScale(); | ||
UpdateModelMeshes(); | ||
UpdateAttachNodes(pushNodes); | ||
UpdateAvailableVariants(); | ||
UpdateDragCubes(); | ||
rcsModelModule.RenameRCSThrustTransforms(rcsThrustTransformName); | ||
UpdateRCSModule(); | ||
ROLStockInterop.UpdatePartHighlighting(part); | ||
//if (HighLogic.LoadedSceneIsEditor) | ||
//GameEvents.onEditorShipModified.Fire(EditorLogic.fetch.ship); | ||
} | ||
|
||
internal void ModelChangedHandlerWithSymmetry(bool pushNodes, bool symmetry) | ||
{ | ||
ModelChangedHandler(pushNodes); | ||
if (symmetry) | ||
{ | ||
foreach (Part p in part.symmetryCounterparts) | ||
{ | ||
p.FindModuleImplementing<ModuleRORCS>().ModelChangedHandler(pushNodes); | ||
} | ||
} | ||
} | ||
|
||
public override void OnLoad(ConfigNode node) | ||
{ | ||
base.OnLoad(node); | ||
if (string.IsNullOrEmpty(configNodeData)) { configNodeData = node.ToString(); } | ||
Initialize(); | ||
} | ||
|
||
public override void OnStart(StartState state) | ||
{ | ||
base.OnStart(state); | ||
mec = part.Modules["ModuleEngineConfigs"]; | ||
rcsfx = part.GetComponent<ModuleRCSFX>(); | ||
|
||
if (!reflectionInitialized) | ||
{ | ||
var mecTy = Type.GetType("RealFuels.ModuleEngineConfigs, RealFuels", true); | ||
MEC_ApplyDynamicPatch = mecTy.GetMethod("ApplyDynamicPatch"); | ||
MEC_GetNonDynamicPatchedConfiguration = mecTy.GetMethod("GetNonDynamicPatchedConfiguration"); | ||
|
||
reflectionInitialized = true; | ||
} | ||
} | ||
|
||
public override void OnStartFinished(StartState state) | ||
{ | ||
base.OnStartFinished(state); | ||
Initialize(); | ||
ModelChangedHandler(false); | ||
InitializeUI(); | ||
} | ||
|
||
//private void OnEditorVesselModified(ShipConstruct ship) => UpdateAvailableVariants(); | ||
|
||
public void OnMECDynamicPatchReset() => UpdateRCSModule(); | ||
|
||
public string[] getSectionNames() => new string[] { "RCS Model", "Base" }; | ||
|
||
public RecoloringData[] getSectionColors(string section) | ||
{ | ||
return section switch | ||
{ | ||
"RCS Model" => rcsModelModule.recoloringData, | ||
"Base" => baseModule.recoloringData, | ||
_ => rcsModelModule.recoloringData, | ||
}; | ||
} | ||
|
||
public void setSectionColors(string section, RecoloringData[] colors) | ||
{ | ||
if (section == "RCS Model") rcsModelModule.setSectionColors(colors); | ||
else if (section == "Base") baseModule.setSectionColors(colors); | ||
} | ||
|
||
public TextureSet getSectionTexture(string section) | ||
{ | ||
return section switch | ||
{ | ||
"RCS Model" => rcsModelModule.textureSet, | ||
"Base" => baseModule.textureSet, | ||
_ => rcsModelModule.textureSet, | ||
}; | ||
} | ||
|
||
private void Initialize() | ||
{ | ||
if (initialized) { return; } | ||
initialized = true; | ||
|
||
baseRotatedRoot = part.transform.FindRecursive("RORCS-BaseRoot"); | ||
if (baseRotatedRoot == null) | ||
{ | ||
baseRotatedRoot = new GameObject("RORCS-BaseRoot").transform; | ||
baseRotatedRoot.NestToParent(part.transform.FindRecursive("model")); | ||
baseRotatedRoot.Rotate(90, -90, 0); | ||
} | ||
|
||
rcsModelRotatedRoot = part.transform.FindRecursive("RORCS-RCSModelRoot"); | ||
if (rcsModelRotatedRoot == null) | ||
{ | ||
rcsModelRotatedRoot = new GameObject("RORCS-RCSModelRoot").transform; | ||
rcsModelRotatedRoot.NestToParent(part.transform.FindRecursive("model")); | ||
rcsModelRotatedRoot.Rotate(0, 0, 0); | ||
} | ||
|
||
ConfigNode node = ROLConfigNodeUtils.ParseConfigNode(configNodeData); | ||
|
||
List<ModelDefinitionLayoutOptions> rcsModelDefList = new List<ModelDefinitionLayoutOptions>(); | ||
foreach (ConfigNode n in node.GetNodes("RCSMODEL")) | ||
{ | ||
string variantName = n.ROLGetStringValue("variant", "Default"); | ||
rcsModelDefs = ROLModelData.getModelDefinitionLayouts(n.ROLGetStringValues("model")); | ||
rcsModelDefList.AddUniqueRange(rcsModelDefs); | ||
ModelDefinitionVariantSet mdvs = GetVariantSet(variantName); | ||
mdvs.AddModels(rcsModelDefs); | ||
} | ||
rcsModelDefs = rcsModelDefList.ToArray(); | ||
baseDefs = ROLModelData.getModelDefinitions(node.GetNodes("RCSBASE")); | ||
|
||
rcsModelTransform = rcsModelRotatedRoot.FindOrCreate("ModuleRORCS-RCSModel"); | ||
rcsModelModule = new ROLModelModule<ModuleRORCS>(part, this, rcsModelTransform, ModelOrientation.CENTRAL, nameof(currentRCSModel), nameof(currentLayout), nameof(currentRCSModelTexture), nameof(rcsModelModulePersistentData)) | ||
{ | ||
name = "ModuleRORCS-RCS", | ||
getSymmetryModule = m => m.rcsModelModule, | ||
getValidOptions = () => GetVariantSet(currentType).definitions, | ||
MassScalar = 3f, | ||
}; | ||
rcsModelModule.setupModelList(rcsModelDefs); | ||
rcsModelModule.setupModel(); | ||
rcsModelModule.updateSelections(); | ||
|
||
baseTransform = baseRotatedRoot.FindOrCreate("ModuleRORCS-BaseModel"); | ||
baseModule = new ROLModelModule<ModuleRORCS>(part, this, baseTransform, ModelOrientation.CENTRAL, nameof(currentBase), nameof(currentLayout), nameof(currentBaseTexture), nameof(baseModulePersistentData)) | ||
{ | ||
name = "ModuleRORCS-Base", | ||
getSymmetryModule = m => m.baseModule, | ||
getValidOptions = () => baseDefs, | ||
MassScalar = 3f, | ||
}; | ||
baseModule.setupModelList(baseDefs); | ||
baseModule.setupModel(); | ||
baseModule.updateSelections(); | ||
|
||
UpdateModelScale(); | ||
rcsModelModule.RenameRCSThrustTransforms(rcsThrustTransformName); | ||
UpdateAttachNodes(false); | ||
} | ||
|
||
private void InitializeUI() | ||
{ | ||
string[] variantNames = ROLUtils.getNames(variantSets.Values, m => m.variantName); | ||
this.ROLupdateUIChooseOptionControl(nameof(currentType), variantNames, variantNames); | ||
Fields[nameof(currentType)].guiActiveEditor = variantSets.Count > 1; | ||
|
||
Fields[nameof(currentType)].uiControlEditor.onFieldChanged = (a, b) => | ||
{ | ||
ModelDefinitionVariantSet prevMdvs = GetVariantSet(rcsModelModule.definition.name); | ||
int previousIndex = prevMdvs.IndexOf(rcsModelModule.layoutOptions); | ||
ModelDefinitionVariantSet mdvs = GetVariantSet(currentType); | ||
ModelDefinitionLayoutOptions newRCSModelDef = mdvs[previousIndex]; | ||
this.ROLactionWithSymmetry(m => | ||
{ | ||
m.rcsModelModule.modelSelected(newRCSModelDef.definition.name); | ||
m.ModelChangedHandler(true); | ||
}); | ||
MonoUtilities.RefreshPartContextWindow(part); | ||
}; | ||
|
||
Fields[nameof(currentScale)].uiControlEditor.onFieldChanged = OnModelSelectionChanged; | ||
|
||
Fields[nameof(currentRCSModel)].uiControlEditor.onFieldChanged = OnModelSelectionChanged; | ||
|
||
Fields[nameof(currentBase)].uiControlEditor.onFieldChanged = OnModelSelectionChanged; | ||
|
||
this.ROLupdateUIFloatEditControl(nameof(currentScale), minScale, maxScale, scaleLargeStep, scaleSmallStep, scaleSlideStep); | ||
|
||
Fields[nameof(currentScale)].guiActiveEditor = allowRescale; | ||
|
||
//------------------MODULE TEXTURE SWITCH UI INIT---------------------// | ||
Fields[nameof(currentRCSModelTexture)].uiControlEditor.onFieldChanged = rcsModelModule.textureSetSelected; | ||
Fields[nameof(currentBaseTexture)].uiControlEditor.onFieldChanged = baseModule.textureSetSelected; | ||
|
||
//if (HighLogic.LoadedSceneIsEditor) | ||
//GameEvents.onEditorShipModified.Add(OnEditorVesselModified); | ||
} | ||
|
||
private void UpdateModelScale() | ||
{ | ||
rcsModelModule.SetPosition(0); | ||
rcsModelModule.SetScale(currentScale); | ||
rcsModelModule.UpdateModelScalesAndLayoutPositions(); | ||
|
||
baseModule.RescaleToDiameter(rcsModelModule.moduleDiameter, baseModule.definition.diameter, 0f); | ||
baseModule.SetPosition(rcsModelModule.ModuleBottom - baseModule.moduleHeight); | ||
baseModule.UpdateModelScalesAndLayoutPositions(); | ||
} | ||
|
||
private void UpdateRCSModule() | ||
{ | ||
if (!reflectionInitialized) return; | ||
if (mec == null || rcsfx == null || rcsModelModule == null) return; | ||
|
||
typeof(ModuleRCS).GetMethod("FindThrusters", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(rcsfx, null); | ||
|
||
// Scaling factors based on RealismOverhaul/RO_SuggestedMods/RO_RCS_Config.cfg | ||
// Note: It is assumed that a scale of 1 corresponds to a 1x RCS block | ||
// Thrust: scale^2 | ||
// Mass: sqrt(thrust) / 4.5 * (nozzles + 0.5) | ||
// Cost: sqrt(thrust) * nozzles | ||
var numNozzles = rcsModelModule.definition.rcsModuleData.nozzles; | ||
var thrustMult = currentScale * currentScale; | ||
var massMult = Mathf.Sqrt(thrustMult) / 4.5f * (numNozzles + 0.5f); | ||
var costMult = Mathf.Sqrt(thrustMult) * numNozzles; | ||
|
||
var baseConfig = (ConfigNode)MEC_GetNonDynamicPatchedConfiguration.Invoke(mec, null); | ||
var patch = new ConfigNode(); | ||
patch.AddValue("thrusterPower", thrustMult * baseConfig.GetFloatValue("thrusterPower")); | ||
patch.AddValue("massMult", massMult * baseConfig.GetFloatValue("massMult", 1f)); | ||
patch.AddValue("cost", costMult * baseConfig.GetFloatValue("cost", part.partInfo.cost)); | ||
MEC_ApplyDynamicPatch.Invoke(mec, new object[] { patch }); | ||
} | ||
|
||
private void UpdateAttachNodes(bool userInput) | ||
{ | ||
float baseBottomZ = baseModule.ModuleBottom; | ||
Vector3 pos = new Vector3(-baseBottomZ, 0, 0); | ||
AttachNode srfNode = part.srfAttachNode; | ||
if (srfNode != null) | ||
{ | ||
ROLAttachNodeUtils.UpdateAttachNodePosition(part, srfNode, pos, Vector3.right, userInput, 0); | ||
} | ||
AttachNode bottomNode = part.FindAttachNode("bottom"); | ||
if (bottomNode != null) | ||
{ | ||
ROLAttachNodeUtils.UpdateAttachNodePosition(part, bottomNode, pos, bottomNode.orientation, userInput, 0); | ||
} | ||
} | ||
|
||
private void UpdateDragCubes() => ROLModInterop.OnPartGeometryUpdate(part, true); | ||
|
||
public void OnModelSelectionChanged(BaseField f, object o) | ||
{ | ||
this.ROLactionWithSymmetry(m => | ||
{ | ||
if (f.name == m.Fields[nameof(currentRCSModel)].name) m.rcsModelModule.modelSelected(this.currentRCSModel); | ||
else if (f.name == m.Fields[nameof(currentBase)].name) m.baseModule.modelSelected(this.currentBase); | ||
else if (f.name == m.Fields[nameof(currentScale)].name) m.currentScale = this.currentScale; | ||
m.ModelChangedHandler(true); | ||
}); | ||
MonoUtilities.RefreshPartContextWindow(part); | ||
} | ||
|
||
public void UpdateAvailableVariants() | ||
{ | ||
rcsModelModule.updateSelections(); | ||
baseModule.updateSelections(); | ||
} | ||
|
||
public void UpdateModelMeshes() | ||
{ | ||
rcsModelModule.UpdateModelScalesAndLayoutPositions(); | ||
baseModule.UpdateModelScalesAndLayoutPositions(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters