Exemplo n.º 1
0
        /// <summary>
        /// Do a "broadcast" GetPersistentVariable, where we iterate over every
        /// part in the craft and find each RasterPropMonitorComputer.  Return
        /// the value from the first one that contains the variable, or the
        /// default value otherwise.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        internal object GetPersistentVariable(string name, object defaultValue)
        {
            if (vessel != null)
            {
                for (int partIdx = 0; partIdx < vessel.parts.Count; ++partIdx)
                {
                    RasterPropMonitorComputer rpmc = RasterPropMonitorComputer.Instantiate(vessel.parts[partIdx], false);
                    if (rpmc.HasPersistentVariable(name, false))
                    {
                        return(rpmc.GetPersistentVariable(name, defaultValue, false));
                    }
                }
            }

            return(defaultValue);
        }
Exemplo n.º 2
0
        public void Start()
        {
            // If we're not in the correct location, there's no point doing anything.
            if (!InstallationPathWarning.Warn())
            {
                return;
            }

            if (HighLogic.LoadedSceneIsEditor)
            {
                return;
            }

            try
            {
                rpmComp = RasterPropMonitorComputer.Instantiate(internalProp, true);
                JUtil.LogMessage(this, "Attaching monitor {2}-{1} to {0}", rpmComp.RPMCid, internalProp.propID, internalProp.internalModel.internalName);

                // Install the calculator module.
                rpmComp.UpdateDataRefreshRate(refreshDataRate);

                // Loading the font...
                List <Texture2D> fontTexture = new List <Texture2D>();
                fontTexture.Add(LoadFont(this, internalProp, fontTransform));

                // Damn KSP's config parser!!!
                if (!string.IsNullOrEmpty(emptyColor))
                {
                    emptyColorValue = ConfigNode.ParseColor32(emptyColor);
                }
                if (!string.IsNullOrEmpty(defaultFontTint))
                {
                    defaultFontTintValue = ConfigNode.ParseColor32(defaultFontTint);
                }

                if (!string.IsNullOrEmpty(fontDefinition))
                {
                    JUtil.LogMessage(this, "Loading font definition from {0}", fontDefinition);
                    fontDefinitionString = File.ReadAllLines(KSPUtil.ApplicationRootPath + "GameData/" + fontDefinition.EnforceSlashes(), Encoding.UTF8)[0];
                }

                // Now that is done, proceed to setting up the screen.

                screenTexture = new RenderTexture(screenPixelWidth, screenPixelHeight, 24, RenderTextureFormat.ARGB32);
                screenMat     = internalProp.FindModelTransform(screenTransform).GetComponent <Renderer>().material;

                bool manuallyInvertY = false;
                if (SystemInfo.graphicsDeviceVersion.StartsWith("Direct3D 9") || SystemInfo.graphicsDeviceVersion.StartsWith("Direct3D 11") || SystemInfo.graphicsDeviceVersion.StartsWith("Direct3D 12"))
                {
                    manuallyInvertY = (UnityEngine.QualitySettings.antiAliasing > 0);
                }

                foreach (string layerID in textureLayerID.Split())
                {
                    screenMat.SetTexture(layerID.Trim(), screenTexture);
                    // This code was written for a much older flavor of Unity, and the Unity 2017.1 update broke
                    // some assumptions about who managed the y-inversion issue between OpenGL and DX9.
                    if (manuallyInvertY)
                    {
                        screenMat.SetTextureScale(layerID.Trim(), new Vector2(1.0f, -1.0f));
                        screenMat.SetTextureOffset(layerID.Trim(), new Vector2(0.0f, 1.0f));
                    }
                }

                if (GameDatabase.Instance.ExistsTexture(noSignalTextureURL.EnforceSlashes()))
                {
                    noSignalTexture = GameDatabase.Instance.GetTexture(noSignalTextureURL.EnforceSlashes(), false);
                }

                // The neat trick. IConfigNode doesn't work. No amount of kicking got it to work.
                // Well, we don't need it. GameDatabase, gimme config nodes for all props!
                foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("PROP"))
                {
                    // Now, we know our own prop name.
                    if (node.GetValue("name") == internalProp.propName)
                    {
                        // So this is the configuration of our prop in memory. Nice place.
                        // We know it contains at least one MODULE node, us.
                        // And we know our moduleID, which is the number in order of being listed in the prop.
                        // Therefore the module by that number is our module's own config node.

                        ConfigNode   moduleConfig = node.GetNodes("MODULE")[moduleID];
                        ConfigNode[] pageNodes    = moduleConfig.GetNodes("PAGE");

                        // Which we can now parse for page definitions.
                        for (int i = 0; i < pageNodes.Length; i++)
                        {
                            // Mwahahaha.
                            try
                            {
                                var newPage = new MonitorPage(i, pageNodes[i], this);
                                activePage = activePage ?? newPage;
                                if (newPage.isDefault)
                                {
                                    activePage = newPage;
                                }
                                pages.Add(newPage);
                            }
                            catch (ArgumentException e)
                            {
                                JUtil.LogMessage(this, "Warning - {0}", e);
                            }
                        }

                        // Now that all pages are loaded, we can use the moment in the loop to suck in all the extra fonts.
                        foreach (string value in moduleConfig.GetValues("extraFont"))
                        {
                            fontTexture.Add(LoadFont(this, internalProp, value));
                        }

                        break;
                    }
                }

                JUtil.LogMessage(this, "Done setting up pages, {0} pages ready.", pages.Count);

                textRenderer = new TextRenderer(fontTexture, new Vector2((float)fontLetterWidth, (float)fontLetterHeight), fontDefinitionString, 17, screenPixelWidth, screenPixelHeight);

                // Load our state from storage...
                persistentVarName = "activePage" + internalProp.propID;
                int activePageID = rpmComp.GetPersistentVariable(persistentVarName, pages.Count, false).MassageToInt();
                if (activePageID < pages.Count)
                {
                    activePage = pages[activePageID];
                }
                activePage.Active(true);

                // If we have global buttons, set them up.
                if (!string.IsNullOrEmpty(globalButtons))
                {
                    string[] tokens = globalButtons.Split(',');
                    for (int i = 0; i < tokens.Length; i++)
                    {
                        string buttonName = tokens[i].Trim();
                        // Notice that holes in the global button list ARE legal.
                        if (!string.IsNullOrEmpty(buttonName))
                        {
                            SmarterButton.CreateButton(internalProp, buttonName, i, GlobalButtonClick, GlobalButtonRelease);
                        }
                    }
                }

                audioOutput = JUtil.SetupIVASound(internalProp, buttonClickSound, buttonClickVolume, false);

                if (needsElectricCharge)
                {
                    delResourceCallback = (Action <bool>)Delegate.CreateDelegate(typeof(Action <bool>), this, "ResourceDepletedCallback");
                    rpmComp.RegisterResourceCallback(resourceName, delResourceCallback);
                }

                if (needsCommConnection)
                {
                    delCommConnectionCallback = (Action <float>)Delegate.CreateDelegate(typeof(Action <float>), this, "CommConnectionCallback");
                    rpmComp.RegisterVariableCallback("COMMNETVESSELCONTROLSTATE", delCommConnectionCallback);
                }

                // And if the try block never completed, startupComplete will never be true.
                startupComplete = true;
            }
            catch
            {
                JUtil.AnnoyUser(this);
                // We can also disable ourselves, that should help.
                enabled = false;
                // And now that we notified the user that config is borked, we rethrow the exception so that
                // it gets logged and we can debug.
                throw;
            }
        }
        public void Start()
        {
            if (!HighLogic.LoadedSceneIsFlight)
                return;

            rpmComp = RasterPropMonitorComputer.Instantiate(internalProp, true);

            // Grrrrrr.
            if (!string.IsNullOrEmpty(nameColor))
                nameColorValue = ConfigNode.ParseColor32(nameColor);
            if (!string.IsNullOrEmpty(distanceColor))
                distanceColorValue = ConfigNode.ParseColor32(distanceColor);
            if (!string.IsNullOrEmpty(selectedColor))
                selectedColorValue = ConfigNode.ParseColor32(selectedColor);
            if (!string.IsNullOrEmpty(unavailableColor))
                unavailableColorValue = ConfigNode.ParseColor32(unavailableColor);

            persistentVarName = "targetfilter" + internalProp.propID;

            // 7 is the bitmask for ship-station-probe;
            VesselFilterFromBitmask(rpmComp.GetPersistentVariable(persistentVarName, defaultFilter, false).MassageToInt());

            nameColorTag = JUtil.ColorToColorTag(nameColorValue);
            distanceColorTag = JUtil.ColorToColorTag(distanceColorValue);
            selectedColorTag = JUtil.ColorToColorTag(selectedColorValue);
            unavailableColorTag = JUtil.ColorToColorTag(unavailableColorValue);
            distanceFormatString = distanceFormatString.UnMangleConfigText();
            menuTitleFormatString = menuTitleFormatString.UnMangleConfigText();

            topMenu.labelColor = nameColorTag;
            topMenu.selectedColor = selectedColorTag;
            topMenu.disabledColor = unavailableColorTag;

            if (!string.IsNullOrEmpty(pageTitle))
                pageTitle = pageTitle.UnMangleConfigText();

            foreach (CelestialBody body in FlightGlobals.Bodies)
            {
                celestialsList.Add(new Celestial(body, vessel.transform.position));
            }

            FindReferencePoints();
            UpdateUndockablesList();

            var menuActions = new List<Action<int, TextMenu.Item>>();
            menuActions.Add(ShowCelestialMenu);
            menuActions.Add(ShowVesselMenu);
            menuActions.Add(ShowSpaceObjectMenu);
            menuActions.Add(ShowReferenceMenu);
            menuActions.Add(ShowUndockMenu);
            menuActions.Add(ArmGrapple);
            menuActions.Add(ShowFiltersMenu);
            menuActions.Add(ClearTarget);
            menuActions.Add(ShowCrewEVA);

            for (int i = 0; i < rootMenu.Count; ++i)
            {
                var menuitem = new TextMenu.Item();
                menuitem.labelText = rootMenu[i];
                menuitem.action = menuActions[i];
                topMenu.Add(menuitem);
                switch (menuitem.labelText)
                {
                    case clearTargetItemText:
                        clearTarget = topMenu[i];
                        break;
                    case undockItemText:
                        undockMenuItem = topMenu[i];
                        break;
                    case armGrappleText:
                        grappleMenuItem = topMenu[i];
                        break;
                    case crewEvaText:
                        float acLevel = ScenarioUpgradeableFacilities.GetFacilityLevel(SpaceCenterFacility.AstronautComplex);
                        bool evaUnlocked = GameVariables.Instance.UnlockedEVA(acLevel);
                        menuitem.isDisabled = !GameVariables.Instance.EVAIsPossible(evaUnlocked, vessel);
                        break;
                }
            }

            activeMenu = topMenu;
        }
        public void Start()
        {
            // If we're not in the correct location, there's no point doing anything.
            if (!InstallationPathWarning.Warn())
            {
                return;
            }

            if (HighLogic.LoadedSceneIsEditor)
            {
                return;
            }

            try
            {
                rpmComp = RasterPropMonitorComputer.Instantiate(internalProp, true);
                JUtil.LogMessage(this, "Attaching monitor {2}-{1} to {0}", rpmComp.RPMCid, internalProp.propID, internalProp.internalModel.internalName);

                // Install the calculator module.
                rpmComp.UpdateDataRefreshRate(refreshDataRate);

                // Loading the font...
                List<Texture2D> fontTexture = new List<Texture2D>();
                fontTexture.Add(LoadFont(this, internalProp, fontTransform));

                // Damn KSP's config parser!!!
                if (!string.IsNullOrEmpty(emptyColor))
                {
                    emptyColorValue = ConfigNode.ParseColor32(emptyColor);
                }
                if (!string.IsNullOrEmpty(defaultFontTint))
                {
                    defaultFontTintValue = ConfigNode.ParseColor32(defaultFontTint);
                }

                if (!string.IsNullOrEmpty(fontDefinition))
                {
                    JUtil.LogMessage(this, "Loading font definition from {0}", fontDefinition);
                    fontDefinitionString = File.ReadAllLines(KSPUtil.ApplicationRootPath + "GameData/" + fontDefinition.EnforceSlashes(), Encoding.UTF8)[0];
                }

                // Now that is done, proceed to setting up the screen.

                screenTexture = new RenderTexture(screenPixelWidth, screenPixelHeight, 24, RenderTextureFormat.ARGB32);
                screenMat = internalProp.FindModelTransform(screenTransform).GetComponent<Renderer>().material;
                foreach (string layerID in textureLayerID.Split())
                {
                    screenMat.SetTexture(layerID.Trim(), screenTexture);
                }

                if (GameDatabase.Instance.ExistsTexture(noSignalTextureURL.EnforceSlashes()))
                {
                    noSignalTexture = GameDatabase.Instance.GetTexture(noSignalTextureURL.EnforceSlashes(), false);
                }

                // Create camera instance...
                cameraStructure = new FlyingCamera(part, cameraAspect);

                // The neat trick. IConfigNode doesn't work. No amount of kicking got it to work.
                // Well, we don't need it. GameDatabase, gimme config nodes for all props!
                foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("PROP"))
                {
                    // Now, we know our own prop name.
                    if (node.GetValue("name") == internalProp.propName)
                    {
                        // So this is the configuration of our prop in memory. Nice place.
                        // We know it contains at least one MODULE node, us.
                        // And we know our moduleID, which is the number in order of being listed in the prop.
                        // Therefore the module by that number is our module's own config node.

                        ConfigNode moduleConfig = node.GetNodes("MODULE")[moduleID];
                        ConfigNode[] pageNodes = moduleConfig.GetNodes("PAGE");

                        // Which we can now parse for page definitions.
                        for (int i = 0; i < pageNodes.Length; i++)
                        {
                            // Mwahahaha.
                            try
                            {
                                var newPage = new MonitorPage(i, pageNodes[i], this);
                                activePage = activePage ?? newPage;
                                if (newPage.isDefault)
                                    activePage = newPage;
                                pages.Add(newPage);
                            }
                            catch (ArgumentException e)
                            {
                                JUtil.LogMessage(this, "Warning - {0}", e);
                            }

                        }

                        // Now that all pages are loaded, we can use the moment in the loop to suck in all the extra fonts.
                        foreach (string value in moduleConfig.GetValues("extraFont"))
                        {
                            fontTexture.Add(LoadFont(this, internalProp, value));
                        }

                        break;
                    }
                }

                JUtil.LogMessage(this, "Done setting up pages, {0} pages ready.", pages.Count);

                textRenderer = new TextRenderer(fontTexture, new Vector2((float)fontLetterWidth, (float)fontLetterHeight), fontDefinitionString, 17, screenPixelWidth, screenPixelHeight);

                // Load our state from storage...
                persistentVarName = "activePage" + internalProp.propID;
                int activePageID = rpmComp.GetPersistentVariable(persistentVarName, pages.Count, false).MassageToInt();
                if (activePageID < pages.Count)
                {
                    activePage = pages[activePageID];
                }
                activePage.Active(true);

                // If we have global buttons, set them up.
                if (!string.IsNullOrEmpty(globalButtons))
                {
                    string[] tokens = globalButtons.Split(',');
                    for (int i = 0; i < tokens.Length; i++)
                    {
                        string buttonName = tokens[i].Trim();
                        // Notice that holes in the global button list ARE legal.
                        if (!string.IsNullOrEmpty(buttonName))
                            SmarterButton.CreateButton(internalProp, buttonName, i, GlobalButtonClick, GlobalButtonRelease);
                    }
                }

                audioOutput = JUtil.SetupIVASound(internalProp, buttonClickSound, buttonClickVolume, false);

                if (needsElectricCharge)
                {
                    del = (Action<bool>)Delegate.CreateDelegate(typeof(Action<bool>), this, "ResourceDepletedCallback");
                    rpmComp.RegisterResourceCallback(resourceName, del);
                }

                // And if the try block never completed, startupComplete will never be true.
                startupComplete = true;
            }
            catch
            {
                JUtil.AnnoyUser(this);
                // We can also disable ourselves, that should help.
                enabled = false;
                // And now that we notified the user that config is borked, we rethrow the exception so that
                // it gets logged and we can debug.
                throw;
            }
        }
        public void Start()
        {
            if (!HighLogic.LoadedSceneIsFlight)
            {
                return;
            }

            rpmComp = RasterPropMonitorComputer.Instantiate(internalProp, true);

            // Grrrrrr.
            if (!string.IsNullOrEmpty(nameColor))
            {
                nameColorValue = ConfigNode.ParseColor32(nameColor);
            }
            if (!string.IsNullOrEmpty(distanceColor))
            {
                distanceColorValue = ConfigNode.ParseColor32(distanceColor);
            }
            if (!string.IsNullOrEmpty(selectedColor))
            {
                selectedColorValue = ConfigNode.ParseColor32(selectedColor);
            }
            if (!string.IsNullOrEmpty(unavailableColor))
            {
                unavailableColorValue = ConfigNode.ParseColor32(unavailableColor);
            }

            persistentVarName = "targetfilter" + internalProp.propID;

            // 7 is the bitmask for ship-station-probe;
            VesselFilterFromBitmask(rpmComp.GetPersistentVariable(persistentVarName, defaultFilter, false).MassageToInt());

            nameColorTag          = JUtil.ColorToColorTag(nameColorValue);
            distanceColorTag      = JUtil.ColorToColorTag(distanceColorValue);
            selectedColorTag      = JUtil.ColorToColorTag(selectedColorValue);
            unavailableColorTag   = JUtil.ColorToColorTag(unavailableColorValue);
            distanceFormatString  = distanceFormatString.UnMangleConfigText();
            menuTitleFormatString = menuTitleFormatString.UnMangleConfigText();

            topMenu.labelColor    = nameColorTag;
            topMenu.selectedColor = selectedColorTag;
            topMenu.disabledColor = unavailableColorTag;

            if (!string.IsNullOrEmpty(pageTitle))
            {
                pageTitle = pageTitle.UnMangleConfigText();
            }

            foreach (CelestialBody body in FlightGlobals.Bodies)
            {
                celestialsList.Add(new Celestial(body, vessel.transform.position));
            }

            FindReferencePoints();
            UpdateUndockablesList();

            var menuActions = new List <Action <int, TextMenu.Item> >();

            menuActions.Add(ShowCelestialMenu);
            menuActions.Add(ShowVesselMenu);
            menuActions.Add(ShowSpaceObjectMenu);
            menuActions.Add(ShowReferenceMenu);
            menuActions.Add(ShowUndockMenu);
            menuActions.Add(ArmGrapple);
            menuActions.Add(ShowFiltersMenu);
            menuActions.Add(ClearTarget);
            menuActions.Add(ShowCrewEVA);

            for (int i = 0; i < rootMenu.Count; ++i)
            {
                var menuitem = new TextMenu.Item();
                menuitem.labelText = rootMenu[i];
                menuitem.action    = menuActions[i];
                topMenu.Add(menuitem);
                switch (menuitem.labelText)
                {
                case clearTargetItemText:
                    clearTarget = topMenu[i];
                    break;

                case undockItemText:
                    undockMenuItem = topMenu[i];
                    break;

                case armGrappleText:
                    grappleMenuItem = topMenu[i];
                    break;

                case crewEvaText:
                    float acLevel     = ScenarioUpgradeableFacilities.GetFacilityLevel(SpaceCenterFacility.AstronautComplex);
                    bool  evaUnlocked = GameVariables.Instance.UnlockedEVA(acLevel);
                    menuitem.isDisabled = !GameVariables.Instance.EVAIsPossible(evaUnlocked, vessel);
                    break;
                }
            }

            activeMenu = topMenu;
        }
