Skip to content

Commit

Permalink
Move ROEngines partmodules into ROLib... again
Browse files Browse the repository at this point in the history
  • Loading branch information
siimav committed Aug 30, 2024
1 parent 8938de8 commit 740a3ce
Show file tree
Hide file tree
Showing 3 changed files with 361 additions and 4 deletions.
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

0 comments on commit 740a3ce

Please sign in to comment.