public void Unequip() { if (!prefabModule) { return; } if (equipMode == EquipMode.Model) { UnityEngine.Object.Destroy(equippedGameObj); if (prefabModule.equipRemoveHelmet) { inventory.SetHelmet(true); } } if (equipMode == EquipMode.Part || equipMode == EquipMode.Physic) { Logger.logInfo("Update config node of equipped part: {0}", availablePart.title); partNode.ClearData(); KIS_Shared.PartSnapshot(equippedPart).CopyTo(partNode); equippedPart.Die(); } evaTransform = null; equippedPart = null; equippedGameObj = null; equipped = false; PlaySound(prefabModule.moveSndPath); prefabModule.OnUnEquip(this); }
/// <summary>Handles keyboard input.</summary> private void UpdateKey() { if (isRunning) { if (Input.GetKeyDown(KeyCode.Escape) || Input.GetKeyDown(KeyCode.Return)) { Logger.logInfo("Cancel key pressed, stop eva attach mode"); StopPointer(); SendPointerClick(PointerTarget.Nothing, Vector3.zero, Quaternion.identity, null, null); } if (GameSettings.Editor_toggleSymMethod.GetKeyDown()) // "R" by default. { if (pointerTarget != PointerTarget.PartMount && attachNodes.Count() > 1) { attachNodeIndex++; if (attachNodeIndex > (attachNodes.Count - 1)) { attachNodeIndex = 0; } Logger.logInfo("Attach node index changed to: {0}", attachNodeIndex); UpdatePointerAttachNode(); ResetMouseOver(); SendPointerState(pointerTarget, PointerState.OnChangeAttachNode, null, null); } else { ScreenMessaging.ShowInfoScreenMessage("This part has only one attach node!"); audioBipWrong.Play(); } } } }
/// <summary>Makes a game object to represent currently dragging assembly.</summary> /// <remarks>It's a very expensive operation.</remarks> static void MakePointer() { DestroyPointer(); // Make pointer node transformations. if (pointerNodeTransform) { pointerNodeTransform.gameObject.DestroyGameObject(); } pointerNodeTransform = new GameObject("KISPointerPartNode").transform; // Deatch will decouple from the parent so, ask to ignore it when looking for the nodes. attachNodes = KIS_Shared.GetAvailableAttachNodes(partToAttach, ignoreAttachedPart: partToAttach.parent); if (!attachNodes.Any()) { //TODO: When there are no nodes try finding ones in the parent or in the children. // Ideally, the caller should have checked if this part has free nodes. Now the only // way is to pick *any* node. The surface one always exists so, it's a good // candidate. Though, for many details it may result in a weird representation. Logger.logError("Part {0} has no free nodes, use {1}", partToAttach, partToAttach.srfAttachNode); attachNodes.Add(partToAttach.srfAttachNode); } attachNodeIndex = 0; // Expect that first node is the best default. UpdatePointerAttachNode(); // Make pointer renderer. var combines = new List <CombineInstance>(); CollectMeshesFromAssembly(partToAttach, combines); // Create one filter per mesh in the hierarhcy. Simple combining all meshes into one // larger mesh may have weird representation artifacts on different video cards. pointer = new GameObject("KISPointer"); foreach (var combine in combines) { var mesh = new Mesh(); mesh.CombineMeshes(new[] { combine }); var childObj = new GameObject("KISPointerChildMesh"); var meshRenderer = childObj.AddComponent <MeshRenderer>(); meshRenderer.shadowCastingMode = ShadowCastingMode.Off; meshRenderer.receiveShadows = false; var filter = childObj.AddComponent <MeshFilter>(); filter.sharedMesh = mesh; childObj.transform.parent = pointer.transform; } allModelMr = pointer.GetComponentsInChildren <MeshRenderer>().ToList(); foreach (var mr in allModelMr) { mr.material = new Material(Shader.Find("Transparent/Diffuse")); } pointerNodeTransform.parent = pointer.transform; Logger.logInfo("New pointer created"); }
public static void StopPointer() { Logger.logInfo("StopPointer()"); running = false; ResetMouseOver(); InputLockManager.RemoveControlLock("KISpointer"); DestroyPointer(); allowedAttachmentParts = allowedAttachmentParts; // Clear selection. }
void Awake() { audioGo = new GameObject(); Logger.logInfo("Loading UI sounds for KIS..."); InitSound(bipWrongSndPath, out audioBipWrong); InitSound(clickSndPath, out audioClick); InitSound(attachPartSndPath, out audioAttach); instance = this; }
void InitConfig(AvailablePart availablePart, ModuleKISInventory inventory, float quantity) { this.inventory = inventory; this.quantity = quantity; prefabModule = availablePart.partPrefab.GetComponent <ModuleKISItem>(); volume = KIS_Shared.GetPartVolume(availablePart); cost = GetCost(); // Set launchID if (partNode.HasValue("launchID")) { if (int.Parse(this.partNode.GetValue("launchID")) == 0) { partNode.SetValue("launchID", this.inventory.part.launchID.ToString(), true); } } else { partNode.SetValue("launchID", this.inventory.part.launchID.ToString(), true); } if (prefabModule) { equipable = prefabModule.equipable; stackable = prefabModule.stackable; equipSlot = prefabModule.equipSlot; usableFromEva = prefabModule.usableFromEva; usableFromContainer = prefabModule.usableFromContainer; usableFromPod = prefabModule.usableFromPod; usableFromEditor = prefabModule.usableFromEditor; carriable = prefabModule.carriable; } int nonStackableModule = 0; foreach (PartModule pModule in availablePart.partPrefab.Modules) { if (!KISAddonConfig.stackableModules.Contains(pModule.moduleName)) { nonStackableModule++; } } if (nonStackableModule == 0 && GetResources().Count == 0) { Logger.logInfo( "No non-stackable module or a resource found on the part, set the item as stackable"); stackable = true; } if (KISAddonConfig.stackableList.Contains(availablePart.name) || availablePart.name.IndexOf('.') != -1 && KISAddonConfig.stackableList.Contains(availablePart.name.Replace('.', '_'))) { Logger.logInfo("Part name present in settings.cfg (node StackableItemOverride)," + " force item as stackable"); stackable = true; } }
public virtual void OnPartUnpack() { if (allowStaticAttach == ItemAttachMode.Disabled || useExternalStaticAttach) { return; } if (staticAttached) { Logger.logInfo("Re-attach static object (OnPartUnpack)"); GroundAttach(); } }
public void GroundDetach() { if (staticAttached) { Logger.logInfo("Removing static rigidbody and fixed joint on: {0}", this.part.partInfo.title); if (staticAttachJoint) { Destroy(staticAttachJoint); } staticAttachJoint = null; staticAttached = false; } }
/// <summary>Sets current pointer visible state.</summary> /// <remarks> /// Method expects all or none of the objects in the pointer to be visible: pointer /// visiblity state is determined by checking the first <c>MeshRenderer</c> only. /// </remarks> /// <param name="isVisible">New state.</param> /// <exception cref="InvalidOperationException">If pointer doesn't exist.</exception> private static void SetPointerVisible(bool isVisible) { foreach (var mr in pointer.GetComponentsInChildren <MeshRenderer>()) { if (mr.enabled == isVisible && mr.material.renderQueue == KIS_Shared.HighlighedPartRenderQueue) { return; // Abort if current state is already up to date. } mr.enabled = isVisible; mr.material.renderQueue = KIS_Shared.HighlighedPartRenderQueue; } Logger.logInfo("Pointer state set to: visibility={0}", isVisible); }
public void Awake() { ConfigAccessor.ReadFieldsInType(GetType(), this); ConfigAccessor.ReadFieldsInType(typeof(ModuleKISInventory), instance: null); // Set inventory module for every eva kerbal Logger.logInfo("Set KIS config..."); ConfigNode nodeSettings = GameDatabase.Instance.GetConfigNode("KIS/settings/KISConfig"); if (nodeSettings == null) { Logger.logError("KIS settings.cfg not found or invalid !"); return; } // Male Kerbal. UpdateEvaPrefab(PartLoader.getPartInfoByName(MaleKerbalEva), nodeSettings); // Female Kerbal. UpdateEvaPrefab(PartLoader.getPartInfoByName(FemaleKerbalEva), nodeSettings); // Set inventory module for every pod with crew capacity. Logger.logInfo("Loading pod inventories..."); foreach (AvailablePart avPart in PartLoader.LoadedPartsList) { if (avPart.name == MaleKerbalEva || avPart.name == FemaleKerbalEva || avPart.name == RdKerbalEva || !avPart.partPrefab || avPart.partPrefab.CrewCapacity < 1) { continue; } Logger.logInfo("Found part with CrewCapacity: {0}", avPart.name); for (int i = 0; i < avPart.partPrefab.CrewCapacity; i++) { try { var moduleInventory = avPart.partPrefab.AddModule(typeof(ModuleKISInventory).Name) as ModuleKISInventory; KIS_Shared.AwakePartModule(moduleInventory); SetInventoryConfig(moduleInventory, nodeSettings); moduleInventory.podSeat = i; moduleInventory.invType = ModuleKISInventory.InventoryType.Pod; Logger.logInfo("Pod inventory module(s) for seat {0} loaded successfully", i); } catch { Logger.logError("Pod inventory module(s) for seat {0} can't be loaded!", i); } } } }
void InitSound(string clipPath, out AudioSource source) { Logger.logInfo("Loading clip: {0}", clipPath); source = audioGo.AddComponent <AudioSource>(); source.volume = GameSettings.UI_VOLUME; source.spatialBlend = 0; //set as 2D audiosource if (GameDatabase.Instance.ExistsAudioClip(clipPath)) { source.clip = GameDatabase.Instance.GetAudioClip(clipPath); } else { Logger.logError("Cannot locate clip: {0}", clipPath); } }
/// <summary>Fixes all structural links to another vessel(s).</summary> /// <remarks> /// Normally compound parts should handle decoupling themselves but sometimes they do it /// horribly wrong. For instance, stock strut connector tries to restore connection when /// part is re-attached to the former vessel which may produce a collision. This method /// deletes all compound parts with target pointing to a different vessel. /// </remarks> /// <param name="vessel">Vessel to fix links for.</param> // TODO: Break the link instead of destroying the part. // TODO: Handle KAS and other popular plugins connectors. public static void CleanupExternalLinks(Vessel vessel) { var parts = vessel.parts.FindAll(p => p is CompoundPart); Logger.logInfo("Check {0} compound part(s) in vessel: {1}", parts.Count(), vessel); foreach (var part in parts) { var compoundPart = part as CompoundPart; if (compoundPart.target && compoundPart.target.vessel != vessel) { Logger.logInfo("Destroy compound part '{0}' which links '{1}' to '{2}'", compoundPart, compoundPart.parent, compoundPart.target); compoundPart.Die(); } } }
/// <summary>Destroyes object(s) allocated to represent a pointer.</summary> /// <remarks>When making pointer for a complex hierarchy a lot of different resources may be /// allocated/dropped. Destroying each one of them can be too slow so, cleanup is done in /// one call to <c>UnloadUnusedAssets()</c>. /// <para>This method also destroys <see cref="pointerNodeTransform"/>.</para> /// </remarks> private static void DestroyPointer() { if (!pointer) { return; // Nothing to do. } pointer.DestroyGameObject(); pointer = null; pointerNodeTransform.gameObject.DestroyGameObject(); pointerNodeTransform = null; allModelMr.Clear(); // On large assemblies memory consumption can be significant. Reclaim it. Resources.UnloadUnusedAssets(); Logger.logInfo("Pointer destroyed"); }
/// <summary>Goes thru part assembly and collects all meshes in the hierarchy.</summary> /// <remarks> /// Returns shared meshes with the right transformations. No new objects are created. /// </remarks> /// <param name="assembly">An assembly to collect meshes from.</param> /// <param name="meshCombines">[out] Collected meshes.</param> /// <param name="worldTransform">A world transformation matrix to apply to every mesh after /// it's translated into world's coordinates. If <c>null</c> then coordinates will be /// calculated relative to the root part of the assembly.</param> private static void CollectMeshesFromAssembly(Part assembly, ICollection <CombineInstance> meshCombines, Matrix4x4?worldTransform = null) { // Always use world transformation from the root. var rootWorldTransform = worldTransform ?? assembly.transform.localToWorldMatrix.inverse; // Get all meshes from the part's model. var meshFilters = assembly.FindModelComponents <MeshFilter>(); if (meshFilters.Count > 0) { Logger.logInfo("Found {0} children meshes in: {1}", meshFilters.Count, assembly); foreach (var meshFilter in meshFilters) { var combine = new CombineInstance(); combine.mesh = meshFilter.sharedMesh; combine.transform = rootWorldTransform * meshFilter.transform.localToWorldMatrix; meshCombines.Add(combine); } } // Skinned meshes are baked on every frame before rendering. Bake them to get current mesh // state. var skinnedMeshRenderers = assembly.FindModelComponents <SkinnedMeshRenderer>(); if (skinnedMeshRenderers.Count > 0) { Logger.logInfo("Found {0} skinned meshes in: {1}", skinnedMeshRenderers.Count, assembly); foreach (var skinnedMeshRenderer in skinnedMeshRenderers) { var combine = new CombineInstance(); combine.mesh = new Mesh(); skinnedMeshRenderer.BakeMesh(combine.mesh); combine.transform = rootWorldTransform * skinnedMeshRenderer.transform.localToWorldMatrix; meshCombines.Add(combine); } } // Collect meshes from the children parts. foreach (Part child in assembly.children) { CollectMeshesFromAssembly(child, meshCombines, worldTransform: rootWorldTransform); } }
IEnumerator WaitAndStaticAttach() { // Wait for part to become active in case of it came from inventory. while (!part.started && part.State != PartStates.DEAD) { yield return(new WaitForFixedUpdate()); } part.vessel.Landed = true; Logger.logInfo("Create fixed joint attached to the world"); if (staticAttachJoint) { Destroy(staticAttachJoint); } staticAttachJoint = part.gameObject.AddComponent <FixedJoint>(); staticAttachJoint.breakForce = staticAttachBreakForce; staticAttachJoint.breakTorque = staticAttachBreakForce; }
public static void CouplePart(Part srcPart, Part tgtPart, string srcAttachNodeID = null, AttachNode tgtAttachNode = null) { // Node links if (srcAttachNodeID != null) { if (srcAttachNodeID == "srfAttach") { Logger.logInfo("Attach type: {0} | ID : {1}", srcPart.srfAttachNode.nodeType, srcPart.srfAttachNode.id); srcPart.attachMode = AttachModes.SRF_ATTACH; srcPart.srfAttachNode.attachedPart = tgtPart; } else { AttachNode srcAttachNode = srcPart.FindAttachNode(srcAttachNodeID); if (srcAttachNode != null) { Logger.logInfo("Attach type : {0} | ID : {1}", srcPart.srfAttachNode.nodeType, srcAttachNode.id); srcPart.attachMode = AttachModes.STACK; srcAttachNode.attachedPart = tgtPart; if (tgtAttachNode != null) { tgtAttachNode.attachedPart = srcPart; } else { Logger.logWarning("Target node is null"); } } else { Logger.logError("Source attach node not found !"); } } } else { Logger.logWarning("Missing source attach node !"); } srcPart.Couple(tgtPart); }
/// <summary>Adds default items to the pod's seats.</summary> /// <remarks>Items are only added to a part created in the editor. Thus, reacting on the editor /// event.</remarks> /// <param name="type">Unused.</param> /// <param name="p">A target part.</param> void OnEditPartCreate(ConstructionEventType type, Part p) { if (type != ConstructionEventType.PartCreated && type != ConstructionEventType.PartCopied) { return; } var inventories = p.GetComponents<ModuleKISInventory>(); foreach (var inventory in inventories) { if (inventory.podSeat != -1 && ModuleKISInventory.defaultItemsForAllSeats.Count > 0) { Logger.logInfo( "Adding default item(s) into seat's {0} inventory of part {1}: {2}", inventory.podSeat, p.name, Logger.C2S(ModuleKISInventory.defaultItemsForAllSeats)); AddItems(inventory, ModuleKISInventory.defaultItemsForAllSeats); } if (inventory.podSeat == 0 && ModuleKISInventory.defaultItemsForTheFirstSeat.Count > 0) { Logger.logInfo("Adding default item(s) into the first seat of part {0}: {1}", p.name, Logger.C2S(ModuleKISInventory.defaultItemsForTheFirstSeat)); AddItems(inventory, ModuleKISInventory.defaultItemsForTheFirstSeat); } } }
public static void StartPointer(Part partToMoveAndAttach, OnPointerClick pClick, OnPointerState pState, Transform from = null) { if (!running) { Logger.logInfo("StartPointer()"); customRot = Vector3.zero; aboveDistance = 0; partToAttach = partToMoveAndAttach; sourceTransform = from; running = true; SendPointerClick = pClick; SendPointerState = pState; MakePointer(); InputLockManager.SetControlLock(ControlTypes.ALLBUTCAMERAS, "KISpointer"); allowedAttachmentParts = allowedAttachmentParts; // Apply selection. } }
public void OnSave(ConfigNode node) { node.AddValue("partName", this.availablePart.name); node.AddValue("slot", slot); node.AddValue("quantity", quantity); node.AddValue("equipped", equipped); node.AddValue("resourceMass", resourceMass); node.AddValue("contentMass", contentMass); node.AddValue("contentCost", contentCost); if (inventoryName != "") { node.AddValue("inventoryName", inventoryName); } if (equipped && (equipMode == EquipMode.Part || equipMode == EquipMode.Physic)) { Logger.logInfo("Update config node of equipped part: {0}", this.availablePart.title); partNode.ClearData(); KIS_Shared.PartSnapshot(equippedPart).CopyTo(partNode); } partNode.CopyTo(node.AddNode("PART")); }
void UpdateEvaPrefab(AvailablePart avPart, ConfigNode nodeSettings) { var prefab = avPart.partPrefab; // Adding module to EVA may cause an NPE but module update will still work. try { prefab.AddModule(typeof(ModuleKISInventory).Name); } catch (Exception ex) { Logger.logInfo( "NOT A BUG! Ignoring error while adding ModuleKISInventory to {0}: {1}", prefab, ex); } try { prefab.AddModule(typeof(ModuleKISPickup).Name); } catch (Exception ex) { Logger.logInfo("NOT A BUG! Ignoring error adding ModuleKISPickup to {0}: {1}", prefab, ex); } // Setup inventory module for eva. var evaInventory = prefab.GetComponent <ModuleKISInventory>(); KIS_Shared.AwakePartModule(evaInventory); if (evaInventory) { SetInventoryConfig(evaInventory, nodeSettings); evaInventory.invType = ModuleKISInventory.InventoryType.Eva; Logger.logInfo("Eva inventory module loaded successfully"); } // Load KSP fields for ModuleKISPickup module. var nodeEvaPickup = nodeSettings.GetNode("EvaPickup"); var evaPickup = prefab.GetComponent <ModuleKISPickup>(); KIS_Shared.AwakePartModule(evaPickup); if (evaPickup && nodeEvaPickup != null) { var fields = new BaseFieldList(evaPickup); fields.Load(nodeEvaPickup); Logger.logInfo("Eva pickup module loaded successfully"); } }
public void Drop(Part fromPart = null) { Logger.logInfo("Drop item"); if (fromPart == null) { fromPart = inventory.part; } Quaternion rot; Vector3 pos; if (prefabModule) { rot = evaTransform.rotation * Quaternion.Euler(prefabModule.equipDir); pos = evaTransform.TransformPoint(prefabModule.equipPos); } else { rot = inventory.part.transform.rotation; pos = inventory.part.transform.position + new Vector3(0, 1, 0); } KIS_Shared.CreatePart(partNode, pos, rot, fromPart); StackRemove(1); }
static IEnumerator WaitAndCouple(Part newPart, Part tgtPart = null, string srcAttachNodeID = null, AttachNode tgtAttachNode = null, OnPartCoupled onPartCoupled = null) { // Get relative position & rotation Vector3 toPartLocalPos = Vector3.zero; Quaternion toPartLocalRot = Quaternion.identity; if (tgtPart) { if (tgtAttachNode == null) { // Local position & rotation from part toPartLocalPos = tgtPart.transform.InverseTransformPoint(newPart.transform.position); toPartLocalRot = Quaternion.Inverse(tgtPart.transform.rotation) * newPart.transform.rotation; } else { // Local position & rotation from node (KAS winch connector) toPartLocalPos = tgtAttachNode.nodeTransform.InverseTransformPoint(newPart.transform.position); toPartLocalRot = Quaternion.Inverse(tgtAttachNode.nodeTransform.rotation) * newPart.transform.rotation; } } // Wait part to initialize while (!newPart.started && newPart.State != PartStates.DEAD) { Logger.logInfo("CreatePart - Waiting initialization of the part..."); if (tgtPart) { // Part stay in position if (tgtAttachNode == null) { newPart.transform.position = tgtPart.transform.TransformPoint(toPartLocalPos); newPart.transform.rotation = tgtPart.transform.rotation * toPartLocalRot; } else { newPart.transform.position = tgtAttachNode.nodeTransform.TransformPoint(toPartLocalPos); newPart.transform.rotation = tgtAttachNode.nodeTransform.rotation * toPartLocalRot; } } yield return(null); } // Part stay in position if (tgtAttachNode == null) { newPart.transform.position = tgtPart.transform.TransformPoint(toPartLocalPos); newPart.transform.rotation = tgtPart.transform.rotation * toPartLocalRot; } else { newPart.transform.position = tgtAttachNode.nodeTransform.TransformPoint(toPartLocalPos); newPart.transform.rotation = tgtAttachNode.nodeTransform.rotation * toPartLocalRot; } Logger.logInfo("CreatePart - Coupling part..."); CouplePart(newPart, tgtPart, srcAttachNodeID, tgtAttachNode); if (onPartCoupled != null) { onPartCoupled(newPart, tgtPart, tgtAttachNode); } }
public void Equip() { // Only equip EVA kerbals. if (!prefabModule || !inventory.vessel.isEVA) { return; } Logger.logInfo("Equip item {0}", this.availablePart.name); // Check skill if needed. Skip the check in sandbox modes. if (HighLogic.CurrentGame.Mode != Game.Modes.SANDBOX && HighLogic.CurrentGame.Mode != Game.Modes.SCIENCE_SANDBOX && !String.IsNullOrEmpty(prefabModule.equipSkill)) { bool skillFound = false; List <ProtoCrewMember> protoCrewMembers = inventory.vessel.GetVesselCrew(); foreach (var expEffect in protoCrewMembers[0].experienceTrait.Effects) { if (expEffect.ToString().Replace("Experience.Effects.", "") == prefabModule.equipSkill) { skillFound = true; break; } } if (!skillFound) { ScreenMessaging.ShowPriorityScreenMessage( "This item can only be used by a kerbal with the skill : {0}", prefabModule.equipSkill); PlaySound(KIS_Shared.bipWrongSndPath); return; } } // Check if already carried if (equipSlot != null) { KIS_Item equippedItem = inventory.GetEquipedItem(equipSlot); if (equippedItem != null) { if (equippedItem.carriable) { ScreenMessaging.ShowPriorityScreenMessage( "Cannot equip item, slot <{0}> already used for carrying {1}", equipSlot, equippedItem.availablePart.title); PlaySound(KIS_Shared.bipWrongSndPath); return; } equippedItem.Unequip(); } } if (equipMode == EquipMode.Model) { GameObject modelGo = availablePart.partPrefab.FindModelTransform("model").gameObject; equippedGameObj = UnityEngine.Object.Instantiate(modelGo); foreach (Collider col in equippedGameObj.GetComponentsInChildren <Collider>()) { UnityEngine.Object.DestroyImmediate(col); } evaTransform = null; var skmrs = new List <SkinnedMeshRenderer>( inventory.part.GetComponentsInChildren <SkinnedMeshRenderer>()); foreach (SkinnedMeshRenderer skmr in skmrs) { if (skmr.name != prefabModule.equipMeshName) { continue; } foreach (Transform bone in skmr.bones) { if (bone.name == prefabModule.equipBoneName) { evaTransform = bone.transform; break; } } } if (!evaTransform) { Logger.logError("evaTransform not found ! "); UnityEngine.Object.Destroy(equippedGameObj); return; } } if (equipMode == EquipMode.Part || equipMode == EquipMode.Physic) { evaTransform = null; var skmrs = new List <SkinnedMeshRenderer>( inventory.part.GetComponentsInChildren <SkinnedMeshRenderer>()); foreach (SkinnedMeshRenderer skmr in skmrs) { if (skmr.name != prefabModule.equipMeshName) { continue; } foreach (Transform bone in skmr.bones) { if (bone.name == prefabModule.equipBoneName) { evaTransform = bone.transform; break; } } } if (!evaTransform) { Logger.logError("evaTransform not found ! "); return; } Part alreadyEquippedPart = this.inventory.part.vessel.Parts.Find(p => p.partInfo.name == this.availablePart.name); if (alreadyEquippedPart) { Logger.logInfo("Part: {0} already found on eva", availablePart.name); equippedPart = alreadyEquippedPart; OnEquippedPartCoupled(equippedPart); } else { Vector3 equipPos = evaTransform.TransformPoint(prefabModule.equipPos); Quaternion equipRot = evaTransform.rotation * Quaternion.Euler(prefabModule.equipDir); equippedPart = KIS_Shared.CreatePart( partNode, equipPos, equipRot, this.inventory.part, this.inventory.part, null, null, OnEquippedPartCoupled); } if (equipMode == EquipMode.Part) { equippedGameObj = equippedPart.gameObject; } } if (prefabModule.equipRemoveHelmet) { inventory.SetHelmet(false); } PlaySound(prefabModule.moveSndPath); equipped = true; prefabModule.OnEquip(this); }