Exemplo n.º 6
0
        private void UpdateOdometer()
        {
            double thisUpdate = Planetarium.GetUniversalTime();
            float  dT         = (float)(thisUpdate - lastUpdate) * odometerRotationScalar;

            float value;

            if (!string.IsNullOrEmpty(perPodPersistenceName))
            {
                bool state             = rpmComp.GetPersistentVariable(perPodPersistenceName, false, false);
                RPMVesselComputer comp = RPMVesselComputer.Instance(rpmComp.vessel);
                value = rpmComp.ProcessVariable((state) ? altVariable : variable, comp).MassageToFloat();
            }
            else
            {
                RPMVesselComputer comp = RPMVesselComputer.Instance(rpmComp.vessel);
                value = rpmComp.ProcessVariable(variable, comp).MassageToFloat();
            }
            // Make sure the value isn't going to be a problem.
            if (float.IsNaN(value))
            {
                value = 0.0f;
            }

            if (value < 0.0f)
            {
                signGoalCoord = 0.625f;
            }
            else if (value > 0.0f)
            {
                signGoalCoord = 0.875f;
            }
            else
            {
                signGoalCoord = 0.75f;
            }

            signCurrentCoord = JUtil.DualLerp(signCurrentCoord, signGoalCoord, 0.0f, 1.0f, dT);

            value = Mathf.Abs(value);

            if (oMode == OdometerMode.SI)
            {
                float leadingDigitExponent;
                if (value < 0.001f)
                {
                    leadingDigitExponent = -3.0f;
                }
                else
                {
                    leadingDigitExponent = Mathf.Floor(Mathf.Log10(value));
                }

                // siExponent is the location relative to the original decimal of
                // the SI prefix.  Is is always the greatest multiple-of-3 less
                // than the leadingDigitExponent.
                int siIndex = (int)Mathf.Floor(leadingDigitExponent / 3.0f);
                if (siIndex > 3)
                {
                    siIndex = 3;
                }
                int siExponent = siIndex * 3;

                prefixGoalCoord    = (float)(siIndex + 1) * 0.125f;
                prefixCurrentCoord = JUtil.DualLerp(prefixCurrentCoord, prefixGoalCoord, 0.0f, 1.0f, dT);

                float scaledValue = value / Mathf.Pow(10.0f, (float)(siExponent - 3));
                int   intValue    = (int)(scaledValue);

                for (int i = 5; i >= 0; --i)
                {
                    float thisCoord = (float)(intValue % 10) / 10.0f;
                    if (i == 5)
                    {
                        // So we can display fractional values:
                        // However, we also quantize it to make it easier to
                        // read during the transition from 9 to 0.
                        thisCoord = Mathf.Floor((scaledValue % 10.0f) * 2.0f) / 20.0f;
                    }
                    intValue          = intValue / 10;
                    goalCoordinate[i] = thisCoord;
                }
            }
            else if (oMode == OdometerMode.TIME_HHHMMSS)
            {
                // Clamp the value
                value = Mathf.Min(value, 59.0f + 59.0f * 60.0f + 999.0f * 60.0f * 24.0f);

                // seconds
                float thisCoord = Mathf.Floor((value % 10.0f) * 2.0f) / 20.0f;
                goalCoordinate[6] = thisCoord;
                int intValue = (int)(value) / 10;

                // tens of seconds
                thisCoord         = (float)(intValue % 6) / 10.0f;
                goalCoordinate[5] = thisCoord;
                intValue         /= 6;

                // minutes
                thisCoord         = (float)(intValue % 10) / 10.0f;
                goalCoordinate[4] = thisCoord;
                intValue         /= 10;

                // tens of minutes
                thisCoord         = (float)(intValue % 6) / 10.0f;
                goalCoordinate[3] = thisCoord;
                intValue         /= 6;

                for (int i = 2; i >= 0; --i)
                {
                    thisCoord         = (float)(intValue % 10) / 10.0f;
                    intValue          = intValue / 10;
                    goalCoordinate[i] = thisCoord;
                }
            }
            else
            {
                int intValue = (int)(value);

                for (int i = 7; i >= 0; --i)
                {
                    float thisCoord = (float)(intValue % 10) / 10.0f;
                    if (i == 7)
                    {
                        thisCoord = Mathf.Floor((value % 10.0f) * 2.0f) / 20.0f;
                    }
                    intValue          = intValue / 10;
                    goalCoordinate[i] = thisCoord;
                }
            }

            // Update interpolants
            for (int i = 0; i < 8; ++i)
            {
                if (currentCoordinate[i] != goalCoordinate[i])
                {
                    float startingPoint;
                    float endingPoint;
                    if (Mathf.Abs(currentCoordinate[i] - goalCoordinate[i]) <= 0.5f)
                    {
                        startingPoint = currentCoordinate[i];
                        endingPoint   = goalCoordinate[i];
                    }
                    else if (goalCoordinate[i] < currentCoordinate[i])
                    {
                        startingPoint = currentCoordinate[i];
                        endingPoint   = goalCoordinate[i] + 1.0f;
                    }
                    else
                    {
                        startingPoint = currentCoordinate[i] + 1.0f;
                        endingPoint   = goalCoordinate[i];
                    }

                    // This lerp causes a rotation that starts quickly but
                    // slows down close to the goal.  It actually looks
                    // pretty good for typical incrementing counts, while the
                    // rapid spinning of small values is chaotic enough that
                    // you can't really tell what's going on, anyway.
                    float goal = JUtil.DualLerp(startingPoint, endingPoint, 0.0f, 1.0f, dT);
                    if (goal > 1.0f)
                    {
                        goal -= 1.0f;
                    }
                    currentCoordinate[i] = goal;
                }
            }
            lastUpdate = thisUpdate;
        }
