diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..50725ec --- /dev/null +++ b/.gitattributes @@ -0,0 +1,55 @@ +# ================================================== +# Auto detect text files and perform LF +# normalization. +# ================================================== + +* text=auto + +# ================================================== +# Plain text +# ================================================== + +*.cfg text eol=lf +*.CFG text eol=lf +*.csproj text eol=lf +*.CSPROJ text eol=lf +*.md text eol=lf +*.MD text eol=lf +*.sln text eol=lf +*.SLN text eol=lf +*.txt text eol=lf +*.TXT text eol=lf +*.xml text eol=lf +*.XML text eol=lf + +# ================================================== +# Images & textures +# ================================================== + +*.dds binary +*.DDS binary +*.png binary +*.PNG binary + +# ================================================== +# Binaries +# ================================================== + +*.dll binary +*.DLL binary + +# ================================================== +# Source code +# ================================================== + +*.cs diff=csharp +*.CS diff=csharp + +# ================================================== +# Ignore list +# ================================================== + +.gitattributes export-ignore +.gitignore export-ignore +*.md export-ignore +*.MD export-ignore diff --git a/.gitignore b/.gitignore index 4290de7..a4918e4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,21 @@ +# ================================================== +# Ignore selected folders and file types from the git +# repository. +# ================================================== + +Source/Builds/* + +*.db +*.DB +*.DS_Store +*.ini +*.INI +*.lnk +*.LNK +*.pdb +*.PDB +*.png +*.PNG *.sublime-workspace *.sublime-project *.user diff --git a/GameData/ProceduralFairings/Config/PF_FilterExtensions_Config.cfg b/GameData/ProceduralFairings/Config/PF_FilterExtensions_Config.cfg new file mode 100644 index 0000000..9dedbc2 --- /dev/null +++ b/GameData/ProceduralFairings/Config/PF_FilterExtensions_Config.cfg @@ -0,0 +1,14 @@ +// ================================================== +// Add bulkhead profiles to all parts for FilterExtensions +// compatibility. +// ================================================== + +@PART[*]:HAS[@MODULE[ProceduralFairing*]]:FOR[ProceduralFairings]:NEEDS[FilterExtension] +{ + @bulkheadProfiles ^= :$:,proc: +} + +@PART[KzThrustPlate]:FOR[ProceduralFairings]:NEEDS[FilterExtension] +{ + @bulkheadProfiles ^= :$:,proc: +} diff --git a/GameData/ProceduralFairings/Config/PF_Settings_Config.cfg b/GameData/ProceduralFairings/Config/PF_Settings_Config.cfg new file mode 100644 index 0000000..995bf53 --- /dev/null +++ b/GameData/ProceduralFairings/Config/PF_Settings_Config.cfg @@ -0,0 +1,162 @@ +// ================================================== +// Global procedural fairings settings. +// ================================================== + +PROCFAIRINGS_MINDIAMETER +{ + start = 1.0 + miniaturization = 0.4 + sandbox = 0.1 +} + +PROCFAIRINGS_MAXDIAMETER +{ + start = 1.50 + advAerodynamics = 4.0 + heavyAerodynamics = 12.0 + experimentalAerodynamics = 30.0 + sandbox = 50.0 +} + +PROCROCKET_MINDIAMETER +{ + start = 1.0 + miniaturization = 0.4 + sandbox = 0.1 +} + +PROCROCKET_MAXDIAMETER +{ + start = 1.5 + advConstruction = 4.0 + metaMaterials = 12.0 + aerospaceTech = 30.0 + sandbox = 50.0 +} + +// ================================================== +// Dummy parts to represent Procedural Fairings +// upgrades in the tech tree. +// ================================================== + +PART +{ + name = pf_tech_fairing04m + module = Part + author = Starstrider42 (config), e-dog (model) + + MODEL + { + model = ProceduralFairings/Parts/base_standard + } + + TechRequired = miniaturization + entryCost = 0 + cost = 0 + category = none + title = Procedural Fairings Upgrade + manufacturer = Keramzit Engineering + description = Allows fairings and plates to be made as small as 0.4 meters. +} + +PART +{ + name = pf_tech_fairing4m + module = Part + author = Starstrider42 (config), e-dog (model) + + MODEL + { + model = ProceduralFairings/Parts/base_standard + } + + TechRequired = advAerodynamics + entryCost = 0 + cost = 0 + category = none + title = Procedural Fairings Upgrade + manufacturer = Keramzit Engineering + description = Allows fairing bases up to 4 meters size. +} + +PART +{ + name = pf_tech_fairing12m + module = Part + author = Starstrider42 (config), e-dog (model) + + description = + + MODEL + { + model = ProceduralFairings/Parts/base_standard + } + + TechRequired = heavyAerodynamics + entryCost = 0 + cost = 0 + category = none + title = Procedural Fairings Upgrade + manufacturer = Keramzit Engineering + description = Allows fairing bases up to 12 meters size. +} + +PART +{ + name = pf_tech_fairing30m + module = Part + author = Starstrider42 (config), e-dog (model) + + MODEL + { + model = ProceduralFairings/Parts/base_standard + } + + TechRequired = experimentalAerodynamics + entryCost = 0 + cost = 0 + category = none + title = Procedural Fairings Upgrade + manufacturer = Keramzit Engineering + description = Allows fairing bases up to 30 meters size. +} + +PART +{ + name = pf_tech_rocket12m + module = Part + author = Starstrider42 (config), e-dog (model) + + MODEL + { + model = ProceduralFairings/Parts/thrust_plate + } + + TechRequired = metaMaterials + entryCost = 0 + cost = 0 + category = none + title = Procedural Fairings Upgrade + manufacturer = Keramzit Engineering + description = Allows thrust plates up to 12 meters size. +} + +PART +{ + name = pf_tech_rocket30m + module = Part + author = Starstrider42 (config), e-dog (model) + + MODEL + { + model = ProceduralFairings/Parts/thrust_plate + } + + TechRequired = aerospaceTech + entryCost = 0 + cost = 0 + category = none + title = Procedural Fairings Upgrade + manufacturer = Keramzit Engineering + description = Allows thrust plates up to 30 meters size. +} diff --git a/GameData/ProceduralFairings/Config/PF_Squad_Config.cfg b/GameData/ProceduralFairings/Config/PF_Squad_Config.cfg new file mode 100644 index 0000000..92e1053 --- /dev/null +++ b/GameData/ProceduralFairings/Config/PF_Squad_Config.cfg @@ -0,0 +1,116 @@ +// ================================================== +// Replace the stock procedural fairings with ours. +// ================================================== + +@PART[fairingSize1]:FOR[ProceduralFairings]:NEEDS[!PFFE] +{ + !MODEL,*{} + + MODEL + { + model = Squad/Parts/Aero/fairings/fairingSize1 + scale = 0.8275, 0.8275, 0.8275 + position = 0.0, -0.115, 0.0 + } + + @node_stack_top = 0.0, 0.0725, 0.0, 0.0, 1.0, 0.0, 0 + @node_stack_bottom = 0.0, -0.265, 0.0, 0.0, -1.0, 0.0, 1 + + %node_stack_connect01 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + %node_stack_connect02 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + %node_stack_connect03 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + %node_stack_connect04 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + %node_stack_connect05 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + %node_stack_connect06 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + %node_stack_connect07 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + %node_stack_connect08 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + + %fx_gasBurst_white = 0.0, 0.0725, 0.0, 0.0, 1.0, 0.0, decouple + + %sound_vent_large = decouple + + @title = AE-FF-PF Airstream Protective Shell + @tags ^=:$: procedural + + !MODULE[ModuleProceduralFairing],*{} + + !MODULE[ModuleCargoBay],*{} + + !MODULE[ModuleStructuralNode*],*{} + + !MODULE[ModulePartVariants],*{} + + MODULE + { + name = ProceduralFairingBase + baseSize = 1.15 + sideThickness = 0.05 + verticalStep = 0.1 + } + + MODULE + { + name = KzNodeNumberTweaker + nodePrefix = connect + maxNumber = 8 + numNodes = 2 + radius = 0.625 + shouldResizeNodes = False + } + + MODULE + { + name = KzFairingBaseResizer + size = 1.25 + costPerTonne = 1000 + specificMass = 0.007, 0.026, 0.010, 0 + specificBreakingForce = 1280 + specificBreakingTorque = 1280 + dragAreaScale = 1.5 + } + + MODULE + { + name = KzFairingBaseShielding + } + + MODULE + { + name = ModuleDecouple + isOmniDecoupler = False + ejectionForce = 250 + ejectionForcePercent = 100 + menuName = Decoupler Staging + stagingEnabled = False + stagingEnableText = Decoupler: Disabled + stagingDisableText = Decoupler: Enabled + } + + MODULE + { + name = ModuleToggleCrossfeed + crossfeedStatus = False + toggleEditor = True + toggleFlight = True + enableText = Enable Crossfeed + disableText = Disable Crossfeed + } +} + +// ================================================== +// Hide the rest of the bases. +// ================================================== + +@PART[fairingSize2]:FOR[ProceduralFairings]:NEEDS[!PFFE] +{ + @TechRequired = none + %TechHidden = True + @category = none +} + +@PART[fairingSize3]:FOR[ProceduralFairings]:NEEDS[!PFFE] +{ + @TechRequired = none + %TechHidden = True + @category = none +} diff --git a/GameData/ProceduralFairings/Parts/base_ring.cfg b/GameData/ProceduralFairings/Parts/base_ring.cfg new file mode 100644 index 0000000..48f846c --- /dev/null +++ b/GameData/ProceduralFairings/Parts/base_ring.cfg @@ -0,0 +1,120 @@ +PART +{ + name = KzResizableFairingBaseRing + module = Part + author = e-dog + + MODEL + { + model = ProceduralFairings/Parts/base_ring + scale = 1.0, 1.0, 1.0 + } + + scale = 1.0 + rescaleFactor = 1.0 + + node_stack_top = 0.0, 0.2, 0.0, 0.0, 1.0, 0.0, 1 + node_stack_bottom = 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1 + + node_stack_connect01 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_connect02 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_connect03 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_connect04 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_connect05 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_connect06 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_connect07 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_connect08 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + + attachRules = 1,0,1,1,0 + + fx_gasBurst_white = 0.0, 0.3, 0.0, 0.0, 1.0, 0.0, decouple + + sound_decoupler_fire = decouple + + TechRequired = aerodynamicSystems + cost = 100 + entryCost = 4600 + category = Payload + subcategory = 0 + title = Procedural Fairing Base Ring + manufacturer = Keramzit Engineering + description = Structural base for mounting side fairings and your payload. Ring style. + + mass = 0 + dragModelType = default + maximum_drag = 0.2 + minimum_drag = 0.2 + angularDrag = 2 + crashTolerance = 12 + breakingForce = 2000 + breakingTorque = 2000 + maxTemp = 2600 + explosionPotential = 0 + fuelCrossFeed = True + thermalMassModifier = 2.0 + skinMassPerArea = 4.0 + skinInternalConductionMult = 0.25 + emissiveConstant = 0.8 + stackSymmetry = 7 + stageOffset = 1 + childStageOffset = 1 + bulkheadProfiles = size1 + tags = aero )cap cargo cone contain drag fairing hollow inter nose payload procedural protect rocket shroud stage (stor transport + + MODULE + { + name = ProceduralFairingBase + baseSize = 1.15 + sideThickness = 0.05 + verticalStep = 0.1 + } + + MODULE + { + name = KzNodeNumberTweaker + nodePrefix = connect + maxNumber = 8 + numNodes = 2 + radius = 0.625 + shouldResizeNodes = False + } + + MODULE + { + name = KzFairingBaseResizer + size = 1.25 + costPerTonne = 1000 + specificMass = 0.006, 0.013, 0.010, 0 + specificBreakingForce = 1280 + specificBreakingTorque = 1280 + dragAreaScale = 1.5 + } + + MODULE + { + name = KzFairingBaseShielding + } + + MODULE + { + name = ModuleDecouple + explosiveNodeID = top + isOmniDecoupler = False + ejectionForce = 250 + ejectionForcePercent = 100 + menuName = Decoupler Staging + stagingEnabled = False + stagingEnableText = Decoupler: Disabled + stagingDisableText = Decoupler: Enabled + } + + MODULE + { + name = ModuleToggleCrossfeed + crossfeedStatus = False + toggleEditor = True + toggleFlight = True + enableText = Enable Crossfeed + disableText = Disable Crossfeed + } +} diff --git a/GameData/ProceduralFairings/baseRingTex.dds b/GameData/ProceduralFairings/Parts/base_ring.dds similarity index 100% rename from GameData/ProceduralFairings/baseRingTex.dds rename to GameData/ProceduralFairings/Parts/base_ring.dds diff --git a/GameData/ProceduralFairings/Parts/base_ring.mu b/GameData/ProceduralFairings/Parts/base_ring.mu new file mode 100644 index 0000000..f69b3ba Binary files /dev/null and b/GameData/ProceduralFairings/Parts/base_ring.mu differ diff --git a/GameData/ProceduralFairings/blackRingTex.dds b/GameData/ProceduralFairings/Parts/base_ring_black.dds similarity index 100% rename from GameData/ProceduralFairings/blackRingTex.dds rename to GameData/ProceduralFairings/Parts/base_ring_black.dds diff --git a/GameData/ProceduralFairings/Parts/base_standard.cfg b/GameData/ProceduralFairings/Parts/base_standard.cfg new file mode 100644 index 0000000..e705343 --- /dev/null +++ b/GameData/ProceduralFairings/Parts/base_standard.cfg @@ -0,0 +1,136 @@ +PART +{ + name = KzResizableFairingBase + module = Part + author = e-dog + + MODEL + { + model = ProceduralFairings/Parts/base_standard + scale = 1.0, 1.0, 1.0 + } + + scale = 1.0 + rescaleFactor = 1.0 + + node_stack_top = 0.0, 0.5, 0.0, 0.0, 1.0, 0.0, 1 + node_stack_bottom = 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1 + + node_stack_connect01 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_connect02 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_connect03 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_connect04 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_connect05 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_connect06 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_connect07 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_connect08 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + + node_stack_interstage01 = 0.0, 1.20, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_interstage01u = 0.0, 1.20, 0.0, 0.0, 1.0, 0.0, 1 + node_stack_interstage02 = 0.0, 1.90, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_interstage02u = 0.0, 1.90, 0.0, 0.0, 1.0, 0.0, 1 + node_stack_interstage03 = 0.0, 2.60, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_interstage03u = 0.0, 2.60, 0.0, 0.0, 1.0, 0.0, 1 + node_stack_interstage04 = 0.0, 3.30, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_interstage04u = 0.0, 3.30, 0.0, 0.0, 1.0, 0.0, 1 + node_stack_interstage05 = 0.0, 4.00, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_interstage05u = 0.0, 4.00, 0.0, 0.0, 1.0, 0.0, 1 + node_stack_interstage06 = 0.0, 4.70, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_interstage06u = 0.0, 4.70, 0.0, 0.0, 1.0, 0.0, 1 + node_stack_interstage07 = 0.0, 5.40, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_interstage07u = 0.0, 5.40, 0.0, 0.0, 1.0, 0.0, 1 + node_stack_interstage08 = 0.0, 6.10, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_interstage08u = 0.0, 6.10, 0.0, 0.0, 1.0, 0.0, 1 + + attachRules = 1,0,1,1,0 + + fx_gasBurst_white = 0.0, 0.3, 0.0, 0.0, 1.0, 0.0, decouple + + sound_vent_large = decouple + + TechRequired = aviation + cost = 100 + entryCost = 4600 + category = Payload + subcategory = 0 + title = Procedural Fairing Base + manufacturer = Keramzit Engineering + description = Structural base for mounting side fairings and your payload. Raised surface can ease loading. + + mass = 0 + dragModelType = default + maximum_drag = 0.2 + minimum_drag = 0.2 + angularDrag = 2 + crashTolerance = 12 + breakingForce = 2000 + breakingTorque = 2000 + maxTemp = 2600 + fuelCrossFeed = True + thermalMassModifier = 2.0 + skinMassPerArea = 4.0 + skinInternalConductionMult = 0.25 + emissiveConstant = 0.8 + stackSymmetry = 7 + stageOffset = 1 + childStageOffset = 1 + bulkheadProfiles = size1 + tags = aero )cap cargo cone contain drag fairing hollow inter nose payload procedural protect rocket shroud stage (stor transport + + MODULE + { + name = ProceduralFairingBase + baseSize = 1.15 + sideThickness = 0.05 + verticalStep = 0.1 + } + + MODULE + { + name = KzNodeNumberTweaker + nodePrefix = connect + maxNumber = 8 + numNodes = 2 + radius = 0.625 + shouldResizeNodes = False + } + + MODULE + { + name = KzFairingBaseResizer + size = 1.25 + costPerTonne = 1000 + specificMass = 0.007, 0.026, 0.010, 0 + specificBreakingForce = 1280 + specificBreakingTorque = 1280 + dragAreaScale = 1.5 + } + + MODULE + { + name = KzFairingBaseShielding + } + + MODULE + { + name = ModuleDecouple + explosiveNodeID = top + isOmniDecoupler = False + ejectionForce = 250 + ejectionForcePercent = 100 + menuName = Decoupler Staging + stagingEnabled = False + stagingEnableText = Decoupler: Disabled + stagingDisableText = Decoupler: Enabled + } + + MODULE + { + name = ModuleToggleCrossfeed + crossfeedStatus = False + toggleEditor = True + toggleFlight = True + enableText = Enable Crossfeed + disableText = Disable Crossfeed + } +} diff --git a/GameData/ProceduralFairings/baseTex.dds b/GameData/ProceduralFairings/Parts/base_standard.dds similarity index 100% rename from GameData/ProceduralFairings/baseTex.dds rename to GameData/ProceduralFairings/Parts/base_standard.dds diff --git a/GameData/ProceduralFairings/Parts/base_standard.mu b/GameData/ProceduralFairings/Parts/base_standard.mu new file mode 100644 index 0000000..8c69271 Binary files /dev/null and b/GameData/ProceduralFairings/Parts/base_standard.mu differ diff --git a/GameData/ProceduralFairings/Parts/fairing.dds b/GameData/ProceduralFairings/Parts/fairing.dds new file mode 100644 index 0000000..44032e1 Binary files /dev/null and b/GameData/ProceduralFairings/Parts/fairing.dds differ diff --git a/GameData/ProceduralFairings/Parts/fairing_NRM.dds b/GameData/ProceduralFairings/Parts/fairing_NRM.dds new file mode 100644 index 0000000..44032e1 Binary files /dev/null and b/GameData/ProceduralFairings/Parts/fairing_NRM.dds differ diff --git a/GameData/ProceduralFairings/Parts/fairing_side.mu b/GameData/ProceduralFairings/Parts/fairing_side.mu new file mode 100644 index 0000000..0cff845 Binary files /dev/null and b/GameData/ProceduralFairings/Parts/fairing_side.mu differ diff --git a/GameData/ProceduralFairings/Parts/fairing_side_A.cfg b/GameData/ProceduralFairings/Parts/fairing_side_A.cfg new file mode 100644 index 0000000..fbd4dc6 --- /dev/null +++ b/GameData/ProceduralFairings/Parts/fairing_side_A.cfg @@ -0,0 +1,100 @@ +PART +{ + name = KzProcFairingSide1 + module = Part + author = e-dog + + MODEL + { + model = ProceduralFairings/Parts/fairing_side + texture = fairing, ProceduralFairings/Textures/fairing + texture = fairing_NRM, ProceduralFairings/Textures/fairing_NRM + } + + scale = 1.0 + rescaleFactor = 1.0 + + node_stack_connect = 0.0, 0.5, 0.0, 0.0, -1.0, 0.0, 0 + + attachRules = 1,0,0,1,1 + + TechRequired = aviation + cost = 100 + entryCost = 4600 + category = Payload + subcategory = 0 + title = Procedural Fairing (Ogive) + manufacturer = Keramzit Engineering + description = Made from the finest materials found in the fields around the Space Center. Can be set to any shape required. + + mass = 0 + dragModelType = default + maximum_drag = 0.1 + minimum_drag = 0.1 + angularDrag = 2 + crashTolerance = 8 + breakingForce = 200 + breakingTorque = 200 + maxTemp = 2600 + thermalMassModifier = 2.0 + skinMassPerArea = 4.0 + skinInternalConductionMult = 0.25 + emissiveConstant = 0.8 + fuelCrossFeed = False + stageOffset = 1 + childStageOffset = 1 + stagingIcon = FUEL_TANK + bulkheadProfiles = size0 + tags = aero )cap cargo cone contain drag fairing hollow inter nose payload procedural protect rocket shroud stage (stor transport + + MODULE + { + name = ProceduralFairingSide + density = 0.1 + costPerTonne = 5000 + specificBreakingForce = 2000 + specificBreakingTorque = 2000 + noseHeightRatio = 2.0 + baseConeShape = 0.3, 0.2, 1.0, 0.5 + noseConeShape = 0.5, 0.0, 1.0, 0.7 + baseConeSegments = 7 + noseConeSegments = 11 + mappingScale = 1024, 1024 + stripMapping = 992, 1024 + horMapping = 10, 490, 500, 980 + vertMapping = 10, 170, 694, 1014 + } + + MODULE + { + name = ProceduralFairingDecoupler + } + + MODULE + { + name = ModulePartVariants + primaryColor = #FAFAFA + secondaryColor = #DCBE87 + baseDisplayName = Original + + VARIANT + { + name = Fuselage + displayName = Fuselage + primaryColor = #D7D7D7 + secondaryColor = #B9B9B9 + + TEXTURE + { + mainTextureURL = ProceduralFairings/Textures/fairing_fuselage + _BumpMap = ProceduralFairings/Textures/fairing_generic_NRM + } + } + } + + MODULE + { + name = ModuleSeeThroughObject + transformName = model + } +} diff --git a/GameData/ProceduralFairings/Parts/fairing_side_B.cfg b/GameData/ProceduralFairings/Parts/fairing_side_B.cfg new file mode 100644 index 0000000..28669f4 --- /dev/null +++ b/GameData/ProceduralFairings/Parts/fairing_side_B.cfg @@ -0,0 +1,100 @@ +PART +{ + name = KzProcFairingSide2 + module = Part + author = e-dog + + MODEL + { + model = ProceduralFairings/Parts/fairing_side + texture = fairing, ProceduralFairings/Textures/fairing + texture = fairing_NRM, ProceduralFairings/Textures/fairing_NRM + } + + scale = 1.0 + rescaleFactor = 1.0 + + node_stack_connect = 0.0, 0.5, 0.0, 0.0, -1.0, 0.0, 0 + + attachRules = 1,0,0,1,1 + + TechRequired = aviation + cost = 100 + entryCost = 4600 + category = Payload + subcategory = 0 + title = Procedural Fairing (Conic) + manufacturer = Keramzit Engineering + description = Made from the finest materials found in the fields around the Space Center. Can be set to any shape required. + + mass = 0 + dragModelType = default + maximum_drag = 0.1 + minimum_drag = 0.1 + angularDrag = 2 + crashTolerance = 8 + breakingForce = 200 + breakingTorque = 200 + maxTemp = 2600 + thermalMassModifier = 2.0 + skinMassPerArea = 4.0 + skinInternalConductionMult = 0.25 + emissiveConstant = 0.8 + fuelCrossFeed = False + stageOffset = 1 + childStageOffset = 1 + stagingIcon = FUEL_TANK + bulkheadProfiles = size0 + tags = aero )cap cargo cone contain drag fairing hollow inter nose payload procedural protect rocket shroud stage (stor transport + + MODULE + { + name = ProceduralFairingSide + density = 0.1 + costPerTonne = 5000 + specificBreakingForce = 2000 + specificBreakingTorque = 2000 + noseHeightRatio = 2.0 + baseConeShape = 0.3, 0.3, 0.7, 0.7 + noseConeShape = 0.1, 0.0, 0.7, 0.7 + baseConeSegments = 7 + noseConeSegments = 11 + mappingScale = 1024, 1024 + stripMapping = 992, 1024 + horMapping = 10, 490, 500, 980 + vertMapping = 10, 170, 694, 1014 + } + + MODULE + { + name = ProceduralFairingDecoupler + } + + MODULE + { + name = ModulePartVariants + primaryColor = #FAFAFA + secondaryColor = #DCBE87 + baseDisplayName = Original + + VARIANT + { + name = Fuselage + displayName = Fuselage + primaryColor = #D7D7D7 + secondaryColor = #B9B9B9 + + TEXTURE + { + mainTextureURL = ProceduralFairings/Textures/fairing_fuselage + _BumpMap = ProceduralFairings/Textures/fairing_generic_NRM + } + } + } + + MODULE + { + name = ModuleSeeThroughObject + transformName = model + } +} diff --git a/GameData/ProceduralFairings/Parts/interstage_adapter.cfg b/GameData/ProceduralFairings/Parts/interstage_adapter.cfg new file mode 100644 index 0000000..385ae86 --- /dev/null +++ b/GameData/ProceduralFairings/Parts/interstage_adapter.cfg @@ -0,0 +1,138 @@ +PART +{ + name = KzInterstageAdapter2 + module = Part + author = e-dog + + MODEL + { + model = ProceduralFairings/Parts/base_ring + scale = 1.0, 1.0, 1.0 + texture = base_ring, ProceduralFairings/Parts/base_ring_black + } + + scale = 1.0 + rescaleFactor = 1.0 + + node_stack_top = 0.0, 0.2, 0.0, 0.0, 1.0, 0.0, 1 + node_stack_top1 = 0.0, 2.0, 0.0, 0.0, 1.0, 0.0, 1 + node_stack_bottom = 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1 + + node_stack_connect01 = -0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_connect02 = 0.0, 0.1, 0.5, 0.0, 1.0, 0.0, 0 + node_stack_connect03 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_connect04 = 0.0, 0.1, -0.5, 0.0, 1.0, 0.0, 0 + node_stack_connect05 = -0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_connect06 = 0.0, 0.1, 0.5, 0.0, 1.0, 0.0, 0 + node_stack_connect07 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_connect08 = 0.0, 0.1, -0.5, 0.0, 1.0, 0.0, 0 + + node_stack_interstage01 = 0.0, 0.425, 0.0, 0.0, -1.0, 0.0, 0 + node_stack_interstage01u = 0.0, 0.425, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_interstage02 = 0.0, 0.650, 0.0, 0.0, -1.0, 0.0, 0 + node_stack_interstage02u = 0.0, 0.650, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_interstage03 = 0.0, 0.875, 0.0, 0.0, -1.0, 0.0, 0 + node_stack_interstage03u = 0.0, 0.875, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_interstage04 = 0.0, 1.100, 0.0, 0.0, -1.0, 0.0, 0 + node_stack_interstage04u = 0.0, 1.100, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_interstage05 = 0.0, 1.325, 0.0, 0.0, -1.0, 0.0, 0 + node_stack_interstage05u = 0.0, 1.325, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_interstage06 = 0.0, 1.550, 0.0, 0.0, -1.0, 0.0, 0 + node_stack_interstage06u = 0.0, 1.550, 0.0, 0.0, 1.0, 0.0, 0 + node_stack_interstage07 = 0.0, 1.775, 0.0, 0.0, -1.0, 0.0, 0 + node_stack_interstage07u = 0.0, 1.775, 0.0, 0.0, 1.0, 0.0, 0 + + attachRules = 1,0,1,1,0 + + fx_gasBurst_white = 0.0, 0.3, 0.0, 0.0, 1.0, 0.0, decouple + + sound_vent_large = decouple + + TechRequired = advConstruction + cost = 100 + entryCost = 4600 + category = Payload + subcategory = 0 + title = Procedural Interstage Fairing Adapter + manufacturer = Keramzit Engineering + description = Enables side fairings to hold the part at the top. + + mass = 0 + dragModelType = default + maximum_drag = 0.2 + minimum_drag = 0.2 + angularDrag = 2 + crashTolerance = 12 + breakingForce = 2000 + breakingTorque = 2000 + maxTemp = 2600 + fuelCrossFeed = True + thermalMassModifier = 2.0 + skinMassPerArea = 4.0 + skinInternalConductionMult = 0.25 + emissiveConstant = 0.8 + stackSymmetry = 7 + stageOffset = 1 + childStageOffset = 1 + bulkheadProfiles = size1 + tags = aero )cap cargo cone contain drag fairing hollow inter nose payload procedural protect rocket shroud stage (stor transport + + MODULE + { + name = ProceduralFairingAdapter + baseSize = 1.25 + topSize = 1.25 + height = 2.0 + costPerTonne = 1000 + specificMass = 0.006, 0.013, 0.010, 0 + specificBreakingForce = 6050 + specificBreakingTorque = 6050 + dragAreaScale = 1.5 + topNodeDecouplesWhenFairingsGone = False + } + + MODULE + { + name = ProceduralFairingBase + baseSize = 1.15 + sideThickness = 0.05 + verticalStep = 0.1 + } + + MODULE + { + name = KzNodeNumberTweaker + nodePrefix = connect + maxNumber = 8 + numNodes = 4 + radius = 0.625 + shouldResizeNodes = False + } + + MODULE + { + name = KzFairingBaseShielding + } + + MODULE + { + name = ModuleDecouple + explosiveNodeID = top1 + isOmniDecoupler = False + ejectionForce = 250 + ejectionForcePercent = 100 + menuName = Decouple Top Node + stagingEnableText = Decoupler: Disabled + stagingDisableText = Decoupler: Enabled + } + + MODULE + { + name = ModuleToggleCrossfeed + crossfeedStatus = False + toggleEditor = True + toggleFlight = True + enableText = Enable Crossfeed + disableText = Disable Crossfeed + } +} diff --git a/GameData/ProceduralFairings/Parts/thrust_plate.cfg b/GameData/ProceduralFairings/Parts/thrust_plate.cfg new file mode 100644 index 0000000..93c68b6 --- /dev/null +++ b/GameData/ProceduralFairings/Parts/thrust_plate.cfg @@ -0,0 +1,90 @@ +PART +{ + name = KzThrustPlate + module = Part + author = e-dog + + MODEL + { + model = ProceduralFairings/Parts/thrust_plate + scale = 1.0, 1.0, 1.0 + } + + scale = 1.0 + rescaleFactor = 1.0 + + node_stack_top = 0.0, 0.1, 0.0, 0.0, 1.0, 0.0, 1 + node_stack_bottom = 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1 + + node_stack_bottom01 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_bottom02 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_bottom03 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_bottom04 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_bottom05 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_bottom06 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_bottom07 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_bottom08 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_bottom09 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_bottom10 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_bottom11 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_bottom12 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_bottom13 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_bottom14 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_bottom15 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 + node_stack_bottom16 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 + + TechRequired = advConstruction + cost = 100 + entryCost = 4200 + category = Structural + subcategory = 0 + title = Procedural Thrust Plate Adapter + manufacturer = Keramzit Engineering + description = When quad-adapter just isn't enough, Keramzit Engineering has you covered with its wonderful Multi-adapter! Designed for building engine clusters, it also found its uses in multiple payload attachment and space bars. + attachRules = 1,0,1,1,0 + + mass = 0 + dragModelType = default + maximum_drag = 0.2 + minimum_drag = 0.2 + angularDrag = 2 + crashTolerance = 12 + breakingForce = 2000 + breakingTorque = 2000 + maxTemp = 2000 + explosionPotential = 0 + fuelCrossFeed = False + bulkheadProfiles = size1 + NoCrossFeedNodeKey = bottom + + MODULE + { + name = KzNodeNumberTweaker + nodePrefix = bottom + maxNumber = 16 + numNodes = 4 + radius = 0.625 + } + + MODULE + { + name = KzThrustPlateResizer + size = 1.25 + costPerTonne = 1000 + specificMass = 0.007, 0.026, 0.01, 0 + specificBreakingForce = 1536 + specificBreakingTorque = 1536 + minSizeName = PROCROCKET_MINDIAMETER + maxSizeName = PROCROCKET_MAXDIAMETER + } + + MODULE + { + name = ModuleToggleCrossfeed + crossfeedStatus = False + toggleEditor = True + toggleFlight = True + enableText = Enable Crossfeed + disableText = Disable Crossfeed + } +} diff --git a/GameData/ProceduralFairings/thrustPlate1.dds b/GameData/ProceduralFairings/Parts/thrust_plate.dds similarity index 100% rename from GameData/ProceduralFairings/thrustPlate1.dds rename to GameData/ProceduralFairings/Parts/thrust_plate.dds diff --git a/GameData/ProceduralFairings/Parts/thrust_plate.mu b/GameData/ProceduralFairings/Parts/thrust_plate.mu new file mode 100644 index 0000000..b25c2cc Binary files /dev/null and b/GameData/ProceduralFairings/Parts/thrust_plate.mu differ diff --git a/GameData/ProceduralFairings/thrustPlate1bump_Normal_NRM.dds b/GameData/ProceduralFairings/Parts/thrust_plate_NRM.dds similarity index 100% rename from GameData/ProceduralFairings/thrustPlate1bump_Normal_NRM.dds rename to GameData/ProceduralFairings/Parts/thrust_plate_NRM.dds diff --git a/GameData/ProceduralFairings/Plugins/ProceduralFairings.dll b/GameData/ProceduralFairings/Plugins/ProceduralFairings.dll new file mode 100644 index 0000000..5cb9352 Binary files /dev/null and b/GameData/ProceduralFairings/Plugins/ProceduralFairings.dll differ diff --git a/GameData/ProceduralFairings/ProceduralFairings.dll b/GameData/ProceduralFairings/ProceduralFairings.dll deleted file mode 100644 index d4cecd2..0000000 Binary files a/GameData/ProceduralFairings/ProceduralFairings.dll and /dev/null differ diff --git a/GameData/ProceduralFairings/Textures/fairing.dds b/GameData/ProceduralFairings/Textures/fairing.dds new file mode 100644 index 0000000..1ccb6f1 Binary files /dev/null and b/GameData/ProceduralFairings/Textures/fairing.dds differ diff --git a/GameData/ProceduralFairings/Textures/fairing_NRM.dds b/GameData/ProceduralFairings/Textures/fairing_NRM.dds new file mode 100644 index 0000000..5f2b097 Binary files /dev/null and b/GameData/ProceduralFairings/Textures/fairing_NRM.dds differ diff --git a/GameData/ProceduralFairings/Textures/fairing_fuselage.dds b/GameData/ProceduralFairings/Textures/fairing_fuselage.dds new file mode 100644 index 0000000..3bb4e2c Binary files /dev/null and b/GameData/ProceduralFairings/Textures/fairing_fuselage.dds differ diff --git a/GameData/ProceduralFairings/Textures/fairing_generic_NRM.dds b/GameData/ProceduralFairings/Textures/fairing_generic_NRM.dds new file mode 100644 index 0000000..648b7c6 Binary files /dev/null and b/GameData/ProceduralFairings/Textures/fairing_generic_NRM.dds differ diff --git a/GameData/ProceduralFairings/adapter2.cfg b/GameData/ProceduralFairings/adapter2.cfg deleted file mode 100644 index e45e1ff..0000000 --- a/GameData/ProceduralFairings/adapter2.cfg +++ /dev/null @@ -1,143 +0,0 @@ -PART -{ -name = KzInterstageAdapter2 -module = Part -author = e-dog - -MODEL -{ - model = ProceduralFairings/baseRingModel - texture = baseRingTex, ProceduralFairings/blackRingTex - scale = 1, 1, 1 -} - -scale = 1 -rescaleFactor = 1 - -// definition format is Position X, Position Y, Position Z, Up X, Up Y, Up Z -node_stack_bottom = 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_top = 0.0, 0.2, 0.0, 0.0, 1.0, 0.0, 1 -node_stack_top1 = 0.0, 2.0, 0.0, 0.0, 1.0, 0.0, 1 -node_stack_connect01 = -0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_connect02 = 0.0, 0.1, 0.5, 0.0, 1.0, 0.0, 0 -node_stack_connect03 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_connect04 = 0.0, 0.1, -0.5, 0.0, 1.0, 0.0, 0 -node_stack_connect05 = -0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_connect06 = 0.0, 0.1, 0.5, 0.0, 1.0, 0.0, 0 -node_stack_connect07 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_connect08 = 0.0, 0.1, -0.5, 0.0, 1.0, 0.0, 0 - -node_stack_interstage01 = 0.0, 0.425, 0.0, 0.0, -1.0, 0.0, 0 -node_stack_interstage01u = 0.0, 0.425, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_interstage02 = 0.0, 0.65, 0.0, 0.0, -1.0, 0.0, 0 -node_stack_interstage02u = 0.0, 0.65, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_interstage03 = 0.0, 0.875, 0.0, 0.0, -1.0, 0.0, 0 -node_stack_interstage03u = 0.0, 0.875, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_interstage04 = 0.0, 1.10, 0.0, 0.0, -1.0, 0.0, 0 -node_stack_interstage04u = 0.0, 1.10, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_interstage05 = 0.0, 1.325, 0.0, 0.0, -1.0, 0.0, 0 -node_stack_interstage05u = 0.0, 1.325, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_interstage06 = 0.0, 1.550, 0.0, 0.0, -1.0, 0.0, 0 -node_stack_interstage06u = 0.0, 1.550, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_interstage07 = 0.0, 1.775, 0.0, 0.0, -1.0, 0.0, 0 -node_stack_interstage07u = 0.0, 1.775, 0.0, 0.0, 1.0, 0.0, 0 - - -stackSymmetry = 7 - -fx_gasBurst_white = 0.0, 0.3, 0.0, 0.0, 1.0, 0.0, decouple -sound_vent_large = decouple - -TechRequired = advConstruction -cost = 100 -entryCost = 4600 -category = Payload -subcategory = 0 -title = Interstage Fairing Adapter -manufacturer = Keramzit Engineering -description = Enables side fairings to hold the part at the top. -attachRules = 1,0,1,1,0 - -tags = procedural fairings - -// --- standard part parameters --- -mass = 0 -dragModelType = default -maximum_drag = 0.2 -minimum_drag = 0.2 -angularDrag = 2 -crashTolerance = 12 -maxTemp = 2600 -explosionPotential = 0 -fuelCrossFeed = False -thermalMassModifier = 2.0 -skinMassPerArea = 4.0 -skinInternalConductionMult = 0.25 -emissiveConstant = 0.8 - -breakingForce = 2000 -breakingTorque = 2000 - -stageOffset = 1 -childStageOffset = 1 - -MODULE -{ - name = ProceduralFairingAdapter - baseSize=1.25 - topSize =1.25 - height=2 - costPerTonne=1000 - specificMass=0.0064, 0.0130, 0.0098, 0 - specificBreakingForce =6050 - specificBreakingTorque=6050 - dragAreaScale = 1.5 - topNodeDecouplesWhenFairingsGone = false -} - -MODULE -{ - name = ProceduralFairingBase - baseSize=1.15 - sideThickness=0.05 - verticalStep=0.1 - fuelCrossFeed=false -} - -MODULE -{ - name = KzNodeNumberTweaker - nodePrefix = connect - maxNumber = 8 - numNodes = 4 - radius = 0.625 - shouldResizeNodes = False -} - -MODULE -{ - name = ModuleDecouple - ejectionForce = 0 - explosiveNodeID = top1 - stagingEnableText = Decoupler: Staging Disabled - stagingDisableText = Decoupler: Staging Enabled - menuName = Decouple TopNode -} - -MODULE -{ - name = KzFairingBaseShielding -} - -MODULE -{ - name = ModuleToggleCrossfeed - crossfeedStatus = false - toggleEditor = true - toggleFlight = true - enableText = Crossfeed: Disabled - disableText = Crossfeed: Enabled -} - -} - diff --git a/GameData/ProceduralFairings/base.cfg b/GameData/ProceduralFairings/base.cfg deleted file mode 100644 index 01a6c14..0000000 --- a/GameData/ProceduralFairings/base.cfg +++ /dev/null @@ -1,127 +0,0 @@ -PART -{ -name = KzResizableFairingBase -module = Part -author = e-dog - -MODEL -{ - model = ProceduralFairings/baseModel - scale = 1, 1, 1 -} - -scale = 1 -rescaleFactor = 1 - -// definition format is Position X, Position Y, Position Z, Up X, Up Y, Up Z -node_stack_bottom = 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_top = 0.0, 0.5, 0.0, 0.0, 1.0, 0.0, 1 -node_stack_connect01 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_connect02 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_connect03 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_connect04 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_connect05 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_connect06 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_connect07 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_connect08 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 - -node_stack_interstage01 = 0.0, 1.20, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_interstage01u = 0.0, 1.20, 0.0, 0.0, 1.0, 0.0, 1 -node_stack_interstage02 = 0.0, 1.90, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_interstage02u = 0.0, 1.90, 0.0, 0.0, 1.0, 0.0, 1 -node_stack_interstage03 = 0.0, 2.60, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_interstage03u = 0.0, 2.60, 0.0, 0.0, 1.0, 0.0, 1 -node_stack_interstage04 = 0.0, 3.30, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_interstage04u = 0.0, 3.30, 0.0, 0.0, 1.0, 0.0, 1 -node_stack_interstage05 = 0.0, 4.00, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_interstage05u = 0.0, 4.00, 0.0, 0.0, 1.0, 0.0, 1 -node_stack_interstage06 = 0.0, 4.70, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_interstage06u = 0.0, 4.70, 0.0, 0.0, 1.0, 0.0, 1 -node_stack_interstage07 = 0.0, 5.40, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_interstage07u = 0.0, 5.40, 0.0, 0.0, 1.0, 0.0, 1 -node_stack_interstage08 = 0.0, 6.10, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_interstage08u = 0.0, 6.10, 0.0, 0.0, 1.0, 0.0, 1 - -stackSymmetry = 7 - -fx_gasBurst_white = 0.0, 0.3, 0.0, 0.0, 1.0, 0.0, deploy -sound_vent_large = deploy - -TechRequired = aviation -cost = 100 -entryCost = 4600 -category = Payload -subcategory = 0 -title = Fairing Base -manufacturer = Keramzit Engineering -description = Structural base for mounting side fairings and your payload. Decoupler sold separately. Raised surface can ease loading. -attachRules = 1,0,1,1,0 - -tags = procedural fairings - -// --- standard part parameters --- -mass = 0 -dragModelType = default -maximum_drag = 0.2 -minimum_drag = 0.2 -angularDrag = 2 -crashTolerance = 12 -maxTemp = 2600 -explosionPotential = 0 -thermalMassModifier = 2.0 -skinMassPerArea = 4.0 -skinInternalConductionMult = 0.25 -emissiveConstant = 0.8 - -breakingForce = 2000 -breakingTorque = 2000 - -MODULE -{ - name = ProceduralFairingBase - baseSize=1.15 - sideThickness=0.05 - verticalStep=0.1 -} - -MODULE -{ - name = KzNodeNumberTweaker - nodePrefix = connect - maxNumber = 8 - numNodes = 2 - radius = 0.625 - shouldResizeNodes = False -} - -MODULE -{ - name = KzFairingBaseResizer - size = 1.25 - costPerTonne=1000 - specificMass=0.0070, 0.0260, 0.0100, 0 - specificBreakingForce = 1280 - specificBreakingTorque = 1280 - dragAreaScale = 1.5 -} - -MODULE -{ - name = KzFairingBaseShielding -} - - - -MODULE -{ - name = ModuleToggleCrossfeed - crossfeedStatus = false - toggleEditor = true - toggleFlight = true - enableText = Crossfeed: Disabled - disableText = Crossfeed: Enabled -} - - -} - diff --git a/GameData/ProceduralFairings/baseModel.mu b/GameData/ProceduralFairings/baseModel.mu deleted file mode 100644 index cfb5618..0000000 Binary files a/GameData/ProceduralFairings/baseModel.mu and /dev/null differ diff --git a/GameData/ProceduralFairings/baseRing.cfg b/GameData/ProceduralFairings/baseRing.cfg deleted file mode 100644 index 6040005..0000000 --- a/GameData/ProceduralFairings/baseRing.cfg +++ /dev/null @@ -1,121 +0,0 @@ -PART -{ -name = KzResizableFairingBaseRing -module = Part -author = e-dog - -MODEL -{ - model = ProceduralFairings/baseRingModel - scale = 1, 1, 1 -} - -scale = 1 -rescaleFactor = 1 - -// definition format is Position X, Position Y, Position Z, Up X, Up Y, Up Z -node_stack_bottom = 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_top = 0.0, 0.2, 0.0, 0.0, 1.0, 0.0, 1 -node_stack_connect01 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_connect02 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_connect03 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_connect04 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_connect05 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_connect06 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_connect07 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 -node_stack_connect08 = 0.5, 0.1, 0.0, 0.0, 1.0, 0.0, 0 - -node_stack_interstage01 = 0.0, 0.90, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_interstage01u = 0.0, 0.90, 0.0, 0.0, 1.0, 0.0, 1 -node_stack_interstage02 = 0.0, 1.60, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_interstage02u = 0.0, 1.60, 0.0, 0.0, 1.0, 0.0, 1 -node_stack_interstage03 = 0.0, 2.30, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_interstage03u = 0.0, 2.30, 0.0, 0.0, 1.0, 0.0, 1 -node_stack_interstage04 = 0.0, 3.00, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_interstage04u = 0.0, 3.00, 0.0, 0.0, 1.0, 0.0, 1 -node_stack_interstage05 = 0.0, 3.70, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_interstage05u = 0.0, 3.70, 0.0, 0.0, 1.0, 0.0, 1 -node_stack_interstage06 = 0.0, 4.40, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_interstage06u = 0.0, 4.40, 0.0, 0.0, 1.0, 0.0, 1 -node_stack_interstage07 = 0.0, 5.10, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_interstage07u = 0.0, 5.10, 0.0, 0.0, 1.0, 0.0, 1 -node_stack_interstage08 = 0.0, 5.80, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_interstage08u = 0.0, 5.80, 0.0, 0.0, 1.0, 0.0, 1 - -stackSymmetry = 7 - -TechRequired = aerodynamicSystems -cost = 100 -entryCost = 4600 -category = Payload -subcategory = 0 -title = Fairing Base Ring -manufacturer = Keramzit Engineering -description = Structural base for mounting side fairings and your payload. Decoupler sold separately. -attachRules = 1,0,1,1,0 - -tags = procedural fairings - -// --- standard part parameters --- -mass = 0 -dragModelType = default -maximum_drag = 0.2 -minimum_drag = 0.2 -angularDrag = 2 -crashTolerance = 12 -maxTemp = 2600 -explosionPotential = 0 -thermalMassModifier = 2.0 -skinMassPerArea = 4.0 -skinInternalConductionMult = 0.25 -emissiveConstant = 0.8 - -breakingForce = 2000 -breakingTorque = 2000 - -MODULE -{ - name = ProceduralFairingBase - baseSize=1.15 - sideThickness=0.05 - verticalStep=0.1 -} - -MODULE -{ - name = KzNodeNumberTweaker - nodePrefix = connect - maxNumber = 8 - numNodes = 2 - radius = 0.625 - shouldResizeNodes = False -} - -MODULE -{ - name = KzFairingBaseResizer - size = 1.25 - costPerTonne=1000 - specificMass=0.0064, 0.0130, 0.0098, 0 - specificBreakingForce = 1280 - specificBreakingTorque = 1280 - dragAreaScale = 1.5 -} - -MODULE -{ - name = KzFairingBaseShielding -} - -MODULE -{ - name = ModuleToggleCrossfeed - crossfeedStatus = false - toggleEditor = true - toggleFlight = true - enableText = Crossfeed: Disabled - disableText = Crossfeed: Enabled -} - -} - diff --git a/GameData/ProceduralFairings/baseRingModel.mu b/GameData/ProceduralFairings/baseRingModel.mu deleted file mode 100644 index 7e7e63d..0000000 Binary files a/GameData/ProceduralFairings/baseRingModel.mu and /dev/null differ diff --git a/GameData/ProceduralFairings/changelog.txt b/GameData/ProceduralFairings/changelog.txt new file mode 100644 index 0000000..de71080 --- /dev/null +++ b/GameData/ProceduralFairings/changelog.txt @@ -0,0 +1,312 @@ +======================================================= +ProceduralFairings v1.4.3-1 for KSP 1.4.3 (2018-05-02) +======================================================= + + • Recompiled for KSP 1.4.3. + • Fixed the fairing decouplers breaking the MechJeb delta-v calculations. + • Fixed (possibly) the UI of the Fairing Bases and Interstage Adapters locking up and being unable to toggle between automatic and manual fairing side shape. + +======================================================= +ProceduralFairings v1.4.1-1 for KSP 1.4.1 (2018-03-14) +======================================================= + + • Recompiled for KSP 1.4.1. + • Added compatibility for FilterExtensions to all parts. + • Added the ability to toggle the fairing side decoupler (no more separate "Fairing" and "Fuselage" sides). + • Added texture switching for the fairing side textures. + • The base and nose shapes of fairing sides can now be independently changed in the editor, without requiring separate part configs. + • Updated the part configs for compatibility with the latest KSP versions. + • Added decoupler modules to the fairing bases (can be toggled and the decoupling force be set manually if required). + • Fairings now will turn invisible in the editor when hovering over them. + • Repackaged the distribution for the components to be in their own directories. + • Changed the versioning system to use a - format (Kopernicus-style). + +======================================================= +ProceduralFairings v3.21 for KSP 1.2 (2017-06-07) +======================================================= + + • With the help of user sarbian, reverse engineered some changes from user KortexM. + • Wait for part.editorStarted or part.started, then call an update to reset attached procedural parts (fixes the part shifting upon craft loading). + +======================================================= +ProceduralFairings v3.20 for KSP 1.2 (2016-11-08) +======================================================= + + Added the following changes by user KortexM: + + • Ready for KSP 1.2 (recompiled, small changes to configs). + • Added Interstage Nodes (but no trusses) to Fairings and Interstage Fairing, two connections possible on each node (up & down). + • A few code cleanups (ForEach to For mostly). + • Fixed fuel cross feed (be aware that flow to or from the interstage nodes is affected too!). + • Fixed ghost nodes appearing when adding a new fairing base in the VAB/SPH. + • Fixed blue ghost lines (invalid fairing outline) when having multiple fairing bases in VAB/SPH. + • Fixed interstage nodes positions for Interstage Adapter when resized. + • Some UI fixes. + • Code cleanups (deLINQing etc). + • All other bugs/features untouched (hopefully...). + +======================================================= +ProceduralFairings v3.17 for KSP 1.1.2 (2016-05-08) +======================================================= + + • Rebuilt for KSP 1.1.2. + • Fixed thermal issues with FAR (patch by user NathanKell). + • Fixed procedural mass issues (patch by user NathanKell). + • Fixed auto-strut joint issue (connecting to the same rigid body). + • Improved payload auto-strut performance (strut heaviest part only). + +======================================================= +ProceduralFairings v3.16 for KSP 1.1 (2016-04-20) +======================================================= + + • Updated for KSP 1.1 (build 1230). + +======================================================= +ProceduralFairings v3.15 for KSP 1.0.4 (2015-06-27) +======================================================= + + • Updated for KSP 1.0.4. + • Merged pull request for Procedural Parts bug fix. + • Adjusted thermal parameters for KSP 1.0.4 (hopefully). + +======================================================= +ProceduralFairings v3.14 for KSP 1.0.2 (2015-05-10) +======================================================= + + • Updated for the new FAR. + • Reduced fairing shape update rate in the editor to 2 times per second. + • Adjusted default fairing decoupler value to avoid "vessel changed" messages spammed by bugged KSP sliders. + +======================================================= +ProceduralFairings v3.13 for KSP 1.0.2 (2015-05-03) +======================================================= + + • Updated for KSP 1.0.2. + • Rewrote automatic payload struts, strutting all shielded parts now. + • Fixed bug when it was impossible to revert sometimes. + • Fixed slowdown in the editor when tweaking fairing sides. + • Fixed thrust plate mass parameters. + +======================================================= +ProceduralFairings v3.12 for KSP 1.0 (2015-04-28) +======================================================= + + • Updated for KSP 1.0. + • Procedural fairings now use new stock air stream shielding and drag cube rendering. + • Inline fairings now check if the top is closed by a single big part of the same vessel. Make sure that's the case or the shielding won't work. + • Changed and rearranged tech limits for the new tech tree. + • Converted textures to DDS. + • Fixed manual shape UI issues. + • Number of shielded parts is now displayed in the right-click menu for the fairing base. It might be inaccurate in the editor. + • Removed old deprecated parts (non-resizable fairing bases etc). + +======================================================= +ProceduralFairings v3.11 for KSP 0.90 (2014-12-17) +======================================================= + + • Updated for KSP 0.90. + • Added optional manual fairing shape controls. + • Fixed tech restrictions checking in science mode (patch by user Zwa333). + +======================================================= +ProceduralFairings v3.10 for KSP 0.25 (2014-10-11) +======================================================= + + • Rebuilt for KSP 0.25. + +======================================================= +ProceduralFairings v3.09 for KSP 0.24.2 (2014-08-03) +======================================================= + + • Updated KAE DLL. + +======================================================= +ProceduralFairings v3.08 for KSP 0.24.2 (2014-07-26) +======================================================= + + • Updated KAE DLL for KSP 0.24.2. + +======================================================= +ProceduralFairings v3.07 for KSP 0.24 (2014-07-25) +======================================================= + + • Decoupler workaround. + +======================================================= +ProceduralFairings v3.06 for KSP 0.24 (2014-07-20) +======================================================= + + • Updated for KSP 0.24. + +======================================================= +ProceduralFairings v3.05 for KSP 0.23.5 (2014-06-17) +======================================================= + + • Fixed collider bug introduced in 3.04. + +======================================================= +ProceduralFairings v3.03 for KSP 0.23.5 (2014-06-17) +======================================================= + + • Added fake parts to make tech upgrades visible in the tech tree. + • Restored TechRequired for old parts to avoid issues with loading old designs in career mode. + • Fixed bug that allowed to cheat tech limits in career mode. + • Reduced default fairing ejection torque. + +======================================================= +ProceduralFairings v3.03 for KSP 0.23.5 (2014-06-06) +======================================================= + + • Added "sandbox" tech to specify minimum and maximum sizes in sandbox mode (see "common.cfg"). + • Changed mass formula for all parts except side fairings. Generally, larger sizes are significantly lighter now. + • Part mass is now displayed when you right-click the part in VAB. + • Rebuilding side fairing mesh only when really needed (faster in VAB, especially with FAR). + +======================================================= +ProceduralFairings v3.02 for KSP 0.23.5 (2014-05-22) +======================================================= + + • Updated KSPAPIExtensions, should work with Procedural Parts now. + • A bit less restrictive tech, allowing sizes a bit larger and smaller than stock ones. + • Trying to avoid moving attached parts after loading design or saved game. + • Fixed wrong size of newly added side nodes. + +======================================================= +ProceduralFairings v3.01 for KSP 0.23.5 (2014-05-14) +======================================================= + + • Updated KSPAPIExtensions. + • Added size step parameters for RSS. + +======================================================= +ProceduralFairings v3.00 for KSP 0.23.5 (2014-05-13) +======================================================= + + • Moved files up to GameData folder (no "Keramzit" folder anymore). Make sure to delete old mod before installing (which is a good practice anyway). + • Added new resizable fairing bases with configurable number of side nodes. + • Old parts (bases and adapter) are deprecated. Launched vessels should be fine, but you might have trouble loading old designs in VAB/SPH in career mode. + • Added new part: Thrust Plate Multi-Adapter. + • Using KSPAPIExtensions for better tweakables. + • Removed old keyboard-based tweaks - use new tweakables. + • Tweaking outer diameter (with fairings), instead of inner radius. + • Added fairing decoupler torque tweakable. + • Side nodes (for attaching fairings) get larger with the base size to make them more sturdy in KSP 0.23.5+ + • Tech limits are not checked in sandbox mode anymore. + • Extra payload radius is now zero by default. + • Fixed interstage adapter decoupling with fuselage fairings. + +======================================================= +ProceduralFairings v2.4.4 for KSP 0.23 (2014-03-31) +======================================================= + + • Added tweakables. + • Rearranged tech tree, added 3.75m and 5m parts. + • Interstage adapter is available earlier now, but its radius is limited by aerodynamics tech. + • Launch clamps are ignored in payload scanning now. + • Payload scanning doesn't follow surface attachment to the parent part anymore. + • Improved interstage fairing shape when its top is inside payload. + • Added base cone angle limit to make fairings look better. + • Part descriptions and readme text copy edited by user Duxwing. + +======================================================= +ProceduralFairings v2.4.3 for KSP 0.23 (2013-12-18) +======================================================= + + • Improved payload scanning for interstage adapter. + • Recompiled for KSP 0.23. + +======================================================= +ProceduralFairings v2.4.2 for KSP 0.22 (2013-10-19) +======================================================= + + • Zero-radius payload is now used when no payload attached, so fairings will always reshape. + • Added parts to the tech tree. + • Moved fuselage shrouds to Structural tab. + • Changing adapter attachment node size with radius. + +======================================================= +ProceduralFairings v2.4.1 for KSP 0.21.1 (2013-08-22) +======================================================= + + • Disabled fuel cross feed on the interstage adapter - enable at your own risk, it confuses Engineer Redux to death. + • Added stock decoupler module to the interstage adapter topmost node to help with delta-v calculations. + • Improved fairing shape for interstage adapter when fairing top is inside payload. + +======================================================= +ProceduralFairings v2.4 for KSP 0.21.1 (2013-08-20) +======================================================= + + • Added procedural interstage fairing adapter with adjustable radii and height which decouples from the top part when fairings are ejected. + • Added conic fuselage. + • Fixed another inline fairing shape bug. + +======================================================= +ProceduralFairings v2.3 for KSP 0.21.1 (2013-08-07) +======================================================= + + • Changed fuselage texture to distinguish it from fairings. + • You can now lock fairing shape: mouse over the side fairing/fuselage and press L. + • Reduced side nodes size for smaller base rings and 0.625m fairing base (for easier placement). + • Fixed inline fairings making a top cone when there should be just a cylinder. + +======================================================= +ProceduralFairings v2.2 for KSP 0.21.1 (2013-07-30) +======================================================= + + • Added experimental egg-shaped fuselage (a side fairing without decoupler). + • Moved fairing decoupler code to separate PartModule. + • Auto-struts are now created between the top inline base and side fairings as well. NOTE: if you payload is wobbly, the sides might still wobble. + • Fixed bug with misplaced fairings on new ring bases. + +======================================================= +ProceduralFairings v2.1 for KSP 0.21.1 (2013-07-28) +======================================================= + + • Added low-profile fairing bases (base rings), intended for inline fairings. All of them have 4 side fairing attachment points. + • Replaced base model with one that looks more lightweight. It has the same size etc., so it won't break your existing ships. + • You can now toggle fuel cross feed for fairing base: mouse over and press G in editor or use right-click menu in flight. + • You can now disable auto-struts between side fairings: mouse over the base and press T. + • Fixed inline fairings not connecting with the top base sometimes. + • Fixed nested inline fairings not connecting to the proper base. + • Fairing outline (blue lines) is not displayed now for inline fairings if sides are attached to any of the two bases. + +======================================================= +ProceduralFairings v2.0 for KSP 0.21.1 (2013-07-24) +======================================================= + + • Inline truncated fairings are now created between two bases (one must be flipped). It won't work properly for off-center bases. If you want it off-center, tell me what for and how it should look. + • You can now change ejection force by pressing F when mouse is over the side fairing. + • Fixed rapid unplanned disassembly of side fairings when going out of time warp sometimes. + +======================================================= +ProceduralFairings v1.3 for KSP 0.20.2 (2013-07-14) +======================================================= + + • Fixed ejection direction bug - it shouldn't matter how you place fairings now. + +======================================================= +ProceduralFairings v1.2 for KSP 0.20.2 (2013-07-12) +======================================================= + + • Added invisible automatically placed struts between side fairings to mostly eliminate wobble. + • Replaced ejectionNoseDv with ejectionTorque so that all ejected fairings have the same motion, regardless of shape. + • Improved payload scanning for better fitting of mesh and box colliders. + • You can now adjust radius by moving the mouse over the base part while holding R (the default key, can be changed in part .cfg file). + • Fixed "recursion" bug which caused misplaced fairings to grow out of control. (It's also a foundation for future inline fairings). + • Using a (hopefully) better method to offset side fairing center of mass. + • Using proportionally smaller part of texture for 1/3 (and smaller) side fairings to reduce texture stretching. + • Renamed "capsule-shaped" fairings to "egg-shaped" to be more Kerbal. + +======================================================= +ProceduralFairings v1.1 for KSP 0.20.2 (2013-07-10) +======================================================= + + • Fix for future FAR compatibility (needs fixed FAR version to actually work). + • Less rotation on eject to reduce collisions with payload and lower stages. + • Conic side fairings added, original ones are made a bit more capsule-shaped. + +======================================================= +ProceduralFairings v1.0 for KSP 0.20.2 (2013-07-09) +======================================================= + + • Initial release. diff --git a/GameData/ProceduralFairings/common.cfg b/GameData/ProceduralFairings/common.cfg deleted file mode 100644 index e9527d3..0000000 --- a/GameData/ProceduralFairings/common.cfg +++ /dev/null @@ -1,158 +0,0 @@ - -PROCFAIRINGS_MINDIAMETER -{ - start = 1.00 - miniaturization = 0.400 - sandbox = 0.1 -} - -PROCFAIRINGS_MAXDIAMETER -{ - start = 1.50 - advAerodynamics = 4 - heavyAerodynamics = 12 - experimentalAerodynamics = 30 - sandbox = 50 -} - - -PROCROCKET_MINDIAMETER -{ - start = 1.00 - miniaturization = 0.400 - sandbox = 0.1 -} - -PROCROCKET_MAXDIAMETER -{ - start = 1.50 - advConstruction = 4 - metaMaterials = 12 - aerospaceTech = 30 - sandbox = 50 -} - - -//----------------------------------------------------------------------- -// Dummy parts to represent Procedural Fairings upgrades in the tech tree - -PART -{ - name = pf_tech_fairing04m - TechRequired = miniaturization - description = Allows fairings and plates to be made as small as 0.4m. - - MODEL - { - model = ProceduralFairings/baseModel - } - - title = Procedural Fairings Upgrade - module = Part - author = Starstrider42 (config), e-dog (model) - entryCost = 0 - cost = 0 - category = none - manufacturer = Keramzit Engineering -} - -PART -{ - name = pf_tech_fairing4m - TechRequired = advAerodynamics - description = Allows fairing bases up to 4m size. - - MODEL - { - model = ProceduralFairings/baseModel - } - - title = Procedural Fairings Upgrade - module = Part - author = Starstrider42 (config), e-dog (model) - entryCost = 0 - cost = 0 - category = none - manufacturer = Keramzit Engineering -} - -PART -{ - name = pf_tech_fairing12m - TechRequired = heavyAerodynamics - description = Allows fairing bases up to 12m size. - - MODEL - { - model = ProceduralFairings/baseModel - } - - title = Procedural Fairings Upgrade - module = Part - author = Starstrider42 (config), e-dog (model) - entryCost = 0 - cost = 0 - category = none - manufacturer = Keramzit Engineering -} - -PART -{ - name = pf_tech_fairing30m - TechRequired = experimentalAerodynamics - description = Allows fairing bases up to 30m size. - - MODEL - { - model = ProceduralFairings/baseModel - } - - title = Procedural Fairings Upgrade - module = Part - author = Starstrider42 (config), e-dog (model) - entryCost = 0 - cost = 0 - category = none - manufacturer = Keramzit Engineering -} - -PART -{ - name = pf_tech_rocket12m - TechRequired = metaMaterials - description = Allows thrust plates up to 12m size. - - MODEL - { - model = ProceduralFairings/thrustPlate - } - - title = Procedural Fairings Upgrade - module = Part - author = Starstrider42 (config), e-dog (model) - entryCost = 0 - cost = 0 - category = none - manufacturer = Keramzit Engineering -} - -PART -{ - name = pf_tech_rocket30m - TechRequired = aerospaceTech - description = Allows thrust plates up to 30m size. - - MODEL - { - model = ProceduralFairings/thrustPlate - } - - title = Procedural Fairings Upgrade - module = Part - author = Starstrider42 (config), e-dog (model) - entryCost = 0 - cost = 0 - category = none - manufacturer = Keramzit Engineering -} - diff --git a/GameData/ProceduralFairings/fairing1.dds b/GameData/ProceduralFairings/fairing1.dds deleted file mode 100644 index ab7f445..0000000 Binary files a/GameData/ProceduralFairings/fairing1.dds and /dev/null differ diff --git a/GameData/ProceduralFairings/fuselage1.cfg b/GameData/ProceduralFairings/fuselage1.cfg deleted file mode 100644 index 5e2e5eb..0000000 --- a/GameData/ProceduralFairings/fuselage1.cfg +++ /dev/null @@ -1,71 +0,0 @@ -PART -{ -name = KzProcFairingFuselage1 -module = Part -author = e-dog - -MODEL -{ - model = ProceduralFairings/sideModel - texture = fairing1, ProceduralFairings/fuselage1 -} - -//scale = 1 -rescaleFactor = 1 - -node_stack_connect = 0, 0.5, 0, 0, -1, 0, 0 - -TechRequired = advConstruction -cost = 100 -entryCost = 2300 -category = Payload -subcategory = 0 -title = Egg-Shaped Fuselage Fairing -manufacturer = Keramzit Engineering -description = Lacks a decoupler. Useful for space bases, flying saucers, hiding things, and other unconventional projects. - -attachRules = 1,0,0,1,1 - -tags = procedural fairings - -mass = 0 -dragModelType = default -maximum_drag = 0.2 -minimum_drag = 0.2 -angularDrag = 2 -crashTolerance = 8 -breakingForce = 200 -breakingTorque = 200 -maxTemp = 2600 -thermalMassModifier = 2.0 -skinMassPerArea = 4.0 -skinInternalConductionMult = 0.25 -emissiveConstant = 0.8 -fuelCrossFeed = True - - -MODULE -{ - name = ProceduralFairingSide - - density=0.1 - costPerTonne=3000 - specificBreakingForce =2000 - specificBreakingTorque=2000 - - noseHeightRatio=2 - baseConeShape=0.3, 0.2, 1, 0.5 - //noseConeShape=0.5, 0, 1, 0.5 - //baseConeShape=0.3, 0.3, 0.7, 0.7 - noseConeShape=0.5, 0, 1, 0.7 - baseConeSegments=7 - noseConeSegments=11 - - mappingScale=1024, 1024 - stripMapping=992, 1024 - horMapping=10, 490, 500, 980 - vertMapping=10, 170, 694, 1014 -} - -} - diff --git a/GameData/ProceduralFairings/fuselage1.dds b/GameData/ProceduralFairings/fuselage1.dds deleted file mode 100644 index 68e172d..0000000 Binary files a/GameData/ProceduralFairings/fuselage1.dds and /dev/null differ diff --git a/GameData/ProceduralFairings/fuselage2.cfg b/GameData/ProceduralFairings/fuselage2.cfg deleted file mode 100644 index f5c131e..0000000 --- a/GameData/ProceduralFairings/fuselage2.cfg +++ /dev/null @@ -1,69 +0,0 @@ -PART -{ -name = KzProcFairingFuselage2 -module = Part -author = e-dog - -MODEL -{ - model = ProceduralFairings/sideModel - texture = fairing1, ProceduralFairings/fuselage1 -} - -//scale = 1 -rescaleFactor = 1 - -node_stack_connect = 0, 0.5, 0, 0, -1, 0, 0 - -TechRequired = advConstruction -cost = 100 -entryCost = 2300 -category = Payload -subcategory = 0 -title = Conic Fuselage Fairing -manufacturer = Keramzit Engineering -description = Lacks a decoupler. Useful for space bases, flying saucers, hiding things, and other unconventional projects. - -attachRules = 1,0,0,1,1 - -tags = procedural fairings - -mass = 0 -dragModelType = default -maximum_drag = 0.2 -minimum_drag = 0.2 -angularDrag = 2 -crashTolerance = 8 -breakingForce = 200 -breakingTorque = 200 -maxTemp = 2600 -thermalMassModifier = 2.0 -skinMassPerArea = 4.0 -skinInternalConductionMult = 0.25 -emissiveConstant = 0.8 -fuelCrossFeed = True - - -MODULE -{ - name = ProceduralFairingSide - - density=0.1 - costPerTonne=3000 - specificBreakingForce =2000 - specificBreakingTorque=2000 - - noseHeightRatio=2 - baseConeShape=0.3, 0.3, 0.7, 0.7 - noseConeShape=0.1, 0, 0.7, 0.667 - baseConeSegments=3 - noseConeSegments=11 - - mappingScale=1024, 1024 - stripMapping=992, 1024 - horMapping=10, 490, 500, 980 - vertMapping=10, 170, 694, 1014 -} - -} - diff --git a/GameData/ProceduralFairings/license.txt b/GameData/ProceduralFairings/license.txt new file mode 100644 index 0000000..38003bd --- /dev/null +++ b/GameData/ProceduralFairings/license.txt @@ -0,0 +1,395 @@ +Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More_considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/GameData/ProceduralFairings/plate.cfg b/GameData/ProceduralFairings/plate.cfg deleted file mode 100644 index 21df705..0000000 --- a/GameData/ProceduralFairings/plate.cfg +++ /dev/null @@ -1,97 +0,0 @@ -PART -{ -name = KzThrustPlate -module = Part -author = e-dog - -MODEL -{ - model = ProceduralFairings/thrustPlate - scale = 1, 1, 1 -} - -scale = 1 -rescaleFactor = 1 - -// definition format is Position X, Position Y, Position Z, Up X, Up Y, Up Z -node_stack_top = 0.0, 0.1, 0.0, 0.0, 1.0, 0.0, 1 -node_stack_bottom = 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_bottom01 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_bottom02 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_bottom03 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_bottom04 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_bottom05 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_bottom06 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_bottom07 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_bottom08 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_bottom09 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_bottom10 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_bottom11 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_bottom12 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_bottom13 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_bottom14 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_bottom15 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 -node_stack_bottom16 = 0.5, 0.0, 0.0, 0.0, -1.0, 0.0, 1 - -//stackSymmetry = 3 - -TechRequired = advConstruction -cost = 100 -entryCost = 4200 -category = Structural -subcategory = 0 -title = Thrust Plate Multi-Adapter -manufacturer = Keramzit Engineering -description = When quad-adapter just isn't enough, Keramzit Engineering has you covered with its wonderful Multi-adapter! Designed for bulding engine clusters, it also found its uses in multiple payload attachment and space bars. -attachRules = 1,0,1,1,0 - -// --- standard part parameters --- -mass = 0 -dragModelType = default -maximum_drag = 0.2 -minimum_drag = 0.2 -angularDrag = 2 -crashTolerance = 12 -maxTemp = 2000 -explosionPotential = 0 -NoCrossFeedNodeKey = bottom - -breakingForce = 2000 -breakingTorque = 2000 - -stageOffset = 1 -childStageOffset = 1 - -MODULE -{ - name = KzNodeNumberTweaker - nodePrefix = bottom - maxNumber = 16 - numNodes = 4 - radius = 0.625 -} - -MODULE -{ - name = KzThrustPlateResizer - size = 1.25 - costPerTonne=1000 - specificMass=0.0070, 0.0260, 0.0100, 0 - specificBreakingForce = 1536 - specificBreakingTorque = 1536 - minSizeName = PROCROCKET_MINDIAMETER - maxSizeName = PROCROCKET_MAXDIAMETER -} - -MODULE -{ - name = ModuleToggleCrossfeed - crossfeedStatus = false - toggleEditor = true - toggleFlight = true - enableText = Crossfeed: Disabled - disableText = Crossfeed: Enabled -} - -} - diff --git a/GameData/ProceduralFairings/readme.txt b/GameData/ProceduralFairings/readme.txt new file mode 100644 index 0000000..c71ca31 --- /dev/null +++ b/GameData/ProceduralFairings/readme.txt @@ -0,0 +1,39 @@ +================================================== +Procedural Fairings +================================================== + +Procedural Fairings is a mod for Kerbal Space Program (KSP) that creates fairings that can automatically reshape for any attached payload. + +Original KSP forum thread: http://forum.kerbalspaceprogram.com/index.php?showtopic=36371 + +Installation: + + Extract the contents of the ProceduralFairings .zip file and then drop the ProceduralFairings folder into the GameData folder. + Note: if you are upgrading then make sure that any previous Procedural Fairings installation has been completely removed beforehand. + +Usage: + + 1. Put a fairing base under your payload (all Procedural Fairings parts are placed under the **Payload** tab) and enable the decoupler if necessary. + 2. Attached fairings automatically reshape for your payload. + 3. Enabling symmetry on fairings will encapsulate your payload + 4. Rearrange the stages to jettison fairings at the proper stage. + +Notes: + + • All part tweakables are accessible via the right-click part action windows (diameter, length, shape, staging, textures etc). + • Flipping another fairing base over and adding it above the payload will cause any side fairings to stick to it instead of creating a nose cone, thereby creating inline fairings between two bases. + • Procedural Fairings includes low-profile base rings intended for inline fairings. Separate interstage bases are also included. + • Procedural Fairings are fully integrated with the career mode. The minimum and maximum part sizes are limited by the available tech (see **PF_Settings.cfg** for more details). + +Credits: + + • e-dog for creating the Procedural Fairings mod: https://github.com/e-dog + • rsparkyc for maintaining it the the absence of e-dog: https://github.com/rsparkyc + +License: + +Procedural Fairings is licensed under a Creative Commons Attribution 4.0 (CC-BY 4.0) license. + +You should have received a copy of the license along with this work. If not, visit the official Creative Commons web page: https://creativecommons.org/licenses/by/4.0/legalcode + +Note that the above license does not cover mod packs. Redistributing this work via a mod pack is not allowed. diff --git a/GameData/ProceduralFairings/side1.cfg b/GameData/ProceduralFairings/side1.cfg deleted file mode 100644 index a37faa7..0000000 --- a/GameData/ProceduralFairings/side1.cfg +++ /dev/null @@ -1,79 +0,0 @@ -PART -{ -name = KzProcFairingSide1 -module = Part -author = e-dog - -MODEL -{ - model = ProceduralFairings/sideModel -} - -//scale = 1 -rescaleFactor = 1 - -node_stack_connect = 0, 0.5, 0, 0, -1, 0, 0 - -TechRequired = aviation -cost = 100 -entryCost = 4600 -category = Payload -subcategory = 0 -title = Egg-Shaped Fairing -manufacturer = Keramzit Engineering -description = Made from the finest materials found in the fields around the Space Center. Egg-shaped version. - -attachRules = 1,0,0,1,1 - -tags = procedural fairings - -mass = 0 -dragModelType = default -maximum_drag = 0.1 -minimum_drag = 0.1 -angularDrag = 2 -crashTolerance = 8 -breakingForce = 200 -breakingTorque = 200 -maxTemp = 2600 -thermalMassModifier = 2.0 -skinMassPerArea = 4.0 -skinInternalConductionMult = 0.25 -emissiveConstant = 0.8 -fuelCrossFeed = False - -stagingIcon = DECOUPLER_HOR - -stageOffset = 1 -childStageOffset = 1 - -MODULE -{ - name = ProceduralFairingSide - - density=0.1 - costPerTonne=5000 - specificBreakingForce =2000 - specificBreakingTorque=2000 - - noseHeightRatio=2 - baseConeShape=0.3, 0.2, 1, 0.5 - //noseConeShape=0.5, 0, 1, 0.5 - //baseConeShape=0.3, 0.3, 0.7, 0.7 - noseConeShape=0.5, 0, 1, 0.7 - baseConeSegments=7 - noseConeSegments=11 - - mappingScale=1024, 1024 - stripMapping=992, 1024 - horMapping=10, 490, 500, 980 - vertMapping=10, 170, 694, 1014 -} - -MODULE -{ - name = ProceduralFairingDecoupler -} - -} - diff --git a/GameData/ProceduralFairings/side2.cfg b/GameData/ProceduralFairings/side2.cfg deleted file mode 100644 index 3544396..0000000 --- a/GameData/ProceduralFairings/side2.cfg +++ /dev/null @@ -1,77 +0,0 @@ -PART -{ -name = KzProcFairingSide2 -module = Part -author = e-dog - -MODEL -{ - model = ProceduralFairings/sideModel -} - -//scale = 1 -rescaleFactor = 1 - -node_stack_connect = 0, 0.5, 0, 0, -1, 0, 0 - -TechRequired = aviation -cost = 100 -entryCost = 4600 -category = Payload -subcategory = 0 -title = Conic Fairing -manufacturer = Keramzit Engineering -description = Made from the finest materials found in the fields around the Space Center. Conic version. - -attachRules = 1,0,0,1,1 - -tags = procedural fairings - -mass = 0 -dragModelType = default -maximum_drag = 0.1 -minimum_drag = 0.1 -angularDrag = 2 -crashTolerance = 8 -breakingForce = 200 -breakingTorque = 200 -maxTemp = 2600 -thermalMassModifier = 2.0 -skinMassPerArea = 4.0 -skinInternalConductionMult = 0.25 -emissiveConstant = 0.8 -fuelCrossFeed = False - -stagingIcon = DECOUPLER_HOR - -stageOffset = 1 -childStageOffset = 1 - -MODULE -{ - name = ProceduralFairingSide - - density=0.1 - costPerTonne=5000 - specificBreakingForce =2000 - specificBreakingTorque=2000 - - noseHeightRatio=2 - baseConeShape=0.3, 0.3, 0.7, 0.7 - noseConeShape=0.1, 0, 0.7, 0.667 - baseConeSegments=3 - noseConeSegments=11 - - mappingScale=1024, 1024 - stripMapping=992, 1024 - horMapping=10, 490, 500, 980 - vertMapping=10, 170, 694, 1014 -} - -MODULE -{ - name = ProceduralFairingDecoupler -} - -} - diff --git a/GameData/ProceduralFairings/sideModel.mu b/GameData/ProceduralFairings/sideModel.mu deleted file mode 100644 index 5cd013d..0000000 Binary files a/GameData/ProceduralFairings/sideModel.mu and /dev/null differ diff --git a/GameData/ProceduralFairings/thrustPlate.mu b/GameData/ProceduralFairings/thrustPlate.mu deleted file mode 100644 index 78af265..0000000 Binary files a/GameData/ProceduralFairings/thrustPlate.mu and /dev/null differ diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..38003bd --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,395 @@ +Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More_considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/Misc/addAlpha.py b/Misc/addAlpha.py deleted file mode 100644 index ed8526d..0000000 --- a/Misc/addAlpha.py +++ /dev/null @@ -1,16 +0,0 @@ -import os, fnmatch, shutil -import Image, struct - - -for root, dirnames, filenames in os.walk('.'): - for fn in fnmatch.filter(filenames, '*-rgb.png'): - filename=os.path.join(root, fn) - afn=os.path.splitext(filename)[0][:-4]+'-alpha.png' - if not os.path.exists(afn): continue - print 'processing '+filename+' + '+afn - - im=Image.open(filename) - aim=Image.open(afn) - im.putalpha(aim.convert('L')) - im.save(os.path.splitext(filename)[0][:-4]+'.png') - diff --git a/Misc/exportTex.py b/Misc/exportTex.py deleted file mode 100644 index 2f18780..0000000 --- a/Misc/exportTex.py +++ /dev/null @@ -1,23 +0,0 @@ -import os -import Image -from psd_tools import PSDImage - - -def export_tex(fn, downscale=2, ext='.png'): - print 'processing', fn - psd=PSDImage.load(fn+".psd") - im=psd.as_PIL() - wd,ht=im.size - if downscale>1: im=im.resize((wd/downscale, ht/downscale), Image.ANTIALIAS) - im.save(os.path.join(target_path, fn+ext)) - - -target_path='../unity/Assets/ProceduralFairings' -export_tex('baseTex') -export_tex('baseRingTex') -export_tex('thrustPlate1') -export_tex('thrustPlate1bump', 1) - -target_path="C:/games/KSPtest/GameData/ProceduralFairings/" -export_tex('fuselage1', 1, '.tga') - diff --git a/Misc/history.txt b/Misc/history.txt deleted file mode 100644 index b31f879..0000000 --- a/Misc/history.txt +++ /dev/null @@ -1,101 +0,0 @@ -3.02 -[*]Updated KSPAPIExtensions, should work with Procedural Parts now. -[*]A bit less restrictive tech, allowing sizes a bit larger and smaller than stock ones. -[*]Trying to avoid moving attached parts after loading design or saved game. -[*]Fixed wrong size of newly added side nodes. - -3.01 -[*]Updated KSPAPIExtensions. -[*]Added size step parameters for RSS. - -3.00 -[*]Moved files up to GameData folder (no Keramzit folder anymore). Make sure to delete old mod before installing (which is a good practice anyway). -[*]Added new resizable fairing bases with configurable number of side nodes. -[*]Old parts (bases and adapter) are deprecated. Launched vessels should be fine, but you might have trouble loading old designs in VAB/SPH in career mode. -[*]Added new part: Thrust Plate Multi-Adapter. -[*]Using KSPAPIExtensions for better tweakables. -[*]Removed old keyboard-based tweaks - use new tweakables. -[*]Tweaking outer diameter (with fairings), instead of inner radius. -[*]Added fairing decoupler torque tweakable. -[*]Side nodes (for attaching fairings) get larger with the base size to make them more sturdy in KSP 0.23.5+ -[*]Tech limits are not checked in sandbox mode anymore. -[*]Extra payload radius is now zero by default. -[*]Fixed interstage adapter decoupling with fuselage fairings. - -2.4.4 -[*]Added tweakables. -[*]Rearranged tech tree, added 3.75m and 5m parts. -[*]Interstage adapter is available earlier now, but its radius is limited by aerodynamics tech. -[*]Launch clamps are ignored in payload scanning now. -[*]Payload scanning doesn't follow surface attachment to the parent part anymore. -[*]Improved interstage fairing shape when its top is inside payload. -[*]Added base cone angle limit to make fairings look better. -[*]Part descriptions and readme text copy edited by Duxwing. - -2.4.3 -[*]Improved payload scanning for interstage adapter. -[*]Recompiled for KSP 0.23. - -2.4.2 -[*]Zero-radius payload is now used when no payload attached, so fairings will always reshape. -[*]Added parts to the tech tree. -[*]Moved fuselage shrouds to Structural tab. -[*]Changing adapter attachment node size with radius. - -2.4.1 -[*]Disabled fuel crossfeed on the interstage adapter - enable at your own risk, it confuses Engineer Redux to death. -[*]Added stock decoupler module to the interstage adapter topmost node to help with delta-v calculations. -[*]Improved fairing shape for interstage adapter when fairing top is inside payload. - -2.4 -[*]Added procedural interstage fairing adapter with adjustable radii and height which decouples from the top part when fairings are ejected. -[*]Added conic fuselage. -[*]Fixed another inline fairing shape bug. - -2.3 -[*]Changed fuselage texture to distinguish it from fairings. -[*]You can now lock fairing shape: mouse over the side fairing/fuselage and press L. -[*]Reduced side nodes size for smaller base rings and 0.625m fairing base (for easier placement). -[*]Fixed inline fairings making a top cone when there should be just a cylinder. - -2.2 -[*]Added experimental egg-shaped fuselage (a side fairing without decoupler). -[*]Moved fairing decoupler code to separate PartModule. -[*]Auto-struts are now created between the top inline base and side fairings as well. NOTE: if you payload is wobbly, the sides might still wobble. -[*]Fixed bug with misplaced fairings on new ring bases. - -2.1 -[*]Added low-profile fairing bases (base rings), intended for inline fairings. All of them have 4 side fairing attachment points. -[*]Replaced base model with one that looks more lightweight. It has the same size etc., so it won't break your existing ships. -[*]You can now toggle fuel crossfeed for fairing base: mouse over and press G in editor or use right-click menu in flight. -[*]You can now disable auto-struts between side fairings: mouse over the base and press T. -[*]Fixed inline fairings not connecting with the top base sometimes. -[*]Fixed nested inline fairings not connecting to the proper base. -[*]Fairing outline (blue lines) is not displayed now for inline fairings if sides are attached to any of the two bases. - -2.0 -[*]Inline truncated fairings are now created between two bases (one must be flipped). It won't work properly for off-center bases. If you want it off-center, tell me what for and how it should look. -[*]You can now change ejection force by pressing F when mouse is over the side fairing. -[*]Fixed rapid unplanned disassembly of side fairings when going out of time warp sometimes. - -1.3 -[*]Fixed ejection direction bug - it shouldn't matter how you place fairings now. - -1.2 -[*]Added invisible automatically placed struts between side fairings to mostly eliminate wobble. -[*]Replaced ejectionNoseDv with ejectionTorque so that all ejected fairings have the same motion, regardless of shape. -[*]Improved payload scanning for better fitting of mesh and box colliders. -[*]You can now adjust radius by moving the mouse over the base part while holding R (the default key, can be changed in part .cfg). -[*]Fixed "recursion" bug which caused misplaced fairings to grow out of control. (It's also a foundation for future inline fairings). -[*]Using a (hopefully) better method to offset side fairing center of mass. -[*]Using proportionally smaller part of texture for 1/3 (and smaller) side fairings to reduce texture stretching. -[*]Renamed "capsule-shaped" fairings to "egg-shaped" to be more Kerbal. - -1.1 -[*]Fix for future FAR compatibility (needs fixed FAR version to actually work). -[*]Less rotation on eject to reduce collisions with payload and lower stages. -[*]Conic side fairings added, original ones are made a bit more capsule-shaped. - -1.0 -[*]Initial release. - diff --git a/Misc/makezip.bat b/Misc/makezip.bat deleted file mode 100644 index 3f66bcd..0000000 --- a/Misc/makezip.bat +++ /dev/null @@ -1,7 +0,0 @@ -@echo off -set name=C:\games\KSPtest\ProcFairings_3.20.zip -del %name% -7z a %name% readme.txt -cd .. -7z a %name% GameData - diff --git a/Misc/readme.txt b/Misc/readme.txt deleted file mode 100644 index 3dc9ca0..0000000 --- a/Misc/readme.txt +++ /dev/null @@ -1,239 +0,0 @@ ---- Forum thread --- -http://forum.kerbalspaceprogram.com/showthread.php/39512 - ---- Download --- -https://github.com/e-dog/ProceduralFairings/releases - ---- License --- -http://creativecommons.org/licenses/by/3.0/ - - ---- Installation --- -Remove old version of the mod. -Copy "ProceduralFairings" folder into "Gamedata" in your KSP folder. - -If you don't need old parts (pre 3.00), remove "ProceduralFairings/deprecated" folder. -Do that if you never installed this mod before or if you're going to start a new game. Otherwise you'll get confusing obsolete parts which show in the tech tree, but not in the VAB. - --- Installation Notes -- - --If you downloaded KSP from Squad's website, then the KSP folder is where you unzipped it when you first downloaded the game --If you downloaded KSP from Steam, then right-clicking KSP in your Steam library, select "properties," switching to the "local files" tab, and pressing "browse local files" opens the game folder. --The "Source" folder is unnecessary unless you want to modify and compile plug-in code. --In the KSP main folder a "GameData" folder contains all add-ons; without any add-ons, it contains only the "Squad" sub-folder - the stock "add-on" from the developers of the game. Unzip the Keramzit folder into your Gamedata folder. - ---- Use --- - --- Tutorial: -- -http://imgur.com/a/xCF0q - --- Steps -- -1 Put a fairing base under your payload (all Procedural Fairings parts are in the Aerodynamics tab) and a decoupler if necessary. -2 Right-click the fairing base to change its size and other parameters. -3 Attached fairings automatically reshape for your payload. -4 Enabling symmetry on fairings will encapsulate your payload -5 Rearrange stages to jettison fairings at the proper stage. - --- Inline Fairings -- --Flipping another fairing base over and adding it above the payload will cause side fairings to stick to it instead of creating a nose cone, thereby creating inline fairings between two bases. --Procedural Fairings includes low-profile base rings intended for inline fairings. - --- Controls -- -Right-click parts and use tweakables. - --- Career mode -- -Maximum (and minimum) part size is limited by tech. See GameData/ProceduralFairings/common.cfg for details. - ---- Version history --- - - -3.20 -- Added the following changes by KortexM: -- Ready for KSP 1.2 (recompiled, small changes to configs) -- Added Interstage Nodes (no trusses) to Fairings and Interstage Fairing, two connections possible on each node (up & down) -- A few code cleanups (foreach mostly) -- Fixed Fuel Crossfeed (be aware that flow to/from interstage nodes is affected too!) -- Fixed ghost nodes appearing when adding a new fairing base in the VAB/SPH -- Fixed blue ghost lines (invalid fairing outline) when having multiple fairing bases in VAB/SPH -- Fixed interstage nodes positions for Interstage Adapter when resized -- Some UI fixes -- Code cleanups (de-Linqed etc.) -- All other bugs/features untouched (hopefully..) - -3.17 --Rebuilt for KSP 1.1.2. --Fixed thermal issues with FAR (patch by NathanKell). --Fixed procedural mass issues (patch by NathanKell). --Fixed auto-strut joint issue (connecting to the same rigid body). --Improved payload auto-strut performance (strut heaviest part only). - -3.16 --Updated for KSP 1.1.0. - -3.15 --Updated for KSP 1.0.4. --Merged pull request for Procedural Parts bug fix. --Adjusted thermal parameters for KSP 1.0.4 (hopefully). - -3.14 --Updated for the new FAR. --Reduced fairing shape update rate in the editor to 2 times per second. --Adjusted default fairing decoupler value to avoid "vessel changed" messages spammed by bugged KSP sliders. - -3.13 --Updated for KSP 1.0.2. --Rewrote automatic payload struts, strutting all shielded parts now. --Fixed bug when it was impossible to revert sometimes. --Fixed slowdown in the editor when tweaking fairing sides. --Fixed thrust plate mass parameters. - -3.12 --Updated for KSP 1.0. --Procedural fairings now use new stock airstream shielding and drag cube rendering. --Inline fairings now check if the top is closed by a single big part of the same vessel. Make sure that's the case or the shielding won't work. --Changed and rearranged tech limits for the new tech tree. --Converted textures to DDS. --Fixed manual shape UI issues. --Number of shielded parts is now displayed in the right-click menu for the fairing base. It might be inaccurate in the editor. --Removed old deprecated parts (non-resizable fairing bases etc). - -3.11 --Updated for KSP 0.90. --Added optional manual fairing shape controls. --Fixed tech restrictions checking in science mode (patch by Zwa333). - -3.10 --Updated KAE DLL for KSP 0.25. --Payload auto-struts by marce155. - -3.09 --Updated KAE DLL. - -3.08 --Updated KAE DLL for KSP 0.24.2. - -3.07 --Added procedural costs for PF parts, KSP 0.24.1 is required. --Added workaround for Win64 decoupler bug. --Made "removed" node markers much less visible (they are still somewhere 10km from the VAB). --Updated KAE DLL. - -3.06 --Updated for KSP 0.24. - -3.05 --Fixed collider bug introduced in 3.04. - -3.04 --Added fake parts to make tech upgrades visible in the tech tree. --Restored TechRequired for old parts to avoid issues with loading old designs in career mode. --Fixed bug that allowed to cheat tech limits in career mode. --Reduced default fairing ejection torque. - -3.03 --Added "sandbox" tech to specify minimum and maximum sizes in sandbox mode (see common.cfg). --Changed mass formula for all parts except side fairings. Generally, larger sizes are significantly lighter now. --Part mass is now displayed when you right-click the part in VAB. --Rebuilding side fairing mesh only when really needed (faster in VAB, especially with FAR). - -3.02 --Updated KSPAPIExtensions, should work with Procedural Parts now. --A bit less restrictive tech, allowing sizes a bit larger and smaller than stock ones. --Trying to avoid moving attached parts after loading design or saved game. --Fixed wrong size of newly added side nodes. - -3.01 --Updated KSPAPIExtensions. --Added size step parameters for RSS. - -3.00 --Moved files up to GameData folder (no Keramzit folder anymore). Make sure to delete old mod before installing (which is a good practice anyway). --Added new resizable fairing bases with configurable number of side nodes. --Old parts (bases and adapter) are deprecated. Launched vessels should be fine, but you might have trouble loading old designs in VAB/SPH in career mode. --Added new part: Thrust Plate Multi-Adapter. --Using KSPAPIExtensions by Swamp-Ig for better tweakables. --Removed old keyboard-based tweaks - use new tweakables. --Tweaking outer diameter (with fairings), instead of inner radius. --Added fairing decoupler torque tweakable. --Side nodes (for attaching fairings) get larger with the base size to make them more sturdy in KSP 0.23.5+ --Tech limits are not checked in sandbox mode anymore. --Extra payload radius is now zero by default. --Fixed interstage adapter decoupling with fuselage fairings. - -2.4.4 --Added tweakables. --Rearranged tech tree, added 3.75m and 5m parts. --Interstage adapter is available earlier now, but its radius is limited by aerodynamics tech. --Launch clamps are ignored in payload scanning now. --Payload scanning doesn't follow surface attachment to the parent part anymore. --Improved interstage fairing shape when its top is inside payload. --Added base cone angle limit to make fairings look better. --Part descriptions and readme text copy edited by Duxwing. - -2.4.3 --Improved payload scanning for interstage adapter. --Recompiled for KSP 0.23. - -2.4.2 --Zero-radius payload is now used when no payload attached; fairings therefore will always reshape. --Added parts to the tech tree. --Moved fuselage shrouds to Structural tab. --Changing adapter attachment node size with radius. - -2.4.1 --Disabled fuel crossfeed on the interstage adapter because enabling it confuses Engineer Redux. --So added stock decoupler module to the interstage adapter's topmost node as to aid delta-v calculations. --Improved fairing shape for interstage adapter when fairing top is inside payload. - -2.4 --Added procedural interstage fairing adapter with adjustable radii and height which decouples from the top part when fairings are ejected. --Added conic fuselage. --Fixed another inline fairing shape bug. - -2.3 --Changed fuselage texture to distinguish it from fairings. --Fairing shape can be locked: mouse over the side fairing/fuselage and press L. --Reduced side nodes size for smaller base rings and 0.625m fairing base (for easier placement). --Fixed inline fairings making a top cone when there should be just a cylinder. - -2.2 --Added experimental egg-shaped fuselage (a side fairing without a decoupler). --Moved fairing decoupler code to separate PartModule. --Auto-struts are now also created between the top inline base and side fairings. If your payload is wobbly, then the sides might wobble. --Fixed bug with misplaced fairings on new ring bases. - -2.1 --Added low-profile fairing bases (base rings), intended for inline fairings. All of them have 4 side fairing attachment points. --Replaced base model with one that looks more lightweight. It has the same size etc., so it won't break your existing ships. --Fuel crossfeed for a fairing base can be toggled by mousing over it and pressing G in the editor or using the right-click menu in flight. --Auto-struts between side fairings can now be disabled by mousing over the base and pressing T. --Fixed inline fairings' not connecting with the top base sometimes. --Fixed nested inline fairings' not connecting to the proper base. --Fairing outline (blue lines) is not displayed now for inline fairings if sides are attached to any two bases. - -2.0 --Inline truncated fairings are now created between two bases (one must be flipped). It won't work properly for off-center bases. If you want it off-center, tell me what for and how it should look. --You can now change ejection force by pressing F when mouse is over the side fairing. --Fixed rapid unplanned disassembly of side fairings when going out of time warp sometimes. - -1.3 --Fixed ejection direction bug - it shouldn't matter how you place fairings now. - -1.2 --Added invisible automatically placed struts between side fairings to mostly eliminate wobble. --Replaced ejectionNoseDv with ejectionTorque so that all ejected fairings have the same motion, regardless of shape. --Improved payload scanning for better fitting of mesh and box colliders. --You can now adjust radius by moving the mouse over the base part while holding R (the default key, can be changed in part .cfg). --Fixed "recursion" bug which caused misplaced fairings to grow out of control. (It's also a foundation for future inline fairings). --Using a (hopefully) better method to offset side fairing center of mass. --Using proportionally smaller part of texture for 1/3 (and smaller) side fairings to reduce texture stretching. --Renamed "capsule-shaped" fairings to "egg-shaped" to be more Kerbal. - -1.1 --Fix for future FAR compatibility (requires fixed FAR version) --So lessened rotation on eject as to reduce collisions with payload and lower stages. --Conic side fairings added. Original ones are made more capsule-shaped. - -1.0 --Initial release. - diff --git a/Misc/texTemplate.py b/Misc/texTemplate.py deleted file mode 100644 index 7668b96..0000000 --- a/Misc/texTemplate.py +++ /dev/null @@ -1,25 +0,0 @@ -import Image, ImageDraw - -im=Image.new('RGB', (1024, 1024), '#800') - -draw=ImageDraw.Draw(im) - -# strip -draw.rectangle((1024-32, 0, 1024, 1024), fill='#ca2') - -# outer -draw.polygon((10, 10+320, 10+480, 10+320, 10+480/2, 10), fill='#88c') -draw.rectangle((10, 1024-10-160, 10+480, 1024-10), fill='#8cc') -draw.rectangle((10, 10+320, 10+480, 1024-10-160), fill='#ccc') - -# inner -draw.polygon((20+480, 10+320, 20+480*2, 10+320, 20+480*3/2, 10), fill='#448') -# draw.rectangle((20+480, 10, 20+480*2, 10+320), fill='#448') -draw.rectangle((20+480, 1024-10-160, 20+480*2, 1024-10), fill='#488') -draw.rectangle((20+480, 10+320, 20+480*2, 1024-10-160), fill='#888') - -del draw - -# im.show() -im.save('template.png') - diff --git a/Misc/toDDS.py b/Misc/toDDS.py deleted file mode 100644 index 5194be7..0000000 --- a/Misc/toDDS.py +++ /dev/null @@ -1,15 +0,0 @@ -from PIL import Image, ImageOps -import os, glob - -for fn in glob.glob("../GameData/ProceduralFairings/*.tga"): - if "_NRM" in fn: - im=Image.open(fn) - r, g, b = im.split() - # g=ImageOps.invert(g) - im=Image.merge('RGBA', (g, g, g, r)) - im.save("tmp.png") - os.system("crunch -yflip -dxt5 -file tmp.png -out "+fn[:-4]+".dds") - os.remove("tmp.png") - else: - os.system("crunch -yflip -dxt5 -file "+fn+" -out "+fn[:-4]+".dds") - diff --git a/README.md b/README.md index 8bbdb5f..a832fc7 100644 --- a/README.md +++ b/README.md @@ -1,58 +1,48 @@ # Procedural Fairings -Procedural Fairings mod for Kerbal Space Program. +![][PF:shield-version] +![][PF:shield-license] -[Forum thread](http://forum.kerbalspaceprogram.com/index.php?/topic/36371-110-procedural-fairings-316-april-20/) +**Procedural Fairings** is a mod for **Kerbal Space Program (KSP)** that creates fairings that can automatically reshape for any attached payload. -[Download](https://github.com/e-dog/ProceduralFairings/releases) +**[Original KSP forum thread][PF:original-forum-link]** -[License](http://creativecommons.org/licenses/by/3.0/) +## Installation +Extract the contents of the **ProceduralFairings** .zip file and then drop the ProceduralFairings folder into the GameData folder. **Note:** if you are upgrading then make sure that any previous Procedural Fairings installation has been completely removed beforehand. -## Installation -Remove old version of the mod. +### Usage -Copy ProceduralFairings into "Gamedata" in your KSP folder. +1. Put a fairing base under your payload (all Procedural Fairings parts are placed under the **Payload** tab) and enable the decoupler if necessary. +2. Attached fairings automatically reshape for your payload. +3. Enabling symmetry on fairings will encapsulate your payload +4. Rearrange the stages to jettison fairings at the proper stage. -## Installation Notes +### Notes -If you downloaded KSP from Squad's website, then the KSP folder is where you unzipped it when you first downloaded the game +* All part tweakables are accessible via the right-click part action windows (diameter, length, shape, staging, textures etc). +* Flipping another fairing base over and adding it above the payload will cause any side fairings to stick to it instead of creating a nose cone, thereby creating inline fairings between two bases. +* Procedural Fairings includes low-profile base rings intended for inline fairings. Separate interstage bases are also included. +* Procedural Fairings are fully integrated with the career mode. The minimum and maximum part sizes are limited by the available tech (see **PF_Settings.cfg** for more details). -If you downloaded KSP from Steam, then right-clicking KSP in your Steam library, select "properties," switching to the "local files" tab, and pressing "browse local files" opens the game folder. +### Credits -In the KSP main folder a "GameData" folder contains all add-ons; without any add-ons, it contains only the "Squad" and "NASAMission" sub-folders - the stock "add-ons" from the developers of the game. Unzip the ProceduralFairings folder into your Gamedata folder. +* **[e-dog][PF:contributor-edog-link]** for creating the Procedural Fairings mod. +* **[rsparkyc][PF:contributor-rsparkyc-link]** for maintaining it the the absence of **e-dog**. -## Tutorial -[Pictures](http://imgur.com/a/xCF0q) +## License -### Steps -1. Put a fairing base under your payload (all Procedural Fairings parts are in the Aerodynamics tab) and a decoupler if necessary. -2. Attached fairings automatically reshape for your payload. -3. Enabling symmetry on fairings will encapsulate your payload -4. Rearrange stages to jettison fairings at the proper stage. - -### Inline Fairings -- Flipping another fairing base over and adding it above the payload will cause side fairings to stick to it instead of creating a nose cone, thereby creating inline fairings between two bases. -- Procedural Fairings includes low-profile base rings intended for inline fairings. - -### Controls -Right-click parts and use tweakables. - -## Career mode -Maximum (and minimum) part size is limited by tech. See GameData/ProceduralFairings/common.cfg for details. - -## Version history -**3.00** -- First release on GitHub. -- Moved files up to GameData folder (no Keramzit folder anymore). Make sure to delete old mod before installing (which is a good practice anyway). -- Added new resizable fairing bases with configurable number of side nodes. -- Old parts (bases and adapter) are deprecated. Launched vessels should be fine, but you might have trouble loading old designs in VAB/SPH in career mode. -- Added new part: Thrust Plate Multi-Adapter. -- Using KSPAPIExtensions by Swamp-Ig for better tweakables. -- Removed old keyboard-based tweaks - use new tweakables. -- Tweaking outer diameter (with fairings), instead of inner radius. -- Added fairing decoupler torque tweakable. -- Side nodes (for attaching fairings) get larger with the base size to make them more sturdy in KSP 0.23.5+ -- Tech limits are not checked in sandbox mode anymore. -- Extra payload radius is now zero by default. -- Fixed interstage adapter decoupling with fuselage fairings. +Procedural Fairings is licensed under a **Creative Commons Attribution 4.0 (CC-BY 4.0)** license. + +You should have received a copy of the license along with this work. If not, visit the **[official Creative Commons web page][PF:cc-license-link]**. + +**Note that the above license does not cover mod packs. Redistributing this work via a mod pack is not allowed.** + +*** + +[PF:cc-license-link]: https://creativecommons.org/licenses/by/4.0/legalcode +[PF:contributor-edog-link]: https://github.com/e-dog +[PF:contributor-rsparkyc-link]: https://github.com/rsparkyc +[PF:original-forum-link]: http://forum.kerbalspaceprogram.com/index.php?showtopic=36371 +[PF:shield-license]: https://img.shields.io/badge/License-CC--BY%204.0-green.svg +[PF:shield-version]: https://img.shields.io/badge/KSP%20Version-1.4.3.2152-red.svg diff --git a/Source/FairingBase.cs b/Source/FairingBase.cs deleted file mode 100644 index 0b23105..0000000 --- a/Source/FairingBase.cs +++ /dev/null @@ -1,868 +0,0 @@ -// Procedural Fairings plug-in by Alexey Volynskov -// Licensed under CC BY 3.0 terms: http://creativecommons.org/licenses/by/3.0/ -using System; -using System.Collections.Generic; -using System.Text; -using UnityEngine; - - -namespace Keramzit -{ - - - //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ// - - - public class ProceduralFairingBase : PartModule - { - [KSPField] public float outlineWidth = 0.05f; - [KSPField] public int outlineSlices = 12; - [KSPField] public Vector4 outlineColor = new Vector4(0, 0, 0.2f, 1); - [KSPField] public float verticalStep = 0.1f; - [KSPField] public float baseSize = 1.25f; - - [KSPField(isPersistant = true, guiActiveEditor = true, guiName = "Extra radius")] - [UI_FloatRange(minValue = -1, maxValue = 2, stepIncrement = 0.01f)] - public float extraRadius = 0.0f; - - [KSPField] public int circleSegments = 24; - - [KSPField] public float sideThickness = 0.05f; - - //[KSPField(isPersistant=true, guiActive=true, guiActiveEditor=true, guiName="Fuel crossfeed")] - //public bool fuelCrossFeed=false; - - - [KSPField(isPersistant = true, guiActiveEditor = true, guiName = "Fairing Auto-struts")] - [UI_Toggle(disabledText = "Off", enabledText = "On")] - public bool autoStrutSides = true; - - - [KSPField(isPersistant = true, guiActiveEditor = true, guiName = "Fairing Auto-shape")] - [UI_Toggle(disabledText = "Off", enabledText = "On")] - public bool autoShape = true; - - [KSPField(isPersistant = true, guiActiveEditor = true, guiName = "Max. size", guiFormat = "S4", guiUnits = "m")] - [UI_FloatEdit(sigFigs = 3, unit = "m", minValue = 0.1f, maxValue = 5, incrementLarge = 1.25f, incrementSmall = 0.125f, incrementSlide = 0.001f)] - public float manualMaxSize = 0.625f; - - [KSPField(isPersistant = true, guiActiveEditor = true, guiName = "Cyl. start", guiFormat = "S4", guiUnits = "m")] - [UI_FloatEdit(sigFigs = 3, unit = "m", minValue = 0, maxValue = 50, incrementLarge = 1.0f, incrementSmall = 0.1f, incrementSlide = 0.001f)] - public float manualCylStart = 0; - - [KSPField(isPersistant = true, guiActiveEditor = true, guiName = "Cyl. end", guiFormat = "S4", guiUnits = "m")] - [UI_FloatEdit(sigFigs = 3, unit = "m", minValue = 0, maxValue = 50, incrementLarge = 1.0f, incrementSmall = 0.1f, incrementSlide = 0.001f)] - public float manualCylEnd = 1; - - private bool limitsSet = false; - - [KSPField] public float diameterStepLarge = 1.25f; - [KSPField] public float diameterStepSmall = 0.125f; - - [KSPField] public float heightStepLarge = 1.0f; - [KSPField] public float heightStepSmall = 0.1f; - - public float updateDelay = 0; - public bool needShapeUpdate = true; - Part topBasePart = null; - - private float lastManualMaxSize, lastManualCylStart, lastManualCylEnd; - - - LineRenderer line = null; - - List outline = new List(); - - - List joints = new List(); - - - //[KSPEvent(name = "ToggleCrossFeed", active=true, guiActive=true, guiActiveEditor=true, - // guiActiveUnfocused=false, guiName="Toggle crossfeed")] - //public void ToggleCrossFeed() - //{ - // part.fuelCrossFeed = fuelCrossFeed = !fuelCrossFeed; - //} - - - - public override string GetInfo() - { - string s = "Attach side fairings and they'll be shaped for your attached payload.\n" + - "Remember to add a decoupler if you need one."; - - return s; - } - - - public override void OnStart(StartState state) - { - limitsSet = false; - - if (!HighLogic.LoadedSceneIsEditor && !HighLogic.LoadedSceneIsFlight) return; - - PFUtils.hideDragStuff(part); - - GameEvents.onEditorShipModified.Add(new EventData.OnEvent(onEditorVesselModified)); - - if (HighLogic.LoadedSceneIsEditor) { - // line=makeLineRenderer("payload outline", Color.red, outlineWidth); //== - if (line) line.transform.Rotate(0, 90, 0); - - - DestroyAllLineRenderers(); - destroyOutline(); /* redundant? */ - - for (int i = 0; i < outlineSlices; ++i) { - var r = makeLineRenderer("fairing outline", outlineColor, outlineWidth); - outline.Add(r); - r.transform.Rotate(0, i * 360f / outlineSlices, 0); - } - - ShowHideInterstageNodes(); - - updateDelay = 0.1f; - needShapeUpdate = true; - } - else { - topBasePart = null; - var adapter = part.GetComponent(); - if (adapter) - topBasePart = adapter.getTopPart(); - else { - var scan = scanPayload(); - if (scan.targets.Count > 0) topBasePart = scan.targets[0]; - } - } - - - SetUIChangedCallBacks(); - - // part.fuelCrossFeed=fuelCrossFeed; - - } - - private void SetUIChangedCallBacks() - { - ((UI_FloatEdit)Fields["manualMaxSize"].uiControlEditor).onFieldChanged += UIChanged; - ((UI_FloatEdit)Fields["manualCylStart"].uiControlEditor).onFieldChanged += UIChanged; - ((UI_FloatEdit)Fields["manualCylEnd"].uiControlEditor).onFieldChanged += UIChanged; - ((UI_Toggle)Fields["autoShape"].uiControlEditor).onFieldChanged += UIChanged; - } - - private bool uiChanged_SomeFields = true; - private void UIChanged(BaseField bf, object obj) - { - uiChanged_SomeFields = true; - } - - - - void onEditorVesselModified(ShipConstruct ship) - { - needShapeUpdate = true; - ShowHideInterstageNodes(); - } - - - public void ShowHideInterstageNodes() - { - var nnt = part.GetComponent(); - if (nnt) { - //if (nnt.showInterstageNodes == nnt.oldShowInterstageState) - // return; - - //nnt.oldShowInterstageState = nnt.showInterstageNodes; - - var nodes = part.FindAttachNodes("interstage"); - if (nodes == null) - return; - - // hide all unused interstage nodes - // just move it away in x direction - if (nnt.showInterstageNodes == false) { - for (int i = 0; i < nodes.Length; i++) { - var node = nodes[i]; - if (node.attachedPart == null) - node.position.x = 10000; - } - } - else { - for (int i = 0; i < nodes.Length; i++) { - var node = nodes[i]; - if (node.attachedPart == null) - node.position.x = 0; - } - } - } - - } - - - - public void removeJoints() - { - while (joints.Count > 0) { - int i = joints.Count - 1; - var joint = joints[i]; joints.RemoveAt(i); - UnityEngine.Object.Destroy(joint); - } - } - - - public void OnPartPack() - { - removeJoints(); - } - - - ConfigurableJoint addStrut(Part p, Part pp) - { - if (p == pp) return null; - - var rb = pp.Rigidbody; - if (rb == null || rb == p.Rigidbody) return null; - - var joint = p.gameObject.AddComponent(); - joint.xMotion = ConfigurableJointMotion.Locked; - joint.yMotion = ConfigurableJointMotion.Locked; - joint.zMotion = ConfigurableJointMotion.Locked; - joint.angularXMotion = ConfigurableJointMotion.Locked; - joint.angularYMotion = ConfigurableJointMotion.Locked; - joint.angularZMotion = ConfigurableJointMotion.Locked; - joint.projectionDistance = 0.1f; - joint.projectionAngle = 5; - joint.breakForce = p.breakingForce; - joint.breakTorque = p.breakingTorque; - joint.connectedBody = rb; - - joints.Add(joint); - return joint; - } - - - // public void OnPartUnpack() - // { - // if (!HighLogic.LoadedSceneIsEditor && autoStrutSides) - // { - // // strut side fairings together - // var attached=part.FindAttachNodes("connect"); - // for (int i=0; i(); - // // if (sf==null) continue; - - // var pp=attached[i>0 ? i-1 : attached.Length-1].attachedPart; - // if (pp==null) continue; - - // addStrut(p, pp); - - // if (topBasePart!=null) addStrut(p, topBasePart); - // } - // } - // } - - - IEnumerator createAutoStruts(List shieldedParts) - { - while (!FlightGlobals.ready || vessel.packed || !vessel.loaded) { - yield return new WaitForFixedUpdate(); - } - - var nnt = part.GetComponent(); - var attached = part.FindAttachNodes("connect"); - for (int i = 0; i < nnt.numNodes; ++i) { - var p = attached[i].attachedPart; - if (p == null || p.Rigidbody == null) continue; - - // var sf=p.GetComponent(); - // if (sf==null) continue; - - var pp = attached[i > 0 ? i - 1 : nnt.numNodes - 1].attachedPart; - if (pp == null) continue; - - addStrut(p, pp); - - if (topBasePart != null) addStrut(p, topBasePart); - } - } - - - public void onShieldingDisabled(List shieldedParts) - { - removeJoints(); - } - - - public void onShieldingEnabled(List shieldedParts) - { - if (!HighLogic.LoadedSceneIsFlight) return; - if (autoStrutSides) StartCoroutine(createAutoStruts(shieldedParts)); - } - - - public virtual void FixedUpdate() - { - if (!limitsSet && PFUtils.canCheckTech()) { - limitsSet = true; - float minSize = PFUtils.getTechMinValue("PROCFAIRINGS_MINDIAMETER", 0.25f); - float maxSize = PFUtils.getTechMaxValue("PROCFAIRINGS_MAXDIAMETER", 30); - - PFUtils.setFieldRange(Fields["manualMaxSize"], minSize, maxSize * 2); - - ((UI_FloatEdit)Fields["manualMaxSize"].uiControlEditor).incrementLarge = diameterStepLarge; - ((UI_FloatEdit)Fields["manualMaxSize"].uiControlEditor).incrementSmall = diameterStepSmall; - - ((UI_FloatEdit)Fields["manualCylStart"].uiControlEditor).incrementLarge = heightStepLarge; - ((UI_FloatEdit)Fields["manualCylStart"].uiControlEditor).incrementSmall = heightStepSmall; - ((UI_FloatEdit)Fields["manualCylEnd"].uiControlEditor).incrementLarge = heightStepLarge; - ((UI_FloatEdit)Fields["manualCylEnd"].uiControlEditor).incrementSmall = heightStepSmall; - } - - if (!part.packed && topBasePart != null) { - var adapter = part.GetComponent(); - if (adapter) { - topBasePart = adapter.getTopPart(); - if (topBasePart == null) removeJoints(); - } - } - } - - - LineRenderer makeLineRenderer(string name, Color color, float wd) - { - var o = new GameObject(name); - o.transform.parent = part.transform; - o.transform.localPosition = Vector3.zero; - o.transform.localRotation = Quaternion.identity; - var r = o.AddComponent(); - r.useWorldSpace = false; - r.material = new Material(Shader.Find("Particles/Additive")); - r.SetColors(color, color); - r.SetWidth(wd, wd); - r.SetVertexCount(0); - return r; - } - - - void destroyOutline() - { - for (int i = 0; i < outline.Count; i++) { - UnityEngine.GameObject.Destroy(outline[i].gameObject); - } - outline.Clear(); - - } - - - /// - /// Fix for the blue ghost lines showing invalid outline when cloning or symmetry-placing fairing bases in the VAB. - /// Find any already assigned (copied) linerenderers and delete them. - /// - void DestroyAllLineRenderers() - { - - LineRenderer[] lr = UnityEngine.GameObject.FindObjectsOfType(); - if (lr != null) { - for (int i = 0; i < lr.Length; i++) { - - Transform _transform = lr[i].transform; - if (!(_transform == null)) { - Transform _parent = _transform.parent; - if (!(_parent == null)) { - GameObject _gameObject = _parent.gameObject; - if (_gameObject) { - if ((_gameObject.Equals(this) ? true : _gameObject.Equals(base.gameObject))) { - GameObjectExtension.DestroyGameObject(lr[i].gameObject); - } - } - } - } - } - } - } - - - public void OnDestroy() - { - GameEvents.onEditorShipModified.Remove(new EventData.OnEvent(onEditorVesselModified)); - - if (line) { - UnityEngine.GameObject.Destroy(line.gameObject); - line = null; - } - - DestroyAllLineRenderers(); - destroyOutline(); - } - - - public void Update() - { - if (HighLogic.LoadedSceneIsEditor) { - if (uiChanged_SomeFields == true) { - uiChanged_SomeFields = false; - - if (lastManualMaxSize != manualMaxSize) needShapeUpdate = true; - if (lastManualCylStart != manualCylStart) needShapeUpdate = true; - if (lastManualCylEnd != manualCylEnd) needShapeUpdate = true; - - lastManualMaxSize = manualMaxSize; - lastManualCylStart = manualCylStart; - lastManualCylEnd = manualCylEnd; - - bool old = Fields["manualMaxSize"].guiActiveEditor; - Fields["manualMaxSize"].guiActiveEditor = !autoShape; - Fields["manualCylStart"].guiActiveEditor = !autoShape; - Fields["manualCylEnd"].guiActiveEditor = !autoShape; - - PFUtils.refreshPartWindow(); - - } - - if (updateDelay > 0) - updateDelay -= Time.deltaTime; - else - if (needShapeUpdate) { - needShapeUpdate = false; - recalcShape(); - updateDelay = 0.5f; - } - - - } - } - - - static public Vector3[] buildFairingShape(float baseRad, float maxRad, - float cylStart, float cylEnd, float noseHeightRatio, - Vector4 baseConeShape, Vector4 noseConeShape, - int baseConeSegments, int noseConeSegments, - Vector4 vertMapping, float mappingScaleY) - { - float baseConeRad = maxRad - baseRad; - float tip = maxRad * noseHeightRatio; - - var baseSlope = new BezierSlope(baseConeShape); - var noseSlope = new BezierSlope(noseConeShape); - - float baseV0 = vertMapping.x / mappingScaleY; - float baseV1 = vertMapping.y / mappingScaleY; - float noseV0 = vertMapping.z / mappingScaleY; - float noseV1 = vertMapping.w / mappingScaleY; - - var shape = new Vector3[1 + (cylStart == 0 ? 0 : baseConeSegments) + 1 + noseConeSegments]; - int vi = 0; - - if (cylStart != 0) { - for (int i = 0; i <= baseConeSegments; ++i, ++vi) { - float t = (float)i / baseConeSegments; - var p = baseSlope.interp(t); - shape[vi] = new Vector3(p.x * baseConeRad + baseRad, p.y * cylStart, - Mathf.Lerp(baseV0, baseV1, t)); - } - } - else - shape[vi++] = new Vector3(baseRad, 0, baseV1); - - for (int i = 0; i <= noseConeSegments; ++i, ++vi) { - float t = (float)i / noseConeSegments; - var p = noseSlope.interp(1 - t); - shape[vi] = new Vector3(p.x * maxRad, (1 - p.y) * tip + cylEnd, - Mathf.Lerp(noseV0, noseV1, t)); - } - - return shape; - } - - - static public Vector3[] buildInlineFairingShape(float baseRad, float maxRad, float topRad, - float cylStart, float cylEnd, float top, - Vector4 baseConeShape, - int baseConeSegments, - Vector4 vertMapping, float mappingScaleY) - { - float baseConeRad = maxRad - baseRad; - float topConeRad = maxRad - topRad; - - var baseSlope = new BezierSlope(baseConeShape); - - float baseV0 = vertMapping.x / mappingScaleY; - float baseV1 = vertMapping.y / mappingScaleY; - float noseV0 = vertMapping.z / mappingScaleY; - - var shape = new Vector3[2 + (cylStart == 0 ? 0 : baseConeSegments + 1) + (cylEnd == top ? 0 : baseConeSegments + 1)]; - int vi = 0; - - if (cylStart != 0) { - for (int i = 0; i <= baseConeSegments; ++i, ++vi) { - float t = (float)i / baseConeSegments; - var p = baseSlope.interp(t); - shape[vi] = new Vector3(p.x * baseConeRad + baseRad, p.y * cylStart, - Mathf.Lerp(baseV0, baseV1, t)); - } - } - - shape[vi++] = new Vector3(maxRad, cylStart, baseV1); - shape[vi++] = new Vector3(maxRad, cylEnd, noseV0); - - if (cylEnd != top) { - for (int i = 0; i <= baseConeSegments; ++i, ++vi) { - float t = (float)i / baseConeSegments; - var p = baseSlope.interp(1 - t); - shape[vi] = new Vector3(p.x * topConeRad + topRad, Mathf.Lerp(top, cylEnd, p.y), - Mathf.Lerp(baseV1, baseV0, t)); - } - } - - return shape; - } - - - - PayloadScan scanPayload() - { - // scan payload and build its profile - var scan = new PayloadScan(part, verticalStep, extraRadius); - - - AttachNode node = part.FindAttachNode("top"); - if (node != null) { - scan.ofs = node.position.y; - if (node.attachedPart != null) scan.addPart(node.attachedPart, part); - } - - - AttachNode[] nodes = part.FindAttachNodes("interstage"); - if (nodes != null) { - for (int j = 0; j < nodes.Length; j++) { - node = nodes[j]; - - if (node != null) { - if (node.attachedPart != null) scan.addPart(node.attachedPart, part); - } - } - } - - for (int i = 0; i < scan.payload.Count; ++i) { - var cp = scan.payload[i]; - - // add connected payload parts - scan.addPart(cp.parent, cp); - for (int j = 0; j < cp.children.Count; j++) - scan.addPart(cp.children[j], cp); - - // scan part colliders - var colls = cp.FindModelComponents(); - for (int j = 0; j < colls.Count; j++) { - var coll = colls[j]; - if (coll.tag != "Untagged") continue; // skip ladders etc. - scan.addPayload(coll); - } - } - - - return scan; - } - - AttachNode HasNodeComponent(AttachNode[] nodes) - { - if (nodes != null) { - for (int i = 0; i < nodes.Length; i++) { - var part = nodes[i].attachedPart; - if (part == null) - continue; - var comp = part.GetComponent(); - if (comp != null) { - return nodes[i]; - } - } - } - - return null; - } - - void recalcShape() - { - var scan = scanPayload(); - - // check for reversed base for inline fairings - float topY = 0; - float topRad = 0; - AttachNode topSideNode = null; - bool isInline = false; - - var adapter = part.GetComponent(); - - if (adapter) { - isInline = true; - topY = adapter.height + adapter.extraHeight; - if (topY < scan.ofs) topY = scan.ofs; - topRad = adapter.topRadius; - - // if (scan.profile.Count<=0) scan.profile.Add(extraRadius); - } - else if (scan.targets.Count > 0) { - isInline = true; - var topBase = scan.targets[0].GetComponent(); - topY = scan.w2l.MultiplyPoint3x4(topBase.part.transform.position).y; - if (topY < scan.ofs) topY = scan.ofs; - - topSideNode = HasNodeComponent(topBase.part.FindAttachNodes("connect")); - - topRad = topBase.baseSize * 0.5f; - } - - // no payload case - if (scan.profile.Count <= 0) scan.profile.Add(extraRadius); - - // fill profile outline (for debugging) - if (line) { - line.SetVertexCount(scan.profile.Count * 2 + 2); - - float prevRad = 0; - int hi = 0; - for (int i = 0; i < scan.profile.Count; i++) { - var r = scan.profile[i]; - line.SetPosition(hi * 2, new Vector3(prevRad, hi * verticalStep + scan.ofs, 0)); - line.SetPosition(hi * 2 + 1, new Vector3(r, hi * verticalStep + scan.ofs, 0)); - hi++; prevRad = r; - } - - line.SetPosition(hi * 2, new Vector3(prevRad, hi * verticalStep + scan.ofs, 0)); - line.SetPosition(hi * 2 + 1, new Vector3(0, hi * verticalStep + scan.ofs, 0)); - } - - // check attached side parts and get params - var attached = part.FindAttachNodes("connect"); - // get number of available nodes from numbertweaker - var nnt = part.GetComponent(); - int numSideParts = nnt.numNodes; - //int numSideParts=attached.Length; - - - var sideNode = HasNodeComponent(attached); - - float noseHeightRatio = 2; - float minBaseConeAngle = 20; - Vector4 baseConeShape = new Vector4(0.5f, 0, 1, 0.5f); - Vector4 noseConeShape = new Vector4(0.5f, 0, 1, 0.5f); - int baseConeSegments = 1; - int noseConeSegments = 1; - Vector2 mappingScale = new Vector2(1024, 1024); - Vector2 stripMapping = new Vector2(992, 1024); - Vector4 horMapping = new Vector4(0, 480, 512, 992); - Vector4 vertMapping = new Vector4(0, 160, 704, 1024); - - if (sideNode != null) { - var sf = sideNode.attachedPart.GetComponent(); - noseHeightRatio = sf.noseHeightRatio; - minBaseConeAngle = sf.minBaseConeAngle; - baseConeShape = sf.baseConeShape; - noseConeShape = sf.noseConeShape; - baseConeSegments = sf.baseConeSegments; - noseConeSegments = sf.noseConeSegments; - mappingScale = sf.mappingScale; - stripMapping = sf.stripMapping; - horMapping = sf.horMapping; - vertMapping = sf.vertMapping; - } - - // compute fairing shape - float baseRad = baseSize * 0.5f; - float minBaseConeTan = Mathf.Tan(minBaseConeAngle * Mathf.Deg2Rad); - - float cylStart = 0; - float maxRad; - int profTop = scan.profile.Count; - - if (isInline) { - profTop = Mathf.CeilToInt((topY - scan.ofs) / verticalStep); - if (profTop > scan.profile.Count) profTop = scan.profile.Count; - - maxRad = 0; - for (int i = 0; i < profTop; ++i) - maxRad = Mathf.Max(maxRad, scan.profile[i]); - - maxRad = Mathf.Max(maxRad, topRad); - } - else - maxRad = PFUtils.GetMaxValueFromList(scan.profile); - - if (maxRad > baseRad) { - // try to fit base cone as high as possible - cylStart = scan.ofs; - for (int i = 1; i < scan.profile.Count; ++i) { - float y = i * verticalStep + scan.ofs; - float r0 = baseRad; - float k = (maxRad - r0) / y; - if (k < minBaseConeTan) break; - - bool ok = true; - float r = r0 + k * scan.ofs; - for (int j = 0; j < i; ++j, r += k * verticalStep) - if (scan.profile[j] > r) { ok = false; break; } - - if (!ok) break; - cylStart = y; - } - } - else - maxRad = baseRad; // no base cone, just cylinder and nose - - float cylEnd = scan.profile.Count * verticalStep + scan.ofs; - - if (isInline) { - float r0 = topRad; - if (profTop > 0 && profTop < scan.profile.Count) { - r0 = Mathf.Max(r0, scan.profile[profTop - 1]); - if (profTop - 2 >= 0) r0 = Mathf.Max(r0, scan.profile[profTop - 2]); - } - - if (maxRad > r0) { - if (cylEnd > topY) cylEnd = topY - verticalStep; - - // try to fit top cone as low as possible - for (int i = profTop - 1; i >= 0; --i) { - float y = i * verticalStep + scan.ofs; - float k = (maxRad - r0) / (y - topY); - - bool ok = true; - float r = maxRad + k * verticalStep; - for (int j = i; j < profTop; ++j, r += k * verticalStep) { - if (r < r0) r = r0; - if (scan.profile[j] > r) { ok = false; break; } - } - - if (!ok) break; - - cylEnd = y; - } - } - else - cylEnd = topY; - } - else { - // try to fit nose cone as low as possible - for (int i = scan.profile.Count - 1; i >= 0; --i) { - float s = verticalStep / noseHeightRatio; - - bool ok = true; - float r = maxRad - s; - for (int j = i; j < scan.profile.Count; ++j, r -= s) - if (scan.profile[j] > r) { ok = false; break; } - - if (!ok) break; - - float y = i * verticalStep + scan.ofs; - cylEnd = y; - } - } - - if (autoShape) { - manualMaxSize = maxRad * 2; - manualCylStart = cylStart; - manualCylEnd = cylEnd; - } - else { - maxRad = manualMaxSize * 0.5f; - cylStart = manualCylStart; - cylEnd = manualCylEnd; - } - - if (cylStart > cylEnd) cylStart = cylEnd; - - // build fairing shape line - Vector3[] shape; - - if (isInline) - shape = buildInlineFairingShape(baseRad, maxRad, topRad, cylStart, cylEnd, topY, - baseConeShape, baseConeSegments, - vertMapping, mappingScale.y); - else - shape = buildFairingShape(baseRad, maxRad, cylStart, cylEnd, noseHeightRatio, - baseConeShape, noseConeShape, baseConeSegments, noseConeSegments, - vertMapping, mappingScale.y); - - if (sideNode == null && topSideNode == null) { - // no side parts - fill fairing outlines - for (int j = 0; j < outline.Count; j++) { - var lr = outline[j]; - lr.SetVertexCount(shape.Length); - for (int i = 0; i < shape.Length; ++i) - lr.SetPosition(i, new Vector3(shape[i].x, shape[i].y)); - - - } - } - else { - for (int j = 0; j < outline.Count; j++) { - var lr = outline[j]; - lr.SetVertexCount(0); - } - } - - // rebuild side parts - int numSegs = circleSegments / numSideParts; - if (numSegs < 2) numSegs = 2; - - for (int i = 0; i < attached.Length; i++) { - var sn = attached[i]; - var sp = sn.attachedPart; - if (!sp) continue; - var sf = sp.GetComponent(); - if (!sf) continue; - - if (sf.shapeLock) continue; - - var mf = sp.FindModelComponent("model"); - if (!mf) { Debug.LogError("[ProceduralFairingBase] no model in side fairing", sp); continue; } - - var nodePos = sn.position; - - mf.transform.position = part.transform.position; - mf.transform.rotation = part.transform.rotation; - float ra = Mathf.Atan2(-nodePos.z, nodePos.x) * Mathf.Rad2Deg; - mf.transform.Rotate(0, ra, 0); - - if (sf.meshPos == mf.transform.localPosition - && sf.meshRot == mf.transform.localRotation - && sf.numSegs == numSegs - && sf.numSideParts == numSideParts - && sf.baseRad == baseRad - && sf.maxRad == maxRad - && sf.cylStart == cylStart - && sf.cylEnd == cylEnd - && sf.topRad == topRad - && sf.inlineHeight == topY - && sf.sideThickness == sideThickness) - continue; - - sf.meshPos = mf.transform.localPosition; - sf.meshRot = mf.transform.localRotation; - sf.numSegs = numSegs; - sf.numSideParts = numSideParts; - sf.baseRad = baseRad; - sf.maxRad = maxRad; - sf.cylStart = cylStart; - sf.cylEnd = cylEnd; - sf.topRad = topRad; - sf.inlineHeight = topY; - sf.sideThickness = sideThickness; - sf.rebuildMesh(); - } - - var shielding = part.GetComponent(); - if (shielding) shielding.reset(); - } - } - - - //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ// - - -} // namespace - diff --git a/Source/FairingDecoupler.cs b/Source/FairingDecoupler.cs deleted file mode 100644 index c13ed8c..0000000 --- a/Source/FairingDecoupler.cs +++ /dev/null @@ -1,197 +0,0 @@ -// Procedural Fairings plug-in by Alexey Volynskov -// Licensed under CC BY 3.0 terms: http://creativecommons.org/licenses/by/3.0/ -using System; -using System.Collections.Generic; -using System.Text; -using UnityEngine; -using KSP.UI.Screens; - - -namespace Keramzit -{ - - - //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ// - - - public class ProceduralFairingDecoupler : PartModule - { - [KSPField] public float ejectionDv = 15; - [KSPField] public float ejectionTorque = 10; - [KSPField] public float ejectionLowDv = 0; - [KSPField] public float ejectionLowTorque = 0; - - [KSPField(isPersistant = true, guiActiveEditor = true, guiName = "Ejection power")] - [UI_FloatRange(minValue = 0, maxValue = 1, stepIncrement = 0.01f)] - public float ejectionPower = 0.32f; - - [KSPField(isPersistant = true, guiActiveEditor = true, guiName = "Ejection torque")] - [UI_FloatRange(minValue = 0, maxValue = 1, stepIncrement = 0.01f)] - public float torqueAmount = 0.01f; - - [KSPField] public string ejectSoundUrl = "Squad/Sounds/sound_decoupler_fire"; - public FXGroup ejectFx; - - [KSPField] public string transformName = "nose_collider"; - [KSPField] public Vector3 forceVector = Vector3.right; - [KSPField] public Vector3 torqueVector = -Vector3.forward; - - [KSPField(isPersistant = true)] bool decoupled = false; - bool didForce = false; - - - public override void OnStart(StartState state) - { - if (state == StartState.None) return; - - ejectFx.audio = part.gameObject.AddComponent(); - ejectFx.audio.volume = GameSettings.SHIP_VOLUME; - ejectFx.audio.rolloffMode = AudioRolloffMode.Logarithmic; - // ejectFx.audio.panLevel=1; - ejectFx.audio.maxDistance = 100; - ejectFx.audio.loop = false; - ejectFx.audio.playOnAwake = false; - - if (GameDatabase.Instance.ExistsAudioClip(ejectSoundUrl)) - ejectFx.audio.clip = GameDatabase.Instance.GetAudioClip(ejectSoundUrl); - else - Debug.LogError("[ProceduralFairingSide] can't find sound: " + ejectSoundUrl, this); - - //GameEvents.onPartJointBreak.Add(OnPartJointBreak); - } - - - public override void OnLoad(ConfigNode cfg) - { - base.OnLoad(cfg); - didForce = decoupled; - } - - public void OnDestroy() - { - //GameEvents.onPartJointBreak.Remove(OnPartJointBreak); - } - - //void OnPartJointBreak(PartJoint joint, float data) - //{ - // Part p = joint.GetComponent(); - // bool isstaging = false; - - // if (p == this.part) - // { - // var mod = this.part.GetComponent(); - // if (mod != null) - // { - // isstaging = mod.StagingEnabled(); - // if (isstaging == true) - // { - // mod.ToggleStaging(); - // mod.ToggleStaging(); - // } - - // isstaging = mod.StagingEnabled(); - // } - // } - - //} - - public void FixedUpdate() - { - if (decoupled) { - if (part.parent) { - var pfa = part.parent.GetComponent(); - for (int i = 0; i < part.parent.children.Count; i++) { - var p = part.parent.children[i]; - - // check if top node allows for decoupling when fairing is gone - if (pfa) { - if (!pfa.topNodeDecouplesWhenFairingsGone) { - var isFairing = p.GetComponent(); - if (!isFairing) - continue; - } - } - - var joints = p.GetComponents(); - for (int j = 0; j < joints.Length; j++) { - var joint = joints[j]; - if (joint != null && (joint.GetComponent() == part.Rigidbody || joint.connectedBody == part.Rigidbody)) - Destroy(joint); - } - } - - part.decouple(0); - - ejectFx.audio.Play(); - } - else if (!didForce) { - var tr = part.FindModelTransform(transformName); - if (tr) { - part.Rigidbody.AddForce(tr.TransformDirection(forceVector) - * Mathf.Lerp(ejectionLowDv, ejectionDv, ejectionPower), - ForceMode.VelocityChange); - part.Rigidbody.AddTorque(tr.TransformDirection(torqueVector) - * Mathf.Lerp(ejectionLowTorque, ejectionTorque, torqueAmount), - ForceMode.VelocityChange); - } - else - Debug.LogError("[ProceduralFairingDecoupler] no '" + transformName + "' transform in part", part); - - didForce = true; - decoupled = false; - } - } - } - - - [KSPEvent(name = "Jettison", active = true, guiActive = true, guiActiveUnfocused = false, guiName = "Jettison")] - public void Jettison() - { - decoupled = true; - - // if (part.parent) - // { - // foreach (var p in part.parent.children) - // foreach (var joint in p.GetComponents()) - // if (joint!=null && (joint.rigidbody==part.Rigidbody || joint.connectedBody==part.Rigidbody)) - // Destroy(joint); - - // part.decouple(0); - - // var tr=part.FindModelTransform(transformName); - // if (tr) - // { - // part.Rigidbody.AddForce(tr.TransformDirection(forceVector) - // *Mathf.Lerp(ejectionLowDv, ejectionDv, ejectionPower), - // ForceMode.VelocityChange); - // part.Rigidbody.AddTorque(tr.TransformDirection(torqueVector) - // *Mathf.Lerp(ejectionLowTorque, ejectionTorque, torqueAmount), - // ForceMode.VelocityChange); - // } - // else - // Debug.LogError("[ProceduralFairingDecoupler] no '"+transformName+"' transform in part", part); - - // ejectFx.audio.Play(); - // } - } - - - public override void OnActive() - { - Jettison(); - } - - - [KSPAction("Jettison", actionGroup = KSPActionGroup.None)] - public void ActionJettison(KSPActionParam param) - { - Jettison(); - } - } - - - //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ// - - -} // namespace - diff --git a/Source/FairingShielding.cs b/Source/FairingShielding.cs deleted file mode 100644 index 977aba4..0000000 --- a/Source/FairingShielding.cs +++ /dev/null @@ -1,341 +0,0 @@ -// Procedural Fairings plug-in by Alexey Volynskov -// Licensed under CC BY 3.0 terms: http://creativecommons.org/licenses/by/3.0/ -using System; -using System.Collections.Generic; -using System.Text; -using UnityEngine; - - -namespace Keramzit -{ - - - //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ// - - - public class KzFairingBaseShielding : PartModule, IAirstreamShield - { - List shieldedParts; - - ProceduralFairingSide sideFairing; - float boundCylY0, boundCylY1, boundCylRad; - Vector3 lookupCenter; - float lookupRad; - Vector3[] shape; - - [KSPField(isPersistant = false, guiActive = true, guiActiveEditor = true, guiName = "Parts shielded")] - public int numShieldedDisplay; - - bool needReset = false; - - - public bool ClosedAndLocked() { return true; } - public Vessel GetVessel() { return vessel; } - public Part GetPart() { return part; } - - - public override void OnAwake() - { - shieldedParts = new List(); - } - - - public override void OnStart(StartState state) - { - if (!HighLogic.LoadedSceneIsEditor && !HighLogic.LoadedSceneIsFlight) return; - - reset(); - - // GameEvents.onEditorShipModified.Add(new EventData.OnEvent(onEditorVesselModified)); - GameEvents.onVesselWasModified.Add(new EventData.OnEvent(onVesselModified)); - GameEvents.onVesselGoOffRails.Add(new EventData.OnEvent(onVesselUnpack)); - GameEvents.onPartDie.Add(new EventData.OnEvent(OnPartDestroyed)); - } - - - void OnDestroy() - { - // GameEvents.onEditorShipModified.Remove(new EventData.OnEvent(onEditorVesselModified)); - GameEvents.onVesselWasModified.Remove(new EventData.OnEvent(onVesselModified)); - GameEvents.onVesselGoOffRails.Remove(new EventData.OnEvent(onVesselUnpack)); - GameEvents.onPartDie.Remove(new EventData.OnEvent(OnPartDestroyed)); - } - - - public void FixedUpdate() - { - if (needReset) { - needReset = false; - getFairingParams(); - bool shield = (HighLogic.LoadedSceneIsEditor || (HighLogic.LoadedSceneIsFlight && !vessel.packed)); - if (shield) enableShielding(); - } - } - - - public void reset() - { - needReset = true; - } - - - AttachNode[] getFairingParams() - { - var nnt = part.GetComponent(); - - // check attached side parts and get params - var attached = part.FindAttachNodes("connect"); - ProceduralFairingSide sf = null; - - //for (int i = 0; i < attached.Length; ++i) - for (int i = 0; i < nnt.numNodes; ++i) { - var n = attached[i]; - if (!n.attachedPart) { sf = null; break; } - sf = n.attachedPart.GetComponent(); - if (!sf) break; - } - - sideFairing = sf; - - if (!sf) { - shape = null; - boundCylY0 = boundCylY1 = boundCylRad = 0; - lookupCenter = Vector3.zero; - lookupRad = 0; - return null; - } - - // get shape polyline - if (sf.inlineHeight <= 0) - shape = ProceduralFairingBase.buildFairingShape( - sf.baseRad, sf.maxRad, sf.cylStart, sf.cylEnd, sf.noseHeightRatio, - sf.baseConeShape, sf.noseConeShape, sf.baseConeSegments, sf.noseConeSegments, - sf.vertMapping, sf.mappingScale.y); - else - shape = ProceduralFairingBase.buildInlineFairingShape( - sf.baseRad, sf.maxRad, sf.topRad, sf.cylStart, sf.cylEnd, sf.inlineHeight, - sf.baseConeShape, sf.baseConeSegments, - sf.vertMapping, sf.mappingScale.y); - - // offset shape by thickness - for (int i = 0; i < shape.Length; ++i) { - if (i == 0 || i == shape.Length - 1) - shape[i] += new Vector3(sf.sideThickness, 0, 0); - else { - Vector2 n = shape[i + 1] - shape[i - 1]; - n.Set(n.y, -n.x); - n.Normalize(); - shape[i] += new Vector3(n.x, n.y, 0) * sf.sideThickness; - } - } - - // compute bounds - float y0, y1, mr; - y0 = y1 = shape[0].y; - mr = shape[0].x; - - for (int i = 0; i < shape.Length; ++i) { - var p = shape[i]; - if (p.x > mr) mr = p.x; - if (p.y < y0) y0 = p.y; - else if (p.y > y1) y1 = p.y; - } - - boundCylY0 = y0; - boundCylY1 = y1; - boundCylRad = mr; - - lookupCenter = new Vector3(0, (y0 + y1) * 0.5f, 0); - lookupRad = new Vector2(mr, (y1 - y0) * 0.5f).magnitude; - - return attached; - } - - - void enableShielding() - { - // print("enableShielding()"); - disableShielding(); - - var attached = getFairingParams(); - if (!sideFairing) return; - - // get all parts in range - var parts = new List(); - var colliders = Physics.OverlapSphere(part.transform.TransformPoint(lookupCenter), lookupRad, 1); - for (int i = colliders.Length - 1; i >= 0; --i) { - var p = colliders[i].gameObject.GetComponentUpwards(); - if (p != null) parts.AddUnique(p); - } - // print("got "+parts.Count+" nearby parts"); - - // filter parts - float sizeSqr = lookupRad * lookupRad * 4; - float boundCylRadSq = boundCylRad * boundCylRad; - - bool isInline = (sideFairing.inlineHeight > 0); - bool topClosed = false; - - Matrix4x4 w2l = Matrix4x4.identity, w2lb = Matrix4x4.identity; - Bounds topBounds = default(Bounds); - - if (isInline) { - w2l = part.transform.worldToLocalMatrix; - w2lb = w2l; - for (int i = 0; i < 3; ++i) - for (int j = 0; j < 3; ++j) - w2lb[i, j] = Mathf.Abs(w2lb[i, j]); - - topBounds = new Bounds(new Vector3(0, boundCylY1, 0), new Vector3(sideFairing.topRad * 2, sideFairing.sideThickness, sideFairing.topRad * 2)); - } - - for (int pi = 0; pi < parts.Count; ++pi) { - var pt = parts[pi]; - - // check special cases - if (pt == part) { shieldedParts.Add(pt); continue; } - - bool isSide = false; - for (int i = 0; i < attached.Length; ++i) if (attached[i].attachedPart == pt) { isSide = true; break; } - if (isSide) continue; - - // print("checking part "+pt.partName+" "+pt.partInfo.title); - - // check if the top is closed in the inline case - var bounds = pt.GetRendererBounds(); - var box = PartGeometryUtil.MergeBounds(bounds, pt.transform); - - if (isInline && !topClosed && pt.vessel == vessel) { - var wb = box; wb.Expand(sideFairing.sideThickness * 4); - var b = new Bounds(w2l.MultiplyPoint3x4(wb.center), w2lb.MultiplyVector(wb.size)); - if (b.Contains(topBounds.min) && b.Contains(topBounds.max)) topClosed = true; - } - - // check if too big to fit - // if (box.size.sqrMagnitude>sizeSqr) continue; - - // check if the centroid is within fairing bounds - var c = part.transform.InverseTransformPoint(PartGeometryUtil.FindBoundsCentroid(bounds, null)); - - float y = c.y; - if (y < boundCylY0 || y > boundCylY1) continue; - - float xsq = new Vector2(c.x, c.z).sqrMagnitude; - if (xsq > boundCylRadSq) continue; - - // accurate centroid check - float x = Mathf.Sqrt(xsq); - bool inside = false; - - for (int i = 1; i < shape.Length; ++i) { - var p0 = shape[i - 1]; - var p1 = shape[i]; - if (p0.y > p1.y) { var p = p0; p0 = p1; p1 = p; } - - if (y < p0.y || y > p1.y) continue; - - float dy = p1.y - p0.y, r; - if (dy <= 1e-6f) r = (p0.x + p1.x) * 0.5f; - else r = (p1.x - p0.x) * (y - p0.y) / dy + p0.x; - - if (x > r) continue; - - inside = true; - break; - } - - if (!inside) continue; - - shieldedParts.Add(pt); - // print("shielded "+pt.partName); - } - - if (isInline && !topClosed) { disableShielding(); return; } - - // add shielding - for (int i = 0; i < shieldedParts.Count; ++i) - shieldedParts[i].AddShield(this); - - numShieldedDisplay = shieldedParts.Count; - - var fbase = part.GetComponent(); - if (fbase != null) fbase.onShieldingEnabled(shieldedParts); - } - - - void disableShielding() - { - if (shieldedParts != null) { - var fbase = part.GetComponent(); - if (fbase != null) fbase.onShieldingDisabled(shieldedParts); - - for (int i = shieldedParts.Count - 1; i >= 0; --i) - if (shieldedParts[i] != null) shieldedParts[i].RemoveShield(this); - shieldedParts.Clear(); - } - - numShieldedDisplay = 0; - } - - - void onEditorVesselModified(ShipConstruct ship) - { - // print("onEditorVesselModified"); - // reset(); - } - - - void onVesselModified(Vessel v) - { - // print("onVesselModified"); - if (v != vessel) { - var dp = v.vesselTransform.position - part.transform.TransformPoint(lookupCenter); - if (dp.sqrMagnitude > lookupRad * lookupRad) return; - } - enableShielding(); - } - - - void onVesselUnpack(Vessel v) - { - // print("onVesselUnpack"); - if (v == vessel) enableShielding(); - } - - - void onVesselPack(Vessel v) - { - // print("onVesselPack"); - if (v == vessel) disableShielding(); - } - - - void OnPartDestroyed(Part p) - { - var nnt = part.GetComponent(); - // print("OnPartDestroyed"); - if (p == part) { disableShielding(); return; } - - // check for side fairing parts - var attached = part.FindAttachNodes("connect"); - //for (int i = 0; i < attached.Length; ++i) - for (int i = 0; i < nnt.numNodes; ++i) - if (p == attached[i].attachedPart) { disableShielding(); return; } - - // check for top parts in inline/adapter case - if (p.vessel == vessel && sideFairing && sideFairing.inlineHeight > 0) - enableShielding(); - } - - public void OnPartPack() - { - disableShielding(); - } - } - - - //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ// - - -} // namespace - diff --git a/Source/FairingSide.cs b/Source/FairingSide.cs deleted file mode 100644 index a723d21..0000000 --- a/Source/FairingSide.cs +++ /dev/null @@ -1,512 +0,0 @@ -// Procedural Fairings plug-in by Alexey Volynskov -// Licensed under CC BY 3.0 terms: http://creativecommons.org/licenses/by/3.0/ -using System; -using System.Collections.Generic; -using System.Text; -using UnityEngine; - - -namespace Keramzit -{ - - - //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ// - - - public class ProceduralFairingSide : PartModule, IPartCostModifier, IPartMassModifier - { - [KSPField] public float noseHeightRatio = 2; - [KSPField] public float minBaseConeAngle = 20; - [KSPField] public Vector4 baseConeShape = new Vector4(0.5f, 0, 1, 0.5f); - [KSPField] public Vector4 noseConeShape = new Vector4(0.5f, 0, 1, 0.5f); - [KSPField] public int baseConeSegments = 5; - [KSPField] public int noseConeSegments = 7; - - [KSPField] public Vector2 mappingScale = new Vector2(1024, 1024); - [KSPField] public Vector2 stripMapping = new Vector2(992, 1024); - [KSPField] public Vector4 horMapping = new Vector4(0, 480, 512, 992); - [KSPField] public Vector4 vertMapping = new Vector4(0, 160, 704, 1024); - - [KSPField] public float density = 0.2f; - [KSPField] public float costPerTonne = 2000; - [KSPField] public float specificBreakingForce = 2000; - [KSPField] public float specificBreakingTorque = 2000; - - [KSPField(isPersistant = true)] public int numSegs = 12; - [KSPField(isPersistant = true)] public int numSideParts = 2; - [KSPField(isPersistant = true)] public float baseRad = 0; - [KSPField(isPersistant = true)] public float maxRad = 1.50f; - [KSPField(isPersistant = true)] public float cylStart = 0.5f; - [KSPField(isPersistant = true)] public float cylEnd = 2.5f; - [KSPField(isPersistant = true)] public float topRad = 0; - [KSPField(isPersistant = true)] public float inlineHeight = 0; - [KSPField(isPersistant = true)] public float sideThickness = 0.05f; - [KSPField(isPersistant = true)] public Vector3 meshPos = Vector3.zero; - [KSPField(isPersistant = true)] public Quaternion meshRot = Quaternion.identity; - - [KSPField(isPersistant = true, guiActiveEditor = true, guiName = "Shape")] - [UI_Toggle(disabledText = "Unlocked", enabledText = "Locked")] - public bool shapeLock = false; - - [KSPField(isPersistant = false, guiActive = false, guiActiveEditor = true, guiName = "Mass")] - public string massDisplay; - - [KSPField(isPersistant = false, guiActive = false, guiActiveEditor = true, guiName = "Cost")] - public string costDisplay; - - - public ModifierChangeWhen GetModuleCostChangeWhen() { return ModifierChangeWhen.FIXED; } - public ModifierChangeWhen GetModuleMassChangeWhen() { return ModifierChangeWhen.FIXED; } - - public float GetModuleCost(float defcost, ModifierStagingSituation sit) - { - return totalMass * costPerTonne - defcost; - } - - public float GetModuleMass(float defmass, ModifierStagingSituation sit) - { - return totalMass - defmass; - } - - - public override string GetInfo() - { - string s = "Attach to Keramzit's fairing base to reshape."; - - return s; - } - - - public void Start() - { - part.mass = totalMass; - } - public override void OnStart(StartState state) - { - if (state == StartState.None) return; - - if (state != StartState.Editor || shapeLock) rebuildMesh(); - part.mass = totalMass; - } - - - public override void OnLoad(ConfigNode cfg) - { - base.OnLoad(cfg); - if (HighLogic.LoadedSceneIsEditor || HighLogic.LoadedSceneIsFlight) rebuildMesh(); - } - - - public void updateNodeSize() - { - var node = part.FindAttachNode("connect"); - if (node != null) { - int s = Mathf.RoundToInt(baseRad * 2 / 1.25f) - 1; - if (s < 0) s = 0; - node.size = s; - } - } - - - public void FixedUpdate() - { - if (HighLogic.LoadedSceneIsEditor) { - int nsym = part.symmetryCounterparts.Count; - if (nsym == 0) { - massDisplay = PFUtils.formatMass(totalMass); - costDisplay = PFUtils.formatCost(part.partInfo.cost + GetModuleCost(part.partInfo.cost, ModifierStagingSituation.CURRENT)); - } - else if (nsym == 1) { - massDisplay = PFUtils.formatMass(totalMass * 2) + " (both)"; - costDisplay = PFUtils.formatCost((part.partInfo.cost + GetModuleCost(part.partInfo.cost, ModifierStagingSituation.CURRENT)) * 2) + " (both)"; - } - else { - massDisplay = PFUtils.formatMass(totalMass * (nsym + 1)) + " (all " + (nsym + 1) + ")"; - costDisplay = PFUtils.formatCost((part.partInfo.cost + GetModuleCost(part.partInfo.cost, ModifierStagingSituation.CURRENT)) * (nsym + 1)) + " (all " + (nsym + 1) + ")"; - } - } - } - - public float totalMass; - public void rebuildMesh() - { - var mf = part.FindModelComponent("model"); - if (!mf) { Debug.LogError("[ProceduralFairingSide] no model in side fairing", part); return; } - - Mesh m = mf.mesh; - if (!m) { Debug.LogError("[ProceduralFairingSide] no mesh in side fairing", part); return; } - - mf.transform.localPosition = meshPos; - mf.transform.localRotation = meshRot; - - updateNodeSize(); - - // build fairing shape line - float tip = maxRad * noseHeightRatio; - - Vector3[] shape; - if (inlineHeight <= 0) - shape = ProceduralFairingBase.buildFairingShape( - baseRad, maxRad, cylStart, cylEnd, noseHeightRatio, - baseConeShape, noseConeShape, baseConeSegments, noseConeSegments, - vertMapping, mappingScale.y); - else - shape = ProceduralFairingBase.buildInlineFairingShape( - baseRad, maxRad, topRad, cylStart, cylEnd, inlineHeight, - baseConeShape, baseConeSegments, - vertMapping, mappingScale.y); - - // set up params - var dirs = new Vector3[numSegs + 1]; - for (int i = 0; i <= numSegs; ++i) { - float a = Mathf.PI * 2 * (i - numSegs * 0.5f) / (numSideParts * numSegs); - dirs[i] = new Vector3(Mathf.Cos(a), 0, Mathf.Sin(a)); - } - - float segOMappingScale = (horMapping.y - horMapping.x) / (mappingScale.x * numSegs); - float segIMappingScale = (horMapping.w - horMapping.z) / (mappingScale.x * numSegs); - float segOMappingOfs = horMapping.x / mappingScale.x; - float segIMappingOfs = horMapping.z / mappingScale.x; - - if (numSideParts > 2) { - segOMappingOfs += segOMappingScale * numSegs * (0.5f - 1f / numSideParts); - segOMappingScale *= 2f / numSideParts; - segIMappingOfs += segIMappingScale * numSegs * (0.5f - 1f / numSideParts); - segIMappingScale *= 2f / numSideParts; - } - - float stripU0 = stripMapping.x / mappingScale.x; - float stripU1 = stripMapping.y / mappingScale.x; - - float ringSegLen = baseRad * Mathf.PI * 2 / (numSegs * numSideParts); - float topRingSegLen = topRad * Mathf.PI * 2 / (numSegs * numSideParts); - - float collWidth = maxRad * Mathf.PI * 2 / (numSideParts * 3); - - int numMainVerts = (numSegs + 1) * (shape.Length - 1) + 1; - int numMainFaces = numSegs * ((shape.Length - 2) * 2 + 1); - - int numSideVerts = shape.Length * 2; - int numSideFaces = (shape.Length - 1) * 2; - - int numRingVerts = (numSegs + 1) * 2; - int numRingFaces = numSegs * 2; - - if (inlineHeight > 0) { - numMainVerts = (numSegs + 1) * shape.Length; - numMainFaces = numSegs * (shape.Length - 1) * 2; - } - - int totalVerts = numMainVerts * 2 + numSideVerts * 2 + numRingVerts; - int totalFaces = numMainFaces * 2 + numSideFaces * 2 + numRingFaces; - - if (inlineHeight > 0) { - totalVerts += numRingVerts; - totalFaces += numRingFaces; - } - - var p = shape[shape.Length - 1]; - float topY = p.y, topV = p.z; - - float collCenter = (cylStart + cylEnd) / 2, collHeight = cylEnd - cylStart; - if (collHeight <= 0) collHeight = Mathf.Min(topY - cylEnd, cylStart) / 2; - - // compute area - double area = 0; - for (int i = 1; i < shape.Length; ++i) - area += (shape[i - 1].x + shape[i].x) * (shape[i].y - shape[i - 1].y) * Mathf.PI / numSideParts; - - // set params based on volume - float volume = (float)(area * sideThickness); - part.mass = totalMass = volume * density; - part.breakingForce = part.mass * specificBreakingForce; - part.breakingTorque = part.mass * specificBreakingTorque; - - var offset = new Vector3(maxRad * 0.7f, topY * 0.5f, 0); - part.CoMOffset = part.transform.InverseTransformPoint(mf.transform.TransformPoint(offset)); - - // remove old colliders - var colls = part.FindModelComponents(); - for (int i = 0; i < colls.Count; i++) { - var c = colls[i]; - // if (c.transform.parent!=mf.transform || c.transform.parent!=mf.transform.parent) continue; - UnityEngine.Object.Destroy(c.gameObject); - } - - // add new colliders - for (int i = -1; i <= 1; ++i) { - var obj = new GameObject("collider"); - obj.transform.parent = mf.transform; - obj.transform.localPosition = Vector3.zero; - obj.transform.localRotation = Quaternion.AngleAxis(90f * i / numSideParts, Vector3.up); - var coll = obj.AddComponent(); - coll.center = new Vector3(maxRad + sideThickness * 0.5f, collCenter, 0); - coll.size = new Vector3(sideThickness, collHeight, collWidth); - } - - { - // nose collider - float r = maxRad * 0.2f; - var obj = new GameObject("nose_collider"); - obj.transform.parent = mf.transform; - obj.transform.localPosition = new Vector3(r, cylEnd + tip - r * 1.2f, 0); - obj.transform.localRotation = Quaternion.identity; - - if (inlineHeight > 0) { - r = sideThickness * 0.5f; - obj.transform.localPosition = new Vector3(maxRad + r, collCenter, 0); - } - - var coll = obj.AddComponent(); - coll.center = Vector3.zero; - coll.radius = r; - } - - // build mesh - m.Clear(); - - var verts = new Vector3[totalVerts]; - var uv = new Vector2[totalVerts]; - var norm = new Vector3[totalVerts]; - var tang = new Vector4[totalVerts]; - - if (inlineHeight <= 0) { - // tip vertex - verts[numMainVerts - 1].Set(0, topY + sideThickness, 0); // outside - verts[numMainVerts * 2 - 1].Set(0, topY, 0); // inside - uv[numMainVerts - 1].Set(segOMappingScale * 0.5f * numSegs + segOMappingOfs, topV); - uv[numMainVerts * 2 - 1].Set(segIMappingScale * 0.5f * numSegs + segIMappingOfs, topV); - norm[numMainVerts - 1] = Vector3.up; - norm[numMainVerts * 2 - 1] = -Vector3.up; - // tang[numMainVerts -1]= Vector3.forward; - // tang[numMainVerts*2-1]=-Vector3.forward; - tang[numMainVerts - 1] = Vector3.zero; - tang[numMainVerts * 2 - 1] = Vector3.zero; - } - - // main vertices - float noseV0 = vertMapping.z / mappingScale.y; - float noseV1 = vertMapping.w / mappingScale.y; - float noseVScale = 1f / (noseV1 - noseV0); - float oCenter = (horMapping.x + horMapping.y) / (mappingScale.x * 2); - float iCenter = (horMapping.z + horMapping.w) / (mappingScale.x * 2); - - int vi = 0; - for (int i = 0; i < shape.Length - (inlineHeight <= 0 ? 1 : 0); ++i) { - p = shape[i]; - - Vector2 n; - if (i == 0) n = shape[1] - shape[0]; - else if (i == shape.Length - 1) n = shape[i] - shape[i - 1]; - else n = shape[i + 1] - shape[i - 1]; - n.Set(n.y, -n.x); - n.Normalize(); - - for (int j = 0; j <= numSegs; ++j, ++vi) { - var d = dirs[j]; - var dp = d * p.x + Vector3.up * p.y; - var dn = d * n.x + Vector3.up * n.y; - if (i == 0 || i == shape.Length - 1) verts[vi] = dp + d * sideThickness; - else verts[vi] = dp + dn * sideThickness; - verts[vi + numMainVerts] = dp; - - float v = (p.z - noseV0) * noseVScale; - float uo = j * segOMappingScale + segOMappingOfs; - float ui = (numSegs - j) * segIMappingScale + segIMappingOfs; - if (v > 0 && v < 1) { - float us = 1 - v; - uo = (uo - oCenter) * us + oCenter; - ui = (ui - iCenter) * us + iCenter; - } - - uv[vi].Set(uo, p.z); - uv[vi + numMainVerts].Set(ui, p.z); - - norm[vi] = dn; - norm[vi + numMainVerts] = -dn; - tang[vi].Set(-d.z, 0, d.x, 0); - tang[vi + numMainVerts].Set(d.z, 0, -d.x, 0); - } - } - - // side strip vertices - float stripScale = Mathf.Abs(stripMapping.y - stripMapping.x) / (sideThickness * mappingScale.y); - - vi = numMainVerts * 2; - float o = 0; - for (int i = 0; i < shape.Length; ++i, vi += 2) { - int si = i * (numSegs + 1); - - var d = dirs[0]; - verts[vi] = verts[si]; - uv[vi].Set(stripU0, o); - norm[vi].Set(d.z, 0, -d.x); - - verts[vi + 1] = verts[si + numMainVerts]; - uv[vi + 1].Set(stripU1, o); - norm[vi + 1] = norm[vi]; - tang[vi] = tang[vi + 1] = (verts[vi + 1] - verts[vi]).normalized; - - if (i + 1 < shape.Length) o += ((Vector2)shape[i + 1] - (Vector2)shape[i]).magnitude * stripScale; - } - - vi += numSideVerts - 2; - for (int i = shape.Length - 1; i >= 0; --i, vi -= 2) { - int si = i * (numSegs + 1) + numSegs; - if (i == shape.Length - 1 && inlineHeight <= 0) si = numMainVerts - 1; - - var d = dirs[numSegs]; - verts[vi] = verts[si]; - uv[vi].Set(stripU0, o); - norm[vi].Set(-d.z, 0, d.x); - - verts[vi + 1] = verts[si + numMainVerts]; - uv[vi + 1].Set(stripU1, o); - norm[vi + 1] = norm[vi]; - tang[vi] = tang[vi + 1] = (verts[vi + 1] - verts[vi]).normalized; - - if (i > 0) o += ((Vector2)shape[i] - (Vector2)shape[i - 1]).magnitude * stripScale; - } - - // ring vertices - vi = numMainVerts * 2 + numSideVerts * 2; - o = 0; - for (int j = numSegs; j >= 0; --j, vi += 2, o += ringSegLen * stripScale) { - verts[vi] = verts[j]; - uv[vi].Set(stripU0, o); - norm[vi] = -Vector3.up; - - verts[vi + 1] = verts[j + numMainVerts]; - uv[vi + 1].Set(stripU1, o); - norm[vi + 1] = -Vector3.up; - tang[vi] = tang[vi + 1] = (verts[vi + 1] - verts[vi]).normalized; - } - - if (inlineHeight > 0) { - // top ring vertices - o = 0; - int si = (shape.Length - 1) * (numSegs + 1); - for (int j = 0; j <= numSegs; ++j, vi += 2, o += topRingSegLen * stripScale) { - verts[vi] = verts[si + j]; - uv[vi].Set(stripU0, o); - norm[vi] = Vector3.up; - - verts[vi + 1] = verts[si + j + numMainVerts]; - uv[vi + 1].Set(stripU1, o); - norm[vi + 1] = Vector3.up; - tang[vi] = tang[vi + 1] = (verts[vi + 1] - verts[vi]).normalized; - } - } - - // set vertex data to mesh - for (int i = 0; i < totalVerts; ++i) tang[i].w = 1; - m.vertices = verts; - m.uv = uv; - m.normals = norm; - m.tangents = tang; - - m.uv2 = null; - m.colors32 = null; - - var tri = new int[totalFaces * 3]; - - // main faces - vi = 0; - int ti1 = 0, ti2 = numMainFaces * 3; - for (int i = 0; i < shape.Length - (inlineHeight <= 0 ? 2 : 1); ++i, ++vi) { - p = shape[i]; - for (int j = 0; j < numSegs; ++j, ++vi) { - tri[ti1++] = vi; - tri[ti1++] = vi + 1 + numSegs + 1; - tri[ti1++] = vi + 1; - - tri[ti1++] = vi; - tri[ti1++] = vi + numSegs + 1; - tri[ti1++] = vi + 1 + numSegs + 1; - - tri[ti2++] = numMainVerts + vi; - tri[ti2++] = numMainVerts + vi + 1; - tri[ti2++] = numMainVerts + vi + 1 + numSegs + 1; - - tri[ti2++] = numMainVerts + vi; - tri[ti2++] = numMainVerts + vi + 1 + numSegs + 1; - tri[ti2++] = numMainVerts + vi + numSegs + 1; - } - } - - if (inlineHeight <= 0) { - // main tip faces - for (int j = 0; j < numSegs; ++j, ++vi) { - tri[ti1++] = vi; - tri[ti1++] = numMainVerts - 1; - tri[ti1++] = vi + 1; - - tri[ti2++] = numMainVerts + vi; - tri[ti2++] = numMainVerts + vi + 1; - tri[ti2++] = numMainVerts + numMainVerts - 1; - } - } - - // side strip faces - vi = numMainVerts * 2; - ti1 = numMainFaces * 2 * 3; - ti2 = ti1 + numSideFaces * 3; - for (int i = 0; i < shape.Length - 1; ++i, vi += 2) { - tri[ti1++] = vi; - tri[ti1++] = vi + 1; - tri[ti1++] = vi + 3; - - tri[ti1++] = vi; - tri[ti1++] = vi + 3; - tri[ti1++] = vi + 2; - - tri[ti2++] = numSideVerts + vi; - tri[ti2++] = numSideVerts + vi + 3; - tri[ti2++] = numSideVerts + vi + 1; - - tri[ti2++] = numSideVerts + vi; - tri[ti2++] = numSideVerts + vi + 2; - tri[ti2++] = numSideVerts + vi + 3; - } - - // ring faces - vi = numMainVerts * 2 + numSideVerts * 2; - ti1 = (numMainFaces + numSideFaces) * 2 * 3; - for (int j = 0; j < numSegs; ++j, vi += 2) { - tri[ti1++] = vi; - tri[ti1++] = vi + 1; - tri[ti1++] = vi + 3; - - tri[ti1++] = vi; - tri[ti1++] = vi + 3; - tri[ti1++] = vi + 2; - } - - if (inlineHeight > 0) { - // top ring faces - vi += 2; - for (int j = 0; j < numSegs; ++j, vi += 2) { - tri[ti1++] = vi; - tri[ti1++] = vi + 1; - tri[ti1++] = vi + 3; - - tri[ti1++] = vi; - tri[ti1++] = vi + 3; - tri[ti1++] = vi + 2; - } - } - - m.triangles = tri; - - if (!HighLogic.LoadedSceneIsEditor) m.Optimize(); - - StartCoroutine(PFUtils.updateDragCubeCoroutine(part, 1)); - } - } - - - //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ// - - -} // namespace - diff --git a/Source/NodeNumberTweaker.cs b/Source/NodeNumberTweaker.cs deleted file mode 100644 index baa9666..0000000 --- a/Source/NodeNumberTweaker.cs +++ /dev/null @@ -1,301 +0,0 @@ -// Procedural Fairings plug-in by Alexey Volynskov -// Licensed under CC BY 3.0 terms: http://creativecommons.org/licenses/by/3.0/ -using System; -using System.Collections.Generic; -using System.Text; -using UnityEngine; - - -namespace Keramzit -{ - - - - public class KzNodeNumberTweaker : PartModule - { - [KSPField] public string nodePrefix = "bottom"; - [KSPField] public int maxNumber = 0; - - [KSPField(guiActiveEditor = true, guiName = "Fairing Nodes")] - [UI_FloatRange(minValue = 1, maxValue = 8, stepIncrement = 1)] - public float uiNumNodes = 2; - - [KSPField(isPersistant = true)] - public int numNodes = 2; - private int numNodesBefore = 0; - - - [KSPField(isPersistant = true, guiActiveEditor = true, guiName = "Node offset", guiFormat = "S4", guiUnits = "m")] - [UI_FloatEdit(sigFigs = 3, unit = "m", minValue = 0.1f, maxValue = 5, incrementLarge = 0.625f, incrementSmall = 0.125f, incrementSlide = 0.001f)] - public float radius = 1.25f; - - [KSPField] public float radiusStepLarge = 0.625f; - [KSPField] public float radiusStepSmall = 0.125f; - - - [KSPField] public bool shouldResizeNodes = true; - - - protected float oldRadius = -1000; - protected bool justLoaded = false; - - - public override string GetInfo() - { - return "Max. Nodes: " + maxNumber; - } - - - //[KSPEvent(name="IncrementNodes", active=true, guiActive=false, guiActiveEditor=true, - // guiActiveUnfocused=false, guiName="More Fairing Nodes")] - //public void IncrementNodes() - //{ - // if (numNodes>=maxNumber) return; - // if (checkNodeAttachments()) return; - - // ++numNodes; - // updateNodes(); - //} - - - //[KSPEvent(name = "DecrementNodes", active = true, guiActive = false, guiActiveEditor = true, - // guiActiveUnfocused = false, guiName = "Fewer Fairing Nodes")] - //public void DecrementNodes() - //{ - // if (numNodes <= 1) return; - // if (checkNodeAttachments()) return; - - // --numNodes; - // updateNodes(); - //} - - [KSPField(isPersistant = true, guiActiveEditor = true, guiName = "Interstage Nodes")] - [UI_Toggle(disabledText = "Off", enabledText = "On")] - public bool showInterstageNodes = true; - - - - - - - - public virtual void FixedUpdate() - { - if (radius != oldRadius) { - oldRadius = radius; - updateNodePositions(); - } - - justLoaded = false; - } - - - public void Update() - { - if (HighLogic.LoadedSceneIsEditor) { - if ((int)uiNumNodes != numNodesBefore) { - if (checkNodeAttachments()) { - uiNumNodes = numNodesBefore; - } - else { - numNodes = (int)uiNumNodes; - numNodesBefore = numNodes; - updateNodes(); - - bool removed = false; - - for (int i = numNodes + 1; i <= maxNumber; ++i) { - var node = findNode(i); - if (node == null) - continue; - - // fix for ghost node when inserting a new pf base in VAB. - // do not delete unused nodes, move them away instead - // be careful to check references to maximum number of nodes - // mentioned elsewhere retreived from 'Findattachnodes("connect")' ! - // slightly hacky, but works. - //part.attachNodes.Remove(node); - HideUnusedNode(node); - removed = true; - } - - if (removed) { - var fbase = part.GetComponent(); - if (fbase) { fbase.needShapeUpdate = true; fbase.updateDelay = 0; } - } - } - } - - - } - } - - // slightly hacky.. - // but it removes the ghost nodes - private void HideUnusedNode(AttachNode node) - { - node.position.x = 10000; - } - - - public override void OnStart(StartState state) - { - // print("NNT: OnStart "+state); - base.OnStart(state); - if (state == StartState.None) return; - - ((UI_FloatEdit)Fields["radius"].uiControlEditor).incrementLarge = radiusStepLarge; - ((UI_FloatEdit)Fields["radius"].uiControlEditor).incrementSmall = radiusStepSmall; - - if (!shouldResizeNodes) { - Fields["radius"].guiActiveEditor = false; - } - - // hide interstage toggle if there are no interstage nodes - var nodes = part.FindAttachNodes("interstage"); - if (nodes == null) { - this.Fields["showInterstageNodes"].guiActiveEditor = false; - } - - // change gui text if there are no fairing connect nodes - nodes = part.FindAttachNodes("connect"); - if (nodes == null) { - this.Fields["uiNumNodes"].guiName = "Side Nodes"; - } - - ((UI_FloatRange)Fields["uiNumNodes"].uiControlEditor).maxValue = maxNumber; - uiNumNodes = numNodes; - numNodesBefore = numNodes; - - - updateNodes(); - } - - - public override void OnLoad(ConfigNode cfg) - { - // print("NNT: OnLoad"); - base.OnLoad(cfg); - justLoaded = true; - - uiNumNodes = numNodes; - numNodesBefore = numNodes; - - if (HighLogic.LoadedSceneIsEditor || HighLogic.LoadedSceneIsFlight) updateNodes(); - } - - - void updateNodes() - { - addRemoveNodes(); - updateNodePositions(); - } - - - string nodeName(int i) { return string.Format("{0}{1:d2}", nodePrefix, i); } - AttachNode findNode(int i) { return part.FindAttachNode(nodeName(i)); } - - - bool checkNodeAttachments() - { - for (int i = 1; i <= maxNumber; ++i) { - var node = findNode(i); - if (node != null && node.attachedPart != null) { - EditorScreenMessager.showMessage("Please detach parts before changing number of nodes", 1); - return true; - } - } - - return false; - } - - - void addRemoveNodes() - { - // print("NNT: setting nodes to "+numNodes); - part.stackSymmetry = numNodes - 1; - - float y = 0; - bool gotY = false; - int nodeSize = 0; - Vector3 dir = Vector3.up; - - int i; - for (i = 1; i <= maxNumber; ++i) { - var node = findNode(i); - if (node == null) continue; - y = node.position.y; - nodeSize = node.size; - dir = node.orientation; - gotY = true; - break; - } - - if (!gotY) { - var node = part.FindAttachNode("bottom"); - if (node != null) y = node.position.y; - } - - for (i = 1; i <= numNodes; ++i) { - var node = findNode(i); - if (node != null) continue; - - // create node - node = new AttachNode(); - node.id = nodeName(i); - node.owner = part; - node.nodeType = AttachNode.NodeType.Stack; - node.position = new Vector3(0, y, 0); - node.orientation = dir; - node.originalPosition = node.position; - node.originalOrientation = node.orientation; - node.size = nodeSize; - part.attachNodes.Add(node); - } - - for (; i <= maxNumber; ++i) { - var node = findNode(i); - if (node == null) continue; - - if (HighLogic.LoadedSceneIsEditor) - node.position.x = 10000; //new Vector3(10000, 0, 0); - else - part.attachNodes.Remove(node); - } - - var fbase = part.GetComponent(); - if (fbase) fbase.needShapeUpdate = true; - } - - - void updateNodePositions() - { - float d = Mathf.Sin(Mathf.PI / numNodes) * radius * 2; - int size = Mathf.RoundToInt(d / (radiusStepLarge * 2)); - - for (int i = 1; i <= numNodes; ++i) { - var node = findNode(i); - if (node == null) continue; - - float a = Mathf.PI * 2 * (i - 1) / numNodes; - node.position.x = Mathf.Cos(a) * radius; - node.position.z = Mathf.Sin(a) * radius; - if (shouldResizeNodes) node.size = size; - - if (!justLoaded) PFUtils.updateAttachedPartPos(node, part); - } - - for (int i = numNodes + 1; i <= maxNumber; ++i) { - var node = findNode(i); - if (node == null) continue; - - node.position.x = 10000; //new Vector3(10000, 0, 0); - } - - - } - } - - -} // namespace - diff --git a/Source/PFKMJoint.cs b/Source/PFKMJoint.cs deleted file mode 100644 index 28340ea..0000000 --- a/Source/PFKMJoint.cs +++ /dev/null @@ -1,433 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace Keramzit -{ - public class PFKMJoints : PartModule - { - [KSPField(isPersistant = true)] - public float breakingForce = 500000f; - - [KSPField(guiActive = true, guiName = "View Joints")] - [UI_Toggle(disabledText = "Off", enabledText = "On")] - public bool viewJoints = false; - - private float w1 = 0.05f; - - private float w2 = 0.15f; - - private List jointLines = new List(); - - private bool morejointsadded = false; - - private Part bottomNodePart = null; - - private List nodeParts = new List(); - - public PFKMJoints() - { - } - - private void AddMoreJoints() - { - int i; - AttachNode attachNode; - if (!this.morejointsadded) { - AttachNode attachNode1 = base.part.FindAttachNode("bottom"); - AttachNode[] attachNodeArray = base.part.FindAttachNodes("interstage"); - AttachNode[] attachNodeArray1 = base.part.FindAttachNodes("top"); - string[] _vessel = new string[] { "[ProceduralFairings] Adding Joints to Vessel: ", base.vessel.vesselName, " (Launch ID: ", base.part.launchID.ToString(), ") (GUID: ", base.vessel.id.ToString(), ")" }; - Debug.Log(string.Concat(_vessel)); - _vessel = new string[] { "[ProceduralFairings] For PF Part: ", base.part.name, " (", base.part.craftID.ToString(), ")" }; - Debug.Log(string.Concat(_vessel)); - Part part = null; - if ((attachNode1 == null ? false : attachNode1.attachedPart != null)) { - part = attachNode1.attachedPart; - this.bottomNodePart = part; - this.addStrut(part, base.part, Vector3.zero); - _vessel = new string[] { "[ProceduralFairings] Bottom Part: ", part.name, " (", part.craftID.ToString(), ")" }; - Debug.Log(string.Concat(_vessel)); - } - Debug.Log("[ProceduralFairings] Top Parts:"); - if (attachNodeArray1 != null) { - for (i = 0; i < (int)attachNodeArray1.Length; i++) { - attachNode = attachNodeArray1[i]; - if (!(attachNode.attachedPart == null)) { - if (part != null) { - this.AddPartJoint(attachNode.attachedPart, part, attachNode.FindOpposingNode(), attachNode1.FindOpposingNode()); - } - this.addStrut(attachNode.attachedPart, base.part, Vector3.zero); - this.nodeParts.Add(attachNode.attachedPart); - _vessel = new string[] { "[ProceduralFairings] ", attachNode.attachedPart.name, " (", attachNode.attachedPart.craftID.ToString(), ")" }; - Debug.Log(string.Concat(_vessel)); - } - } - } - if (attachNodeArray != null) { - for (i = 0; i < (int)attachNodeArray.Length; i++) { - attachNode = attachNodeArray[i]; - if (!(attachNode.attachedPart == null)) { - if (part != null) { - this.AddPartJoint(attachNode.attachedPart, part, attachNode.FindOpposingNode(), attachNode1.FindOpposingNode()); - } - this.addStrut(attachNode.attachedPart, base.part, Vector3.zero); - this.nodeParts.Add(attachNode.attachedPart); - _vessel = new string[] { "[ProceduralFairings] ", attachNode.attachedPart.name, " (", attachNode.attachedPart.craftID.ToString(), ")" }; - Debug.Log(string.Concat(_vessel)); - } - } - } - this.morejointsadded = true; - } - } - - private void AddPartJoint(Part p, Part pp, AttachNode pnode, AttachNode ppnode) - { - PartJoint partJoint = PartJoint.Create(p, pp, pnode, ppnode, 0); - partJoint.SetBreakingForces(this.breakingForce, this.breakingForce); - PartJoint partJoint1 = p.gameObject.AddComponent(); - partJoint1 = partJoint; - } - - private ConfigurableJoint addStrut(Part p, Part pp, Vector3 pos) - { - ConfigurableJoint configurableJoint; - if (!(p == pp)) { - Rigidbody rigidbody = pp.Rigidbody; - if ((rigidbody == null ? false : !(rigidbody == p.Rigidbody))) { - ConfigurableJoint configurableJoint1 = p.gameObject.AddComponent(); - configurableJoint1.xMotion = 0; - configurableJoint1.yMotion = 0; - configurableJoint1.zMotion = 0; - configurableJoint1.angularXMotion = 0; - configurableJoint1.angularYMotion = 0; - configurableJoint1.angularZMotion = 0; - configurableJoint1.projectionDistance = 0.1f; - configurableJoint1.projectionAngle = 5f; - configurableJoint1.breakForce = this.breakingForce; - configurableJoint1.breakTorque = this.breakingForce; - configurableJoint1.connectedBody = rigidbody; - configurableJoint1.targetPosition = pos; - configurableJoint = configurableJoint1; - } - else { - configurableJoint = null; - } - } - else { - configurableJoint = null; - } - return configurableJoint; - } - - private void ClearJointLines() - { - for (int i = 0; i < this.jointLines.Count; i++) { - UnityEngine.Object.Destroy(this.jointLines[i].gameObject); - } - this.jointLines.Clear(); - } - - public virtual void FixedUpdate() - { - if (!this.morejointsadded) { - if ((!FlightGlobals.ready || base.vessel.packed ? false : base.vessel.loaded)) { - this.AddMoreJoints(); - } - } - } - - private LineRenderer JointLine(Vector3 posp, Vector3 pospp, Color col, float width) - { - LineRenderer lineRenderer = this.makeLineRenderer("JointLine", col, width); - lineRenderer.SetVertexCount(2); - lineRenderer.SetPosition(0, posp); - lineRenderer.SetPosition(1, pospp); - lineRenderer.useWorldSpace = true; - return lineRenderer; - } - - public void ListJoints() - { - int j; - string[] _name; - float _breakForce; - Vector3 _anchor; - string str; - string str1; - this.ClearJointLines(); - List activeVessel = FlightGlobals.ActiveVessel.parts; - for (int i = 0; i < activeVessel.Count; i++) { - ConfigurableJoint[] components = activeVessel[i].gameObject.GetComponents(); - if (components != null) { - for (j = 0; j < (int)components.Length; j++) { - ConfigurableJoint configurableJoint = components[j]; - _name = new string[18]; - _name[0] = "[PF] , "; - _name[1] = activeVessel[i].name; - _name[2] = ", "; - _name[3] = (configurableJoint.connectedBody == null ? "" : configurableJoint.connectedBody.name); - _name[4] = ", "; - _breakForce = configurableJoint.breakForce; - _name[5] = _breakForce.ToString(); - _name[6] = ", "; - _breakForce = configurableJoint.breakTorque; - _name[7] = _breakForce.ToString(); - _name[8] = ", "; - _anchor = configurableJoint.anchor; - _name[9] = _anchor.ToString(); - _name[10] = ", "; - _anchor = configurableJoint.connectedAnchor; - _name[11] = _anchor.ToString(); - _name[12] = ", "; - string[] strArrays = _name; - if (configurableJoint.connectedBody == null) { - str1 = "--"; - } - else { - _anchor = activeVessel[i].transform.position - configurableJoint.connectedBody.position; - str1 = _anchor.ToString(); - } - strArrays[13] = str1; - _name[14] = ", "; - _breakForce = configurableJoint.linearLimitSpring.damper; - _name[15] = _breakForce.ToString("F2"); - _name[16] = ", "; - _breakForce = configurableJoint.linearLimitSpring.spring; - _name[17] = _breakForce.ToString("F2"); - Debug.Log(string.Concat(_name)); - } - } - PartJoint[] partJointArray = activeVessel[i].gameObject.GetComponents(); - if (partJointArray != null) { - for (j = 0; j < (int)partJointArray.Length; j++) { - PartJoint partJoint = partJointArray[j]; - if ((partJoint.Host != null ? true : !(partJoint.Target == null))) { - _name = new string[] { "[PF] , ", partJoint.Host.name, ", ", null, null, null, null, null, null, null, null }; - _name[3] = (partJoint.Target == null ? "" : partJoint.Target.name); - string[] strArrays1 = _name; - if (partJoint.Joint == null) { - int count = partJoint.joints.Count; - str = string.Concat(" (", count.ToString(), ")"); - } - else { - _breakForce = partJoint.Joint.breakForce; - string str2 = _breakForce.ToString(); - _breakForce = partJoint.Joint.breakTorque; - str = string.Concat(", ", str2, ", ", _breakForce.ToString()); - } - strArrays1[4] = str; - _name[5] = ", "; - _breakForce = partJoint.stiffness; - _name[6] = _breakForce.ToString("F2"); - _name[7] = ", "; - _anchor = partJoint.HostAnchor; - _name[8] = _anchor.ToString(); - _name[9] = ", "; - _anchor = partJoint.TgtAnchor; - _name[10] = _anchor.ToString(); - Debug.Log(string.Concat(_name)); - } - else { - Debug.Log("[PF] , , "); - } - if (partJoint.Target) { - AttachNode attachNode = activeVessel[i].FindAttachNodeByPart(partJoint.Target); - if (attachNode != null) { - object[] objArray = new object[] { "[PF] , ", partJoint.Host.name, ", ", partJoint.Target.name, ", ", attachNode.breakingForce.ToString(), ", ", attachNode.breakingTorque.ToString(), ", ", attachNode.contactArea.ToString("F2"), ", ", attachNode.attachMethod, ", ", attachNode.rigid.ToString(), ", ", attachNode.radius.ToString("F2") }; - Debug.Log(string.Concat(objArray)); - AttachNode attachNode1 = attachNode.FindOpposingNode(); - if ((attachNode1 == null ? false : attachNode1.owner != null)) { - objArray = new object[] { "[PF] , ", attachNode1.owner.name, ", ", (attachNode1.attachedPart != null ? attachNode1.attachedPart.name : ""), ", ", attachNode1.breakingForce.ToString(), ", ", attachNode1.breakingTorque.ToString(), ", ", attachNode1.contactArea.ToString("F2"), ", ", attachNode1.attachMethod, ", ", attachNode1.rigid.ToString(), ", ", attachNode1.radius.ToString("F2") }; - Debug.Log(string.Concat(objArray)); - } - } - } - } - } - FixedJoint[] fixedJointArray = activeVessel[i].gameObject.GetComponents(); - if (fixedJointArray != null) { - for (j = 0; j < (int)fixedJointArray.Length; j++) { - FixedJoint fixedJoint = fixedJointArray[j]; - _name = new string[] { "[PF] , ", fixedJoint.name, ", ", null, null, null, null, null, null, null, null, null }; - _name[3] = (fixedJoint.connectedBody == null ? "" : fixedJoint.connectedBody.name); - _name[4] = ", "; - _breakForce = fixedJoint.breakForce; - _name[5] = _breakForce.ToString(); - _name[6] = ", "; - _breakForce = fixedJoint.breakTorque; - _name[7] = _breakForce.ToString(); - _name[8] = ", "; - _anchor = fixedJoint.anchor; - _name[9] = _anchor.ToString(); - _name[10] = ", "; - _anchor = fixedJoint.connectedAnchor; - _name[11] = _anchor.ToString(); - Debug.Log(string.Concat(_name)); - } - } - } - } - - private LineRenderer makeLineRenderer(string name, Color color, float wd) - { - GameObject gameObject = new GameObject(name); - gameObject.transform.parent = base.part.transform; - gameObject.transform.localPosition = Vector3.zero; - gameObject.transform.localRotation = Quaternion.identity; - LineRenderer lineRenderer = gameObject.AddComponent(); - lineRenderer.useWorldSpace = true; - lineRenderer.material = new Material(Shader.Find("Particles/Additive")); - lineRenderer.SetColors(color, color); - lineRenderer.SetWidth(wd, wd); - lineRenderer.SetVertexCount(0); - return lineRenderer; - } - - public void OnDestroy() - { - this.viewJoints = false; - this.ClearJointLines(); - GameEvents.onGameSceneLoadRequested.Remove(new EventData.OnEvent(OnGameSceneLoadRequested)); - GameEvents.onVesselWasModified.Remove(new EventData.OnEvent(OnVesselModified)); - GameEvents.onPartJointBreak.Remove(new EventData.OnEvent(OnPartJointBreak)); - GameEvents.onVesselGoOffRails.Remove(new EventData.OnEvent(OnVesselGoOffRails)); - } - - private void OnGameSceneLoadRequested(GameScenes scene) - { - if ((scene == GameScenes.FLIGHT ? false : this.viewJoints)) { - this.viewJoints = false; - this.ClearJointLines(); - } - } - - private void OnPartJointBreak(PartJoint pj, float value) - { - Part host; - int i; - bool flag; - if (!(pj.Host == base.part)) { - if (pj.Target == base.part) { - host = pj.Host; - if (this.nodeParts.Contains(host)) { - if (this.bottomNodePart != null) { - this.RemoveJoints(host, this.bottomNodePart); - } - this.RemoveJoints(host, base.part); - flag = this.nodeParts.Remove(host); - } - else if (host == this.bottomNodePart) { - for (i = 0; i < this.nodeParts.Count; i++) { - this.RemoveJoints(this.nodeParts[i], this.bottomNodePart); - } - this.RemoveJoints(this.bottomNodePart, base.part); - } - return; - } - return; - } - else { - host = pj.Target; - } - if (this.nodeParts.Contains(host)) { - if (this.bottomNodePart != null) { - this.RemoveJoints(host, this.bottomNodePart); - } - this.RemoveJoints(host, base.part); - flag = this.nodeParts.Remove(host); - } - else if (host == this.bottomNodePart) { - for (i = 0; i < this.nodeParts.Count; i++) { - this.RemoveJoints(this.nodeParts[i], this.bottomNodePart); - } - this.RemoveJoints(this.bottomNodePart, base.part); - } - } - - public override void OnStart(PartModule.StartState state) - { - base.OnStart(state); - UI_Toggle _uiControlFlight = (UI_Toggle)base.Fields["viewJoints"].uiControlFlight; - _uiControlFlight.onFieldChanged = (Callback)Delegate.Combine(_uiControlFlight.onFieldChanged, new Callback(UIviewJoints_changed)); - GameEvents.onGameSceneLoadRequested.Add(new EventData.OnEvent(OnGameSceneLoadRequested)); - GameEvents.onVesselWasModified.Add(new EventData.OnEvent(OnVesselModified)); - GameEvents.onPartJointBreak.Add(new EventData.OnEvent(OnPartJointBreak)); - GameEvents.onVesselGoOffRails.Add(new EventData.OnEvent(OnVesselGoOffRails)); - } - - private void OnVesselGoOffRails(Vessel v) - { - if ((v == null ? true : this == null)) { - } - } - - private void OnVesselModified(Vessel v) - { - if (v == base.vessel) { - if (this.viewJoints) { - this.ViewJoints(); - } - } - } - - private void RemoveJoints(Part p, Part pp) - { - if ((p == null || p.Rigidbody == null || pp == null ? false : !(pp.Rigidbody == null))) { - ConfigurableJoint[] components = p.gameObject.GetComponents(); - for (int i = 0; i < (int)components.Length; i++) { - ConfigurableJoint configurableJoint = components[i]; - if (configurableJoint.connectedBody == pp.Rigidbody) { - try { - UnityEngine.Object.Destroy(configurableJoint); - } - catch (Exception exception1) { - Exception exception = exception1; - string[] str = new string[] { "[PF] RemoveJoint Anomaly (", p.ToString(), ", ", pp.ToString(), "): ", exception.Message }; - Debug.Log(string.Concat(str)); - } - } - } - } - } - - private void UIviewJoints_changed(BaseField bf, object obj) - { - if (this.viewJoints) { - this.ListJoints(); - this.ViewJoints(); - } - else { - this.ClearJointLines(); - } - } - - public void ViewJoints() - { - this.ClearJointLines(); - List activeVessel = FlightGlobals.ActiveVessel.parts; - for (int i = 0; i < activeVessel.Count; i++) { - ConfigurableJoint[] components = activeVessel[i].gameObject.GetComponents(); - if (components != null) { - for (int j = 0; j < (int)components.Length; j++) { - ConfigurableJoint configurableJoint = components[j]; - if (!(configurableJoint.connectedBody == null)) { - Vector3 vector3 = new Vector3(0f, 5f, 0f); - Vector3 vector31 = new Vector3(0.25f, 0f, 0f); - Vector3 _position = activeVessel[i].transform.position + vector3; - Vector3 _position1 = configurableJoint.connectedBody.position + vector3; - Vector3 _position2 = (activeVessel[i].transform.position + (activeVessel[i].transform.rotation * configurableJoint.anchor)) + vector3; - Vector3 vector32 = (configurableJoint.connectedBody.position + (configurableJoint.connectedBody.rotation * configurableJoint.connectedAnchor)) + vector3; - this.jointLines.Add(this.JointLine(_position, _position1, Color.blue, this.w1)); - this.jointLines.Add(this.JointLine(_position2, vector32 + vector31, Color.yellow, this.w2)); - this.jointLines.Add(this.JointLine(_position, _position2, Color.gray, 0.03f)); - this.jointLines.Add(this.JointLine(_position1, vector32, Color.gray, 0.03f)); - } - } - } - } - } - } -} - diff --git a/Source/PayloadScan.cs b/Source/PayloadScan.cs deleted file mode 100644 index 560be55..0000000 --- a/Source/PayloadScan.cs +++ /dev/null @@ -1,179 +0,0 @@ -// Procedural Fairings plug-in by Alexey Volynskov -// Licensed under CC BY 3.0 terms: http://creativecommons.org/licenses/by/3.0/ -using System; -using System.Collections.Generic; -using System.Text; -using UnityEngine; - - -namespace Keramzit -{ - - - //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ// - - - struct PayloadScan - { - public List profile; - public List payload; - public HashSet hash; - - public List targets; - - public Matrix4x4 w2l; - - public float ofs, verticalStep, extraRadius; - - public int nestedBases; - - - public PayloadScan(Part p, float vs, float er) - { - profile = new List(); - payload = new List(); - targets = new List(); - hash = new HashSet(); - hash.Add(p); - w2l = p.transform.worldToLocalMatrix; - ofs = 0; - verticalStep = vs; - extraRadius = er; - nestedBases = 0; - } - - - public void addPart(Part p, Part prevPart) - { - if (p == null || hash.Contains(p)) return; - hash.Add(p); - - if (p.GetComponent() != null) return; - if (p == prevPart.parent && prevPart.srfAttachNode.attachedPart == p) return; - - // check for another fairing base - if (p.GetComponent() != null - && p.GetComponent() == null) { - AttachNode node = p.FindAttachNode("top"); - if (node != null && node.attachedPart == prevPart) { - // reversed base - potential inline fairing target - if (nestedBases <= 0) { targets.Add(p); return; } - else --nestedBases; - } - else ++nestedBases; - } - - payload.Add(p); - } - - - public void addPayloadEdge(Vector3 v0, Vector3 v1) - { - float r0 = Mathf.Sqrt(v0.x * v0.x + v0.z * v0.z) + extraRadius; - float r1 = Mathf.Sqrt(v1.x * v1.x + v1.z * v1.z) + extraRadius; - - float y0 = (v0.y - ofs) / verticalStep; - float y1 = (v1.y - ofs) / verticalStep; - - if (y0 > y1) { - float tmp; - tmp = y0; y0 = y1; y1 = tmp; - tmp = r0; r0 = r1; r1 = tmp; - } - - int h0 = Mathf.FloorToInt(y0); - int h1 = Mathf.FloorToInt(y1); - if (h1 < 0) return; - - - - if (h1 >= profile.Count) { - float[] farray = new float[h1 - profile.Count + 1]; - for (int i = 0; i < farray.Length; i++) - farray[i] = 0; - - profile.AddRange(farray); - } - - if (h0 >= 0) profile[h0] = Mathf.Max(profile[h0], r0); - profile[h1] = Mathf.Max(profile[h1], r1); - - - if (h0 != h1) { - float k = (r1 - r0) / (y1 - y0); - float b = r0 + k * (h0 + 1 - y0); - float maxR = Mathf.Max(r0, r1); - - for (int h = Math.Max(h0, 0); h < h1; ++h) { - float r = Mathf.Min(k * (h - h0) + b, maxR); - profile[h] = Mathf.Max(profile[h], r); - profile[h + 1] = Mathf.Max(profile[h + 1], r); - } - } - } - - - public void addPayload(Bounds box, Matrix4x4 boxTm) - { - Matrix4x4 m = w2l * boxTm; - - Vector3 p0 = box.min, p1 = box.max; - var verts = new Vector3[8]; - for (int i = 0; i < 8; ++i) - verts[i] = m.MultiplyPoint3x4(new Vector3( - (i & 1) != 0 ? p1.x : p0.x, - (i & 2) != 0 ? p1.y : p0.y, - (i & 4) != 0 ? p1.z : p0.z)); - - addPayloadEdge(verts[0], verts[1]); - addPayloadEdge(verts[2], verts[3]); - addPayloadEdge(verts[4], verts[5]); - addPayloadEdge(verts[6], verts[7]); - - addPayloadEdge(verts[0], verts[2]); - addPayloadEdge(verts[1], verts[3]); - addPayloadEdge(verts[4], verts[6]); - addPayloadEdge(verts[5], verts[7]); - - addPayloadEdge(verts[0], verts[4]); - addPayloadEdge(verts[1], verts[5]); - addPayloadEdge(verts[2], verts[6]); - addPayloadEdge(verts[3], verts[7]); - } - - - public void addPayload(Collider c) - { - var mc = c as MeshCollider; - var bc = c as BoxCollider; - if (mc) { - // addPayload(mc.sharedMesh.bounds, - // c.GetComponent().localToWorldMatrix); - var m = w2l * mc.transform.localToWorldMatrix; - var verts = mc.sharedMesh.vertices; - var faces = mc.sharedMesh.triangles; - for (int i = 0; i < faces.Length; i += 3) { - var v0 = m.MultiplyPoint3x4(verts[faces[i]]); - var v1 = m.MultiplyPoint3x4(verts[faces[i + 1]]); - var v2 = m.MultiplyPoint3x4(verts[faces[i + 2]]); - addPayloadEdge(v0, v1); - addPayloadEdge(v1, v2); - addPayloadEdge(v2, v0); - } - } - else if (bc) - addPayload(new Bounds(bc.center, bc.size), - bc.transform.localToWorldMatrix); - else { - // Debug.Log("generic collider "+c); - addPayload(c.bounds, Matrix4x4.identity); - } - } - } - - - //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ// - - -} // namespace - diff --git a/Source/ProcAdapter.cs b/Source/ProcAdapter.cs deleted file mode 100644 index 53eb030..0000000 --- a/Source/ProcAdapter.cs +++ /dev/null @@ -1,569 +0,0 @@ -// Procedural Fairings plug-in by Alexey Volynskov -// Licensed under CC BY 3.0 terms: http://creativecommons.org/licenses/by/3.0/ -using System; -using System.Collections.Generic; -using System.Text; -using UnityEngine; -using KSP.UI.Screens; - -namespace Keramzit -{ - - - //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ// - - - abstract class ProceduralAdapterBase : PartModule - { - [KSPField(isPersistant = true, guiActiveEditor = true, guiName = "Base", guiFormat = "S4", guiUnits = "m")] - [UI_FloatEdit(sigFigs = 3, unit = "m", minValue = 0.1f, maxValue = 5, incrementLarge = 1.25f, incrementSmall = 0.125f, incrementSlide = 0.001f)] - public float baseSize = 1.25f; - - [KSPField(isPersistant = true, guiActiveEditor = true, guiName = "Top", guiFormat = "S4", guiUnits = "m")] - [UI_FloatEdit(sigFigs = 3, unit = "m", minValue = 0.1f, maxValue = 5, incrementLarge = 1.25f, incrementSmall = 0.125f, incrementSlide = 0.001f)] - public float topSize = 1.25f; - - [KSPField(isPersistant = true, guiActiveEditor = true, guiName = "Height", guiFormat = "S4", guiUnits = "m")] - [UI_FloatEdit(sigFigs = 3, unit = "m", minValue = 0.1f, maxValue = 50, incrementLarge = 1.0f, incrementSmall = 0.1f, incrementSlide = 0.001f)] - public float height = 1; - - [KSPField] public string topNodeName = "top1"; - - [KSPField] public float diameterStepLarge = 1.25f; - [KSPField] public float diameterStepSmall = 0.125f; - - [KSPField] public float heightStepLarge = 1.0f; - [KSPField] public float heightStepSmall = 0.1f; - - public bool changed = true; - - abstract public float minHeight { get; } - - - private float lastBaseSize = -1000; - private float lastTopSize = -1000; - private float lastHeight = -1000; - - protected bool justLoaded = false; - - - public virtual void checkTweakables() - { - if (baseSize != lastBaseSize) { lastBaseSize = baseSize; changed = true; } - if (topSize != lastTopSize) { lastTopSize = topSize; changed = true; } - if (height != lastHeight) { lastHeight = height; changed = true; } - } - - public virtual void FixedUpdate() - { - checkTweakables(); - if (changed) - updateShape(); - justLoaded = false; - } - - public virtual void updateShape() - { - changed = false; - float topheight = 0; - float topnodeheight = 0; - - var node = part.FindAttachNode("bottom"); - if (node != null) node.size = Mathf.RoundToInt(baseSize / diameterStepLarge); - - node = part.FindAttachNode("top"); - if (node != null) { - node.size = Mathf.RoundToInt(baseSize / diameterStepLarge); - topheight = node.position.y; - } - - node = part.FindAttachNode(topNodeName); - if (node != null) { - node.position = new Vector3(0, height, 0); - node.size = Mathf.RoundToInt(topSize / diameterStepLarge); - if (!justLoaded) PFUtils.updateAttachedPartPos(node, part); - topnodeheight = height; - } - else - Debug.LogError("[ProceduralAdapterBase] No '" + topNodeName + "' node in part", this); - - var internodes = part.FindAttachNodes("interstage"); - if (internodes != null) { - var inc = (topnodeheight - topheight) / (internodes.Length / 2 + 1); - - for (int i = 0, j = 0; i < internodes.Length; i = i + 2) { - var height = topheight + (j + 1) * inc; - j++; - - node = internodes[i]; - node.position.y = height; - node.size = node.size = Mathf.RoundToInt(topSize / diameterStepLarge) - 1; - if (!justLoaded) PFUtils.updateAttachedPartPos(node, part); - - node = internodes[i + 1]; - node.position.y = height; - node.size = node.size = Mathf.RoundToInt(topSize / diameterStepLarge) - 1; - if (!justLoaded) PFUtils.updateAttachedPartPos(node, part); - } - } - } - - - - - public override void OnStart(StartState state) - { - base.OnStart(state); - - if (state == StartState.None) return; - - StartCoroutine(FireFirstChanged()); - - } - - public IEnumerator FireFirstChanged() - { - while(!(part.editorStarted || part.started)) { - yield return new WaitForFixedUpdate(); - } - //wait a little more - yield return new WaitForSeconds(.01f); - changed = true; - } - - public override void OnLoad(ConfigNode cfg) - { - base.OnLoad(cfg); - justLoaded = true; - changed = true; - } - - } - - - //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ// - - - class ProceduralFairingAdapter : ProceduralAdapterBase, IPartCostModifier, IPartMassModifier - { - [KSPField] public float sideThickness = 0.05f / 1.25f; - [KSPField] public Vector4 specificMass = new Vector4(0.005f, 0.011f, 0.009f, 0f); - [KSPField] public float specificBreakingForce = 6050; - [KSPField] public float specificBreakingTorque = 6050; - [KSPField] public float costPerTonne = 2000; - - [KSPField] public float dragAreaScale = 1; - - [KSPField(isPersistant = true)] - public bool topNodeDecouplesWhenFairingsGone = false; - - public bool isTopNodePartPresent = true; - public bool isFairingPresent = true; - - [KSPEvent(name = "decNoFairings", active = true, guiActive = true, guiActiveEditor = true, guiActiveUnfocused = true, guiName = "text")] - public void UIToggleTopNodeDecouple() - { - if (topNodeDecouplesWhenFairingsGone) - topNodeDecouplesWhenFairingsGone = false; - else - topNodeDecouplesWhenFairingsGone = true; - - UpdateUIdecNoFairingsText(topNodeDecouplesWhenFairingsGone); - } - - void UpdateUIdecNoFairingsText(bool flag) - { - if (flag) - this.Events["UIToggleTopNodeDecouple"].guiName = "Decouple when Fairing gone: Yes"; - else - this.Events["UIToggleTopNodeDecouple"].guiName = "Decouple when Fairing gone: No"; - } - - - public override float minHeight { get { return baseSize * 0.2f; } } - - public ModifierChangeWhen GetModuleCostChangeWhen() { return ModifierChangeWhen.FIXED; } - public ModifierChangeWhen GetModuleMassChangeWhen() { return ModifierChangeWhen.FIXED; } - - public float GetModuleCost(float defcost, ModifierStagingSituation sit) - { - return totalMass * costPerTonne - defcost; - } - - public float GetModuleMass(float defmass, ModifierStagingSituation sit) - { - return totalMass - defmass; - } - - public float calcSideThickness() - { - return Mathf.Min( - sideThickness * Mathf.Max(baseSize, topSize), - Mathf.Min(baseSize, topSize) * 0.25f); - } - - public float topRadius { get { return topSize * 0.5f - calcSideThickness(); } } - - [KSPField(isPersistant = true, guiActiveEditor = true, guiName = "Extra height", guiFormat = "S4", guiUnits = "m")] - [UI_FloatEdit(sigFigs = 3, unit = "m", minValue = 0, maxValue = 50, incrementLarge = 1.0f, incrementSmall = 0.1f, incrementSlide = 0.001f)] - public float extraHeight = 0; - - public bool engineFairingRemoved = false; - - [KSPField(isPersistant = false, guiActive = false, guiActiveEditor = true, guiName = "Mass")] - public string massDisplay; - - [KSPField(isPersistant = false, guiActive = false, guiActiveEditor = true, guiName = "Cost")] - public string costDisplay; - - - private bool limitsSet = false; - - - private float lastExtraHt = -1000; - - public override void checkTweakables() - { - base.checkTweakables(); - if (extraHeight != lastExtraHt) { lastExtraHt = extraHeight; changed = true; } - } - - private void RemoveTopPartJoints() - { - Part topPart = this.getTopPart(); - Part bottomPart = this.getBottomPart(); - if ((topPart == null ? false : !(bottomPart == null))) { - ConfigurableJoint[] components = topPart.gameObject.GetComponents(); - for (int i = 0; i < (int)components.Length; i++) { - ConfigurableJoint configurableJoint = components[i]; - if (configurableJoint.connectedBody == bottomPart.Rigidbody) { - UnityEngine.Object.Destroy(configurableJoint); - } - } - } - } - - public void Start() - { - part.mass = totalMass; - } - - public override void OnStart(StartState state) - { - base.OnStart(state); - limitsSet = false; - part.mass = totalMass; - - isFairingPresent = CheckForFairingPresent(); - isTopNodePartPresent = (getTopPart() != null) ? true : false; - - UpdateUIdecNoFairingsText(topNodeDecouplesWhenFairingsGone); - - GameEvents.onEditorShipModified.Add(OnEditorShipModified); - GameEvents.onVesselWasModified.Add(OnVesselWasModified); - GameEvents.onVesselCreate.Add(OnVesselCreate); - GameEvents.onVesselGoOffRails.Add(OnVesselGoOffRails); - GameEvents.onVesselLoaded.Add(OnVesselLoaded); - GameEvents.onStageActivate.Add(OnStageActivate); - } - - - public void OnDestroy() - { - GameEvents.onEditorShipModified.Remove(OnEditorShipModified); - GameEvents.onVesselWasModified.Remove(OnVesselWasModified); - GameEvents.onVesselCreate.Remove(OnVesselCreate); - GameEvents.onVesselGoOffRails.Remove(OnVesselGoOffRails); - GameEvents.onVesselLoaded.Remove(OnVesselLoaded); - GameEvents.onStageActivate.Remove(OnStageActivate); - } - - - bool isShipModified = true; - bool isStaged = false; - int stageNum = 0; - - - // lets catch some events.. - void OnEditorShipModified(ShipConstruct sc) - { - isShipModified = true; - } - - void OnVesselWasModified(Vessel ves) - { - isShipModified = true; - } - - void OnVesselCreate(Vessel ves) - { - isShipModified = true; - } - - void OnVesselGoOffRails(Vessel ves) - { - isShipModified = true; - } - - void OnVesselLoaded(Vessel ves) - { - isShipModified = true; - } - - void OnStageActivate(int stage) - { - isStaged = true; - stageNum = stage; - } - - - - - public float totalMass; - public override void updateShape() - { - base.updateShape(); - - float sth = calcSideThickness(); - float br = baseSize * 0.5f - sth; - float scale = br * 2; - - part.mass = totalMass = ((specificMass.x * scale + specificMass.y) * scale + specificMass.z) * scale + specificMass.w; - massDisplay = PFUtils.formatMass(totalMass); - costDisplay = PFUtils.formatCost(part.partInfo.cost + GetModuleCost(part.partInfo.cost, ModifierStagingSituation.CURRENT)); - part.breakingForce = specificBreakingForce * Mathf.Pow(br, 2); - part.breakingTorque = specificBreakingTorque * Mathf.Pow(br, 2); - - var model = part.FindModelTransform("model"); - if (model != null) model.localScale = Vector3.one * scale; - else Debug.LogError("[ProceduralFairingAdapter] No 'model' transform in the part", this); - part.rescaleFactor = scale; - - var node = part.FindAttachNode("top"); - node.position = node.originalPosition * scale; - if (!justLoaded) PFUtils.updateAttachedPartPos(node, part); - - var topNode = part.FindAttachNode("top"); - var bottomNode = part.FindAttachNode("bottom"); - - float y = (topNode.position.y + bottomNode.position.y) * 0.5f; - int sideNodeSize = Mathf.RoundToInt(scale / diameterStepLarge) - 1; - if (sideNodeSize < 0) sideNodeSize = 0; - - var nodes = part.FindAttachNodes("connect"); - if (nodes != null) { - for (int i = 0; i < nodes.Length; i++) { - var n = nodes[i]; - n.position.y = y; - n.size = sideNodeSize; - if (!justLoaded) PFUtils.updateAttachedPartPos(n, part); - } - } - - var topnode2 = part.FindAttachNode(topNodeName); - var internodes = part.FindAttachNodes("interstage"); - if (internodes != null && topnode2 != null) { - var topheight = topNode.position.y; - var topnode2height = topnode2.position.y; - var inc = (topnode2height - topheight) / (internodes.Length / 2 + 1); - - for (int i = 0, j = 0; i < internodes.Length; i = i + 2) { - var height = topheight + (j + 1) * inc; - j++; - - node = internodes[i]; - node.position.y = height; - node.size = topNode.size; - if (!justLoaded) PFUtils.updateAttachedPartPos(node, part); - - node = internodes[i + 1]; - node.position.y = height; - node.size = sideNodeSize; - if (!justLoaded) PFUtils.updateAttachedPartPos(node, part); - } - } - - var nnt = part.GetComponent(); - if (nnt) { - nnt.radius = baseSize * 0.5f; - } - - var fbase = part.GetComponent(); - if (fbase) { - fbase.baseSize = br * 2; - fbase.sideThickness = sth; - fbase.needShapeUpdate = true; - } - - StartCoroutine(PFUtils.updateDragCubeCoroutine(part, dragAreaScale)); - } - - - public override void FixedUpdate() - { - base.FixedUpdate(); - - if (!limitsSet && PFUtils.canCheckTech()) { - limitsSet = true; - float minSize = PFUtils.getTechMinValue("PROCFAIRINGS_MINDIAMETER", 0.25f); - float maxSize = PFUtils.getTechMaxValue("PROCFAIRINGS_MAXDIAMETER", 30); - - PFUtils.setFieldRange(Fields["baseSize"], minSize, maxSize); - PFUtils.setFieldRange(Fields["topSize"], minSize, maxSize); - - ((UI_FloatEdit)Fields["baseSize"].uiControlEditor).incrementLarge = diameterStepLarge; - ((UI_FloatEdit)Fields["baseSize"].uiControlEditor).incrementSmall = diameterStepSmall; - ((UI_FloatEdit)Fields["topSize"].uiControlEditor).incrementLarge = diameterStepLarge; - ((UI_FloatEdit)Fields["topSize"].uiControlEditor).incrementSmall = diameterStepSmall; - - ((UI_FloatEdit)Fields["height"].uiControlEditor).incrementLarge = heightStepLarge; - ((UI_FloatEdit)Fields["height"].uiControlEditor).incrementSmall = heightStepSmall; - ((UI_FloatEdit)Fields["extraHeight"].uiControlEditor).incrementLarge = heightStepLarge; - ((UI_FloatEdit)Fields["extraHeight"].uiControlEditor).incrementSmall = heightStepSmall; - } - - - if (isShipModified) { - - isShipModified = false; - // remove engine fairing if there is any from topmost node - if (!engineFairingRemoved) { - var node = part.FindAttachNode(topNodeName); - if (node != null && node.attachedPart != null) { - var tp = node.attachedPart; - - if (HighLogic.LoadedSceneIsEditor || !tp.packed) { - var comps = tp.GetComponents(); - for (int i = 0; i < comps.Length; i++) { - var mj = comps[i]; - // print("[ProceduralFairingAdapter] removing engine fairings "+mj); - var jt = tp.FindModelTransform(mj.jettisonName); - if (jt == null) - jt = mj.jettisonTransform; - if (jt != null) { - // print("[ProceduralFairingAdapter] disabling engine fairing "+jt); - jt.gameObject.SetActive(false); - } - - mj.jettisonName = null; - mj.jettisonTransform = null; - - // tp.RemoveModule(mj); - } - - if (!HighLogic.LoadedSceneIsEditor) engineFairingRemoved = true; - } - } - } - - - - if (!HighLogic.LoadedSceneIsEditor) { - if (isTopNodePartPresent) { - var tp = getTopPart(); - - if (tp == null) { - isTopNodePartPresent = false; - this.Events["UIToggleTopNodeDecouple"].guiActive = false; - } - else - if (topNodeDecouplesWhenFairingsGone && !CheckForFairingPresent()) { - - PartModule item = base.part.Modules["ModuleDecouple"]; - - if (item == null) { - Debug.LogError("[ProceduralFairingAdapter] Can't decouple from top part", this); - } - else { - this.RemoveTopPartJoints(); - ((ModuleDecouple)item).Decouple(); - this.part.stackIcon.RemoveIcon(); - StageManager.Instance.SortIcons(true); - - isFairingPresent = false; - isTopNodePartPresent = false; - this.Events["UIToggleTopNodeDecouple"].guiActive = false; - } - } - } - - - if (isStaged) { - isStaged = false; - - if (this.part != null) { - if (stageNum == this.part.inverseStage) { - this.part.stackIcon.RemoveIcon(true); - StageManager.Instance.SortIcons(true); - this.Events["UIToggleTopNodeDecouple"].guiActive = false; - } - } - } - - } - } - } - - - public Part getBottomPart() - { - Part part; - AttachNode attachNode = base.part.FindAttachNode("bottom"); - if (attachNode != null) { - part = attachNode.attachedPart; - } - else { - part = null; - } - return part; - } - - public bool CheckForFairingPresent() - { - if (!isFairingPresent) - return false; - - var nodes = part.FindAttachNodes("connect"); - if (nodes == null) - return false; - - for (int i = 0; i < nodes.Length; i++) { - var n = nodes[i]; - if (n.attachedPart != null) { - return true; - } - } - - return false; - } - - - public Part getTopPart() - { - var node = part.FindAttachNode(topNodeName); - if (node == null) return null; - return node.attachedPart; - } - - - public override void OnLoad(ConfigNode cfg) - { - base.OnLoad(cfg); - - if (cfg.HasValue("baseRadius") && cfg.HasValue("topRadius")) { - // load legacy settings - float br = float.Parse(cfg.GetValue("baseRadius")); - float tr = float.Parse(cfg.GetValue("topRadius")); - baseSize = (br + sideThickness * br) * 2; - topSize = (tr + sideThickness * br) * 2; - sideThickness *= 1.15f / 1.25f; - } - } - } - - - //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ// - - -} // namespace - diff --git a/Source/ProceduralFairings.csproj b/Source/ProceduralFairings.csproj deleted file mode 100644 index 3131469..0000000 --- a/Source/ProceduralFairings.csproj +++ /dev/null @@ -1,62 +0,0 @@ - - - - - Debug - AnyCPU - {C14C9097-E14E-4DBD-B1C1-877B6C390F27} - Library - Properties - ProceduralFairings - ProceduralFairings - v3.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - False - C:\Users\caske\Downloads\ksp-win64-1.3\KSP_win64\KSP_x64_Data\Managed\Assembly-CSharp.dll - - - - - - - - - False - C:\Users\caske\Downloads\ksp-win64-1.3\KSP_win64\KSP_x64_Data\Managed\UnityEngine.dll - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Source/ProceduralFairings.sln b/Source/ProceduralFairings.sln index 87a00bd..917ad90 100644 --- a/Source/ProceduralFairings.sln +++ b/Source/ProceduralFairings.sln @@ -1,22 +1,25 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26430.4 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProceduralFairings", "ProceduralFairings.csproj", "{C14C9097-E14E-4DBD-B1C1-877B6C390F27}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {C14C9097-E14E-4DBD-B1C1-877B6C390F27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C14C9097-E14E-4DBD-B1C1-877B6C390F27}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C14C9097-E14E-4DBD-B1C1-877B6C390F27}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C14C9097-E14E-4DBD-B1C1-877B6C390F27}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProceduralFairings", "ProceduralFairings\ProceduralFairings.csproj", "{51CE67F2-5981-4AD2-97E8-0E2B44792AB2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {51CE67F2-5981-4AD2-97E8-0E2B44792AB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {51CE67F2-5981-4AD2-97E8-0E2B44792AB2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {51CE67F2-5981-4AD2-97E8-0E2B44792AB2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {51CE67F2-5981-4AD2-97E8-0E2B44792AB2}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + BaseDirectory = .. + outputpath = References + Policies = $0 + $0.DotNetNamingPolicy = $1 + $1.DirectoryNamespaceAssociation = None + $1.ResourceNamePolicy = FileFormatDefault + EndGlobalSection +EndGlobal diff --git a/Source/ProceduralFairings/FairingBase.cs b/Source/ProceduralFairings/FairingBase.cs new file mode 100644 index 0000000..d2effc4 --- /dev/null +++ b/Source/ProceduralFairings/FairingBase.cs @@ -0,0 +1,1124 @@ +// ================================================== +// Procedural Fairings plug-in by Alexey Volynskov. + +// Licensed under CC-BY-4.0 terms: https://creativecommons.org/licenses/by/4.0/legalcode +// ================================================== + +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Keramzit +{ + public class ProceduralFairingBase : PartModule + { + [KSPField] public float outlineWidth = 0.05f; + [KSPField] public int outlineSlices = 12; + [KSPField] public Vector4 outlineColor = new Vector4 (0, 0, 0.2f, 1); + [KSPField] public float verticalStep = 0.1f; + [KSPField] public float baseSize = 1.25f; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiName = "Extra radius")] + [UI_FloatRange (minValue = -1, maxValue = 2, stepIncrement = 0.01f)] + public float extraRadius; + + [KSPField] public int circleSegments = 24; + + [KSPField] public float sideThickness = 0.05f; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiName = "Fairing Auto-struts")] + [UI_Toggle (disabledText = "Off", enabledText = "On")] + public bool autoStrutSides = true; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiName = "Fairing Auto-shape")] + [UI_Toggle (disabledText = "Off", enabledText = "On")] + public bool autoShape = true; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiName = "Max. size", guiFormat = "S4", guiUnits = "m")] + [UI_FloatEdit (sigFigs = 3, unit = "m", minValue = 0.1f, maxValue = 5, incrementLarge = 1.25f, incrementSmall = 0.125f, incrementSlide = 0.001f)] + public float manualMaxSize = 0.625f; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiName = "Cyl. start", guiFormat = "S4", guiUnits = "m")] + [UI_FloatEdit (sigFigs = 3, unit = "m", minValue = 0, maxValue = 50, incrementLarge = 1.0f, incrementSmall = 0.1f, incrementSlide = 0.001f)] + public float manualCylStart = 0; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiName = "Cyl. end", guiFormat = "S4", guiUnits = "m")] + [UI_FloatEdit (sigFigs = 3, unit = "m", minValue = 0, maxValue = 50, incrementLarge = 1.0f, incrementSmall = 0.1f, incrementSlide = 0.001f)] + public float manualCylEnd = 1; + + bool limitsSet; + + [KSPField] public float diameterStepLarge = 1.25f; + [KSPField] public float diameterStepSmall = 0.125f; + + [KSPField] public float heightStepLarge = 1.0f; + [KSPField] public float heightStepSmall = 0.1f; + + public float updateDelay; + public bool needShapeUpdate = true; + + Part topBasePart; + + LineRenderer line; + + readonly List outline = new List(); + + List joints = new List(); + + public override string GetInfo () + { + const string infoString = "Attach side fairings and they will be shaped for your attached payload.\n" + "Remember to enable the decoupler if you need one."; + + return infoString; + } + + public override void OnStart (StartState state) + { + limitsSet = false; + + if (!HighLogic.LoadedSceneIsEditor && !HighLogic.LoadedSceneIsFlight) + { + return; + } + + PFUtils.hideDragStuff (part); + + GameEvents.onEditorShipModified.Add (new EventData.OnEvent (onEditorVesselModified)); + + if (HighLogic.LoadedSceneIsEditor) + { + if (line) + { + line.transform.Rotate (0, 90, 0); + } + + DestroyAllLineRenderers (); + + destroyOutline (); + + for (int i = 0; i < outlineSlices; ++i) + { + var r = makeLineRenderer ("fairing outline", outlineColor, outlineWidth); + + outline.Add (r); + + r.transform.Rotate (0, i * 360f / outlineSlices, 0); + } + + ShowHideInterstageNodes (); + + recalcShape (); + + updateDelay = 0.1f; + + needShapeUpdate = true; + } + else + { + topBasePart = null; + + var adapter = part.GetComponent(); + + if (adapter) + { + topBasePart = adapter.getTopPart (); + } + else + { + var scan = scanPayload (); + + if (scan.targets.Count > 0) + { + topBasePart = scan.targets [0]; + } + } + } + + SetUIChangedCallBacks (); + + OnToggleAutoshapeUI (); + } + + void SetUIChangedCallBacks () + { + ((UI_Toggle) Fields["autoShape"].uiControlEditor).onFieldChanged += OnChangeAutoshapeUI; + + ((UI_FloatEdit) Fields["manualMaxSize"].uiControlEditor).onFieldChanged += OnChangeShapeUI; + ((UI_FloatEdit) Fields["manualCylStart"].uiControlEditor).onFieldChanged += OnChangeShapeUI; + ((UI_FloatEdit) Fields["manualCylEnd"].uiControlEditor).onFieldChanged += OnChangeShapeUI; + } + + void OnChangeAutoshapeUI (BaseField bf, object obj) + { + OnToggleAutoshapeUI (); + + needShapeUpdate = true; + } + + void OnToggleAutoshapeUI () + { + Fields["manualMaxSize"].guiActiveEditor = !autoShape; + Fields["manualCylStart"].guiActiveEditor = !autoShape; + Fields["manualCylEnd"].guiActiveEditor = !autoShape; + + PFUtils.refreshPartWindow (); + } + + void OnChangeShapeUI (BaseField bf, object obj) + { + needShapeUpdate = true; + } + + void onEditorVesselModified (ShipConstruct ship) + { + ShowHideInterstageNodes (); + + needShapeUpdate = true; + } + + public void ShowHideInterstageNodes () + { + var nnt = part.GetComponent(); + + if (nnt) + { + var nodes = part.FindAttachNodes ("interstage"); + + if (nodes == null) + { + return; + } + + if (nnt.showInterstageNodes) + { + for (int i = 0; i < nodes.Length; i++) + { + var node = nodes [i]; + + if (node.attachedPart == null) + { + node.position.x = 0; + } + } + } + else + { + for (int i = 0; i < nodes.Length; i++) + { + var node = nodes [i]; + + if (node.attachedPart == null) + { + node.position.x = 10000; + } + } + } + } + } + + public void removeJoints () + { + while (joints.Count > 0) + { + int i = joints.Count - 1; + + var joint = joints [i]; joints.RemoveAt (i); + + UnityEngine.Object.Destroy (joint); + } + } + + public void OnPartPack () + { + removeJoints (); + } + + ConfigurableJoint addStrut (Part p, Part pp) + { + if (p == pp) + { + return null; + } + + var rb = pp.Rigidbody; + + if (rb == null || rb == p.Rigidbody) + { + return null; + } + + var joint = p.gameObject.AddComponent(); + + joint.xMotion = ConfigurableJointMotion.Locked; + joint.yMotion = ConfigurableJointMotion.Locked; + joint.zMotion = ConfigurableJointMotion.Locked; + joint.angularXMotion = ConfigurableJointMotion.Locked; + joint.angularYMotion = ConfigurableJointMotion.Locked; + joint.angularZMotion = ConfigurableJointMotion.Locked; + joint.projectionDistance = 0.1f; + joint.projectionAngle = 5; + joint.breakForce = p.breakingForce; + joint.breakTorque = p.breakingTorque; + joint.connectedBody = rb; + + joints.Add (joint); + + return joint; + } + + IEnumerator createAutoStruts (List shieldedParts) + { + while (!FlightGlobals.ready || vessel.packed || !vessel.loaded) + { + yield return new WaitForFixedUpdate (); + } + + var nnt = part.GetComponent(); + + var attached = part.FindAttachNodes ("connect"); + + for (int i = 0; i < nnt.numNodes; ++i) + { + var p = attached [i].attachedPart; + + if (p == null || p.Rigidbody == null) + { + continue; + } + + var pp = attached [i > 0 ? i - 1 : nnt.numNodes - 1].attachedPart; + + if (pp == null) + { + continue; + } + + addStrut (p, pp); + + if (topBasePart != null) + { + addStrut (p, topBasePart); + } + } + } + + public void onShieldingDisabled (List shieldedParts) + { + removeJoints (); + } + + public void onShieldingEnabled (List shieldedParts) + { + if (!HighLogic.LoadedSceneIsFlight) + { + return; + } + + if (autoStrutSides) + { + StartCoroutine(createAutoStruts (shieldedParts)); + } + } + + public virtual void FixedUpdate () + { + if (!limitsSet && PFUtils.canCheckTech ()) + { + limitsSet = true; + + float minSize = PFUtils.getTechMinValue ("PROCFAIRINGS_MINDIAMETER", 0.25f); + float maxSize = PFUtils.getTechMaxValue ("PROCFAIRINGS_MAXDIAMETER", 30); + + PFUtils.setFieldRange (Fields["manualMaxSize"], minSize, maxSize * 2); + + ((UI_FloatEdit) Fields["manualMaxSize"].uiControlEditor).incrementLarge = diameterStepLarge; + ((UI_FloatEdit) Fields["manualMaxSize"].uiControlEditor).incrementSmall = diameterStepSmall; + + ((UI_FloatEdit) Fields["manualCylStart"].uiControlEditor).incrementLarge = heightStepLarge; + ((UI_FloatEdit) Fields["manualCylStart"].uiControlEditor).incrementSmall = heightStepSmall; + ((UI_FloatEdit) Fields["manualCylEnd"].uiControlEditor).incrementLarge = heightStepLarge; + ((UI_FloatEdit) Fields["manualCylEnd"].uiControlEditor).incrementSmall = heightStepSmall; + } + + if (!part.packed && topBasePart != null) + { + var adapter = part.GetComponent(); + + if (adapter) + { + topBasePart = adapter.getTopPart (); + + if (topBasePart == null) + { + removeJoints (); + } + } + } + } + + LineRenderer makeLineRenderer (string gameObjectName, Color color, float wd) + { + var o = new GameObject (gameObjectName); + + o.transform.parent = part.transform; + o.transform.localPosition = Vector3.zero; + o.transform.localRotation = Quaternion.identity; + + var lineRenderer = o.AddComponent(); + + lineRenderer.useWorldSpace = false; + lineRenderer.material = new Material (Shader.Find ("Particles/Additive")); + lineRenderer.startColor = color; + lineRenderer.endColor = color; + lineRenderer.startWidth = wd; + lineRenderer.endWidth = wd; + lineRenderer.positionCount = 0; + + return lineRenderer; + } + + void destroyOutline () + { + for (int i = 0; i < outline.Count; i++) + { + Destroy (outline [i].gameObject); + } + + outline.Clear (); + } + + /// + /// Fix for the blue ghost lines showing invalid outlines when cloning or symmetry-placing fairing bases in the editor. + /// Find any already assigned (copied) LineRenderers and delete them. + /// + + void DestroyAllLineRenderers () + { + LineRenderer [] lr = FindObjectsOfType(); + + if (lr != null) + { + for (int i = 0; i < lr.Length; i++) + { + Transform _transform = lr[i].transform; + + if (_transform != null) + { + Transform _parent = _transform.parent; + + if (_parent != null) + { + GameObject _gameObject = _parent.gameObject; + + if (_gameObject) + { + if ((_gameObject.Equals (this) ? true : _gameObject.Equals (gameObject))) + { + GameObjectExtension.DestroyGameObject (lr [i].gameObject); + } + } + } + } + } + } + } + + public void OnDestroy () + { + GameEvents.onEditorShipModified.Remove (new EventData.OnEvent (onEditorVesselModified)); + + if (line) + { + Destroy (line.gameObject); + + line = null; + } + + DestroyAllLineRenderers (); + + destroyOutline (); + } + + public void Update () + { + if (HighLogic.LoadedSceneIsEditor) + { + if (updateDelay > 0) + { + updateDelay -= Time.deltaTime; + } + else + { + if (needShapeUpdate) + { + needShapeUpdate = false; + updateDelay = 0.1f; + + recalcShape (); + } + } + } + } + + static public Vector3 [] buildFairingShape (float baseRad, float maxRad, float cylStart, float cylEnd, float noseHeightRatio, Vector4 baseConeShape, Vector4 noseConeShape, int baseConeSegments, int noseConeSegments, Vector4 vertMapping, float mappingScaleY) + { + float baseConeRad = maxRad - baseRad; + float tip = maxRad * noseHeightRatio; + + var baseSlope = new BezierSlope (baseConeShape); + var noseSlope = new BezierSlope (noseConeShape); + + float baseV0 = vertMapping.x / mappingScaleY; + float baseV1 = vertMapping.y / mappingScaleY; + float noseV0 = vertMapping.z / mappingScaleY; + float noseV1 = vertMapping.w / mappingScaleY; + + var shape = new Vector3 [1 + (cylStart.Equals (0) ? 0 : baseConeSegments) + 1 + noseConeSegments]; + + int vi = 0; + + if (!cylStart.Equals (0)) + { + for (int i = 0; i <= baseConeSegments; ++i, ++vi) + { + float t = (float) i / baseConeSegments; + + var p = baseSlope.interp (t); + + shape [vi] = new Vector3 (p.x * baseConeRad + baseRad, p.y * cylStart, Mathf.Lerp (baseV0, baseV1, t)); + } + } + else + { + shape [vi++] = new Vector3 (baseRad, 0, baseV1); + } + + for (int i = 0; i <= noseConeSegments; ++i, ++vi) + { + float t = (float) i / noseConeSegments; + + var p = noseSlope.interp (1 - t); + + shape [vi] = new Vector3 (p.x * maxRad, (1 - p.y) * tip + cylEnd, Mathf.Lerp (noseV0, noseV1, t)); + } + + return shape; + } + + static public Vector3 [] buildInlineFairingShape (float baseRad, float maxRad, float topRad, float cylStart, float cylEnd, float top, Vector4 baseConeShape, int baseConeSegments, Vector4 vertMapping, float mappingScaleY) + { + float baseConeRad = maxRad - baseRad; + float topConeRad = maxRad - topRad; + + var baseSlope = new BezierSlope (baseConeShape); + + float baseV0 = vertMapping.x / mappingScaleY; + float baseV1 = vertMapping.y / mappingScaleY; + float noseV0 = vertMapping.z / mappingScaleY; + + var shape = new Vector3 [2 + (cylStart.Equals (0) ? 0 : baseConeSegments + 1) + (cylEnd.Equals (top) ? 0 : baseConeSegments + 1)]; + + int vi = 0; + + if (!cylStart.Equals(0)) + { + for (int i = 0; i <= baseConeSegments; ++i, ++vi) + { + float t = (float) i / baseConeSegments; + + var p = baseSlope.interp (t); + + shape [vi] = new Vector3 (p.x * baseConeRad + baseRad, p.y * cylStart, Mathf.Lerp (baseV0, baseV1, t)); + } + } + + shape [vi++] = new Vector3 (maxRad, cylStart, baseV1); + shape [vi++] = new Vector3 (maxRad, cylEnd, noseV0); + + if (!cylEnd.Equals (top)) + { + for (int i = 0; i <= baseConeSegments; ++i, ++vi) + { + float t = (float) i / baseConeSegments; + + var p = baseSlope.interp (1 - t); + + shape [vi] = new Vector3 (p.x * topConeRad + topRad, Mathf.Lerp (top, cylEnd, p.y), Mathf.Lerp (baseV1, baseV0, t)); + } + } + + return shape; + } + + PayloadScan scanPayload () + { + // Scan the payload and build it's profile. + + var scan = new PayloadScan (part, verticalStep, extraRadius); + + AttachNode node = part.FindAttachNode ("top"); + + if (node != null) + { + scan.ofs = node.position.y; + + if (node.attachedPart != null) + { + scan.addPart (node.attachedPart, part); + } + } + + AttachNode [] nodes = part.FindAttachNodes ("interstage"); + + if (nodes != null) + { + for (int j = 0; j < nodes.Length; j++) + { + node = nodes [j]; + + if (node != null) + { + if (node.attachedPart != null) + { + scan.addPart (node.attachedPart, part); + } + } + } + } + + for (int i = 0; i < scan.payload.Count; ++i) + { + var cp = scan.payload [i]; + + // Add any connected payload parts. + + scan.addPart (cp.parent, cp); + + for (int j = 0; j < cp.children.Count; j++) + { + scan.addPart(cp.children[j], cp); + } + + // Scan for the part colliders. + + var colls = cp.FindModelComponents(); + + for (int j = 0; j < colls.Count; j++) + { + var coll = colls [j]; + + // Skip ladders etc... + + if (coll.tag != "Untagged") + { + continue; + } + + scan.addPayload (coll); + } + } + + return scan; + } + + AttachNode HasNodeComponent (AttachNode [] nodes) + { + if (nodes != null) + { + for (int i = 0; i < nodes.Length; i++) + { + var partAttached = nodes [i].attachedPart; + + if (partAttached == null) + { + continue; + } + + var comp = partAttached.GetComponent(); + + if (!comp.Equals (null)) + { + return nodes [i]; + } + } + } + + return null; + } + + public void recalcShape () + { + var scan = scanPayload (); + + // Check for reversed bases (inline fairings). + + float topY = 0; + float topRad = 0; + + AttachNode topSideNode = null; + + bool isInline = false; + + var adapter = part.GetComponent(); + + if (adapter) + { + isInline = true; + + topY = adapter.height + adapter.extraHeight; + + if (topY < scan.ofs) + { + topY = scan.ofs; + } + + topRad = adapter.topRadius; + } + else if (scan.targets.Count > 0) + { + isInline = true; + + var topBase = scan.targets [0].GetComponent(); + + topY = scan.w2l.MultiplyPoint3x4 (topBase.part.transform.position).y; + + if (topY < scan.ofs) + { + topY = scan.ofs; + } + + topSideNode = HasNodeComponent(topBase.part.FindAttachNodes ("connect")); + + topRad = topBase.baseSize * 0.5f; + } + + // No payload case. + + if (scan.profile.Count <= 0) + { + scan.profile.Add (extraRadius); + } + + // Fill profile outline (for debugging). + + if (line) + { + line.positionCount = scan.profile.Count * 2 + 2; + + float prevRad = 0; + + int hi = 0; + + for (int i = 0; i < scan.profile.Count; i++) + { + var r = scan.profile [i]; + + line.SetPosition (hi * 2, new Vector3 (prevRad, hi * verticalStep + scan.ofs, 0)); + line.SetPosition (hi * 2 + 1, new Vector3 (r, hi * verticalStep + scan.ofs, 0)); + + hi++; prevRad = r; + } + + line.SetPosition (hi * 2, new Vector3 (prevRad, hi * verticalStep + scan.ofs, 0)); + line.SetPosition (hi * 2 + 1, new Vector3 (0, hi * verticalStep + scan.ofs, 0)); + } + + // Check for attached side parts. + + var attached = part.FindAttachNodes ("connect"); + + // Get the number of available fairing attachment nodes from NodeNumberTweaker. + + var nnt = part.GetComponent(); + + int numSideParts = nnt.numNodes; + + var sideNode = HasNodeComponent(attached); + + var baseConeShape = new Vector4 (0, 0, 0, 0); + var noseConeShape = new Vector4 (0, 0, 0, 0); + var mappingScale = new Vector2 (1024, 1024); + var stripMapping = new Vector2 (992, 1024); + var horMapping = new Vector4 (0, 480, 512, 992); + var vertMapping = new Vector4 (0, 160, 704, 1024); + + float baseCurveStartX = 0; + float baseCurveStartY = 0; + float baseCurveEndX = 0; + float baseCurveEndY = 0; + + int baseConeSegments = 1; + + float noseCurveStartX = 0; + float noseCurveStartY = 0; + float noseCurveEndX = 0; + float noseCurveEndY = 0; + + int noseConeSegments = 1; + float noseHeightRatio = 1; + float minBaseConeAngle = 20; + + float density = 0; + + if (sideNode != null) + { + var sf = sideNode.attachedPart.GetComponent(); + + mappingScale = sf.mappingScale; + stripMapping = sf.stripMapping; + horMapping = sf.horMapping; + vertMapping = sf.vertMapping; + noseHeightRatio = sf.noseHeightRatio; + minBaseConeAngle = sf.minBaseConeAngle; + baseConeShape = sf.baseConeShape; + baseCurveStartX = sf.baseCurveStartX; + baseCurveStartY = sf.baseCurveStartY; + baseCurveEndX = sf.baseCurveEndX; + baseCurveEndY = sf.baseCurveEndY; + baseConeSegments = (int) sf.baseConeSegments; + noseConeShape = sf.noseConeShape; + noseCurveStartX = sf.noseCurveStartX; + noseCurveStartY = sf.noseCurveStartY; + noseCurveEndX = sf.noseCurveEndX; + noseCurveEndY = sf.noseCurveEndY; + noseConeSegments = (int) sf.noseConeSegments; + density = sf.density; + } + + // Compute the fairing shape. + + float baseRad = baseSize * 0.5f; + float minBaseConeTan = Mathf.Tan (minBaseConeAngle * Mathf.Deg2Rad); + + float cylStart = 0; + float maxRad; + + int profTop = scan.profile.Count; + + if (isInline) + { + profTop = Mathf.CeilToInt ((topY - scan.ofs) / verticalStep); + + if (profTop > scan.profile.Count) + { + profTop = scan.profile.Count; + } + + maxRad = 0; + + for (int i = 0; i < profTop; ++i) + { + maxRad = Mathf.Max (maxRad, scan.profile [i]); + } + + maxRad = Mathf.Max (maxRad, topRad); + } + else + { + maxRad = PFUtils.GetMaxValueFromList (scan.profile); + } + + if (maxRad > baseRad) + { + // Try to fit the base cone as high as possible. + + cylStart = scan.ofs; + + for (int i = 1; i < scan.profile.Count; ++i) + { + float y = i * verticalStep + scan.ofs; + float r0 = baseRad; + float k = (maxRad - r0) / y; + + if (k < minBaseConeTan) + { + break; + } + + bool ok = true; + + float r = r0 + k * scan.ofs; + + for (int j = 0; j < i; ++j, r += k * verticalStep) + { + if (scan.profile [j] > r) + { + ok = false; + + break; + } + } + + if (!ok) + { + break; + } + + cylStart = y; + } + } + else + { + // No base cone, just a cylinder and a nose. + + maxRad = baseRad; + } + + float cylEnd = scan.profile.Count * verticalStep + scan.ofs; + + if (isInline) + { + float r0 = topRad; + + if (profTop > 0 && profTop < scan.profile.Count) + { + r0 = Mathf.Max (r0, scan.profile [profTop - 1]); + + if (profTop - 2 >= 0) r0 = Mathf.Max (r0, scan.profile [profTop - 2]); + } + + if (maxRad > r0) + { + if (cylEnd > topY) + { + cylEnd = topY - verticalStep; + } + + // Try to fit the top cone as low as possible. + + for (int i = profTop - 1; i >= 0; --i) + { + float y = i * verticalStep + scan.ofs; + float k = (maxRad - r0) / (y - topY); + + bool ok = true; + + float r = maxRad + k * verticalStep; + + for (int j = i; j < profTop; ++j, r += k * verticalStep) + { + if (r < r0) + { + r = r0; + } + + if (scan.profile [j] > r) + { + ok = false; + + break; + } + } + + if (!ok) + { + break; + } + + cylEnd = y; + } + } + else + { + cylEnd = topY; + } + } + else + { + // Try to fit the nose cone as low as possible. + + for (int i = scan.profile.Count - 1; i >= 0; --i) + { + float s = verticalStep / noseHeightRatio; + + bool ok = true; + + float r = maxRad - s; + + for (int j = i; j < scan.profile.Count; ++j, r -= s) + { + if (scan.profile [j] > r) + { + ok = false; + + break; + } + } + + if (!ok) break; + + float y = i * verticalStep + scan.ofs; + + cylEnd = y; + } + } + + if (autoShape) + { + manualMaxSize = maxRad * 2; + manualCylStart = cylStart; + manualCylEnd = cylEnd; + } + else + { + maxRad = manualMaxSize * 0.5f; + cylStart = manualCylStart; + cylEnd = manualCylEnd; + } + + if (cylStart > cylEnd) + { + cylStart = cylEnd; + } + + // Build the fairing shape line. + + Vector3 [] shape; + + if (isInline) + { + shape = buildInlineFairingShape (baseRad, maxRad, topRad, cylStart, cylEnd, topY, baseConeShape, baseConeSegments, vertMapping, mappingScale.y); + } + else + { + shape = buildFairingShape (baseRad, maxRad, cylStart, cylEnd, noseHeightRatio, baseConeShape, noseConeShape, baseConeSegments, noseConeSegments, vertMapping, mappingScale.y); + } + + if (sideNode == null && topSideNode == null) + { + // No side parts - fill fairing outlines. + + for (int j = 0; j < outline.Count; j++) + { + var lr = outline [j]; + + lr.positionCount = shape.Length; + + for (int i = 0; i < shape.Length; ++i) + { + lr.SetPosition (i, new Vector3 (shape [i].x, shape [i].y)); + } + } + } + else + { + for (int j = 0; j < outline.Count; j++) + { + var lr = outline [j]; + + lr.positionCount = 0; + } + } + + // Rebuild the side parts. + + int numSegs = circleSegments / numSideParts; + + if (numSegs < 2) + { + numSegs = 2; + } + + for (int i = 0; i < attached.Length; i++) + { + var sn = attached [i]; + var sp = sn.attachedPart; + + if (!sp) + { + continue; + } + + var sf = sp.GetComponent(); + + if (!sf) + { + continue; + } + + if (sf.shapeLock) + { + continue; + } + + var mf = sp.FindModelComponent("model"); + + if (!mf) + { + Debug.LogError ("[PF]: No model in side fairing!", sp); + + continue; + } + + var nodePos = sn.position; + + mf.transform.position = part.transform.position; + mf.transform.rotation = part.transform.rotation; + + float ra = Mathf.Atan2 (-nodePos.z, nodePos.x) * Mathf.Rad2Deg; + + mf.transform.Rotate (0, ra, 0); + + if (sf.meshPos == mf.transform.localPosition + && sf.meshRot == mf.transform.localRotation + && sf.numSegs == numSegs + && sf.numSideParts == numSideParts + && sf.baseRad.Equals (baseRad) + && sf.maxRad.Equals (maxRad) + && sf.cylStart.Equals (cylStart) + && sf.cylEnd.Equals (cylEnd) + && sf.topRad.Equals (topRad) + && sf.inlineHeight.Equals (topY) + && sf.sideThickness.Equals (sideThickness) + && !sf.baseCurveStartX.Equals (baseCurveStartX) + && !sf.baseCurveStartY.Equals (baseCurveStartY) + && !sf.baseCurveEndX.Equals (baseCurveEndX) + && !sf.baseCurveEndY.Equals (baseCurveEndY) + && !sf.baseConeSegments.Equals (baseConeSegments) + && !sf.noseCurveStartX.Equals (noseCurveStartX) + && !sf.noseCurveStartY.Equals (noseCurveStartY) + && !sf.noseCurveEndX.Equals (noseCurveEndX) + && !sf.noseCurveEndY.Equals (noseCurveEndY) + && !sf.noseConeSegments.Equals (noseConeSegments) + && !sf.noseHeightRatio.Equals (noseHeightRatio) + && !sf.density.Equals (density)) + { + continue; + } + + sf.meshPos = mf.transform.localPosition; + sf.meshRot = mf.transform.localRotation; + sf.numSegs = numSegs; + sf.numSideParts = numSideParts; + sf.baseRad = baseRad; + sf.maxRad = maxRad; + sf.cylStart = cylStart; + sf.cylEnd = cylEnd; + sf.topRad = topRad; + sf.inlineHeight = topY; + sf.sideThickness = sideThickness; + sf.baseCurveStartX = baseCurveStartX; + sf.baseCurveStartY = baseCurveStartY; + sf.baseCurveEndX = baseCurveEndX; + sf.baseCurveEndY = baseCurveEndY; + sf.baseConeSegments = baseConeSegments; + sf.noseCurveStartX = noseCurveStartX; + sf.noseCurveStartY = noseCurveStartY; + sf.noseCurveEndX = noseCurveEndX; + sf.noseCurveEndY = noseCurveEndY; + sf.noseConeSegments = noseConeSegments; + sf.noseHeightRatio = noseHeightRatio; + sf.density = density; + + sf.rebuildMesh (); + } + + var shielding = part.GetComponent(); + + if (shielding) + { + shielding.reset (); + } + } + } +} diff --git a/Source/ProceduralFairings/FairingDecoupler.cs b/Source/ProceduralFairings/FairingDecoupler.cs new file mode 100644 index 0000000..422f48c --- /dev/null +++ b/Source/ProceduralFairings/FairingDecoupler.cs @@ -0,0 +1,228 @@ +// ================================================== +// Procedural Fairings plug-in by Alexey Volynskov. + +// Licensed under CC-BY-4.0 terms: https://creativecommons.org/licenses/by/4.0/legalcode +// ================================================== + +using KSP.UI.Screens; +using System; +using UnityEngine; + +namespace Keramzit +{ + public class ProceduralFairingDecoupler : PartModule + { + [KSPField] public float ejectionDv = 15; + [KSPField] public float ejectionTorque = 10; + [KSPField] public float ejectionLowDv; + [KSPField] public float ejectionLowTorque; + + [KSPField (isPersistant = true)] bool decoupled; + + bool didForce; + + bool decouplerStagingSet = true; + + [KSPField] public string ejectSoundUrl = "Squad/Sounds/sound_decoupler_fire"; + public FXGroup ejectFx; + + [KSPField] public string transformName = "nose_collider"; + [KSPField] public Vector3 forceVector = Vector3.right; + [KSPField] public Vector3 torqueVector = -Vector3.forward; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiName = "Ejection power")] + [UI_FloatRange (minValue = 0, maxValue = 1, stepIncrement = 0.01f)] + public float ejectionPower = 0.32f; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiName = "Ejection torque")] + [UI_FloatRange (minValue = 0, maxValue = 1, stepIncrement = 0.01f)] + public float torqueAmount = 0.01f; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiName = "Fairing Decoupler")] + [UI_Toggle (disabledText = "Off", enabledText = "On", affectSymCounterparts = UI_Scene.All)] + public bool fairingStaged = true; + + [KSPAction ("Jettison Fairing", actionGroup = KSPActionGroup.None)] + public void ActionJettison (KSPActionParam param) + { + OnJettisonFairing (); + } + + public void FixedUpdate () + { + // More hacky-hacky: for some reason the staging icons cannot be updated correctly + // via the OnStart () method but require an additional update here. This snippet + // sets the staging icon states one more time after transitioning a scene. + + if (HighLogic.LoadedSceneIsFlight || HighLogic.LoadedSceneIsEditor) + { + if (decouplerStagingSet) + { + OnSetStagingIcons (); + + decouplerStagingSet = false; + } + } + + if (decoupled) + { + if (part.parent) + { + var pfa = part.parent.GetComponent(); + + for (int i = 0; i < part.parent.children.Count; i++) + { + var p = part.parent.children [i]; + + // Check if the top node allows decoupling when the fairing is also decoupled. + + if (pfa) + { + if (!pfa.topNodeDecouplesWhenFairingsGone) + { + var isFairing = p.GetComponent(); + + if (!isFairing) + { + continue; + } + } + } + + var joints = p.GetComponents(); + + for (int j = 0; j < joints.Length; j++) + { + var joint = joints [j]; + + if (joint != null && (joint.GetComponent() == part.Rigidbody || joint.connectedBody == part.Rigidbody)) + { + Destroy (joint); + } + } + } + + part.decouple (0); + + ejectFx.audio.Play (); + } + else if (!didForce) + { + var tr = part.FindModelTransform (transformName); + + if (tr) + { + part.Rigidbody.AddForce (tr.TransformDirection (forceVector) * Mathf.Lerp (ejectionLowDv, ejectionDv, ejectionPower), ForceMode.VelocityChange); + part.Rigidbody.AddTorque (tr.TransformDirection (torqueVector) * Mathf.Lerp (ejectionLowTorque, ejectionTorque, torqueAmount), ForceMode.VelocityChange); + } + else + { + Debug.LogError ("[PF]: No '" + transformName + "' transform in part!", part); + } + + didForce = true; + decoupled = false; + } + } + } + + public override void OnActive () + { + OnJettisonFairing (); + } + + [KSPEvent (name = "Jettison", active = true, guiActive = true, guiActiveUnfocused = false, guiName = "Jettison Fairing")] + public void OnJettisonFairing () + { + decoupled |= fairingStaged; + } + + public override void OnLoad (ConfigNode node) + { + base.OnLoad (node); + + didForce = decoupled; + } + + public void OnSetStagingIcons () + { + // Set the staging icon for the parent part. + + if (fairingStaged) + { + part.stackIcon.CreateIcon (); + } + else + { + part.stackIcon.RemoveIcon (); + } + + // Hacky, hacky? Five dollars... + + foreach (Part FairingSide in part.symmetryCounterparts) + { + if (fairingStaged) + { + FairingSide.stackIcon.CreateIcon (); + } + else + { + FairingSide.stackIcon.RemoveIcon (); + } + } + + // Reorder the staging icons. + + StageManager.Instance.SortIcons (true); + } + + public override void OnStart (StartState state) + { + if (state == StartState.None) + { + return; + } + + if (state == StartState.Editor) + { + // Set up the GUI editor update callback. + + ((UI_Toggle) Fields["fairingStaged"].uiControlEditor).onFieldChanged += OnUpdateUI; + } + + ejectFx.audio = part.gameObject.AddComponent(); + ejectFx.audio.volume = GameSettings.SHIP_VOLUME; + ejectFx.audio.rolloffMode = AudioRolloffMode.Logarithmic; + ejectFx.audio.maxDistance = 100; + ejectFx.audio.loop = false; + ejectFx.audio.playOnAwake = false; + ejectFx.audio.dopplerLevel = 0f; + ejectFx.audio.spatialBlend = 1.0f; + ejectFx.audio.panStereo = 0f; + + if (GameDatabase.Instance.ExistsAudioClip (ejectSoundUrl)) + { + ejectFx.audio.clip = GameDatabase.Instance.GetAudioClip (ejectSoundUrl); + } + else + { + Debug.LogError ("[PF]: Cannot find decoupler sound: " + ejectSoundUrl, this); + } + + // Set the state of the "Jettison Fairing" PAW button. + + Events["OnJettisonFairing"].guiActive = fairingStaged; + + // Update the staging icon sequence. + + OnSetStagingIcons (); + } + + void OnUpdateUI (BaseField bf, object obj) + { + // Update the staging icon sequence. + + OnSetStagingIcons (); + } + } +} diff --git a/Source/ProceduralFairings/FairingShielding.cs b/Source/ProceduralFairings/FairingShielding.cs new file mode 100644 index 0000000..f94069d --- /dev/null +++ b/Source/ProceduralFairings/FairingShielding.cs @@ -0,0 +1,482 @@ +// ================================================== +// Procedural Fairings plug-in by Alexey Volynskov. + +// Licensed under CC-BY-4.0 terms: https://creativecommons.org/licenses/by/4.0/legalcode +// ================================================== + +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Keramzit +{ + public class KzFairingBaseShielding : PartModule, IAirstreamShield + { + List shieldedParts; + + ProceduralFairingSide sideFairing; + + float boundCylY0, boundCylY1, boundCylRad; + float lookupRad; + + Vector3 lookupCenter; + Vector3 [] shape; + + [KSPField (isPersistant = false, guiActive = true, guiActiveEditor = true, guiName = "Parts shielded")] + public int numShieldedDisplay; + + bool needReset; + + public bool ClosedAndLocked () { return true; } + public Vessel GetVessel () { return vessel; } + public Part GetPart () { return part; } + + public override void OnAwake () + { + shieldedParts = new List(); + } + + public override void OnStart (StartState state) + { + if (!HighLogic.LoadedSceneIsEditor && !HighLogic.LoadedSceneIsFlight) + { + return; + } + + reset (); + + GameEvents.onVesselWasModified.Add (new EventData.OnEvent (onVesselModified)); + GameEvents.onVesselGoOffRails.Add (new EventData.OnEvent (onVesselUnpack)); + GameEvents.onPartDie.Add (new EventData.OnEvent (OnPartDestroyed)); + } + + void OnDestroy () + { + GameEvents.onVesselWasModified.Remove (new EventData.OnEvent (onVesselModified)); + GameEvents.onVesselGoOffRails.Remove (new EventData.OnEvent (onVesselUnpack)); + GameEvents.onPartDie.Remove (new EventData.OnEvent (OnPartDestroyed)); + } + + public void FixedUpdate () + { + if (needReset) + { + needReset = false; + + getFairingParams (); + + bool shield = (HighLogic.LoadedSceneIsEditor || (HighLogic.LoadedSceneIsFlight && !vessel.packed)); + + if (shield) + { + enableShielding (); + } + } + } + + public void reset () + { + needReset = true; + } + + AttachNode [] getFairingParams () + { + var nnt = part.GetComponent(); + + // Check for attached side parts and get their parameters. + + var attached = part.FindAttachNodes ("connect"); + + ProceduralFairingSide sf = null; + + for (int i = 0; i < nnt.numNodes; ++i) + { + var n = attached [i]; + + if (!n.attachedPart) + { + sf = null; + + break; + } + + sf = n.attachedPart.GetComponent(); + + if (!sf) + { + break; + } + } + + sideFairing = sf; + + if (!sf) + { + shape = null; + boundCylY0 = boundCylY1 = boundCylRad = 0; + lookupCenter = Vector3.zero; + lookupRad = 0; + + return null; + } + + // Get the polyline shape. + + if (sf.inlineHeight <= 0) + { + shape = ProceduralFairingBase.buildFairingShape (sf.baseRad, sf.maxRad, sf.cylStart, sf.cylEnd, sf.noseHeightRatio, sf.baseConeShape, sf.noseConeShape, (int) sf.baseConeSegments, (int) sf.noseConeSegments, sf.vertMapping, sf.mappingScale.y); + } + else + { + shape = ProceduralFairingBase.buildInlineFairingShape (sf.baseRad, sf.maxRad, sf.topRad, sf.cylStart, sf.cylEnd, sf.inlineHeight, sf.baseConeShape, (int) sf.baseConeSegments, sf.vertMapping, sf.mappingScale.y); + } + + // Offset shape by thickness. + + for (int i = 0; i < shape.Length; ++i) + { + if (i == 0 || i == shape.Length - 1) + { + shape [i] += new Vector3 (sf.sideThickness, 0, 0); + } + else + { + Vector2 n = shape [i + 1] - shape [i - 1]; + + n.Set (n.y, -n.x); + + n.Normalize (); + + shape [i] += new Vector3 (n.x, n.y, 0) * sf.sideThickness; + } + } + + // Compute the bounds. + + float y0, y1, mr; + + y0 = y1 = shape [0].y; + mr = shape [0].x; + + for (int i = 0; i < shape.Length; ++i) + { + var p = shape [i]; + + if (p.x > mr) + { + mr = p.x; + } + + if (p.y < y0) + { + y0 = p.y; + } + else if (p.y > y1) + { + y1 = p.y; + } + } + + boundCylY0 = y0; + boundCylY1 = y1; + boundCylRad = mr; + + lookupCenter = new Vector3 (0, (y0 + y1) * 0.5f, 0); + lookupRad = new Vector2 (mr, (y1 - y0) * 0.5f).magnitude; + + return attached; + } + + void enableShielding () + { + disableShielding (); + + var attached = getFairingParams (); + + if (!sideFairing) + { + return; + } + + // Get all parts in range. + + var parts = new List(); + + var colliders = Physics.OverlapSphere (part.transform.TransformPoint (lookupCenter), lookupRad, 1); + + for (int i = colliders.Length - 1; i >= 0; --i) + { + var p = colliders [i].gameObject.GetComponentUpwards(); + + if (p != null) + { + parts.AddUnique (p); + } + } + + // Filter parts. + + float sizeSqr = lookupRad * lookupRad * 4; + float boundCylRadSq = boundCylRad * boundCylRad; + + bool isInline = (sideFairing.inlineHeight > 0); + bool topClosed = false; + + Matrix4x4 w2l = Matrix4x4.identity, w2lb = Matrix4x4.identity; + + Bounds topBounds = default (Bounds); + + if (isInline) + { + w2l = part.transform.worldToLocalMatrix; + w2lb = w2l; + + for (int i = 0; i < 3; ++i) + { + for (int j = 0; j < 3; ++j) + { + w2lb [i, j] = Mathf.Abs (w2lb [i, j]); + } + } + + topBounds = new Bounds (new Vector3 (0, boundCylY1, 0), new Vector3 (sideFairing.topRad * 2, sideFairing.sideThickness, sideFairing.topRad * 2)); + } + + for (int pi = 0; pi < parts.Count; ++pi) + { + var pt = parts [pi]; + + // Check special cases. + + if (pt == part) + { + shieldedParts.Add (pt); + + continue; + } + + bool isSide = false; + + for (int i = 0; i < attached.Length; ++i) + { + if (attached [i].attachedPart == pt) + { + isSide = true; + + break; + } + } + + if (isSide) + { + continue; + } + + // Check if the top is closed in the inline case. + + var bounds = pt.GetRendererBounds (); + + var box = PartGeometryUtil.MergeBounds (bounds, pt.transform); + + if (isInline && !topClosed && pt.vessel == vessel) + { + var wb = box; wb.Expand (sideFairing.sideThickness * 4); + + var b = new Bounds (w2l.MultiplyPoint3x4 (wb.center), w2lb.MultiplyVector (wb.size)); + + if (b.Contains (topBounds.min) && b.Contains (topBounds.max)) + { + topClosed = true; + } + } + + // Check if the centroid is within the fairing bounds. + + var c = part.transform.InverseTransformPoint (PartGeometryUtil.FindBoundsCentroid (bounds, null)); + + float y = c.y; + + if (y < boundCylY0 || y > boundCylY1) + { + continue; + } + + float xsq = new Vector2 (c.x, c.z).sqrMagnitude; + + if (xsq > boundCylRadSq) + { + continue; + } + + // Accurate centroid check. + + float x = Mathf.Sqrt (xsq); + + bool inside = false; + + for (int i = 1; i < shape.Length; ++i) + { + var p0 = shape [i - 1]; + var p1 = shape [i]; + + if (p0.y > p1.y) + { + var p = p0; + + p0 = p1; + p1 = p; + } + + if (y < p0.y || y > p1.y) + { + continue; + } + + float dy = p1.y - p0.y, r; + + if (dy <= 1e-6f) + { + r = (p0.x + p1.x) * 0.5f; + } + else + { + r = (p1.x - p0.x) * (y - p0.y) / dy + p0.x; + } + + if (x > r) + { + continue; + } + + inside = true; + + break; + } + + if (!inside) + { + continue; + } + + shieldedParts.Add (pt); + } + + if (isInline && !topClosed) + { + disableShielding (); + + return; + } + + // Add shielding. + + for (int i = 0; i < shieldedParts.Count; ++i) + { + shieldedParts [i].AddShield (this); + } + + numShieldedDisplay = shieldedParts.Count; + + var fbase = part.GetComponent(); + + if (fbase != null) + { + fbase.onShieldingEnabled (shieldedParts); + } + } + + void disableShielding () + { + if (shieldedParts != null) + { + var fbase = part.GetComponent(); + + if (fbase != null) + { + fbase.onShieldingDisabled (shieldedParts); + } + + for (int i = shieldedParts.Count - 1; i >= 0; --i) + { + if (shieldedParts [i] != null) + { + shieldedParts [i].RemoveShield (this); + } + } + + shieldedParts.Clear (); + } + + numShieldedDisplay = 0; + } + + void onVesselModified (Vessel v) + { + if (v != vessel) + { + var dp = v.vesselTransform.position - part.transform.TransformPoint (lookupCenter); + + if (dp.sqrMagnitude > lookupRad * lookupRad) + { + return; + } + } + + enableShielding (); + } + + void onVesselUnpack (Vessel v) + { + if (v == vessel) + { + enableShielding (); + } + } + + void onVesselPack (Vessel v) + { + if (v == vessel) + { + disableShielding (); + } + } + + void OnPartDestroyed (Part p) + { + var nnt = part.GetComponent(); + + if (p == part) + { + disableShielding (); + + return; + } + + // Check for attached side fairing parts. + + var attached = part.FindAttachNodes ("connect"); + + for (int i = 0; i < nnt.numNodes; ++i) + { + if (p == attached [i].attachedPart) + { + disableShielding (); + + return; + } + } + + // Check for top parts in the inline/adapter case. + + if (p.vessel == vessel && sideFairing && sideFairing.inlineHeight > 0) + { + enableShielding (); + } + } + + public void OnPartPack () + { + disableShielding (); + } + } +} diff --git a/Source/ProceduralFairings/FairingSide.cs b/Source/ProceduralFairings/FairingSide.cs new file mode 100644 index 0000000..564ed47 --- /dev/null +++ b/Source/ProceduralFairings/FairingSide.cs @@ -0,0 +1,833 @@ +// ================================================== +// Procedural Fairings plug-in by Alexey Volynskov. + +// Licensed under CC-BY-4.0 terms: https://creativecommons.org/licenses/by/4.0/legalcode +// ================================================== + +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Keramzit +{ + public class ProceduralFairingSide : PartModule, IPartCostModifier, IPartMassModifier + { + [KSPField] public float minBaseConeAngle = 20; + [KSPField] public Vector4 baseConeShape = new Vector4 (0, 0, 0, 0); + [KSPField] public Vector4 noseConeShape = new Vector4 (0, 0, 0, 0); + + [KSPField] public Vector2 mappingScale = new Vector2 (1024, 1024); + [KSPField] public Vector2 stripMapping = new Vector2 (992, 1024); + [KSPField] public Vector4 horMapping = new Vector4 (0, 480, 512, 992); + [KSPField] public Vector4 vertMapping = new Vector4 (0, 160, 704, 1024); + + [KSPField] public float costPerTonne = 2000; + [KSPField] public float specificBreakingForce = 2000; + [KSPField] public float specificBreakingTorque = 2000; + + public float defaultBaseCurveStartX; + public float defaultBaseCurveStartY; + public float defaultBaseCurveEndX; + public float defaultBaseCurveEndY; + public float defaultBaseConeSegments; + + public float defaultNoseCurveStartX; + public float defaultNoseCurveStartY; + public float defaultNoseCurveEndX; + public float defaultNoseCurveEndY; + public float defaultNoseConeSegments; + public float defaultNoseHeightRatio; + + public float totalMass; + + [KSPField (isPersistant = true)] public int numSegs = 12; + [KSPField (isPersistant = true)] public int numSideParts = 2; + [KSPField (isPersistant = true)] public float baseRad; + [KSPField (isPersistant = true)] public float maxRad = 1.50f; + [KSPField (isPersistant = true)] public float cylStart = 0.5f; + [KSPField (isPersistant = true)] public float cylEnd = 2.5f; + [KSPField (isPersistant = true)] public float topRad; + [KSPField (isPersistant = true)] public float inlineHeight; + [KSPField (isPersistant = true)] public float sideThickness = 0.05f; + [KSPField (isPersistant = true)] public Vector3 meshPos = Vector3.zero; + [KSPField (isPersistant = true)] public Quaternion meshRot = Quaternion.identity; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiName = "Base Auto-shape")] + [UI_Toggle (disabledText = "Off", enabledText = "On")] + public bool baseAutoShape = true; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiActive = false, guiName = "Base Curve Point A", guiFormat = "S4")] + [UI_FloatEdit (sigFigs = 2, minValue = 0.0f, maxValue = 1.0f, incrementLarge = 0.1f, incrementSmall = 0.01f, incrementSlide = 0.01f)] + public float baseCurveStartX = 0.5f; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiActive = false, guiName = "Base Curve Point B", guiFormat = "S4")] + [UI_FloatEdit (sigFigs = 2, minValue = 0.0f, maxValue = 1.0f, incrementLarge = 0.1f, incrementSmall = 0.01f, incrementSlide = 0.01f)] + public float baseCurveStartY = 0.0f; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiActive = false, guiName = "Base Curve Point C", guiFormat = "S4")] + [UI_FloatEdit (sigFigs = 2, minValue = 0.0f, maxValue = 1.0f, incrementLarge = 0.1f, incrementSmall = 0.01f, incrementSlide = 0.01f)] + public float baseCurveEndX = 1.0f; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiActive = false, guiName = "Base Curve Point D", guiFormat = "S4")] + [UI_FloatEdit (sigFigs = 2, minValue = 0.0f, maxValue = 1.0f, incrementLarge = 0.1f, incrementSmall = 0.01f, incrementSlide = 0.01f)] + public float baseCurveEndY = 0.5f; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiName = "Base Cone Segments")] + [UI_FloatRange (minValue = 1, maxValue = 12, stepIncrement = 1)] + public float baseConeSegments = 5; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiName = "Nose Auto-shape")] + [UI_Toggle (disabledText = "Off", enabledText = "On")] + public bool noseAutoShape = true; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiActive = false, guiName = "Nose Curve Point A", guiFormat = "S4")] + [UI_FloatEdit (sigFigs = 2, minValue = 0.0f, maxValue = 1.0f, incrementLarge = 0.1f, incrementSmall = 0.01f, incrementSlide = 0.01f)] + public float noseCurveStartX = 0.5f; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiActive = false, guiName = "Nose Curve Point B", guiFormat = "S4")] + [UI_FloatEdit (sigFigs = 2, minValue = 0.0f, maxValue = 1.0f, incrementLarge = 0.1f, incrementSmall = 0.01f, incrementSlide = 0.01f)] + public float noseCurveStartY = 0.0f; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiActive = false, guiName = "Nose Curve Point C", guiFormat = "S4")] + [UI_FloatEdit (sigFigs = 2, minValue = 0.0f, maxValue = 1.0f, incrementLarge = 0.1f, incrementSmall = 0.01f, incrementSlide = 0.01f)] + public float noseCurveEndX = 1.0f; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiActive = false, guiName = "Nose Curve Point D", guiFormat = "S4")] + [UI_FloatEdit (sigFigs = 2, minValue = 0.0f, maxValue = 1.0f, incrementLarge = 0.1f, incrementSmall = 0.01f, incrementSlide = 0.01f)] + public float noseCurveEndY = 0.5f; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiName = "Nose Cone Segments")] + [UI_FloatRange (minValue = 1, maxValue = 12, stepIncrement = 1)] + public float noseConeSegments = 7; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiActive = false, guiName = "Nose-height Ratio", guiFormat = "S4")] + [UI_FloatEdit (sigFigs = 2, minValue = 0.1f, maxValue = 5.0f, incrementLarge = 1.0f, incrementSmall = 0.1f, incrementSlide = 0.01f)] + public float noseHeightRatio = 2.0f; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiName = "Shape")] + [UI_Toggle (disabledText = "Unlocked", enabledText = "Locked")] + public bool shapeLock; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiName = "Density")] + [UI_FloatRange (minValue = 0.01f, maxValue = 1.0f, stepIncrement = 0.01f)] + public float density = 0.2f; + + [KSPField (isPersistant = false, guiActive = false, guiActiveEditor = true, guiName = "Mass")] + public string massDisplay; + + [KSPField (isPersistant = false, guiActive = false, guiActiveEditor = true, guiName = "Cost")] + public string costDisplay; + + public ModifierChangeWhen GetModuleCostChangeWhen () { return ModifierChangeWhen.FIXED; } + public ModifierChangeWhen GetModuleMassChangeWhen () { return ModifierChangeWhen.FIXED; } + + public float GetModuleCost (float defcost, ModifierStagingSituation sit) + { + return totalMass * costPerTonne - defcost; + } + + public float GetModuleMass (float defmass, ModifierStagingSituation sit) + { + return totalMass - defmass; + } + + public override string GetInfo () + { + const string infoString = "Attach to a procedural fairing base to reshape. Right-click it to set it's parameters."; + + return infoString; + } + + public void Start () + { + part.mass = totalMass; + } + + public override void OnStart (StartState state) + { + if (state == StartState.None) + { + return; + } + + if (state != StartState.Editor || shapeLock) + { + rebuildMesh (); + } + + // Set the initial fairing side curve values from the part config. + + baseCurveStartX = baseConeShape.x; + baseCurveStartY = baseConeShape.y; + baseCurveEndX = baseConeShape.z; + baseCurveEndY = baseConeShape.w; + + noseCurveStartX = noseConeShape.x; + noseCurveStartY = noseConeShape.y; + noseCurveEndX = noseConeShape.z; + noseCurveEndY = noseConeShape.w; + + // Save the default fairing side values for later use. + + defaultBaseCurveStartX = baseCurveStartX; + defaultBaseCurveStartY = baseCurveStartY; + defaultBaseCurveEndX = baseCurveEndX; + defaultBaseCurveEndY = baseCurveEndY; + defaultBaseConeSegments = baseConeSegments; + + defaultNoseCurveStartX = noseCurveStartX; + defaultNoseCurveStartY = noseCurveStartY; + defaultNoseCurveEndX = noseCurveEndX; + defaultNoseCurveEndY = noseCurveEndY; + defaultNoseConeSegments = noseConeSegments; + defaultNoseHeightRatio = noseHeightRatio; + + // Set the initial fairing side mass value. + + part.mass = totalMass; + + // Set up the GUI update callbacks. + + OnUpdateFairingSideUI (); + + OnToggleFairingShapeUI (); + } + + public override void OnLoad (ConfigNode cfg) + { + base.OnLoad (cfg); + + if (HighLogic.LoadedSceneIsEditor || HighLogic.LoadedSceneIsFlight) + { + rebuildMesh (); + } + } + + void OnUpdateFairingSideUI () + { + ((UI_Toggle) Fields["baseAutoShape"].uiControlEditor).onFieldChanged += OnChangeShapeUI; + ((UI_Toggle) Fields["noseAutoShape"].uiControlEditor).onFieldChanged += OnChangeShapeUI; + + ((UI_FloatEdit) Fields["baseCurveStartX"].uiControlEditor).onFieldChanged += OnChangeShapeUI; + ((UI_FloatEdit) Fields["baseCurveStartY"].uiControlEditor).onFieldChanged += OnChangeShapeUI; + ((UI_FloatEdit) Fields["baseCurveEndX"].uiControlEditor).onFieldChanged += OnChangeShapeUI; + ((UI_FloatEdit) Fields["baseCurveEndY"].uiControlEditor).onFieldChanged += OnChangeShapeUI; + + ((UI_FloatEdit) Fields["noseCurveStartX"].uiControlEditor).onFieldChanged += OnChangeShapeUI; + ((UI_FloatEdit) Fields["noseCurveStartY"].uiControlEditor).onFieldChanged += OnChangeShapeUI; + ((UI_FloatEdit) Fields["noseCurveEndX"].uiControlEditor).onFieldChanged += OnChangeShapeUI; + ((UI_FloatEdit) Fields["noseCurveEndY"].uiControlEditor).onFieldChanged += OnChangeShapeUI; + ((UI_FloatEdit) Fields["noseHeightRatio"].uiControlEditor).onFieldChanged += OnChangeShapeUI; + + ((UI_FloatRange) Fields["baseConeSegments"].uiControlEditor).onFieldChanged += OnChangeShapeUI; + ((UI_FloatRange) Fields["noseConeSegments"].uiControlEditor).onFieldChanged += OnChangeShapeUI; + ((UI_FloatRange) Fields["density"].uiControlEditor).onFieldChanged += OnChangeShapeUI; + } + + void OnChangeShapeUI (BaseField bf, object obj) + { + // Set the default values of the fairing side base parameters if the auto-shape is enabled. + + if (baseAutoShape) + { + baseCurveStartX = defaultBaseCurveStartX; + baseCurveStartY = defaultBaseCurveStartY; + baseCurveEndX = defaultBaseCurveEndX; + baseCurveEndY = defaultBaseCurveEndY; + baseConeSegments = defaultBaseConeSegments; + } + + // Set the default values of the fairing side nose parameters if the auto-shape is enabled. + + if (noseAutoShape) + { + noseCurveStartX = defaultNoseCurveStartX; + noseCurveStartY = defaultNoseCurveStartY; + noseCurveEndX = defaultNoseCurveEndX; + noseCurveEndY = defaultNoseCurveEndY; + noseConeSegments = defaultNoseConeSegments; + noseHeightRatio = defaultNoseHeightRatio; + } + + // Set the state of the advanced fairing side base and nose options. + + OnToggleFairingShapeUI (); + + // Update the fairing shape. + + var fairingSide = part.GetComponent(); + + if (fairingSide != null) + { + // Rebuild the fairing mesh. + + fairingSide.needShapeUpdate = true; + } + } + + void OnToggleFairingShapeUI () + { + Fields["baseCurveStartX"].guiActiveEditor = !baseAutoShape; + Fields["baseCurveStartY"].guiActiveEditor = !baseAutoShape; + Fields["baseCurveEndX"].guiActiveEditor = !baseAutoShape; + Fields["baseCurveEndY"].guiActiveEditor = !baseAutoShape; + Fields["baseConeSegments"].guiActiveEditor = !baseAutoShape; + + Fields["noseCurveStartX"].guiActiveEditor = !noseAutoShape; + Fields["noseCurveStartY"].guiActiveEditor = !noseAutoShape; + Fields["noseCurveEndX"].guiActiveEditor = !noseAutoShape; + Fields["noseCurveEndY"].guiActiveEditor = !noseAutoShape; + Fields["noseHeightRatio"].guiActiveEditor = !noseAutoShape; + Fields["noseConeSegments"].guiActiveEditor = !noseAutoShape; + } + + public void updateNodeSize () + { + var node = part.FindAttachNode ("connect"); + + if (node != null) + { + int s = Mathf.RoundToInt (baseRad * 2 / 1.25f) - 1; + + if (s < 0) + { + s = 0; + } + + node.size = s; + } + } + + public void FixedUpdate () + { + if (HighLogic.LoadedSceneIsEditor) + { + int nsym = part.symmetryCounterparts.Count; + + if (nsym == 0) + { + massDisplay = PFUtils.formatMass (totalMass); + costDisplay = PFUtils.formatCost (part.partInfo.cost + GetModuleCost (part.partInfo.cost, ModifierStagingSituation.CURRENT)); + } + else if (nsym == 1) + { + massDisplay = PFUtils.formatMass (totalMass * 2) + " (both)"; + costDisplay = PFUtils.formatCost ((part.partInfo.cost + GetModuleCost (part.partInfo.cost, ModifierStagingSituation.CURRENT)) * 2) + " (both)"; + } + else + { + massDisplay = PFUtils.formatMass (totalMass * (nsym + 1)) + " (all " + (nsym + 1) + ")"; + costDisplay = PFUtils.formatCost ((part.partInfo.cost + GetModuleCost (part.partInfo.cost, ModifierStagingSituation.CURRENT)) * (nsym + 1)) + " (all " + (nsym + 1) + ")"; + } + } + } + + public void rebuildMesh () + { + var mf = part.FindModelComponent("model"); + + if (!mf) + { + Debug.LogError ("[PF]: No model for side fairing!", part); + + return; + } + + Mesh m = mf.mesh; + + if (!m) + { + Debug.LogError ("[PF]: No mesh in side fairing model!", part); + + return; + } + + mf.transform.localPosition = meshPos; + mf.transform.localRotation = meshRot; + + updateNodeSize (); + + // Build the fairing shape line. + + float tip = maxRad * noseHeightRatio; + + Vector3 [] shape; + + baseConeShape = new Vector4 (baseCurveStartX, baseCurveStartY, baseCurveEndX, baseCurveEndY); + noseConeShape = new Vector4 (noseCurveStartX, noseCurveStartY, noseCurveEndX, noseCurveEndY); + + if (inlineHeight <= 0) + { + shape = ProceduralFairingBase.buildFairingShape (baseRad, maxRad, cylStart, cylEnd, noseHeightRatio, baseConeShape, noseConeShape, (int) baseConeSegments, (int) noseConeSegments, vertMapping, mappingScale.y); + } + else + { + shape = ProceduralFairingBase.buildInlineFairingShape (baseRad, maxRad, topRad, cylStart, cylEnd, inlineHeight, baseConeShape, (int) baseConeSegments, vertMapping, mappingScale.y); + } + + // Set up parameters. + + var dirs = new Vector3 [numSegs + 1]; + + for (int i = 0; i <= numSegs; ++i) + { + float a = Mathf.PI * 2 * (i - numSegs * 0.5f) / (numSideParts * numSegs); + + dirs [i] = new Vector3 (Mathf.Cos (a), 0, Mathf.Sin (a)); + } + + float segOMappingScale = (horMapping.y - horMapping.x) / (mappingScale.x * numSegs); + float segIMappingScale = (horMapping.w - horMapping.z) / (mappingScale.x * numSegs); + float segOMappingOfs = horMapping.x / mappingScale.x; + float segIMappingOfs = horMapping.z / mappingScale.x; + + if (numSideParts > 2) + { + segOMappingOfs += segOMappingScale * numSegs * (0.5f - 1f / numSideParts); + segOMappingScale *= 2f / numSideParts; + + segIMappingOfs += segIMappingScale * numSegs * (0.5f - 1f / numSideParts); + segIMappingScale *= 2f / numSideParts; + } + + float stripU0 = stripMapping.x / mappingScale.x; + float stripU1 = stripMapping.y / mappingScale.x; + + float ringSegLen = baseRad * Mathf.PI * 2 / (numSegs * numSideParts); + float topRingSegLen = topRad * Mathf.PI * 2 / (numSegs * numSideParts); + + float collWidth = maxRad * Mathf.PI * 2 / (numSideParts * 3); + + int numMainVerts = (numSegs + 1) * (shape.Length - 1) + 1; + int numMainFaces = numSegs * ((shape.Length - 2) * 2 + 1); + + int numSideVerts = shape.Length * 2; + int numSideFaces = (shape.Length - 1) * 2; + + int numRingVerts = (numSegs + 1) * 2; + int numRingFaces = numSegs * 2; + + if (inlineHeight > 0) + { + numMainVerts = (numSegs + 1) * shape.Length; + numMainFaces = numSegs * (shape.Length - 1) * 2; + } + + int totalVerts = numMainVerts * 2 + numSideVerts * 2 + numRingVerts; + int totalFaces = numMainFaces * 2 + numSideFaces * 2 + numRingFaces; + + if (inlineHeight > 0) + { + totalVerts += numRingVerts; + totalFaces += numRingFaces; + } + + var p = shape [shape.Length - 1]; + + float topY = p.y, topV = p.z; + + float collCenter = (cylStart + cylEnd) / 2; + float collHeight = cylEnd - cylStart; + + if (collHeight <= 0) + { + collHeight = Mathf.Min (topY - cylEnd, cylStart) / 2; + } + + // Compute the area. + + double area = 0; + + for (int i = 1; i < shape.Length; ++i) + { + area += (shape [i - 1].x + shape [i].x) * (shape [i].y - shape [i - 1].y) * Mathf.PI / numSideParts; + } + + // Set the parameters based on volume. + + float volume = (float) (area * sideThickness); + + part.mass = totalMass = volume * density; + part.breakingForce = part.mass * specificBreakingForce; + part.breakingTorque = part.mass * specificBreakingTorque; + + var offset = new Vector3 (maxRad * 0.7f, topY * 0.5f, 0); + + part.CoMOffset = part.transform.InverseTransformPoint (mf.transform.TransformPoint (offset)); + + // Remove any old colliders. + + var colls = part.FindModelComponents(); + + for (int i = 0; i < colls.Count; i++) + { + var c = colls [i]; + + UnityEngine.Object.Destroy (c.gameObject); + } + + // Add the new colliders. + + for (int i = -1; i <= 1; ++i) + { + var obj = new GameObject ("collider"); + + obj.transform.parent = mf.transform; + obj.transform.localPosition = Vector3.zero; + obj.transform.localRotation = Quaternion.AngleAxis (90f * i / numSideParts, Vector3.up); + + var coll = obj.AddComponent(); + + coll.center = new Vector3 (maxRad + sideThickness * 0.5f, collCenter, 0); + coll.size = new Vector3 (sideThickness, collHeight, collWidth); + } + { + // Nose collider. + + float r = maxRad * 0.2f; + + var obj = new GameObject ("nose_collider"); + + obj.transform.parent = mf.transform; + obj.transform.localPosition = new Vector3 (r, cylEnd + tip - r * 1.2f, 0); + obj.transform.localRotation = Quaternion.identity; + + if (inlineHeight > 0) + { + r = sideThickness * 0.5f; + + obj.transform.localPosition = new Vector3 (maxRad + r, collCenter, 0); + } + + var coll = obj.AddComponent(); + + coll.center = Vector3.zero; + coll.radius = r; + } + + // Build the fairing mesh. + + m.Clear (); + + var verts = new Vector3 [totalVerts]; + var uv = new Vector2 [totalVerts]; + var norm = new Vector3 [totalVerts]; + var tang = new Vector4 [totalVerts]; + + if (inlineHeight <= 0) + { + // Tip vertex. + + verts [numMainVerts - 1].Set (0, topY + sideThickness, 0); // Outside. + verts [numMainVerts * 2 - 1].Set (0, topY, 0); // Inside. + + uv [numMainVerts - 1].Set (segOMappingScale * 0.5f * numSegs + segOMappingOfs, topV); + uv [numMainVerts * 2 - 1].Set (segIMappingScale * 0.5f * numSegs + segIMappingOfs, topV); + + norm [numMainVerts - 1] = Vector3.up; + norm [numMainVerts * 2 - 1] = -Vector3.up; + + tang [numMainVerts - 1] = Vector3.zero; + tang [numMainVerts * 2 - 1] = Vector3.zero; + } + + // Main vertices. + + float noseV0 = vertMapping.z / mappingScale.y; + float noseV1 = vertMapping.w / mappingScale.y; + float noseVScale = 1f / (noseV1 - noseV0); + float oCenter = (horMapping.x + horMapping.y) / (mappingScale.x * 2); + float iCenter = (horMapping.z + horMapping.w) / (mappingScale.x * 2); + + int vi = 0; + + for (int i = 0; i < shape.Length - (inlineHeight <= 0 ? 1 : 0); ++i) + { + p = shape [i]; + + Vector2 n; + + if (i == 0) + { + n = shape [1] - shape [0]; + } + else if (i == shape.Length - 1) + { + n = shape [i] - shape [i - 1]; + } + else + { + n = shape [i + 1] - shape [i - 1]; + } + + n.Set (n.y, -n.x); + + n.Normalize (); + + for (int j = 0; j <= numSegs; ++j, ++vi) + { + var d = dirs [j]; + + var dp = d * p.x + Vector3.up * p.y; + var dn = d * n.x + Vector3.up * n.y; + + if (i == 0 || i == shape.Length - 1) + { + verts [vi] = dp + d * sideThickness; + } + else + { + verts [vi] = dp + dn * sideThickness; + } + + verts[vi + numMainVerts] = dp; + + float v = (p.z - noseV0) * noseVScale; + float uo = j * segOMappingScale + segOMappingOfs; + float ui = (numSegs - j) * segIMappingScale + segIMappingOfs; + + if (v > 0 && v < 1) + { + float us = 1 - v; + + uo = (uo - oCenter) * us + oCenter; + ui = (ui - iCenter) * us + iCenter; + } + + uv [vi].Set (uo, p.z); + + uv [vi + numMainVerts].Set (ui, p.z); + + norm [vi] = dn; + norm [vi + numMainVerts] = -dn; + + tang [vi].Set (-d.z, 0, d.x, 0); + tang [vi + numMainVerts].Set (d.z, 0, -d.x, 0); + } + } + + // Side strip vertices. + + float stripScale = Mathf.Abs (stripMapping.y - stripMapping.x) / (sideThickness * mappingScale.y); + + vi = numMainVerts * 2; + + float o = 0; + + for (int i = 0; i < shape.Length; ++i, vi += 2) + { + int si = i * (numSegs + 1); + + var d = dirs [0]; + + verts [vi] = verts [si]; + + uv [vi].Set (stripU0, o); + norm [vi].Set (d.z, 0, -d.x); + + verts [vi + 1] = verts [si + numMainVerts]; + uv [vi + 1].Set (stripU1, o); + norm [vi + 1] = norm[vi]; + tang [vi] = tang [vi + 1] = (verts [vi + 1] - verts [vi]).normalized; + + if (i + 1 < shape.Length) + { + o += ((Vector2) shape [i + 1] - (Vector2) shape [i]).magnitude * stripScale; + } + } + + vi += numSideVerts - 2; + + for (int i = shape.Length - 1; i >= 0; --i, vi -= 2) + { + int si = i * (numSegs + 1) + numSegs; + + if (i == shape.Length - 1 && inlineHeight <= 0) + { + si = numMainVerts - 1; + } + + var d = dirs [numSegs]; + + verts [vi] = verts [si]; + uv [vi].Set (stripU0, o); + norm [vi].Set (-d.z, 0, d.x); + + verts [vi + 1] = verts [si + numMainVerts]; + uv [vi + 1].Set (stripU1, o); + norm [vi + 1] = norm [vi]; + tang [vi] = tang [vi + 1] = (verts [vi + 1] - verts [vi]).normalized; + + if (i > 0) + { + o += ((Vector2) shape [i] - (Vector2) shape [i - 1]).magnitude * stripScale; + } + } + + // Ring vertices. + + vi = numMainVerts * 2 + numSideVerts * 2; + + o = 0; + + for (int j = numSegs; j >= 0; --j, vi += 2, o += ringSegLen * stripScale) + { + verts [vi] = verts [j]; + uv [vi].Set (stripU0, o); + norm [vi] = -Vector3.up; + + verts [vi + 1] = verts [j + numMainVerts]; + uv [vi + 1].Set (stripU1, o); + norm [vi + 1] = -Vector3.up; + tang [vi] = tang [vi + 1] = (verts [vi + 1] - verts [vi]).normalized; + } + + if (inlineHeight > 0) + { + // Top ring vertices. + + o = 0; + + int si = (shape.Length - 1) * (numSegs + 1); + + for (int j = 0; j <= numSegs; ++j, vi += 2, o += topRingSegLen * stripScale) + { + verts [vi] = verts [si + j]; + uv [vi].Set (stripU0, o); + norm [vi] = Vector3.up; + + verts [vi + 1] = verts [si + j + numMainVerts]; + uv [vi + 1].Set (stripU1, o); + norm [vi + 1] = Vector3.up; + tang [vi] = tang [vi + 1] = (verts [vi + 1] - verts [vi]).normalized; + } + } + + // Set vertex data to mesh. + + for (int i = 0; i < totalVerts; ++i) + { + tang [i].w = 1; + } + + m.vertices = verts; + m.uv = uv; + m.normals = norm; + m.tangents = tang; + + m.uv2 = null; + m.colors32 = null; + + var tri = new int [totalFaces * 3]; + + // Main faces. + + vi = 0; + + int ti1 = 0, ti2 = numMainFaces * 3; + + for (int i = 0; i < shape.Length - (inlineHeight <= 0 ? 2 : 1); ++i, ++vi) + { + p = shape [i]; + + for (int j = 0; j < numSegs; ++j, ++vi) + { + tri [ti1++] = vi; + tri [ti1++] = vi + 1 + numSegs + 1; + tri [ti1++] = vi + 1; + + tri [ti1++] = vi; + tri [ti1++] = vi + numSegs + 1; + tri [ti1++] = vi + 1 + numSegs + 1; + + tri [ti2++] = numMainVerts + vi; + tri [ti2++] = numMainVerts + vi + 1; + tri [ti2++] = numMainVerts + vi + 1 + numSegs + 1; + + tri [ti2++] = numMainVerts + vi; + tri [ti2++] = numMainVerts + vi + 1 + numSegs + 1; + tri [ti2++] = numMainVerts + vi + numSegs + 1; + } + } + + if (inlineHeight <= 0) + { + // Main tip faces. + + for (int j = 0; j < numSegs; ++j, ++vi) + { + tri [ti1++] = vi; + tri [ti1++] = numMainVerts - 1; + tri [ti1++] = vi + 1; + + tri [ti2++] = numMainVerts + vi; + tri [ti2++] = numMainVerts + vi + 1; + tri [ti2++] = numMainVerts + numMainVerts - 1; + } + } + + // Side strip faces. + + vi = numMainVerts * 2; + ti1 = numMainFaces * 2 * 3; + ti2 = ti1 + numSideFaces * 3; + + for (int i = 0; i < shape.Length - 1; ++i, vi += 2) + { + tri [ti1++] = vi; + tri [ti1++] = vi + 1; + tri [ti1++] = vi + 3; + + tri [ti1++] = vi; + tri [ti1++] = vi + 3; + tri [ti1++] = vi + 2; + + tri [ti2++] = numSideVerts + vi; + tri [ti2++] = numSideVerts + vi + 3; + tri [ti2++] = numSideVerts + vi + 1; + + tri [ti2++] = numSideVerts + vi; + tri [ti2++] = numSideVerts + vi + 2; + tri [ti2++] = numSideVerts + vi + 3; + } + + // Ring faces. + + vi = numMainVerts * 2 + numSideVerts * 2; + ti1 = (numMainFaces + numSideFaces) * 2 * 3; + + for (int j = 0; j < numSegs; ++j, vi += 2) + { + tri [ti1++] = vi; + tri [ti1++] = vi + 1; + tri [ti1++] = vi + 3; + + tri [ti1++] = vi; + tri [ti1++] = vi + 3; + tri [ti1++] = vi + 2; + } + + if (inlineHeight > 0) + { + // Top ring faces. + + vi += 2; + + for (int j = 0; j < numSegs; ++j, vi += 2) + { + tri [ti1++] = vi; + tri [ti1++] = vi + 1; + tri [ti1++] = vi + 3; + + tri [ti1++] = vi; + tri [ti1++] = vi + 3; + tri [ti1++] = vi + 2; + } + } + + m.triangles = tri; + + StartCoroutine (PFUtils.updateDragCubeCoroutine (part, 1)); + } + } +} diff --git a/Source/ProceduralFairings/NodeNumberTweaker.cs b/Source/ProceduralFairings/NodeNumberTweaker.cs new file mode 100644 index 0000000..f7f34e7 --- /dev/null +++ b/Source/ProceduralFairings/NodeNumberTweaker.cs @@ -0,0 +1,348 @@ +// ================================================== +// Procedural Fairings plug-in by Alexey Volynskov. + +// Licensed under CC-BY-4.0 terms: https://creativecommons.org/licenses/by/4.0/legalcode +// ================================================== + +using System; +using UnityEngine; + +namespace Keramzit +{ + public class KzNodeNumberTweaker : PartModule + { + [KSPField] public string nodePrefix = "bottom"; + [KSPField] public int maxNumber; + + [KSPField (guiActiveEditor = true, guiName = "Fairing Nodes")] + [UI_FloatRange (minValue = 1, maxValue = 8, stepIncrement = 1)] + public float uiNumNodes = 2; + + [KSPField (isPersistant = true)] + public int numNodes = 2; + + int numNodesBefore; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiName = "Node offset", guiFormat = "S4", guiUnits = "m")] + [UI_FloatEdit (sigFigs = 3, unit = "m", minValue = 0.1f, maxValue = 5, incrementLarge = 0.625f, incrementSmall = 0.125f, incrementSlide = 0.001f)] + public float radius = 1.25f; + + [KSPField] public float radiusStepLarge = 0.625f; + [KSPField] public float radiusStepSmall = 0.125f; + + [KSPField] public bool shouldResizeNodes = true; + + protected float oldRadius = -1000; + protected bool justLoaded; + + public override string GetInfo () + { + return "Max. Nodes: " + maxNumber; + } + + [KSPField (isPersistant = true, guiActiveEditor = true, guiName = "Interstage Nodes")] + [UI_Toggle (disabledText = "Off", enabledText = "On")] + public bool showInterstageNodes = true; + + public virtual void FixedUpdate () + { + if (!radius.Equals (oldRadius)) + { + oldRadius = radius; + + updateNodePositions (); + } + + justLoaded = false; + } + + public void Update () + { + if (HighLogic.LoadedSceneIsEditor) + { + if ((int) uiNumNodes != numNodesBefore) + { + if (checkNodeAttachments ()) + { + uiNumNodes = numNodesBefore; + } + else + { + numNodes = (int) uiNumNodes; + numNodesBefore = numNodes; + + updateNodes (); + + bool removed = false; + + for (int i = numNodes + 1; i <= maxNumber; ++i) + { + var node = findNode (i); + + if (node == null) + { + continue; + } + + // Fix for ghost node when inserting a new PF base in + // the editor scene: do not delete unused nodes, move + // them away instead. Be careful to check references + // of the maximum number of nodes, mentioned elsewhere + // and retrieved via 'Findattachnodes("connect")'! + // Slightly hacky, but it works... + + HideUnusedNode (node); + + removed = true; + } + + if (removed) + { + var fbase = part.GetComponent(); + + if (fbase) + { + fbase.needShapeUpdate = true; + fbase.updateDelay = 0.5f; + } + } + } + } + } + } + + // Slightly hacky...but it removes the ghost nodes. + + void HideUnusedNode (AttachNode node) + { + node.position.x = 10000; + } + + public override void OnStart (StartState state) + { + base.OnStart (state); + + if (state == StartState.None) + { + return; + } + + ((UI_FloatEdit) Fields["radius"].uiControlEditor).incrementLarge = radiusStepLarge; + ((UI_FloatEdit) Fields["radius"].uiControlEditor).incrementSmall = radiusStepSmall; + + Fields["radius"].guiActiveEditor = shouldResizeNodes; + + // Hide the interstage toggle button if there are no interstage nodes. + + var nodes = part.FindAttachNodes ("interstage"); + + if (nodes == null) + { + Fields["showInterstageNodes"].guiActiveEditor = false; + } + + // Change the GUI text if there are no fairing attachment nodes. + + nodes = part.FindAttachNodes ("connect"); + + if (nodes == null) + { + Fields["uiNumNodes"].guiName = "Side Nodes"; + } + + ((UI_FloatRange) Fields["uiNumNodes"].uiControlEditor).maxValue = maxNumber; + + uiNumNodes = numNodes; + numNodesBefore = numNodes; + + updateNodes (); + } + + public override void OnLoad (ConfigNode cfg) + { + base.OnLoad (cfg); + + justLoaded = true; + + uiNumNodes = numNodes; + numNodesBefore = numNodes; + + if (HighLogic.LoadedSceneIsEditor || HighLogic.LoadedSceneIsFlight) + { + updateNodes (); + } + } + + void updateNodes () + { + addRemoveNodes (); + + updateNodePositions (); + } + + string nodeName (int i) + { + return string.Format ("{0}{1:d2}", nodePrefix, i); + } + + AttachNode findNode (int i) + { + return part.FindAttachNode (nodeName (i)); + } + + bool checkNodeAttachments() + { + for (int i = 1; i <= maxNumber; ++i) + { + var node = findNode (i); + + if (node != null && node.attachedPart != null) + { + EditorScreenMessager.showMessage ("Please detach any fairing parts before changing the number of nodes!", 1); + + return true; + } + } + + return false; + } + + void addRemoveNodes () + { + part.stackSymmetry = numNodes - 1; + + float y = 0; + + bool gotY = false; + + int nodeSize = 0; + + Vector3 dir = Vector3.up; + + int i; + + for (i = 1; i <= maxNumber; ++i) + { + var node = findNode (i); + + if (node == null) + { + continue; + } + + y = node.position.y; + nodeSize = node.size; + dir = node.orientation; + + gotY = true; + + break; + } + + if (!gotY) + { + var node = part.FindAttachNode ("bottom"); + + if (node != null) + { + y = node.position.y; + } + } + + for (i = 1; i <= numNodes; ++i) + { + var node = findNode (i); + + if (node != null) + { + continue; + } + + // Create the fairing attachment node. + + node = new AttachNode (); + + node.id = nodeName (i); + node.owner = part; + node.nodeType = AttachNode.NodeType.Stack; + node.position = new Vector3 (0, y, 0); + node.orientation = dir; + node.originalPosition = node.position; + node.originalOrientation = node.orientation; + node.size = nodeSize; + + part.attachNodes.Add (node); + } + + for (; i <= maxNumber; ++i) + { + var node = findNode (i); + + if (node == null) + { + continue; + } + + if (HighLogic.LoadedSceneIsEditor) + { + node.position.x = 10000; + } + else + { + part.attachNodes.Remove (node); + } + } + + var fbase = part.GetComponent(); + + if (fbase) + { + fbase.needShapeUpdate = true; + } + } + + void updateNodePositions () + { + float d = Mathf.Sin (Mathf.PI / numNodes) * radius * 2; + + int size = Mathf.RoundToInt (d / (radiusStepLarge * 2)); + + for (int i = 1; i <= numNodes; ++i) + { + var node = findNode (i); + + if (node == null) + { + continue; + } + + float a = Mathf.PI * 2 * (i - 1) / numNodes; + + node.position.x = Mathf.Cos (a) * radius; + node.position.z = Mathf.Sin (a) * radius; + + if (shouldResizeNodes) + { + node.size = size; + } + + if (!justLoaded) + { + PFUtils.updateAttachedPartPos (node, part); + } + } + + for (int i = numNodes + 1; i <= maxNumber; ++i) + { + var node = findNode (i); + + if (node == null) + { + continue; + } + + node.position.x = 10000; + } + } + } +} diff --git a/Source/ProceduralFairings/PFKMJoint.cs b/Source/ProceduralFairings/PFKMJoint.cs new file mode 100644 index 0000000..2f9cb95 --- /dev/null +++ b/Source/ProceduralFairings/PFKMJoint.cs @@ -0,0 +1,605 @@ +// ================================================== +// Procedural Fairings plug-in by Alexey Volynskov. + +// Licensed under CC-BY-4.0 terms: https://creativecommons.org/licenses/by/4.0/legalcode +// ================================================== + +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Keramzit +{ + public class PFKMJoints : PartModule + { + [KSPField (isPersistant = true)] + public float breakingForce = 500000f; + + [KSPField (guiActive = true, guiName = "View Joints")] + [UI_Toggle (disabledText = "Off", enabledText = "On")] + public bool viewJoints; + + const float w1 = 0.05f; + const float w2 = 0.15f; + + readonly List jointLines = new List(); + + bool morejointsadded; + + Part bottomNodePart; + + List nodeParts = new List(); + + void AddMoreJoints () + { + int i; + + AttachNode attachNode; + + if (!morejointsadded) + { + AttachNode attachNode1 = base.part.FindAttachNode ("bottom"); + + AttachNode [] attachNodeArray = base.part.FindAttachNodes ("interstage"); + AttachNode [] attachNodeArray1 = base.part.FindAttachNodes ("top"); + + string [] _vessel = { "[PF]: Adding Joints to Vessel: ", vessel.vesselName, " (Launch ID: ", base.part.launchID.ToString(), ") (GUID: ", base.vessel.id.ToString(), ")" }; + + Debug.Log (string.Concat (_vessel)); + + _vessel = new [] { "[PF]: For PF Part: ", base.part.name, " (", base.part.craftID.ToString (), ")" }; + + Debug.Log (string.Concat (_vessel)); + + Part part = null; + + if ((attachNode1 == null ? false : attachNode1.attachedPart != null)) + { + part = attachNode1.attachedPart; + + bottomNodePart = part; + + addStrut (part, base.part, Vector3.zero); + + _vessel = new [] { "[PF]: Bottom Part: ", part.name, " (", part.craftID.ToString (), ")" }; + + Debug.Log (string.Concat (_vessel)); + } + + Debug.Log ("[PF]: Top Parts:"); + + if (attachNodeArray1 != null) + { + for (i = 0; i < (int)attachNodeArray1.Length; i++) + { + attachNode = attachNodeArray1 [i]; + + if (attachNode.attachedPart != null) + { + if (part != null) + { + AddPartJoint (attachNode.attachedPart, part, attachNode.FindOpposingNode (), attachNode1.FindOpposingNode ()); + } + + addStrut (attachNode.attachedPart, base.part, Vector3.zero); + + nodeParts.Add (attachNode.attachedPart); + + _vessel = new [] { "[PF]:", attachNode.attachedPart.name, " (", attachNode.attachedPart.craftID.ToString (), ")" }; + + Debug.Log (string.Concat (_vessel)); + } + } + } + + if (attachNodeArray != null) + { + for (i = 0; i < (int)attachNodeArray.Length; i++) + { + attachNode = attachNodeArray [i]; + + if (attachNode.attachedPart != null) + { + if (part != null) + { + AddPartJoint (attachNode.attachedPart, part, attachNode.FindOpposingNode (), attachNode1.FindOpposingNode ()); + } + + addStrut (attachNode.attachedPart, base.part, Vector3.zero); + + nodeParts.Add (attachNode.attachedPart); + + _vessel = new [] { "[PF]:", attachNode.attachedPart.name, " (", attachNode.attachedPart.craftID.ToString (), ")" }; + + Debug.Log (string.Concat (_vessel)); + } + } + } + + morejointsadded = true; + } + } + + void AddPartJoint (Part p, Part pp, AttachNode pnode, AttachNode ppnode) + { + PartJoint partJoint = PartJoint.Create (p, pp, pnode, ppnode, 0); + + partJoint.SetBreakingForces (breakingForce, breakingForce); + + PartJoint partJoint1 = p.gameObject.AddComponent(); + + partJoint1 = partJoint; + } + + ConfigurableJoint addStrut (Part p, Part pp, Vector3 pos) + { + ConfigurableJoint configurableJoint; + + if (p != pp) + { + Rigidbody rigidbody = pp.Rigidbody; + + if ((rigidbody == null ? false : !(rigidbody == p.Rigidbody))) + { + ConfigurableJoint configurableJoint1 = p.gameObject.AddComponent(); + + configurableJoint1.xMotion = 0; + configurableJoint1.yMotion = 0; + configurableJoint1.zMotion = 0; + configurableJoint1.angularXMotion = 0; + configurableJoint1.angularYMotion = 0; + configurableJoint1.angularZMotion = 0; + configurableJoint1.projectionDistance = 0.1f; + configurableJoint1.projectionAngle = 5f; + configurableJoint1.breakForce = breakingForce; + configurableJoint1.breakTorque = breakingForce; + configurableJoint1.connectedBody = rigidbody; + configurableJoint1.targetPosition = pos; + configurableJoint = configurableJoint1; + } + else + { + configurableJoint = null; + } + } + else + { + configurableJoint = null; + } + + return configurableJoint; + } + + void ClearJointLines () + { + for (int i = 0; i < jointLines.Count; i++) + { + UnityEngine.Object.Destroy (jointLines [i].gameObject); + } + + jointLines.Clear (); + } + + public virtual void FixedUpdate () + { + if (!morejointsadded) + { + if ((!FlightGlobals.ready || vessel.packed ? false : vessel.loaded)) + { + AddMoreJoints (); + } + } + } + + LineRenderer JointLine (Vector3 posp, Vector3 pospp, Color col, float width) + { + LineRenderer lineRenderer = makeLineRenderer ("JointLine", col, width); + + lineRenderer.positionCount = 2; + + lineRenderer.SetPosition (0, posp); + lineRenderer.SetPosition (1, pospp); + + lineRenderer.useWorldSpace = true; + + return lineRenderer; + } + + public void ListJoints () + { + int j; + + string [] _name; + + float _breakForce; + + Vector3 _anchor; + + string str; + string str1; + + ClearJointLines (); + + List activeVessel = FlightGlobals.ActiveVessel.parts; + + for (int i = 0; i < activeVessel.Count; i++) + { + ConfigurableJoint [] components = activeVessel[i].gameObject.GetComponents(); + + if (components != null) + { + for (j = 0; j < (int)components.Length; j++) + { + ConfigurableJoint configurableJoint = components [j]; + + _name = new string [18]; + + _name[0] = "[PF]: , "; + _name[1] = activeVessel [i].name; + _name[2] = ", "; + _name[3] = (configurableJoint.connectedBody == null ? "" : configurableJoint.connectedBody.name); + _name[4] = ", "; + _breakForce = configurableJoint.breakForce; + _name[5] = _breakForce.ToString (); + _name[6] = ", "; + _breakForce = configurableJoint.breakTorque; + _name[7] = _breakForce.ToString (); + _name[8] = ", "; + _anchor = configurableJoint.anchor; + _name[9] = _anchor.ToString (); + _name[10] = ", "; + _anchor = configurableJoint.connectedAnchor; + _name[11] = _anchor.ToString (); + _name[12] = ", "; + + string [] strArrays = _name; + + if (configurableJoint.connectedBody == null) + { + str1 = "--"; + } + else + { + _anchor = activeVessel [i].transform.position - configurableJoint.connectedBody.position; + + str1 = _anchor.ToString (); + } + + strArrays [13] = str1; + + _name [14] = ", "; + _breakForce = configurableJoint.linearLimitSpring.damper; + _name [15] = _breakForce.ToString ("F2"); + _name [16] = ", "; + _breakForce = configurableJoint.linearLimitSpring.spring; + _name [17] = _breakForce.ToString ("F2"); + + Debug.Log (string.Concat (_name)); + } + } + + PartJoint [] partJointArray = activeVessel[i].gameObject.GetComponents(); + + if (partJointArray != null) + { + for (j = 0; j < (int)partJointArray.Length; j++) + { + PartJoint partJoint = partJointArray [j]; + + if ((partJoint.Host != null ? true : !(partJoint.Target == null))) + { + _name = new string [] { "[PF]: , ", partJoint.Host.name, ", ", null, null, null, null, null, null, null, null }; + + _name[3] = (partJoint.Target == null ? "" : partJoint.Target.name); + + string [] strArrays1 = _name; + + if (partJoint.Joint == null) + { + int count = partJoint.joints.Count; + + str = string.Concat (" (", count.ToString (), ")"); + } + else + { + _breakForce = partJoint.Joint.breakForce; + + string str2 = _breakForce.ToString (); + + _breakForce = partJoint.Joint.breakTorque; + + str = string.Concat (", ", str2, ", ", _breakForce.ToString ()); + } + + strArrays1 [4] = str; + + _name [5] = ", "; + _breakForce = partJoint.stiffness; + _name [6] = _breakForce.ToString ("F2"); + _name [7] = ", "; + _anchor = partJoint.HostAnchor; + _name [8] = _anchor.ToString (); + _name [9] = ", "; + _anchor = partJoint.TgtAnchor; + _name [10] = _anchor.ToString (); + + Debug.Log (string.Concat (_name)); + } + else + { + Debug.Log ("[PF]: , , "); + } + + if (partJoint.Target) + { + AttachNode attachNode = activeVessel [i].FindAttachNodeByPart (partJoint.Target); + + if (attachNode != null) + { + object [] objArray = { "[PF]: , ", partJoint.Host.name, ", ", partJoint.Target.name, ", ", attachNode.breakingForce.ToString(), ", ", attachNode.breakingTorque.ToString(), ", ", attachNode.contactArea.ToString("F2"), ", ", attachNode.attachMethod, ", ", attachNode.rigid.ToString (), ", ", attachNode.radius.ToString ("F2") }; + + Debug.Log (string.Concat (objArray)); + + AttachNode attachNode1 = attachNode.FindOpposingNode (); + + if ((attachNode1 == null ? false : attachNode1.owner != null)) + { + objArray = new object [] { "[PF]: , ", attachNode1.owner.name, ", ", (attachNode1.attachedPart != null ? attachNode1.attachedPart.name : ""), ", ", attachNode1.breakingForce.ToString(), ", ", attachNode1.breakingTorque.ToString(), ", ", attachNode1.contactArea.ToString("F2"), ", ", attachNode1.attachMethod, ", ", attachNode1.rigid.ToString (), ", ", attachNode1.radius.ToString ("F2") }; + + Debug.Log (string.Concat (objArray)); + } + } + } + } + } + + FixedJoint [] fixedJointArray = activeVessel [i].gameObject.GetComponents(); + + if (fixedJointArray != null) + { + for (j = 0; j < (int)fixedJointArray.Length; j++) + { + FixedJoint fixedJoint = fixedJointArray [j]; + + _name = new string [] { "[PF]: , ", fixedJoint.name, ", ", null, null, null, null, null, null, null, null, null }; + + _name [3] = (fixedJoint.connectedBody == null ? "" : fixedJoint.connectedBody.name); + _name [4] = ", "; + _breakForce = fixedJoint.breakForce; + _name [5] = _breakForce.ToString (); + _name [6] = ", "; + _breakForce = fixedJoint.breakTorque; + _name [7] = _breakForce.ToString (); + _name [8] = ", "; + _anchor = fixedJoint.anchor; + _name [9] = _anchor.ToString (); + _name [10] = ", "; + _anchor = fixedJoint.connectedAnchor; + _name [11] = _anchor.ToString (); + + Debug.Log (string.Concat (_name)); + } + } + } + } + + LineRenderer makeLineRenderer (string objectName, Color color, float wd) + { + var gameObjectLine = new GameObject (objectName); + + gameObjectLine.transform.parent = part.transform; + + gameObjectLine.transform.localPosition = Vector3.zero; + gameObjectLine.transform.localRotation = Quaternion.identity; + + LineRenderer lineRenderer = gameObjectLine.AddComponent(); + + lineRenderer.useWorldSpace = true; + lineRenderer.material = new Material (Shader.Find ("Particles/Additive")); + lineRenderer.startColor = color; + lineRenderer.endColor = color; + lineRenderer.startWidth = wd; + lineRenderer.endWidth = wd; + lineRenderer.positionCount = 0; + + return lineRenderer; + } + + public void OnDestroy () + { + viewJoints = false; + + ClearJointLines (); + + GameEvents.onGameSceneLoadRequested.Remove (new EventData.OnEvent (OnGameSceneLoadRequested)); + GameEvents.onVesselWasModified.Remove (new EventData.OnEvent (OnVesselModified)); + GameEvents.onPartJointBreak.Remove (new EventData.OnEvent (OnPartJointBreak)); + GameEvents.onVesselGoOffRails.Remove (new EventData.OnEvent (OnVesselGoOffRails)); + } + + void OnGameSceneLoadRequested (GameScenes scene) + { + if ((scene == GameScenes.FLIGHT ? false : viewJoints)) + { + viewJoints = false; + + ClearJointLines (); + } + } + + void OnPartJointBreak (PartJoint pj, float value) + { + Part host; + int i; + bool flag; + + if (pj.Host != part) + { + if (pj.Target == part) + { + host = pj.Host; + + if (nodeParts.Contains(host)) + { + if (bottomNodePart != null) + { + RemoveJoints (host, bottomNodePart); + } + + RemoveJoints (host, part); + + flag = nodeParts.Remove (host); + } + else if (host == bottomNodePart) + { + for (i = 0; i < nodeParts.Count; i++) + { + RemoveJoints (nodeParts [i], bottomNodePart); + } + + RemoveJoints (bottomNodePart, part); + } + + return; + } + + return; + } + + host = pj.Target; + + if (nodeParts.Contains(host)) + { + if (bottomNodePart != null) + { + RemoveJoints (host, bottomNodePart); + } + + RemoveJoints (host, part); + + flag = nodeParts.Remove (host); + } + else if (host == bottomNodePart) + { + for (i = 0; i < nodeParts.Count; i++) + { + RemoveJoints (nodeParts [i], bottomNodePart); + } + + RemoveJoints (bottomNodePart, part); + } + } + + public override void OnStart (PartModule.StartState state) + { + base.OnStart (state); + + var _uiControlFlight = (UI_Toggle) Fields["viewJoints"].uiControlFlight; + + _uiControlFlight.onFieldChanged = (Callback)Delegate.Combine (_uiControlFlight.onFieldChanged, new Callback(UIviewJoints_changed)); + + GameEvents.onGameSceneLoadRequested.Add (new EventData.OnEvent (OnGameSceneLoadRequested)); + GameEvents.onVesselWasModified.Add (new EventData.OnEvent (OnVesselModified)); + GameEvents.onPartJointBreak.Add (new EventData.OnEvent (OnPartJointBreak)); + GameEvents.onVesselGoOffRails.Add (new EventData.OnEvent (OnVesselGoOffRails)); + } + + void OnVesselGoOffRails (Vessel v) + { + if ((v == null ? true : this == null)) + { + } + } + + void OnVesselModified (Vessel v) + { + if (v == vessel) + { + if (viewJoints) + { + ViewJoints (); + } + } + } + + void RemoveJoints (Part p, Part pp) + { + if ((p == null || p.Rigidbody == null || pp == null ? false : !(pp.Rigidbody == null))) + { + ConfigurableJoint [] components = p.gameObject.GetComponents(); + + for (int i = 0; i < (int)components.Length; i++) + { + ConfigurableJoint configurableJoint = components [i]; + + if (configurableJoint.connectedBody == pp.Rigidbody) + { + try + { + UnityEngine.Object.Destroy (configurableJoint); + } + catch (Exception exception1) + { + Exception exception = exception1; + + string [] str = { "[PF]: RemoveJoint Anomaly (", p.ToString(), ", ", pp.ToString(), "): ", exception.Message }; + + Debug.Log (string.Concat (str)); + } + } + } + } + } + + void UIviewJoints_changed (BaseField bf, object obj) + { + if (viewJoints) + { + ListJoints (); + + ViewJoints (); + } + else + { + ClearJointLines(); + } + } + + public void ViewJoints () + { + ClearJointLines (); + + List activeVessel = FlightGlobals.ActiveVessel.parts; + + for (int i = 0; i < activeVessel.Count; i++) + { + ConfigurableJoint [] components = activeVessel [i].gameObject.GetComponents(); + + if (components != null) + { + for (int j = 0; j < (int)components.Length; j++) + { + ConfigurableJoint configurableJoint = components [j]; + + if (configurableJoint.connectedBody != null) + { + var vector3 = new Vector3 (0f, 5f, 0f); + var vector31 = new Vector3 (0.25f, 0f, 0f); + + Vector3 _position = activeVessel [i].transform.position + vector3; + Vector3 _position1 = configurableJoint.connectedBody.position + vector3; + Vector3 _position2 = (activeVessel [i].transform.position + (activeVessel [i].transform.rotation * configurableJoint.anchor)) + vector3; + + Vector3 vector32 = (configurableJoint.connectedBody.position + (configurableJoint.connectedBody.rotation * configurableJoint.connectedAnchor)) + vector3; + + jointLines.Add (JointLine (_position, _position1, Color.blue, w1)); + jointLines.Add (JointLine (_position2, vector32 + vector31, Color.yellow, w2)); + jointLines.Add (JointLine (_position, _position2, Color.gray, 0.03f)); + jointLines.Add (JointLine (_position1, vector32, Color.gray, 0.03f)); + } + } + } + } + } + } +} diff --git a/Source/ProceduralFairings/PayloadScan.cs b/Source/ProceduralFairings/PayloadScan.cs new file mode 100644 index 0000000..c0bd250 --- /dev/null +++ b/Source/ProceduralFairings/PayloadScan.cs @@ -0,0 +1,211 @@ +// ================================================== +// Procedural Fairings plug-in by Alexey Volynskov. + +// Licensed under CC-BY-4.0 terms: https://creativecommons.org/licenses/by/4.0/legalcode +// ================================================== + +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Keramzit +{ + struct PayloadScan + { + public List profile; + public List payload; + public HashSet hash; + + public List targets; + + public Matrix4x4 w2l; + + public float ofs, verticalStep, extraRadius; + + public int nestedBases; + + public PayloadScan (Part p, float vs, float er) + { + profile = new List(); + payload = new List(); + targets = new List(); + hash = new HashSet(); + + hash.Add (p); + + w2l = p.transform.worldToLocalMatrix; + ofs = 0; + verticalStep = vs; + extraRadius = er; + nestedBases = 0; + } + + public void addPart (Part p, Part prevPart) + { + if (p == null || hash.Contains (p)) + { + return; + } + + hash.Add (p); + + if (p.GetComponent() != null) + { + return; + } + + if (p == prevPart.parent && prevPart.srfAttachNode.attachedPart == p) + { + return; + } + + // Check for another fairing base. + + if (p.GetComponent() != null && p.GetComponent() == null) + { + AttachNode node = p.FindAttachNode ("top"); + + if (node != null && node.attachedPart == prevPart) + { + // Reversed base - potential inline fairing target. + + if (nestedBases <= 0) + { + targets.Add (p); + + return; + } + + --nestedBases; + } + else + { + ++nestedBases; + } + } + + payload.Add (p); + } + + public void addPayloadEdge (Vector3 v0, Vector3 v1) + { + float r0 = Mathf.Sqrt (v0.x * v0.x + v0.z * v0.z) + extraRadius; + float r1 = Mathf.Sqrt (v1.x * v1.x + v1.z * v1.z) + extraRadius; + + float y0 = (v0.y - ofs) / verticalStep; + float y1 = (v1.y - ofs) / verticalStep; + + if (y0 > y1) + { + float tmp; + + tmp = y0; y0 = y1; y1 = tmp; + tmp = r0; r0 = r1; r1 = tmp; + } + + int h0 = Mathf.FloorToInt (y0); + int h1 = Mathf.FloorToInt (y1); + + if (h1 < 0) + { + return; + } + + if (h1 >= profile.Count) + { + var farray = new float [h1 - profile.Count + 1]; + + for (int i = 0; i < farray.Length; i++) + { + farray [i] = 0; + } + + profile.AddRange (farray); + } + + if (h0 >= 0) + { + profile [h0] = Mathf.Max (profile [h0], r0); + } + + profile [h1] = Mathf.Max (profile [h1], r1); + + if (h0 != h1) + { + float k = (r1 - r0) / (y1 - y0); + float b = r0 + k * (h0 + 1 - y0); + float maxR = Mathf.Max (r0, r1); + + for (int h = Math.Max (h0, 0); h < h1; ++h) + { + float r = Mathf.Min (k * (h - h0) + b, maxR); + + profile [h] = Mathf.Max (profile [h], r); + profile [h + 1] = Mathf.Max (profile [h + 1], r); + } + } + } + + public void addPayload (Bounds box, Matrix4x4 boxTm) + { + Matrix4x4 m = w2l * boxTm; + + Vector3 p0 = box.min, p1 = box.max; + + var verts = new Vector3 [8]; + + for (int i = 0; i < 8; ++i) + { + verts [i] = m.MultiplyPoint3x4 (new Vector3 ((i & 1) != 0 ? p1.x : p0.x, (i & 2) != 0 ? p1.y : p0.y, (i & 4) != 0 ? p1.z : p0.z)); + } + + addPayloadEdge (verts [0], verts [1]); + addPayloadEdge (verts [2], verts [3]); + addPayloadEdge (verts [4], verts [5]); + addPayloadEdge (verts [6], verts [7]); + + addPayloadEdge (verts [0], verts [2]); + addPayloadEdge (verts [1], verts [3]); + addPayloadEdge (verts [4], verts [6]); + addPayloadEdge (verts [5], verts [7]); + + addPayloadEdge (verts [0], verts [4]); + addPayloadEdge (verts [1], verts [5]); + addPayloadEdge (verts [2], verts [6]); + addPayloadEdge (verts [3], verts [7]); + } + + public void addPayload (Collider c) + { + var mc = c as MeshCollider; + var bc = c as BoxCollider; + + if (mc) + { + var m = w2l * mc.transform.localToWorldMatrix; + + var verts = mc.sharedMesh.vertices; + var faces = mc.sharedMesh.triangles; + + for (int i = 0; i < faces.Length; i += 3) + { + var v0 = m.MultiplyPoint3x4 (verts [faces [i]]); + var v1 = m.MultiplyPoint3x4 (verts [faces [i + 1]]); + var v2 = m.MultiplyPoint3x4 (verts [faces [i + 2]]); + + addPayloadEdge (v0, v1); + addPayloadEdge (v1, v2); + addPayloadEdge (v2, v0); + } + } + else if (bc) + { + addPayload (new Bounds (bc.center, bc.size), bc.transform.localToWorldMatrix); + } + else + { + addPayload (c.bounds, Matrix4x4.identity); + } + } + } +} diff --git a/Source/ProceduralFairings/ProcAdapter.cs b/Source/ProceduralFairings/ProcAdapter.cs new file mode 100644 index 0000000..7570ac6 --- /dev/null +++ b/Source/ProceduralFairings/ProcAdapter.cs @@ -0,0 +1,711 @@ +// ================================================== +// Procedural Fairings plug-in by Alexey Volynskov. + +// Licensed under CC-BY-4.0 terms: https://creativecommons.org/licenses/by/4.0/legalcode +// ================================================== + +using KSP.UI.Screens; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Keramzit +{ + abstract class ProceduralAdapterBase : PartModule + { + [KSPField (isPersistant = true, guiActiveEditor = true, guiName = "Base", guiFormat = "S4", guiUnits = "m")] + [UI_FloatEdit (sigFigs = 3, unit = "m", minValue = 0.1f, maxValue = 5, incrementLarge = 1.25f, incrementSmall = 0.125f, incrementSlide = 0.001f)] + public float baseSize = 1.25f; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiName = "Top", guiFormat = "S4", guiUnits = "m")] + [UI_FloatEdit (sigFigs = 3, unit = "m", minValue = 0.1f, maxValue = 5, incrementLarge = 1.25f, incrementSmall = 0.125f, incrementSlide = 0.001f)] + public float topSize = 1.25f; + + [KSPField (isPersistant = true, guiActiveEditor = true, guiName = "Height", guiFormat = "S4", guiUnits = "m")] + [UI_FloatEdit (sigFigs = 3, unit = "m", minValue = 0.1f, maxValue = 50, incrementLarge = 1.0f, incrementSmall = 0.1f, incrementSlide = 0.001f)] + public float height = 1; + + [KSPField] public string topNodeName = "top1"; + + [KSPField] public float diameterStepLarge = 1.25f; + [KSPField] public float diameterStepSmall = 0.125f; + + [KSPField] public float heightStepLarge = 1.0f; + [KSPField] public float heightStepSmall = 0.1f; + + public bool changed = true; + + abstract public float minHeight { get; } + + float lastBaseSize = -1000; + float lastTopSize = -1000; + float lastHeight = -1000; + + protected bool justLoaded; + + public virtual void checkTweakables () + { + if (!baseSize.Equals (lastBaseSize)) + { + lastBaseSize = baseSize; + + changed = true; + } + + if (!topSize.Equals (lastTopSize)) + { + lastTopSize = topSize; + + changed = true; + } + + if (!height.Equals (lastHeight)) + { + lastHeight = height; + + changed = true; + } + } + + public virtual void FixedUpdate () + { + checkTweakables (); + + if (changed) + { + updateShape (); + } + + justLoaded = false; + } + + public virtual void updateShape () + { + changed = false; + + float topheight = 0; + float topnodeheight = 0; + + var node = part.FindAttachNode ("bottom"); + + if (node != null) + { + node.size = Mathf.RoundToInt(baseSize / diameterStepLarge); + } + + node = part.FindAttachNode ("top"); + + if (node != null) + { + node.size = Mathf.RoundToInt (baseSize / diameterStepLarge); + + topheight = node.position.y; + } + + node = part.FindAttachNode (topNodeName); + + if (node != null) + { + node.position = new Vector3 (0, height, 0); + + node.size = Mathf.RoundToInt (topSize / diameterStepLarge); + + if (!justLoaded) + { + PFUtils.updateAttachedPartPos (node, part); + } + + topnodeheight = height; + } + else + { + Debug.LogError ("[PF]: No '" + topNodeName + "' node in part!", this); + } + + var internodes = part.FindAttachNodes ("interstage"); + + if (internodes != null) + { + var inc = (topnodeheight - topheight) / (internodes.Length / 2 + 1); + + for (int i = 0, j = 0; i < internodes.Length; i = i + 2) + { + var height = topheight + (j + 1) * inc; + + j++; + + node = internodes [i]; + + node.position.y = height; + node.size = node.size = Mathf.RoundToInt (topSize / diameterStepLarge) - 1; + + if (!justLoaded) + { + PFUtils.updateAttachedPartPos (node, part); + } + + node = internodes [i + 1]; + + node.position.y = height; + node.size = node.size = Mathf.RoundToInt (topSize / diameterStepLarge) - 1; + + if (!justLoaded) + { + PFUtils.updateAttachedPartPos (node, part); + } + } + } + } + + public override void OnStart(StartState state) + { + base.OnStart (state); + + if (state == StartState.None) + { + return; + } + + StartCoroutine (FireFirstChanged ()); + + } + + public IEnumerator FireFirstChanged () + { + while(!(part.editorStarted || part.started)) + { + yield return new WaitForFixedUpdate (); + } + + // Wait a little more... + + yield return new WaitForSeconds (.01f); + + changed = true; + } + + public override void OnLoad (ConfigNode cfg) + { + base.OnLoad (cfg); + + justLoaded = true; + changed = true; + } + } + + class ProceduralFairingAdapter : ProceduralAdapterBase, IPartCostModifier, IPartMassModifier + { + [KSPField] public float sideThickness = 0.05f / 1.25f; + [KSPField] public Vector4 specificMass = new Vector4 (0.005f, 0.011f, 0.009f, 0f); + [KSPField] public float specificBreakingForce = 6050; + [KSPField] public float specificBreakingTorque = 6050; + [KSPField] public float costPerTonne = 2000; + + [KSPField] public float dragAreaScale = 1; + + [KSPField (isPersistant = true)] + public bool topNodeDecouplesWhenFairingsGone; + + public bool isTopNodePartPresent = true; + public bool isFairingPresent = true; + + [KSPEvent (name = "decNoFairings", active = true, guiActive = true, guiActiveEditor = true, guiActiveUnfocused = true, guiName = "text")] + public void UIToggleTopNodeDecouple () + { + topNodeDecouplesWhenFairingsGone = !topNodeDecouplesWhenFairingsGone; + + UpdateUIdecNoFairingsText (topNodeDecouplesWhenFairingsGone); + } + + void UpdateUIdecNoFairingsText (bool flag) + { + if (flag) + { + Events["UIToggleTopNodeDecouple"].guiName = "Decouple when Fairing gone: Yes"; + } + else + { + Events["UIToggleTopNodeDecouple"].guiName = "Decouple when Fairing gone: No"; + } + } + + public override float minHeight + { + get + { + return baseSize * 0.2f; + } + } + + public ModifierChangeWhen GetModuleCostChangeWhen() { return ModifierChangeWhen.FIXED; } + public ModifierChangeWhen GetModuleMassChangeWhen() { return ModifierChangeWhen.FIXED; } + + public float GetModuleCost (float defcost, ModifierStagingSituation sit) + { + return totalMass * costPerTonne - defcost; + } + + public float GetModuleMass (float defmass, ModifierStagingSituation sit) + { + return totalMass - defmass; + } + + public float calcSideThickness () + { + return Mathf.Min (sideThickness * Mathf.Max (baseSize, topSize), Mathf.Min (baseSize, topSize) * 0.25f); + } + + public float topRadius + { + get + { + return topSize * 0.5f - calcSideThickness (); + } + } + + [KSPField (isPersistant = true, guiActiveEditor = true, guiName = "Extra height", guiFormat = "S4", guiUnits = "m")] + [UI_FloatEdit (sigFigs = 3, unit = "m", minValue = 0, maxValue = 50, incrementLarge = 1.0f, incrementSmall = 0.1f, incrementSlide = 0.001f)] + public float extraHeight = 0; + + public bool engineFairingRemoved; + + [KSPField (isPersistant = false, guiActive = false, guiActiveEditor = true, guiName = "Mass")] + public string massDisplay; + + [KSPField (isPersistant = false, guiActive = false, guiActiveEditor = true, guiName = "Cost")] + public string costDisplay; + + bool limitsSet; + + float lastExtraHt = -1000; + + public override void checkTweakables () + { + base.checkTweakables (); + + if (!extraHeight.Equals (lastExtraHt)) + { + lastExtraHt = extraHeight; + + changed = true; + } + } + + void RemoveTopPartJoints () + { + Part topPart = getTopPart (); + + Part bottomPart = getBottomPart (); + + if (topPart == null ? false : (bottomPart != null)) + { + ConfigurableJoint [] components = topPart.gameObject.GetComponents(); + + for (int i = 0; i < (int) components.Length; i++) + { + ConfigurableJoint configurableJoint = components [i]; + + if (configurableJoint.connectedBody == bottomPart.Rigidbody) + { + UnityEngine.Object.Destroy (configurableJoint); + } + } + } + } + + public void Start () + { + part.mass = totalMass; + } + + public override void OnStart (StartState state) + { + base.OnStart (state); + + limitsSet = false; + + part.mass = totalMass; + + isFairingPresent = CheckForFairingPresent (); + + isTopNodePartPresent = (getTopPart () != null); + + UpdateUIdecNoFairingsText (topNodeDecouplesWhenFairingsGone); + + GameEvents.onEditorShipModified.Add (OnEditorShipModified); + GameEvents.onVesselWasModified.Add (OnVesselWasModified); + GameEvents.onVesselCreate.Add (OnVesselCreate); + GameEvents.onVesselGoOffRails.Add (OnVesselGoOffRails); + GameEvents.onVesselLoaded.Add (OnVesselLoaded); + GameEvents.onStageActivate.Add (OnStageActivate); + } + + public void OnDestroy () + { + GameEvents.onEditorShipModified.Remove (OnEditorShipModified); + GameEvents.onVesselWasModified.Remove (OnVesselWasModified); + GameEvents.onVesselCreate.Remove (OnVesselCreate); + GameEvents.onVesselGoOffRails.Remove (OnVesselGoOffRails); + GameEvents.onVesselLoaded.Remove (OnVesselLoaded); + GameEvents.onStageActivate.Remove (OnStageActivate); + } + + bool isShipModified = true; + bool isStaged; + + int stageNum; + + // Lets catch some events... + + void OnEditorShipModified (ShipConstruct sc) + { + isShipModified = true; + } + + void OnVesselWasModified (Vessel ves) + { + isShipModified = true; + } + + void OnVesselCreate (Vessel ves) + { + isShipModified = true; + } + + void OnVesselGoOffRails (Vessel ves) + { + isShipModified = true; + } + + void OnVesselLoaded (Vessel ves) + { + isShipModified = true; + } + + void OnStageActivate (int stage) + { + isStaged = true; + + stageNum = stage; + } + + public float totalMass; + + public override void updateShape () + { + base.updateShape (); + + float sth = calcSideThickness (); + + float br = baseSize * 0.5f - sth; + float scale = br * 2; + + part.mass = totalMass = ((specificMass.x * scale + specificMass.y) * scale + specificMass.z) * scale + specificMass.w; + + massDisplay = PFUtils.formatMass (totalMass); + costDisplay = PFUtils.formatCost (part.partInfo.cost + GetModuleCost (part.partInfo.cost, ModifierStagingSituation.CURRENT)); + + part.breakingForce = specificBreakingForce * Mathf.Pow (br, 2); + part.breakingTorque = specificBreakingTorque * Mathf.Pow (br, 2); + + var model = part.FindModelTransform ("model"); + + if (model != null) + { + model.localScale = Vector3.one * scale; + } + else + { + Debug.LogError("[PF]: No 'model' transform found in part!", this); + } + + part.rescaleFactor = scale; + + var node = part.FindAttachNode ("top"); + + node.position = node.originalPosition * scale; + + if (!justLoaded) + { + PFUtils.updateAttachedPartPos (node, part); + } + + var topNode = part.FindAttachNode ("top"); + var bottomNode = part.FindAttachNode ("bottom"); + + float y = (topNode.position.y + bottomNode.position.y) * 0.5f; + + int sideNodeSize = Mathf.RoundToInt(scale / diameterStepLarge) - 1; + + if (sideNodeSize < 0) + { + sideNodeSize = 0; + } + + var nodes = part.FindAttachNodes ("connect"); + + if (nodes != null) + { + for (int i = 0; i < nodes.Length; i++) + { + var n = nodes [i]; + + n.position.y = y; + n.size = sideNodeSize; + + if (!justLoaded) + { + PFUtils.updateAttachedPartPos (n, part); + } + } + } + + var topnode2 = part.FindAttachNode (topNodeName); + var internodes = part.FindAttachNodes ("interstage"); + + if (internodes != null && topnode2 != null) + { + var topheight = topNode.position.y; + var topnode2height = topnode2.position.y; + + var inc = (topnode2height - topheight) / (internodes.Length / 2 + 1); + + for (int i = 0, j = 0; i < internodes.Length; i = i + 2) + { + var baseHeight = topheight + (j + 1) * inc; + + j++; + + node = internodes [i]; + + node.position.y = baseHeight; + node.size = topNode.size; + + if (!justLoaded) + { + PFUtils.updateAttachedPartPos (node, part); + } + + node = internodes [i + 1]; + + node.position.y = baseHeight; + node.size = sideNodeSize; + + if (!justLoaded) + { + PFUtils.updateAttachedPartPos (node, part); + } + } + } + + var nnt = part.GetComponent(); + + if (nnt) + { + nnt.radius = baseSize * 0.5f; + } + + var fbase = part.GetComponent(); + + if (fbase) + { + fbase.baseSize = br * 2; + fbase.sideThickness = sth; + fbase.needShapeUpdate = true; + } + + StartCoroutine (PFUtils.updateDragCubeCoroutine (part, dragAreaScale)); + } + + public override void FixedUpdate () + { + base.FixedUpdate (); + + if (!limitsSet && PFUtils.canCheckTech ()) + { + limitsSet = true; + + float minSize = PFUtils.getTechMinValue ("PROCFAIRINGS_MINDIAMETER", 0.25f); + float maxSize = PFUtils.getTechMaxValue ("PROCFAIRINGS_MAXDIAMETER", 30); + + PFUtils.setFieldRange (Fields["baseSize"], minSize, maxSize); + PFUtils.setFieldRange (Fields["topSize"], minSize, maxSize); + + ((UI_FloatEdit) Fields["baseSize"].uiControlEditor).incrementLarge = diameterStepLarge; + ((UI_FloatEdit) Fields["baseSize"].uiControlEditor).incrementSmall = diameterStepSmall; + ((UI_FloatEdit) Fields["topSize"].uiControlEditor).incrementLarge = diameterStepLarge; + ((UI_FloatEdit) Fields["topSize"].uiControlEditor).incrementSmall = diameterStepSmall; + + ((UI_FloatEdit) Fields["height"].uiControlEditor).incrementLarge = heightStepLarge; + ((UI_FloatEdit) Fields["height"].uiControlEditor).incrementSmall = heightStepSmall; + ((UI_FloatEdit) Fields["extraHeight"].uiControlEditor).incrementLarge = heightStepLarge; + ((UI_FloatEdit) Fields["extraHeight"].uiControlEditor).incrementSmall = heightStepSmall; + } + + if (isShipModified) + { + isShipModified = false; + + // Remove the engine fairing (if there is any) from topmost node. + + if (!engineFairingRemoved) + { + var node = part.FindAttachNode (topNodeName); + + if (node != null && node.attachedPart != null) + { + var tp = node.attachedPart; + + if (HighLogic.LoadedSceneIsEditor || !tp.packed) + { + var comps = tp.GetComponents(); + + for (int i = 0; i < comps.Length; i++) + { + var mj = comps [i]; + + var jt = tp.FindModelTransform (mj.jettisonName); + + if (jt == null) + { + jt = mj.jettisonTransform; + } + + if (jt != null) + { + jt.gameObject.SetActive (false); + } + + mj.jettisonName = null; + mj.jettisonTransform = null; + } + + if (!HighLogic.LoadedSceneIsEditor) + { + engineFairingRemoved = true; + } + } + } + } + + if (!HighLogic.LoadedSceneIsEditor) + { + if (isTopNodePartPresent) + { + var tp = getTopPart (); + + if (tp == null) + { + isTopNodePartPresent = false; + + Events["UIToggleTopNodeDecouple"].guiActive = false; + } + else + { + if (topNodeDecouplesWhenFairingsGone && !CheckForFairingPresent ()) + { + PartModule item = part.Modules["ModuleDecouple"]; + + if (item == null) + { + Debug.LogError ("[PF]: Cannot decouple from top part!", this); + } + else + { + RemoveTopPartJoints (); + + ((ModuleDecouple)item).Decouple (); + + part.stackIcon.RemoveIcon (); + + StageManager.Instance.SortIcons (true); + + isFairingPresent = false; + isTopNodePartPresent = false; + + Events["UIToggleTopNodeDecouple"].guiActive = false; + } + } + } + } + + if (isStaged) + { + isStaged = false; + + if (part != null) + { + if (stageNum == part.inverseStage) + { + part.stackIcon.RemoveIcon (); + + StageManager.Instance.SortIcons (true); + + Events["UIToggleTopNodeDecouple"].guiActive = false; + } + } + } + } + } + } + + public Part getBottomPart () + { + AttachNode attachNode = part.FindAttachNode ("bottom"); + + return (attachNode == null) ? null : attachNode.attachedPart; + } + + public bool CheckForFairingPresent() + { + if (!isFairingPresent) + { + return false; + } + + var nodes = part.FindAttachNodes ("connect"); + + if (nodes == null) + { + return false; + } + + for (int i = 0; i < nodes.Length; i++) + { + var n = nodes [i]; + + if (n.attachedPart != null) + { + return true; + } + } + + return false; + } + + public Part getTopPart () + { + var node = part.FindAttachNode (topNodeName); + + return (node == null) ? null : node.attachedPart; + } + + public override void OnLoad (ConfigNode cfg) + { + base.OnLoad (cfg); + + if (cfg.HasValue ("baseRadius") && cfg.HasValue ("topRadius")) + { + // Load legacy settings. + + float br = float.Parse (cfg.GetValue ("baseRadius")); + float tr = float.Parse (cfg.GetValue ("topRadius")); + + baseSize = (br + sideThickness * br) * 2; + topSize = (tr + sideThickness * br) * 2; + + sideThickness *= 1.15f / 1.25f; + } + } + } +} diff --git a/Source/ProceduralFairings/ProceduralFairings.csproj b/Source/ProceduralFairings/ProceduralFairings.csproj new file mode 100644 index 0000000..209941d --- /dev/null +++ b/Source/ProceduralFairings/ProceduralFairings.csproj @@ -0,0 +1,82 @@ + + + + Debug + AnyCPU + {51CE67F2-5981-4AD2-97E8-0E2B44792AB2} + Library + ProceduralFairings + ProceduralFairings + v3.5 + False + OnBuildSuccess + False + False + False + ..\Builds\$(Configuration)\ + + + true + PdbOnly + False + ..\..\GameData\ProceduralFairings\Plugins\ + prompt + 4 + false + + + None + True + ..\..\GameData\ProceduralFairings\Plugins\ + prompt + 4 + false + + + False + ..\Builds\ + DEBUG; + Project + + + 4194304 + AnyCPU + False + Auto + 4096 + + + False + ..\Builds\ + Project + + + + + + + + + + + + + + + + + ..\..\..\..\..\..\..\Program Files %28x86%29\Steam\steamapps\common\Kerbal Space Program\KSP_Data\Managed\Assembly-CSharp.dll + False + + + + ..\..\..\..\..\..\..\Program Files %28x86%29\Steam\steamapps\common\Kerbal Space Program\KSP_Data\Managed\UnityEngine.dll + False + + + ..\..\..\..\..\..\..\Program Files %28x86%29\Steam\steamapps\common\Kerbal Space Program\KSP_Data\Managed\UnityEngine.UI.dll + False + + + + \ No newline at end of file diff --git a/Source/ProceduralFairings/Properties/AssemblyInfo.cs b/Source/ProceduralFairings/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..cd422ae --- /dev/null +++ b/Source/ProceduralFairings/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about the specified assembly. + +[assembly: AssemblyTitle ("ProceduralFairings")] +[assembly: AssemblyDescription ("Procedural Fairings for KSP")] +[assembly: AssemblyCopyright ("Copyright © 2016 - 2018, e-dog, rsparkyc")] +[assembly: AssemblyConfiguration ("Release")] +[assembly: AssemblyProduct ("ProceduralFairings")] + +// Hide the specified assembly from any COM components. + +[assembly: ComVisible (false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM. + +[assembly: Guid ("71c1f577-92c0-4ad6-9d1c-58a6eb02a0bc")] + +// Assembly version information. Consists of the following four values: +// +// • Major Version +// • Minor Version +// • Build Number +// • Revision + +[assembly: AssemblyVersion ("1.4.3.2152")] +[assembly: AssemblyFileVersion ("1.4.3.1")] + +// The KSPAssembly attribute can be used to ensure that the plugin assemblies +// are loaded in the correct order. +// This attribute is not currently used but it is included here for completeness. + +[assembly: KSPAssembly ("ProceduralFairings", 1, 0)] diff --git a/Source/ProceduralFairings/Resizers.cs b/Source/ProceduralFairings/Resizers.cs new file mode 100644 index 0000000..5541cc8 --- /dev/null +++ b/Source/ProceduralFairings/Resizers.cs @@ -0,0 +1,332 @@ +// ================================================== +// Procedural Fairings plug-in by Alexey Volynskov. + +// Licensed under CC-BY-4.0 terms: https://creativecommons.org/licenses/by/4.0/legalcode +// ================================================== + +using System; +using UnityEngine; + +namespace Keramzit +{ + public abstract class KzPartResizer : PartModule, IPartCostModifier, IPartMassModifier + { + [KSPField (isPersistant = true, guiActiveEditor = true, guiName = "Size", guiFormat = "S4", guiUnits = "m")] + [UI_FloatEdit (sigFigs = 3, unit = "m", minValue = 0.1f, maxValue = 5, incrementLarge = 1.25f, incrementSmall = 0.125f, incrementSlide = 0.001f)] + public float size = 1.25f; + + [KSPField] public float diameterStepLarge = 1.25f; + [KSPField] public float diameterStepSmall = 0.125f; + + [KSPField] public Vector4 specificMass = new Vector4 (0.005f, 0.011f, 0.009f, 0f); + [KSPField] public float specificBreakingForce = 1536; + [KSPField] public float specificBreakingTorque = 1536; + [KSPField] public float costPerTonne = 2000; + + [KSPField] public string minSizeName = "PROCFAIRINGS_MINDIAMETER"; + [KSPField] public string maxSizeName = "PROCFAIRINGS_MAXDIAMETER"; + + [KSPField] public float dragAreaScale = 1; + + [KSPField(isPersistant = false, guiActive = false, guiActiveEditor = true, guiName = "Mass")] + public string massDisplay; + + [KSPField(isPersistant = false, guiActive = false, guiActiveEditor = true, guiName = "Cost")] + public string costDisplay; + + protected float oldSize = -1000; + protected bool justLoaded, limitsSet; + + public ModifierChangeWhen GetModuleCostChangeWhen () { return ModifierChangeWhen.FIXED; } + public ModifierChangeWhen GetModuleMassChangeWhen () { return ModifierChangeWhen.FIXED; } + + public float GetModuleCost (float defcost, ModifierStagingSituation sit) + { + return totalMass * costPerTonne - defcost; + } + + public float GetModuleMass (float defmass, ModifierStagingSituation sit) + { + return totalMass - defmass; + } + + public void Start () + { + part.mass = totalMass; + } + + public override void OnStart (StartState state) + { + base.OnStart (state); + + limitsSet = false; + + updateNodeSize (size); + + part.mass = totalMass; + } + + public override void OnLoad (ConfigNode cfg) + { + base.OnLoad (cfg); + + justLoaded = true; + + if (HighLogic.LoadedSceneIsEditor || HighLogic.LoadedSceneIsFlight) + { + updateNodeSize (size); + } + } + + public virtual void FixedUpdate () + { + if (!limitsSet && PFUtils.canCheckTech ()) + { + limitsSet = true; + + float minSize = PFUtils.getTechMinValue (minSizeName, 0.25f); + float maxSize = PFUtils.getTechMaxValue (maxSizeName, 30); + + PFUtils.setFieldRange (Fields["size"], minSize, maxSize); + + ((UI_FloatEdit) Fields["size"].uiControlEditor).incrementLarge = diameterStepLarge; + ((UI_FloatEdit) Fields["size"].uiControlEditor).incrementSmall = diameterStepSmall; + } + + if (!size.Equals (oldSize)) + { + resizePart (size); + + StartCoroutine (PFUtils.updateDragCubeCoroutine (part, dragAreaScale)); + } + + justLoaded = false; + } + + public void scaleNode (AttachNode node, float scale, bool setSize) + { + if (node == null) + { + return; + } + + node.position = node.originalPosition * scale; + + if (!justLoaded) + { + PFUtils.updateAttachedPartPos (node, part); + } + + if (setSize) + { + node.size = Mathf.RoundToInt (scale / diameterStepLarge); + } + + if (node.attachedPart != null) + { + var baseEventDatum = new BaseEventDetails (0); + + baseEventDatum.Set("location", node.position); + baseEventDatum.Set("orientation", node.orientation); + baseEventDatum.Set("secondaryAxis", node.secondaryAxis); + baseEventDatum.Set("node", node); + + node.attachedPart.SendEvent ("OnPartAttachNodePositionChanged", baseEventDatum); + } + } + + public void setNodeSize (AttachNode node, float scale) + { + if (node == null) + { + return; + } + + node.size = Mathf.RoundToInt (scale / diameterStepLarge); + } + + public virtual void updateNodeSize (float scale) + { + setNodeSize (part.FindAttachNode ("top"), scale); + setNodeSize (part.FindAttachNode ("bottom"), scale); + + var nodes = part.FindAttachNodes ("interstage"); + + if (nodes != null) + { + for (int i = 0; i < nodes.Length; i++) + { + setNodeSize (nodes [i], scale); + } + } + } + + public float totalMass; + + public virtual void resizePart (float scale) + { + oldSize = size; + + part.mass = totalMass = ((specificMass.x * scale + specificMass.y) * scale + specificMass.z) * scale + specificMass.w; + + massDisplay = PFUtils.formatMass (totalMass); + costDisplay = PFUtils.formatCost (part.partInfo.cost + GetModuleCost(part.partInfo.cost, ModifierStagingSituation.CURRENT) + part.partInfo.cost); + + part.breakingForce = specificBreakingForce * Mathf.Pow (scale, 2); + part.breakingTorque = specificBreakingTorque * Mathf.Pow (scale, 2); + + var model = part.FindModelTransform ("model"); + + if (model != null) + { + model.localScale = Vector3.one * scale; + } + else + { + Debug.LogError ("[PF]: No 'model' transform found in part!", this); + } + + part.rescaleFactor = scale; + + scaleNode(part.FindAttachNode ("top"), scale, true); + scaleNode(part.FindAttachNode ("bottom"), scale, true); + + var nodes = part.FindAttachNodes ("interstage"); + + if (nodes != null) + { + for (int i = 0; i < nodes.Length; i++) + { + scaleNode (nodes [i], scale, true); + } + } + } + } + + public class KzFairingBaseResizer : KzPartResizer + { + [KSPField] public float sideThickness = 0.05f / 1.25f; + + public float calcSideThickness () + { + return Mathf.Min (sideThickness * size, size * 0.25f); + } + + public override void updateNodeSize (float scale) + { + float sth = calcSideThickness (); + + float br = size * 0.5f - sth; + scale = br * 2; + + base.updateNodeSize (scale); + + int sideNodeSize = Mathf.RoundToInt (scale / diameterStepLarge) - 1; + + if (sideNodeSize < 0) + { + sideNodeSize = 0; + } + + var nodes = part.FindAttachNodes ("connect"); + + for (int i = 0; i < nodes.Length; i++) + { + var n = nodes [i]; + + n.size = sideNodeSize; + } + } + + public override void resizePart (float scale) + { + float sth = calcSideThickness (); + + float br = size * 0.5f - sth; + scale = br * 2; + + base.resizePart (scale); + + var topNode = part.FindAttachNode ("top"); + var bottomNode = part.FindAttachNode ("bottom"); + + float y = (topNode.position.y + bottomNode.position.y) * 0.5f; + + int sideNodeSize = Mathf.RoundToInt(scale / diameterStepLarge) - 1; + + if (sideNodeSize < 0) + { + sideNodeSize = 0; + } + + var nodes = part.FindAttachNodes ("connect"); + + for (int i = 0; i < nodes.Length; i++) + { + var n = nodes [i]; + + n.position.y = y; + n.size = sideNodeSize; + + if (!justLoaded) + { + PFUtils.updateAttachedPartPos (n, part); + } + } + + var nnt = part.GetComponent(); + + if (nnt) + { + nnt.radius = size * 0.5f; + } + + var fbase = part.GetComponent(); + + if (fbase) + { + fbase.baseSize = br * 2; + fbase.sideThickness = sth; + fbase.needShapeUpdate = true; + } + } + } + + public class KzThrustPlateResizer : KzPartResizer + { + public override void resizePart (float scale) + { + base.resizePart (scale); + + var node = part.FindAttachNode ("bottom"); + + var nodes = part.FindAttachNodes ("bottom"); + + for (int i = 0; i < nodes.Length; i++) + { + var n = nodes [i]; + + n.position.y = node.position.y; + + if (!justLoaded) + { + PFUtils.updateAttachedPartPos (n, part); + } + } + + var nnt = part.GetComponent(); + + if (nnt) + { + float mr = size * 0.5f; + + if (nnt.radius > mr) + { + nnt.radius = mr; + } + + ((UI_FloatEdit) nnt.Fields["radius"].uiControlEditor).maxValue = mr; + } + } + } +} diff --git a/Source/ProceduralFairings/Utilities.cs b/Source/ProceduralFairings/Utilities.cs new file mode 100644 index 0000000..a426779 --- /dev/null +++ b/Source/ProceduralFairings/Utilities.cs @@ -0,0 +1,428 @@ +// ================================================== +// Procedural Fairings plug-in by Alexey Volynskov. + +// Licensed under CC-BY-4.0 terms: https://creativecommons.org/licenses/by/4.0/legalcode +// ================================================== + +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Keramzit +{ + struct BezierSlope + { + Vector2 p1, p2; + + public BezierSlope (Vector4 v) + { + p1 = new Vector2 (v.x, v.y); + p2 = new Vector2 (v.z, v.w); + } + + public Vector2 interp (float t) + { + Vector2 a = Vector2.Lerp (Vector2.zero, p1, t); + Vector2 b = Vector2.Lerp (p1, p2, t); + Vector2 c = Vector2.Lerp (p2, Vector2.one, t); + Vector2 d = Vector2.Lerp (a, b, t); + Vector2 e = Vector2.Lerp (b, c, t); + + return Vector2.Lerp (d, e, t); + } + } + + class Tuple + { + internal T1 Item1 { get; set; } + internal T2 Item2 { get; set; } + + public Tuple (T1 item1, T2 item2) + { + this.Item1 = item1; + this.Item2 = item2; + } + } + + public static class PFUtils + { + public static bool canCheckTech () + { + return HighLogic.LoadedSceneIsEditor && (ResearchAndDevelopment.Instance != null || (HighLogic.CurrentGame.Mode != Game.Modes.CAREER && HighLogic.CurrentGame.Mode != Game.Modes.SCIENCE_SANDBOX)); + } + + public static bool haveTech (string name) + { + if (HighLogic.CurrentGame.Mode != Game.Modes.CAREER && HighLogic.CurrentGame.Mode != Game.Modes.SCIENCE_SANDBOX) + { + return name == "sandbox"; + } + + return ResearchAndDevelopment.GetTechnologyState (name) == RDTech.State.Available; + } + + public static float getTechMinValue (string cfgname, float defVal) + { + bool hasValue = false; + float minVal = 0; + + var confnodes = GameDatabase.Instance.GetConfigNodes (cfgname); + + for (int j = 0; j < confnodes.Length; j++) + { + var tech = confnodes [j]; + + for (int i = 0; i < tech.values.Count; ++i) + { + var value = tech.values [i]; + + if (!haveTech(value.name)) + { + continue; + } + + float v = float.Parse (value.value); + + if (!hasValue || v < minVal) + { + minVal = v; + hasValue = true; + } + } + } + + return (!hasValue) ? defVal : minVal; + } + + public static float getTechMaxValue (string cfgname, float defVal) + { + bool hasValue = false; + float maxVal = 0; + + var confnodes = GameDatabase.Instance.GetConfigNodes (cfgname); + + for (int j = 0; j < confnodes.Length; j++) + { + var tech = confnodes [j]; + + for (int i = 0; i < tech.values.Count; ++i) + { + var value = tech.values [i]; + + if (!haveTech(value.name)) + { + continue; + } + + float v = float.Parse (value.value); + + if (!hasValue || v > maxVal) + { + maxVal = v; + hasValue = true; + } + } + } + + return (!hasValue) ? defVal : maxVal; + } + + public static void setFieldRange (BaseField field, float minval, float maxval) + { + var fr = field.uiControlEditor as UI_FloatRange; + + if (fr != null) + { + fr.minValue = minval; + fr.maxValue = maxval; + } + + var fe = field.uiControlEditor as UI_FloatEdit; + + if (fe != null) + { + fe.minValue = minval; + fe.maxValue = maxval; + } + } + + public static void updateAttachedPartPos (AttachNode node, Part part) + { + if (node == null || part == null) + { + return; + } + + var ap = node.attachedPart; + + if (!ap) + { + return; + } + + var an = ap.FindAttachNodeByPart (part); + + if (an == null) + { + return; + } + + var dp = part.transform.TransformPoint (node.position) - ap.transform.TransformPoint (an.position); + + if (ap == part.parent) + { + while (ap.parent) ap = ap.parent; + ap.transform.position += dp; + part.transform.position -= dp; + } + else + { + ap.transform.position += dp; + } + } + + public static string formatMass (float mass) + { + if (mass < 0.01f) + { + return (mass * 1e3f).ToString ("n3") + "kg"; + } + + return mass.ToString("n3") + "t"; + } + + public static string formatCost (float cost) + { + return cost.ToString ("n0"); + } + + public static void enableRenderer (Transform t, bool e) + { + if (!t) + { + return; + } + + var r = t.GetComponent(); + + if (r) + { + r.enabled = e; + } + } + + public static void hideDragStuff (Part part) + { + enableRenderer (part.FindModelTransform ("dragOnly"), false); + } + + public static bool FARinstalled, FARchecked; + + public static bool isFarInstalled () + { + if (!FARchecked) + { + var asmlist = AssemblyLoader.loadedAssemblies; + + if (asmlist != null) + { + for (int i = 0; i < asmlist.Count; i++) + { + if (asmlist [i].name == "FerramAerospaceResearch") + { + FARinstalled = true; + + break; + } + } + } + + FARchecked = true; + } + + return FARinstalled; + } + + public static void updateDragCube (Part part, float areaScale) + { + if (isFarInstalled ()) + { + Debug.Log ("[PF]: Calling FAR to update voxels..."); + + part.SendMessage ("GeometryPartModuleRebuildMeshData"); + } + + if (!HighLogic.LoadedSceneIsFlight) + { + return; + } + + enableRenderer (part.FindModelTransform ("dragOnly"), true); + + var dragCube = DragCubeSystem.Instance.RenderProceduralDragCube (part); + + enableRenderer (part.FindModelTransform ("dragOnly"), false); + + for (int i = 0; i < 6; ++i) + { + dragCube.Area [i] *= areaScale; + } + + part.DragCubes.ClearCubes (); + part.DragCubes.Cubes.Add (dragCube); + part.DragCubes.ResetCubeWeights (); + } + + public static IEnumerator updateDragCubeCoroutine (Part part, float areaScale) + { + while (true) + { + if (part == null || part.Equals (null)) + { + yield break; + } + + if (HighLogic.LoadedSceneIsFlight) + { + if (part.vessel == null || part.vessel.Equals (null)) + { + yield break; + } + + if (!FlightGlobals.ready || part.packed || !part.vessel.loaded) + { + yield return new WaitForFixedUpdate (); + + continue; + } + + break; + } + + if (HighLogic.LoadedSceneIsEditor) + { + yield return new WaitForFixedUpdate (); + + break; + } + + yield break; + } + + PFUtils.updateDragCube (part, areaScale); + } + + public static void refreshPartWindow () + { + var objs = UnityEngine.Object.FindObjectsOfType(); + + for (int i = 0; i < objs.Length; i++) + { + var w = objs [i]; + + w.displayDirty = true; + } + } + + public static Part partFromHit (this RaycastHit hit) + { + if (hit.collider == null || hit.collider.gameObject == null) + { + return null; + } + + var go = hit.collider.gameObject; + + var p = Part.FromGO (go); + + while (p == null) + { + if (go.transform != null && go.transform.parent != null && go.transform.parent.gameObject != null) + { + go = go.transform.parent.gameObject; + } + else + { + break; + } + + p = Part.FromGO (go); + } + + return p; + } + + public static List getAllChildrenRecursive (this Part rootPart, bool root) + { + var children = new List(); + + if (!root) + { + children.Add (rootPart); + } + + for (int i = 0; i < rootPart.children.Count; i++) + { + var child = rootPart.children [i]; + + children.AddRange (child.getAllChildrenRecursive (false)); + } + + return children; + } + + public static float GetMaxValueFromList (List list) + { + float max = 0; + + for (int i = 0; i < list.Count; i++) + { + if (max < list [i]) + { + max = list [i]; + } + } + + return max; + } + } + + [KSPAddon (KSPAddon.Startup.EditorAny, false)] + + public class EditorScreenMessager : MonoBehaviour + { + static float osdMessageTime; + static string osdMessageText; + + public static void showMessage (string msg, float delay) + { + osdMessageText = msg; + osdMessageTime = Time.time + delay; + } + + void OnGUI () + { + if (!HighLogic.LoadedSceneIsEditor) + { + return; + } + + if (Time.time < osdMessageTime) + { + GUI.skin = HighLogic.Skin; + + var style = new GUIStyle ("Label"); + + style.alignment = TextAnchor.MiddleCenter; + style.fontSize = 20; + style.normal.textColor = Color.black; + + GUI.Label (new Rect (2, 2 + (Screen.height / 9), Screen.width, 50), osdMessageText, style); + + style.normal.textColor = Color.yellow; + + GUI.Label (new Rect (0, Screen.height / 9, Screen.width, 50), osdMessageText, style); + } + } + } +} diff --git a/Source/Properties/AssemblyInfo.cs b/Source/Properties/AssemblyInfo.cs deleted file mode 100644 index 3ad1ed9..0000000 --- a/Source/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// Allgemeine Informationen über eine Assembly werden über die folgenden -// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, -// die mit einer Assembly verknüpft sind. -[assembly: AssemblyTitle("ProceduralFairings")] -[assembly: AssemblyDescription("Procedural Fairings 4.0 for KSP 1.3")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ProceduralFairings.Properties")] -[assembly: AssemblyCopyright("Copyright © 2017")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar -// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von -// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. -[assembly: ComVisible(false)] - -// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird -[assembly: Guid("71c1f577-92c0-4ad6-9d1c-58a6eb02a0bc")] - -// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: -// -// Hauptversion -// Nebenversion -// Buildnummer -// Revision -// -[assembly: AssemblyVersion("0.0.4.0")] -[assembly: AssemblyFileVersion("0.0.4.0")] diff --git a/Source/Resizers.cs b/Source/Resizers.cs deleted file mode 100644 index d29e5a7..0000000 --- a/Source/Resizers.cs +++ /dev/null @@ -1,281 +0,0 @@ -// Procedural Fairings plug-in by Alexey Volynskov -// Licensed under CC BY 3.0 terms: http://creativecommons.org/licenses/by/3.0/ -using System; -using System.Collections.Generic; -using System.Text; -using UnityEngine; - - -namespace Keramzit -{ - - - public abstract class KzPartResizer : PartModule, IPartCostModifier, IPartMassModifier - { - [KSPField(isPersistant = true, guiActiveEditor = true, guiName = "Size", guiFormat = "S4", guiUnits = "m")] - [UI_FloatEdit(sigFigs = 3, unit = "m", minValue = 0.1f, maxValue = 5, incrementLarge = 1.25f, incrementSmall = 0.125f, incrementSlide = 0.001f)] - public float size = 1.25f; - - [KSPField] public float diameterStepLarge = 1.25f; - [KSPField] public float diameterStepSmall = 0.125f; - - [KSPField] public Vector4 specificMass = new Vector4(0.005f, 0.011f, 0.009f, 0f); - [KSPField] public float specificBreakingForce = 1536; - [KSPField] public float specificBreakingTorque = 1536; - [KSPField] public float costPerTonne = 2000; - - [KSPField] public string minSizeName = "PROCFAIRINGS_MINDIAMETER"; - [KSPField] public string maxSizeName = "PROCFAIRINGS_MAXDIAMETER"; - - [KSPField] public float dragAreaScale = 1; - - [KSPField(isPersistant = false, guiActive = false, guiActiveEditor = true, guiName = "Mass")] - public string massDisplay; - - [KSPField(isPersistant = false, guiActive = false, guiActiveEditor = true, guiName = "Cost")] - public string costDisplay; - - - protected float oldSize = -1000; - protected bool justLoaded = false, limitsSet = false; - - // ProceduralParts needs this - // [KSPAPIExtensions.PartMessage.PartMessageEvent(false)] - // public event KSPAPIExtensions.PartMessage.PartAttachNodePositionChanged AttachNodeChanged; - - public ModifierChangeWhen GetModuleCostChangeWhen() { return ModifierChangeWhen.FIXED; } - public ModifierChangeWhen GetModuleMassChangeWhen() { return ModifierChangeWhen.FIXED; } - - public float GetModuleCost(float defcost, ModifierStagingSituation sit) - { - return totalMass * costPerTonne - defcost; - } - - public float GetModuleMass(float defmass, ModifierStagingSituation sit) - { - return totalMass - defmass; - } - - - public void Start() - { - part.mass = totalMass; - } - public override void OnStart(StartState state) - { - base.OnStart(state); - // KSPAPIExtensions.PartMessage.PartMessageService.Register(this); - limitsSet = false; - updateNodeSize(size); - part.mass = totalMass; - } - - - public override void OnLoad(ConfigNode cfg) - { - base.OnLoad(cfg); - justLoaded = true; - if (HighLogic.LoadedSceneIsEditor || HighLogic.LoadedSceneIsFlight) updateNodeSize(size); - } - - - public virtual void FixedUpdate() - { - if (!limitsSet && PFUtils.canCheckTech()) { - limitsSet = true; - float minSize = PFUtils.getTechMinValue(minSizeName, 0.25f); - float maxSize = PFUtils.getTechMaxValue(maxSizeName, 30); - - PFUtils.setFieldRange(Fields["size"], minSize, maxSize); - - ((UI_FloatEdit)Fields["size"].uiControlEditor).incrementLarge = diameterStepLarge; - ((UI_FloatEdit)Fields["size"].uiControlEditor).incrementSmall = diameterStepSmall; - } - - if (size != oldSize) { - resizePart(size); - StartCoroutine(PFUtils.updateDragCubeCoroutine(part, dragAreaScale)); - } - - justLoaded = false; - } - - - public void scaleNode(AttachNode node, float scale, bool setSize) - { - if (node == null) return; - node.position = node.originalPosition * scale; - if (!justLoaded) PFUtils.updateAttachedPartPos(node, part); - if (setSize) node.size = Mathf.RoundToInt(scale / diameterStepLarge); - - if (node.attachedPart != null) { - BaseEventDetails baseEventDatum = new BaseEventDetails(0); - baseEventDatum.Set("location", node.position); - baseEventDatum.Set("orientation", node.orientation); - baseEventDatum.Set("secondaryAxis", node.secondaryAxis); - baseEventDatum.Set("node", node); - node.attachedPart.SendEvent("OnPartAttachNodePositionChanged", baseEventDatum); - } - - - // Tell ProceduralParts, so it can update its node stuff... - // AttachNodeChanged(node, node.position, node.orientation, node.secondaryAxis); - } - - - public void setNodeSize(AttachNode node, float scale) - { - if (node == null) return; - node.size = Mathf.RoundToInt(scale / diameterStepLarge); - } - - - public virtual void updateNodeSize(float scale) - { - setNodeSize(part.FindAttachNode("top"), scale); - setNodeSize(part.FindAttachNode("bottom"), scale); - - var nodes = part.FindAttachNodes("interstage"); - if (nodes != null) { - for (int i = 0; i < nodes.Length; i++) { - setNodeSize(nodes[i], scale); - } - } - } - - public float totalMass; - public virtual void resizePart(float scale) - { - oldSize = size; - - part.mass = totalMass = ((specificMass.x * scale + specificMass.y) * scale + specificMass.z) * scale + specificMass.w; - massDisplay = PFUtils.formatMass(totalMass); - costDisplay = PFUtils.formatCost(part.partInfo.cost + GetModuleCost(part.partInfo.cost, ModifierStagingSituation.CURRENT) + part.partInfo.cost); - part.breakingForce = specificBreakingForce * Mathf.Pow(scale, 2); - part.breakingTorque = specificBreakingTorque * Mathf.Pow(scale, 2); - - var model = part.FindModelTransform("model"); - if (model != null) model.localScale = Vector3.one * scale; - else Debug.LogError("[KzPartResizer] No 'model' transform in the part", this); - part.rescaleFactor = scale; - - scaleNode(part.FindAttachNode("top"), scale, true); - scaleNode(part.FindAttachNode("bottom"), scale, true); - - var nodes = part.FindAttachNodes("interstage"); - if (nodes != null) { - for (int i = 0; i < nodes.Length; i++) { - scaleNode(nodes[i], scale, true); - } - } - - - } - } - - - //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ// - - - public class KzFairingBaseResizer : KzPartResizer - { - [KSPField] public float sideThickness = 0.05f / 1.25f; - - - public float calcSideThickness() - { - return Mathf.Min(sideThickness * size, size * 0.25f); - } - - - public override void updateNodeSize(float scale) - { - float sth = calcSideThickness(); - float br = size * 0.5f - sth; - scale = br * 2; - - base.updateNodeSize(scale); - - int sideNodeSize = Mathf.RoundToInt(scale / diameterStepLarge) - 1; - if (sideNodeSize < 0) sideNodeSize = 0; - - var nodes = part.FindAttachNodes("connect"); - for (int i = 0; i < nodes.Length; i++) { - var n = nodes[i]; - n.size = sideNodeSize; - } - - } - - - public override void resizePart(float scale) - { - float sth = calcSideThickness(); - float br = size * 0.5f - sth; - scale = br * 2; - - base.resizePart(scale); - - var topNode = part.FindAttachNode("top"); - var bottomNode = part.FindAttachNode("bottom"); - - float y = (topNode.position.y + bottomNode.position.y) * 0.5f; - int sideNodeSize = Mathf.RoundToInt(scale / diameterStepLarge) - 1; - if (sideNodeSize < 0) sideNodeSize = 0; - - var nodes = part.FindAttachNodes("connect"); - for (int i = 0; i < nodes.Length; i++) { - var n = nodes[i]; - n.position.y = y; - n.size = sideNodeSize; - if (!justLoaded) PFUtils.updateAttachedPartPos(n, part); - } - - var nnt = part.GetComponent(); - if (nnt) { - nnt.radius = size * 0.5f; - } - - var fbase = part.GetComponent(); - if (fbase) { - fbase.baseSize = br * 2; - fbase.sideThickness = sth; - fbase.needShapeUpdate = true; - } - } - } - - - //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ// - - - public class KzThrustPlateResizer : KzPartResizer - { - public override void resizePart(float scale) - { - base.resizePart(scale); - - var node = part.FindAttachNode("bottom"); - - var nodes = part.FindAttachNodes("bottom"); - for (int i = 0; i < nodes.Length; i++) { - var n = nodes[i]; - n.position.y = node.position.y; - if (!justLoaded) PFUtils.updateAttachedPartPos(n, part); - } - - var nnt = part.GetComponent(); - if (nnt) { - float mr = size * 0.5f; - if (nnt.radius > mr) nnt.radius = mr; - ((UI_FloatEdit)nnt.Fields["radius"].uiControlEditor).maxValue = mr; - } - } - } - - - //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ// - - -} // namespace - diff --git a/Source/build.bat b/Source/build.bat deleted file mode 100644 index e1bac14..0000000 --- a/Source/build.bat +++ /dev/null @@ -1,13 +0,0 @@ -@echo off -set KSP=C:\games\KSPtest -%WINDIR%\Microsoft.NET\Framework64\v3.5\csc /nologo /t:library^ - /out:"%KSP%\GameData\ProceduralFairings\ProceduralFairings.dll"^ - /r:"%KSP%\KSP_Data\Managed\Assembly-CSharp.dll"^ - /r:"%KSP%\KSP_Data\Managed\UnityEngine.dll"^ - /r:"%KSP%\KSP_Data\Managed\UnityEngine.UI.dll"^ - NodeNumberTweaker.cs Resizers.cs FairingShielding.cs ^ - FairingBase.cs FairingDecoupler.cs FairingSide.cs PayloadScan.cs ProcAdapter.cs utils.cs -if errorlevel 1 goto exit -rem copy /y %KSP%\GameData\ProceduralFairings\ProceduralFairings.dll "C:\Steam\SteamApps\common\Kerbal Space Program\GameData\ProceduralFairings\" -echo ====================================== -:exit diff --git a/Source/s.bat b/Source/s.bat deleted file mode 100644 index 61d39c2..0000000 --- a/Source/s.bat +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -c: -cd c:\games\KSPtest -start KSP_x64 diff --git a/Source/utils.cs b/Source/utils.cs deleted file mode 100644 index 1961e45..0000000 --- a/Source/utils.cs +++ /dev/null @@ -1,340 +0,0 @@ -// Procedural Fairings plug-in by Alexey Volynskov -// Licensed under CC BY 3.0 terms: http://creativecommons.org/licenses/by/3.0/ -using System; -using System.Collections.Generic; -using System.Text; -using UnityEngine; - - -namespace Keramzit -{ - - - //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ// - - - struct BezierSlope - { - Vector2 p1, p2; - - public BezierSlope(Vector4 v) - { - p1 = new Vector2(v.x, v.y); - p2 = new Vector2(v.z, v.w); - } - - public Vector2 interp(float t) - { - Vector2 a = Vector2.Lerp(Vector2.zero, p1, t); - Vector2 b = Vector2.Lerp(p1, p2, t); - Vector2 c = Vector2.Lerp(p2, Vector2.one, t); - - Vector2 d = Vector2.Lerp(a, b, t); - Vector2 e = Vector2.Lerp(b, c, t); - - return Vector2.Lerp(d, e, t); - } - } - - - //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ// - - internal class Tuple - { - internal T1 Item1 { get; set; } - internal T2 Item2 { get; set; } - - public Tuple(T1 item1, T2 item2) - { - this.Item1 = item1; - this.Item2 = item2; - } - } - - //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ// - - public static class PFUtils - { - public static bool canCheckTech() - { - return HighLogic.LoadedSceneIsEditor && - (ResearchAndDevelopment.Instance != null || (HighLogic.CurrentGame.Mode != Game.Modes.CAREER && HighLogic.CurrentGame.Mode != Game.Modes.SCIENCE_SANDBOX)); - } - - - public static bool haveTech(string name) - { - if (HighLogic.CurrentGame.Mode != Game.Modes.CAREER && HighLogic.CurrentGame.Mode != Game.Modes.SCIENCE_SANDBOX) return name == "sandbox"; - return ResearchAndDevelopment.GetTechnologyState(name) == RDTech.State.Available; - } - - - public static float getTechMinValue(string cfgname, float defVal) - { - bool hasValue = false; - float minVal = 0; - - var confnodes = GameDatabase.Instance.GetConfigNodes(cfgname); - for (int j = 0; j < confnodes.Length; j++) { - var tech = confnodes[j]; - for (int i = 0; i < tech.values.Count; ++i) { - var value = tech.values[i]; - if (!haveTech(value.name)) continue; - float v = float.Parse(value.value); - if (!hasValue || v < minVal) { minVal = v; hasValue = true; } - } - } - - if (!hasValue) return defVal; - return minVal; - } - - - public static float getTechMaxValue(string cfgname, float defVal) - { - bool hasValue = false; - float maxVal = 0; - - var confnodes = GameDatabase.Instance.GetConfigNodes(cfgname); - for (int j = 0; j < confnodes.Length; j++) { - var tech = confnodes[j]; - for (int i = 0; i < tech.values.Count; ++i) { - var value = tech.values[i]; - if (!haveTech(value.name)) continue; - float v = float.Parse(value.value); - if (!hasValue || v > maxVal) { maxVal = v; hasValue = true; } - } - } - - if (!hasValue) return defVal; - return maxVal; - } - - - public static void setFieldRange(BaseField field, float minval, float maxval) - { - var fr = field.uiControlEditor as UI_FloatRange; - if (fr != null) { - fr.minValue = minval; - fr.maxValue = maxval; - } - - var fe = field.uiControlEditor as UI_FloatEdit; - if (fe != null) { - fe.minValue = minval; - fe.maxValue = maxval; - } - } - - - public static void updateAttachedPartPos(AttachNode node, Part part) - { - if (node == null || part == null) return; - - var ap = node.attachedPart; - if (!ap) return; - - var an = ap.FindAttachNodeByPart(part); - if (an == null) return; - - var dp = - part.transform.TransformPoint(node.position) - - ap.transform.TransformPoint(an.position); - - if (ap == part.parent) { - while (ap.parent) ap = ap.parent; - ap.transform.position += dp; - part.transform.position -= dp; - } - else - ap.transform.position += dp; - } - - - public static string formatMass(float mass) - { - if (mass < 0.01f) return (mass * 1e3f).ToString("n3") + "kg"; - else return mass.ToString("n3") + "t"; - } - - public static string formatCost(float cost) - { - return cost.ToString("n0"); - } - - public static void enableRenderer(Transform t, bool e) - { - if (!t) return; - var r = t.GetComponent(); - if (r) r.enabled = e; - } - - public static void hideDragStuff(Part part) - { - enableRenderer(part.FindModelTransform("dragOnly"), false); - } - - public static bool FARinstalled = false, FARchecked = false; - - public static bool isFarInstalled() - { - if (!FARchecked) { - var asmlist = AssemblyLoader.loadedAssemblies; - - if (asmlist != null) { - for (int i = 0; i < asmlist.Count; i++) { - if (asmlist[i].name == "FerramAerospaceResearch") { - FARinstalled = true; - break; - } - } - } - //FARinstalled = AssemblyLoader.loadedAssemblies.Any(a => a.assembly.GetName().Name == "FerramAerospaceResearch"); - FARchecked = true; - } - - return FARinstalled; - } - - public static void updateDragCube(Part part, float areaScale) - { - if (isFarInstalled()) { - Debug.Log("[PF] calling FAR to update voxels"); - part.SendMessage("GeometryPartModuleRebuildMeshData"); - } - - if (!HighLogic.LoadedSceneIsFlight) return; - - enableRenderer(part.FindModelTransform("dragOnly"), true); - - var dragCube = DragCubeSystem.Instance.RenderProceduralDragCube(part); - - enableRenderer(part.FindModelTransform("dragOnly"), false); - - for (int i = 0; i < 6; ++i) dragCube.Area[i] *= areaScale; - // dragCube.Area[(int)DragCube.DragFace.YP]*=areaScale; - // dragCube.Area[(int)DragCube.DragFace.YN]*=areaScale; - - // Debug.Log(part.name+" dragCube area="+dragCube.Area[(int)DragCube.DragFace.YP]+" size="+dragCube.Size+" ms="+model.localScale); - part.DragCubes.ClearCubes(); - part.DragCubes.Cubes.Add(dragCube); - part.DragCubes.ResetCubeWeights(); - } - - public static IEnumerator updateDragCubeCoroutine(Part part, float areaScale) - { - while (true) { - if (part == null || part.Equals(null)) yield break; - - if (HighLogic.LoadedSceneIsFlight) { - if (part.vessel == null || part.vessel.Equals(null)) yield break; - - if (!FlightGlobals.ready || part.packed || !part.vessel.loaded) { - yield return new WaitForFixedUpdate(); - continue; - } - break; - } - else if (HighLogic.LoadedSceneIsEditor) { - yield return new WaitForFixedUpdate(); - break; - } - else - yield break; - } - - PFUtils.updateDragCube(part, areaScale); - } - - public static void refreshPartWindow() - { - var objs = UnityEngine.Object.FindObjectsOfType(); - for (int i = 0; i < objs.Length; i++) { - var w = objs[i]; - w.displayDirty = true; - } - } - - public static Part partFromHit(this RaycastHit hit) - { - if (hit.collider == null || hit.collider.gameObject == null) { - return null; - } - var go = hit.collider.gameObject; - var p = Part.FromGO(go); - while (p == null) { - if (go.transform != null && go.transform.parent != null && go.transform.parent.gameObject != null) { - go = go.transform.parent.gameObject; - } - else { - break; - } - p = Part.FromGO(go); - } - return p; - } - - public static List getAllChildrenRecursive(this Part rootPart, bool root) - { - var children = new List(); - if (!root) { - children.Add(rootPart); - } - - for (int i = 0; i < rootPart.children.Count; i++) { - var child = rootPart.children[i]; - children.AddRange(child.getAllChildrenRecursive(false)); - } - return children; - } - - public static float GetMaxValueFromList(List list) - { - float max = 0; - for (int i = 0; i < list.Count; i++) - if (max < list[i]) - max = list[i]; - - return max; - } - } - - - //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ// - - - [KSPAddon(KSPAddon.Startup.EditorAny, false)] - public class EditorScreenMessager : MonoBehaviour - { - static float osdMessageTime = 0; - static string osdMessageText = null; - - public static void showMessage(string msg, float delay) - { - osdMessageText = msg; - osdMessageTime = Time.time + delay; - } - - public void OnGUI() - { - if (!HighLogic.LoadedSceneIsEditor) return; - - if (Time.time < osdMessageTime) { - GUI.skin = HighLogic.Skin; - GUIStyle style = new GUIStyle("Label"); - style.alignment = TextAnchor.MiddleCenter; - style.fontSize = 20; - style.normal.textColor = Color.black; - GUI.Label(new Rect(2, 2 + (Screen.height / 9), Screen.width, 50), osdMessageText, style); - style.normal.textColor = Color.yellow; - GUI.Label(new Rect(0, Screen.height / 9, Screen.width, 50), osdMessageText, style); - } - } - } - - - //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ// - - -} // namespace -