Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move ROEngines partmodules into ROLib #26

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
356 changes: 356 additions & 0 deletions Source/ROLib/Modules/ModuleRORCS.cs
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();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace ROLib
/// This is the module that allows engines (like the RL10-B2) to deploy. This code is orignally written by
/// ShadowMage as part of the SSTU Mod. It has been adapted to work with the ROEngines code.
/// </summary>
public class ROLDeployableEngine : PartModule
public class ROEDeployableEngine : PartModule
{
/// <summary>
/// engine ID for the engine module that this deployable engine module is responsible for
Expand Down Expand Up @@ -70,7 +70,7 @@ public override void OnLoad(ConfigNode node)

public override void OnStartFinished(StartState state)
{
engineModule = part.GetComponents<ModuleEnginesFX>().Where(x => x.engineID == engineID).FirstOrDefault();
engineModule = part.GetComponents<ModuleEnginesFX>().FirstOrDefault(x => x.engineID == engineID);
if (engineModule == null)
{
engineModule = part.GetComponents<ModuleEnginesFX>().FirstOrDefault();
Expand All @@ -86,7 +86,7 @@ private void Initialize()
ConfigNode node = ROLUtils.parseConfigNode(configNodeData);
AnimationData animData = new AnimationData(node.GetNode("ANIMATIONDATA"));
animationModule = new ROLAnimationModule(part, this, nameof(persistentState), null, nameof(DeployEngineEvent), nameof(RetractEngineEvent));
animationModule.getSymmetryModule = m => ((ROLDeployableEngine)m).animationModule;
animationModule.getSymmetryModule = m => ((ROEDeployableEngine)m).animationModule;
animationModule.setupAnimations(animData, part.transform.ROLFindRecursive("model"), 0);
animationModule.onAnimStateChangeCallback = OnAnimationStateChange;
}
Expand Down
3 changes: 2 additions & 1 deletion Source/ROLib/ROLib.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,11 @@
<Compile Include="DebugTools\DrawTools.cs" />
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="Modules\ModuelROPayload.cs" />
<Compile Include="Modules\ModuleRORCS.cs" />
<Compile Include="Modules\ModuleROSolar.cs" />
<Compile Include="Modules\ModuleROTank_KorolevCross.cs" />
<Compile Include="Modules\ROLAnimateEngineHeat.cs" />
<Compile Include="Modules\ROLDeployableEngine.cs" />
<Compile Include="Modules\ROEDeployableEngine.cs" />
<Compile Include="ROSolar\SolarTechLimit.cs" />
<Compile Include="UI\DimensionWindow.cs" />
<Compile Include="UI\AbstractWindow.cs" />
Expand Down
Loading