Exemplo n.º 7
0
        public void Click()
        {
            bool switchEnabled = true;

            if (!forcedShutdown)
            {
                if (perPodMasterSwitchValid)
                {
                    switchEnabled = rpmComp.GetPersistentVariable(perPodMasterSwitchName, false, false);
                }
                if (masterVariable != null)
                {
                    switchEnabled = masterVariable.IsInRange();
                }
            }
            if (!switchEnabled)
            {
                // If the master switch is 'off' and we're not here because
                // of a forced shutdown, don't allow this switch to work.
                // early return
                return;
            }

            if (isCustomAction)
            {
                if (switchGroupIdentifier >= 0)
                {
                    if (!forcedShutdown && !customGroupState)
                    {
                        customGroupState = true;
                        if (persistentVarValid)
                        {
                            rpmComp.SetPersistentVariable(persistentVarName, switchGroupIdentifier, perPodPersistenceIsGlobal);
                        }
                    }
                    // else: can't turn off a radio group switch.
                }
                else if (customAction == CustomActions.Plugin && stateVariable != null)
                {
                    int ivalue = stateVariable.AsInt();
                    customGroupState = (ivalue < 1) && !forcedShutdown;
                }
                else
                {
                    customGroupState = !customGroupState;
                    if (persistentVarValid)
                    {
                        rpmComp.SetPersistentVariable(persistentVarName, customGroupState, perPodPersistenceIsGlobal);
                    }
                }
            }
            else
            {
                vessel.ActionGroups.ToggleGroup(kspAction);
            }

            // Now we do extra things that with regular actions can't happen.
            switch (customAction)
            {
            case CustomActions.IntLight:
                SetInternalLights(customGroupState);
                break;

            case CustomActions.Plugin:
                actionHandler(customGroupState);
                break;

            case CustomActions.Stage:
                if (InputLockManager.IsUnlocked(ControlTypes.STAGING))
                {
                    StageManager.ActivateNextStage();
                }
                break;

            case CustomActions.TransferToPersistent:
                if (stateVariable != null)
                {
                    // stateVariable can disable the button functionality.
                    int ivalue = stateVariable.AsInt();
                    if (ivalue < 1)
                    {
                        return;     // early - button disabled
                    }
                }
                float getValue = transferGetter.AsFloat();
                rpmComp.SetPersistentVariable(transferPersistentName, getValue, false);
                break;

            case CustomActions.TransferFromPersistent:
                if (stateVariable != null)
                {
                    // stateVariable can disable the button functionality.
                    int ivalue = stateVariable.AsInt();
                    if (ivalue < 1)
                    {
                        return;     // early - button disabled
                    }
                }
                if (rpmComp.HasPersistentVariable(transferPersistentName, false))
                {
                    transferSetter(rpmComp.GetPersistentVariable(transferPersistentName, 0.0, false).MassageToDouble());
                }
                break;

            case CustomActions.TransferFromVariable:
                if (stateVariable != null)
                {
                    // stateVariable can disable the button functionality.
                    int ivalue = stateVariable.AsInt();
                    if (ivalue < 1)
                    {
                        return;     // early - button disabled
                    }
                }
                double xferValue = transferGetter.AsDouble();
                transferSetter(xferValue);
                break;
            }
        }
