/// <summary>Fixes null persistent fields in the module.</summary> /// <remarks>Used to prevent NREs in methods that persist KSP fields.</remarks> /// <param name="module">Module to fix.</param> public static void CleanupFieldsInModule(PartModule module) { // Ensure the module is awaken. Otherwise, any access to base fields list will result in NRE. // HACK: Accessing Fields property of a non-awaken module triggers NRE. If it happens then do // explicit awakening of the *base* module class. try { var unused = module.Fields.GetEnumerator(); } catch { Logger.logWarning("WORKAROUND. Module {0} on part prefab {1} is not awaken. Call Awake on it", module.GetType(), module.part); AwakePartModule(module); } foreach (var field in module.Fields) { var baseField = field as BaseField; if (baseField.isPersistant && baseField.GetValue(module) == null) { var proto = new StandardOrdinaryTypesProto(); var defValue = proto.ParseFromString("", baseField.FieldInfo.FieldType); Logger.logWarning("WORKAROUND. Found null field {0} in module prefab {1}," + " fixing to default value of type {2}: {3}", baseField.name, module.moduleName, baseField.FieldInfo.FieldType, defValue); baseField.SetValue(defValue, module); } } }
/// <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 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); }
public Dictionary <AttachNode, List <string> > GetMounts() { var mounts = new Dictionary <AttachNode, List <string> >(); ConfigNode node = KIS_Shared.GetBaseConfigNode(this); foreach (ConfigNode mountNode in node.GetNodes("MOUNT")) { if (mountNode.HasValue("attachNode") && mountNode.HasValue("allowedPartName")) { string attachNodeName = mountNode.GetValue("attachNode"); AttachNode an = this.part.FindAttachNode(attachNodeName); if (an == null) { Logger.logError("GetMountNodes - Node : {0} not found !", attachNodeName); continue; } var allowedPartNames = new List <string>(); foreach (string partName in mountNode.GetValues("allowedPartName")) { allowedPartNames.Add(partName.Replace('_', '.')); } mounts.Add(an, allowedPartNames); } } return(mounts); }
/// <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(); } } } }
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; } }
/// <summary>Adds the specified items into the inventory.</summary> /// <param name="inventory">An inventory to add items into.</param> /// <param name="itemNames">A list of names of the parts to add.</param> void AddItems(ModuleKISInventory inventory, List<string> itemNames) { foreach (var defItemName in itemNames) { var defPart = PartLoader.getPartInfoByName(defItemName); if (defPart != null) { inventory.AddItem(defPart.partPrefab); } else { Logger.logError("Cannot make item {0} specified as a default for the pod seat", defItemName); } } }
// Resets item state when joint is broken. // A callback from MonoBehaviour. void OnJointBreak(float breakForce) { if (staticAttached) { Logger.logWarning("A static joint has just been broken! Force: {0}", breakForce); } else { Logger.logWarning("A fixed joint has just been broken! Force: {0}", breakForce); } GroundDetach(); }
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); } } } }
/// <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"); }
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); } }
// Called once when script is loaded; use to initialize variables and state void Awake() { audioGo = new GameObject(); audioBipWrong = audioGo.AddComponent <AudioSource>(); audioBipWrong.volume = GameSettings.UI_VOLUME; audioBipWrong.spatialBlend = 0; //set as 2D audiosource if (GameDatabase.Instance.ExistsAudioClip(KIS_Shared.bipWrongSndPath)) { audioBipWrong.clip = GameDatabase.Instance.GetAudioClip(KIS_Shared.bipWrongSndPath); } else { Logger.logError("Awake(AttachPointer) Bip wrong sound not found in the game database !"); } }
/// <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>Makes a call to <c>Awake()</c> method of the part module.</summary> /// <remarks>Modules added to prefab via <c>AddModule()</c> call are not get activated as they /// would if activated by the Unity core. As a result some vital fields may be left uninitialized /// which may result in an NRE later when working with the prefab (e.g. making a part snapshot). /// This method finds and invokes method <c>Awake</c> via reflection which is normally done by /// Unity. /// <para><b>IMPORTANT!</b> This method cannot awake a module! To make the things right every /// class in the hierarchy should get its <c>Awake</c> called. This method only calls <c>Awake</c> /// method on <c>PartModule</c> parent class which is not enough to do a complete awakening. /// </para> /// <para>This is a HACK since <c>Awake()</c> method is not supposed to be called by anyone but /// Unity. For now it works fine but one day it may awake the kraken.</para> /// </remarks> /// <param name="module">Module instance to awake.</param> public static void AwakePartModule(PartModule module) { // Private method can only be accessed via reflection when requested on the class that declares // it. So, don't use type of the argument and specify it explicitly. var moduleAwakeMethod = typeof(PartModule).GetMethod( "Awake", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (moduleAwakeMethod != null) { moduleAwakeMethod.Invoke(module, new object[] {}); } else { Logger.logError("Cannot find Awake() method on {0}. Skip awakening of component: {1}", module.GetType(), module.GetType()); } }
/// <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"); } }
/// <summary>Walks thru all modules in the part and fixes null persistent fields.</summary> /// <remarks>Used to prevent NREs in methods that persist KSP fields. /// <para>Bad modules that cannot be fixed will be dropped which may make the part to be not /// behaving as expected. It's guaranteed that <i>stock</i> modules that need fixing will be /// fixed successfully. So, failures are only expected on the modules from the third-parties mods. /// </para></remarks> /// <param name="part">Prefab to fix.</param> public static void CleanupModuleFieldsInPart(Part part) { var badModules = new List <PartModule>(); foreach (var moduleObj in part.Modules) { var module = moduleObj as PartModule; try { CleanupFieldsInModule(module); } catch { badModules.Add(module); } } // Cleanup modules that block KIS. It's a bad thing to do but not working KIS is worse. foreach (var moduleToDrop in badModules) { Logger.logError( "Module on part prefab {0} is setup improperly: name={1}, type={2}. Drop it!", part, moduleToDrop.moduleName, moduleToDrop.GetType()); part.RemoveModule(moduleToDrop); } }
public override void OnItemUse(KIS_Item item, KIS_Item.UseFrom useFrom) { pageList.Clear(); ConfigNode node = KIS_Shared.GetBaseConfigNode(this); foreach (string page in node.GetValues("page")) { pageList.Add(page); } if (pageList.Count > 0) { pageIndex = 0; pageTotal = pageList.Count; pageTexture = GameDatabase.Instance.GetTexture(pageList[0], false); showPage = true; item.inventory.PlaySound(bookOpenSndPath, false, true); } else { Logger.logError("The book has no pages configured"); } }
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); }
public static bool createFXSound(Part part, FXGroup group, string sndPath, bool loop, float maxDistance = 30f) { group.audio = part.gameObject.AddComponent <AudioSource>(); group.audio.volume = GameSettings.SHIP_VOLUME; group.audio.rolloffMode = AudioRolloffMode.Linear; group.audio.dopplerLevel = 0f; group.audio.spatialBlend = 1f; group.audio.maxDistance = maxDistance; group.audio.loop = loop; group.audio.playOnAwake = false; if (GameDatabase.Instance.ExistsAudioClip(sndPath)) { group.audio.clip = GameDatabase.Instance.GetAudioClip(sndPath); return(true); } else { Logger.logError("Sound not found in the game database !"); ScreenMessaging.ShowPriorityScreenMessageWithTimeout( 10, "Sound file : {0} has not been found, please check your KIS installation !", sndPath); return(false); } }