Exemplo n.º 8
0
        public void Start()
        {
            if (HighLogic.LoadedSceneIsEditor)
            {
                return;
            }

            try
            {
                rpmComp = RasterPropMonitorComputer.Instantiate(internalProp, true);

                if (!groupList.ContainsKey(actionName) && !customGroupList.ContainsKey(actionName))
                {
                    JUtil.LogErrorMessage(this, "Action \"{0}\" is not supported.", actionName);
                    return;
                }

                // Parse the needs-electric-charge here.
                if (!string.IsNullOrEmpty(needsElectricCharge))
                {
                    switch (needsElectricCharge.ToLowerInvariant().Trim())
                    {
                    case "true":
                    case "yes":
                    case "1":
                        needsElectricChargeValue = true;
                        break;

                    case "false":
                    case "no":
                    case "0":
                        needsElectricChargeValue = false;
                        break;
                    }
                }

                // Now parse consumeOnToggle and consumeWhileActive...
                if (!string.IsNullOrEmpty(consumeOnToggle))
                {
                    string[] tokens = consumeOnToggle.Split(',');
                    if (tokens.Length == 3)
                    {
                        consumeOnToggleName = tokens[0].Trim();
                        if (!(PartResourceLibrary.Instance.GetDefinition(consumeOnToggleName) != null &&
                              float.TryParse(tokens[1].Trim(), NumberStyles.Any, CultureInfo.InvariantCulture,
                                             out consumeOnToggleAmount)))
                        {
                            JUtil.LogErrorMessage(this, "Could not parse \"{0}\"", consumeOnToggle);
                        }
                        switch (tokens[2].Trim().ToLower())
                        {
                        case "on":
                            consumingOnToggleUp = true;
                            break;

                        case "off":
                            consumingOnToggleDown = true;
                            break;

                        case "both":
                            consumingOnToggleUp   = true;
                            consumingOnToggleDown = true;
                            break;

                        default:
                            JUtil.LogErrorMessage(this, "So should I consume resources when turning on, turning off, or both in \"{0}\"?", consumeOnToggle);
                            break;
                        }
                    }
                }

                if (!string.IsNullOrEmpty(consumeWhileActive))
                {
                    string[] tokens = consumeWhileActive.Split(',');
                    if (tokens.Length == 2)
                    {
                        consumeWhileActiveName = tokens[0].Trim();
                        if (!(PartResourceLibrary.Instance.GetDefinition(consumeWhileActiveName) != null &&
                              float.TryParse(tokens[1].Trim(),
                                             NumberStyles.Any, CultureInfo.InvariantCulture,
                                             out consumeWhileActiveAmount)))
                        {
                            JUtil.LogErrorMessage(this, "Could not parse \"{0}\"", consumeWhileActive);
                        }
                        else
                        {
                            consumingWhileActive = true;
                            JUtil.LogMessage(this, "Switch in prop {0} prop id {1} will consume {2} while active at a rate of {3}", internalProp.propName,
                                             internalProp.propID, consumeWhileActiveName, consumeWhileActiveAmount);
                        }
                    }
                }

                if (groupList.ContainsKey(actionName))
                {
                    kspAction    = groupList[actionName];
                    currentState = vessel.ActionGroups[kspAction];
                    // action group switches may not belong to a radio group
                    switchGroupIdentifier = -1;
                }
                else
                {
                    isCustomAction = true;
                    switch (actionName)
                    {
                    case "intlight":
                        persistentVarName = internalLightName;
                        if (!string.IsNullOrEmpty(internalLightName))
                        {
                            Light[] availableLights = internalModel.FindModelComponents <Light>();
                            if (availableLights != null && availableLights.Length > 0)
                            {
                                List <Light> lights = new List <Light>(availableLights);
                                for (int i = lights.Count - 1; i >= 0; --i)
                                {
                                    if (lights[i].name != internalLightName)
                                    {
                                        lights.RemoveAt(i);
                                    }
                                }
                                if (lights.Count > 0)
                                {
                                    lightObjects              = lights.ToArray();
                                    needsElectricChargeValue |= string.IsNullOrEmpty(needsElectricCharge) || needsElectricChargeValue;
                                }
                                else
                                {
                                    actionName = "dummy";
                                }
                            }
                        }
                        else
                        {
                            actionName = "dummy";
                        }
                        break;

                    case "plugin":
                        persistentVarName = string.Empty;
                        rpmComp.UpdateDataRefreshRate(refreshRate);

                        foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("PROP"))
                        {
                            if (node.GetValue("name") == internalProp.propName)
                            {
                                foreach (ConfigNode pluginConfig in node.GetNodes("MODULE")[moduleID].GetNodes("PLUGINACTION"))
                                {
                                    if (pluginConfig.HasValue("name") && pluginConfig.HasValue("actionMethod"))
                                    {
                                        string action = pluginConfig.GetValue("name").Trim() + ":" + pluginConfig.GetValue("actionMethod").Trim();
                                        actionHandler = (Action <bool>)rpmComp.GetMethod(action, internalProp, typeof(Action <bool>));

                                        if (actionHandler == null)
                                        {
                                            JUtil.LogErrorMessage(this, "Failed to instantiate action handler {0}", action);
                                        }
                                        else
                                        {
                                            if (pluginConfig.HasValue("stateMethod"))
                                            {
                                                string state = pluginConfig.GetValue("name").Trim() + ":" + pluginConfig.GetValue("stateMethod").Trim();
                                                stateVariable = rpmComp.InstantiateVariableOrNumber("PLUGIN_" + state);
                                            }
                                            else if (pluginConfig.HasValue("stateVariable"))
                                            {
                                                stateVariable = rpmComp.InstantiateVariableOrNumber(pluginConfig.GetValue("stateVariable").Trim());
                                            }
                                            isPluginAction = true;
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                        if (actionHandler == null)
                        {
                            actionName = "dummy";
                            JUtil.LogMessage(this, "Plugin handlers did not start, reverting to dummy mode.");
                        }
                        break;

                    case "transfer":
                        persistentVarName = string.Empty;
                        rpmComp.UpdateDataRefreshRate(refreshRate);

                        foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("PROP"))
                        {
                            if (node.GetValue("name") == internalProp.propName)
                            {
                                foreach (ConfigNode pluginConfig in node.GetNodes("MODULE")[moduleID].GetNodes("TRANSFERACTION"))
                                {
                                    if (pluginConfig.HasValue("name") || pluginConfig.HasValue("getVariable"))
                                    {
                                        if (pluginConfig.HasValue("stateMethod"))
                                        {
                                            string state = pluginConfig.GetValue("name").Trim() + ":" + pluginConfig.GetValue("stateMethod").Trim();
                                            stateVariable = rpmComp.InstantiateVariableOrNumber("PLUGIN_" + state);
                                        }
                                        else if (pluginConfig.HasValue("stateVariable"))
                                        {
                                            stateVariable = rpmComp.InstantiateVariableOrNumber(pluginConfig.GetValue("stateVariable").Trim());
                                        }
                                        if (pluginConfig.HasValue("setMethod"))
                                        {
                                            string action = pluginConfig.GetValue("name").Trim() + ":" + pluginConfig.GetValue("setMethod").Trim();
                                            transferSetter = (Action <double>)rpmComp.GetMethod(action, internalProp, typeof(Action <double>));

                                            if (transferSetter == null)
                                            {
                                                JUtil.LogErrorMessage(this, "Failed to instantiate transfer handler {0}", pluginConfig.GetValue("name"));
                                            }
                                            else if (pluginConfig.HasValue("perPodPersistenceName"))
                                            {
                                                transferPersistentName = pluginConfig.GetValue("perPodPersistenceName").Trim();
                                                actionName             = "transferFromPersistent";
                                                customAction           = CustomActions.TransferFromPersistent;
                                            }
                                            else if (pluginConfig.HasValue("getVariable"))
                                            {
                                                transferGetter = rpmComp.InstantiateVariableOrNumber(pluginConfig.GetValue("getVariable").Trim());
                                                actionName     = "transferFromVariable";
                                                customAction   = CustomActions.TransferFromVariable;
                                            }
                                            else
                                            {
                                                JUtil.LogErrorMessage(this, "Unable to configure transfer setter method in {0} - no perPodPersistenceName or getVariable", internalProp.name);
                                                transferSetter = null;
                                                //JUtil.LogMessage(this, "Got setter {0}", action);
                                            }
                                        }
                                        else if (pluginConfig.HasValue("getMethod"))
                                        {
                                            if (pluginConfig.HasValue("perPodPersistenceName"))
                                            {
                                                string action = pluginConfig.GetValue("name").Trim() + ":" + pluginConfig.GetValue("getMethod").Trim();
                                                var    getter = (Func <double>)rpmComp.GetMethod(action, internalProp, typeof(Func <double>));

                                                if (getter == null)
                                                {
                                                    JUtil.LogErrorMessage(this, "Failed to instantiate transfer handler {0} in {1}", pluginConfig.GetValue("name"), internalProp.name);
                                                }
                                                else
                                                {
                                                    transferGetter         = rpmComp.InstantiateVariableOrNumber("PLUGIN_" + action);
                                                    transferPersistentName = pluginConfig.GetValue("perPodPersistenceName").Trim();
                                                    actionName             = "transferToPersistent";
                                                    customAction           = CustomActions.TransferToPersistent;
                                                    //JUtil.LogMessage(this, "Got getter {0}", action);
                                                    break;
                                                }
                                            }
                                            else
                                            {
                                                JUtil.LogErrorMessage(this, "Transfer handler in {0} configured with 'getVariable', but no 'perPodPeristenceName'", internalProp.name);
                                            }
                                        }
                                        else if (pluginConfig.HasValue("getVariable"))
                                        {
                                            if (pluginConfig.HasValue("perPodPersistenceName"))
                                            {
                                                transferGetter         = rpmComp.InstantiateVariableOrNumber(pluginConfig.GetValue("getVariable").Trim());
                                                transferPersistentName = pluginConfig.GetValue("perPodPersistenceName").Trim();
                                                actionName             = "transferToPersistent";
                                                customAction           = CustomActions.TransferToPersistent;
                                            }
                                            else
                                            {
                                                JUtil.LogErrorMessage(this, "Transfer handler in {0} configured with 'getVariable', but no 'perPodPeristenceName'", internalProp.name);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        if (transferGetter == null && transferSetter == null)
                        {
                            actionName    = "dummy";
                            stateVariable = null;
                            JUtil.LogMessage(this, "Transfer handlers did not start, reverting to dummy mode.");
                        }
                        break;

                    default:
                        persistentVarName = "switch" + internalProp.propID + "_" + moduleID;
                        break;
                    }
                    if (!string.IsNullOrEmpty(perPodPersistenceName))
                    {
                        persistentVarName = perPodPersistenceName;
                    }
                    else
                    {
                        // If there's no persistence name, there's no valid group id for this switch
                        switchGroupIdentifier = -1;
                    }

                    persistentVarValid = !string.IsNullOrEmpty(persistentVarName);
                }

                perPodPersistenceValid = !string.IsNullOrEmpty(perPodPersistenceName);

                if (customGroupList.ContainsKey(actionName))
                {
                    customAction = customGroupList[actionName];
                }

                if (needsElectricChargeValue || persistentVarValid || !string.IsNullOrEmpty(perPodMasterSwitchName) || !string.IsNullOrEmpty(masterVariableName) ||
                    transferGetter != null || transferSetter != null)
                {
                    rpmComp.UpdateDataRefreshRate(refreshRate);

                    if (!string.IsNullOrEmpty(masterVariableName))
                    {
                        string[] range = masterVariableRange.Split(',');
                        if (range.Length == 2)
                        {
                            masterVariable = new VariableOrNumberRange(rpmComp, masterVariableName, range[0], range[1]);
                        }
                        else
                        {
                            masterVariable = null;
                        }
                    }
                }

                if (needsElectricChargeValue)
                {
                    del = (Action <bool>)Delegate.CreateDelegate(typeof(Action <bool>), this, "ResourceDepletedCallback");
                    rpmComp.RegisterResourceCallback(resourceName, del);
                }

                // set up the toggle switch
                if (!string.IsNullOrEmpty(switchTransform))
                {
                    if (momentarySwitch)
                    {
                        SmarterButton.CreateButton(internalProp, switchTransform, Click, Click);
                    }
                    else
                    {
                        SmarterButton.CreateButton(internalProp, switchTransform, Click);
                    }
                }

                if (isCustomAction)
                {
                    if (isPluginAction && stateVariable != null)
                    {
                        currentState = stateVariable.AsInt() > 0;
                    }
                    else
                    {
                        if (persistentVarValid)
                        {
                            if (switchGroupIdentifier >= 0)
                            {
                                int activeSwitch = rpmComp.GetPersistentVariable(persistentVarName, 0, perPodPersistenceIsGlobal).MassageToInt();

                                currentState = customGroupState = (switchGroupIdentifier == activeSwitch);
                            }
                            else
                            {
                                currentState = customGroupState = rpmComp.GetPersistentVariable(persistentVarName, initialState, perPodPersistenceIsGlobal);
                            }

                            if (customAction == CustomActions.IntLight)
                            {
                                // We have to restore lighting after reading the
                                // persistent variable.
                                SetInternalLights(customGroupState);
                            }
                        }
                    }
                }

                if (persistentVarValid && !rpmComp.HasPersistentVariable(persistentVarName, perPodPersistenceIsGlobal))
                {
                    if (switchGroupIdentifier >= 0)
                    {
                        if (currentState)
                        {
                            rpmComp.SetPersistentVariable(persistentVarName, switchGroupIdentifier, perPodPersistenceIsGlobal);
                        }
                    }
                    else
                    {
                        rpmComp.SetPersistentVariable(persistentVarName, currentState, perPodPersistenceIsGlobal);
                    }
                }

                if (!string.IsNullOrEmpty(animationName))
                {
                    // Set up the animation
                    Animation[] animators = animateExterior ? part.FindModelAnimators(animationName) : internalProp.FindModelAnimators(animationName);
                    if (animators.Length > 0)
                    {
                        anim = animators[0];
                    }
                    else
                    {
                        JUtil.LogErrorMessage(this, "Could not find animation \"{0}\" on {2} \"{1}\"",
                                              animationName, animateExterior ? part.name : internalProp.name, animateExterior ? "part" : "prop");
                        return;
                    }
                    anim[animationName].wrapMode = WrapMode.Once;

                    if (currentState ^ reverse)
                    {
                        anim[animationName].speed          = float.MaxValue;
                        anim[animationName].normalizedTime = 0;
                    }
                    else
                    {
                        anim[animationName].speed          = float.MinValue;
                        anim[animationName].normalizedTime = 1;
                    }
                    anim.Play(animationName);
                }
                else if (!string.IsNullOrEmpty(coloredObject))
                {
                    // Set up the color shift.
                    Renderer colorShiftRenderer = internalProp.FindModelComponent <Renderer>(coloredObject);
                    disabledColorValue = JUtil.ParseColor32(disabledColor, part, ref rpmComp);
                    enabledColorValue  = JUtil.ParseColor32(enabledColor, part, ref rpmComp);
                    colorShiftMaterial = colorShiftRenderer.material;
                    colorNameId        = Shader.PropertyToID(colorName);
                    colorShiftMaterial.SetColor(colorNameId, (currentState ^ reverse ? enabledColorValue : disabledColorValue));
                }
                else
                {
                    JUtil.LogMessage(this, "Warning, neither color nor animation are defined in prop {0} #{1} (this may be okay).", internalProp.propName, internalProp.propID);
                }

                audioOutput = JUtil.SetupIVASound(internalProp, switchSound, switchSoundVolume, false);

                if (!string.IsNullOrEmpty(loopingSound) && loopingSoundVolume > 0.0f)
                {
                    loopingOutput = JUtil.SetupIVASound(internalProp, loopingSound, loopingSoundVolume, true);
                }

                perPodMasterSwitchValid = !string.IsNullOrEmpty(perPodMasterSwitchName);

                JUtil.LogMessage(this, "Configuration complete in prop {0} ({1}).", internalProp.propID, internalProp.propName);

                startupComplete = true;
            }
            catch (Exception e)
            {
                JUtil.LogErrorMessage(this, "Exception configuring prop {0} ({1}): {2}", internalProp.propID, internalProp.propName, e);
                JUtil.AnnoyUser(this);
                enabled = false;
            }
        }