private IEnumerator CreateSolversForAllBombComponents()
    {
        yield return(null);

        if (CheckedMods == null)
        {
            CheckedMods = new HashSet <Mod>();
        }
        if (!(typeof(ModManager).GetField("loadedMods", BindingFlags.NonPublic | BindingFlags.Instance)?.GetValue(ModManager.Instance) is Dictionary <string, Mod> loadedMods))
        {
            yield break;
        }

        Mod[]           mods         = loadedMods.Values.Where(x => CheckedMods.Add(x)).ToArray();
        KMBombModule[]  bombModules  = mods.SelectMany(x => x.GetModObjects <KMBombModule>()).ToArray();
        KMNeedyModule[] needyModules = mods.SelectMany(x => x.GetModObjects <KMNeedyModule>()).ToArray();
        DebugHelper.Log($"Found {bombModules.Length} solvable modules and {needyModules.Length} needy modules in {mods.Length} mods");
        DebugHelper.Log($"Solvable Modules: {string.Join(", ", bombModules.Select(x => x.ModuleType).ToArray()).Wrap(80)}");
        DebugHelper.Log($"Needy Modules: {string.Join(", ", needyModules.Select(x => x.ModuleType).ToArray()).Wrap(80)}");

        if (bombModules.Length > 0)
        {
            ComponentSolverFactory.SilentMode = true;
            DebugHelper.Log("Creating a solver for each Solvable module");
            foreach (KMBombModule bombComponent in bombModules)
            {
                ComponentSolver solver = null;
                try
                {
                    solver = ComponentSolverFactory.CreateSolver(null, bombComponent.GetComponent <ModBombComponent>(), ComponentTypeEnum.Mod);
                }
                catch (Exception e)
                {
                    DebugHelper.LogException(e, "Couldn't create a component solver during startup for the following reason:");
                }
                DebugHelper.Log(solver != null
                                        ? $"Found a solver of type \"{solver.GetType().FullName}\" for solvable component \"{bombComponent.ModuleDisplayName}\" ({bombComponent.ModuleType}). This module is {(solver.UnsupportedModule ? "not supported" : "supported")} by Twitch Plays."
                                        : $"No solver found for solvable component \"{bombComponent.ModuleDisplayName}\". This module is not supported by Twitch Plays.");
                yield return(null);
            }
            DebugHelper.Log("Finished creating solvers for each Solvable module");
        }

        if (needyModules.Length > 0)
        {
            ComponentSolverFactory.SilentMode = true;
            DebugHelper.Log("Creating a solver for each Needy module");
            foreach (KMNeedyModule bombComponent in needyModules)
            {
                ComponentSolver solver = null;
                try
                {
                    solver = ComponentSolverFactory.CreateSolver(null, bombComponent.GetComponent <ModNeedyComponent>(), ComponentTypeEnum.NeedyMod);
                }
                catch (Exception e)
                {
                    DebugHelper.LogException(e, "Couldn't create a component solver during startup for the following reason:");
                }
                DebugHelper.Log(solver != null
                                        ? $"Found a solver of type \"{solver.GetType().FullName}\" for needy component \"{bombComponent.ModuleDisplayName}\" ({bombComponent.ModuleType}). This module is {(solver.UnsupportedModule ? "not supported" : "supported")} by Twitch Plays."
                                        : $"No solver found for needy component \"{bombComponent.ModuleDisplayName}\". This module is not supported by Twitch Plays.");
                yield return(null);
            }
            DebugHelper.Log("Finished creating solvers for each Needy module");
        }

        ComponentSolverFactory.SilentMode = false;
        ModuleData.WriteDataToFile();
    }
Beispiel #2
0
    static IEnumerator TestComponents(List <KtaneModule> modules)
    {
        IEnumerable <BombComponent> untestedComponents = GetUntestedComponents(modules);
        Dictionary <string, string> nameMap            = GetNameMap(modules);

        GameObject fakeModule = new GameObject();

        gameObjects.Add(fakeModule);
        TwitchModule module = fakeModule.AddComponent <TwitchModule>();

        module.enabled = false;

        HashSet <string>          unsupportedModules = new HashSet <string>();
        Dictionary <string, bool> supportStatus      = new Dictionary <string, bool>();

        ComponentSolverFactory.SilentMode = true;

        // Try to create a ComponentSolver for each module so we can see what modules are supported.
        foreach (BombComponent bombComponent in untestedComponents)
        {
            ComponentSolver solver = null;
            try
            {
                module.BombComponent = bombComponent.GetComponent <BombComponent>();

                solver = ComponentSolverFactory.CreateSolver(module);

                module.StopAllCoroutines();                 // Stop any coroutines to prevent any exceptions or from affecting the next module.
            }
            catch (Exception e)
            {
                DebugHelper.LogException(e, $"Couldn't create a component solver for \"{bombComponent.GetModuleDisplayName()}\" during startup for the following reason:");
            }

            ModuleData.DataHasChanged |= solver != null;

            DebugHelper.Log(solver != null
                                ? $"Found a solver of type \"{solver.GetType().FullName}\" for component \"{bombComponent.GetModuleDisplayName()}\". This module is {(solver.UnsupportedModule ? "not supported" : "supported")} by Twitch Plays."
                                : $"No solver found for component \"{bombComponent.GetModuleDisplayName()}\". This module is not supported by Twitch Plays.");

            string moduleID = bombComponent.GetComponent <KMBombModule>()?.ModuleType ?? bombComponent.GetComponent <KMNeedyModule>()?.ModuleType;
            if (solver?.UnsupportedModule != false && moduleID != null)
            {
                unsupportedModules.Add(moduleID);
            }

            supportStatus[bombComponent.GetModuleDisplayName()] = !(solver?.UnsupportedModule != false && moduleID != null);

            yield return(null);
        }

        ComponentSolverFactory.SilentMode = false;
        ModuleData.WriteDataToFile();
        Object.Destroy(fakeModule);

        // Always disable the modules from the spreadsheet
        var disabledSheet = new GoogleSheet("1G6hZW0RibjW7n72AkXZgDTHZ-LKj0usRkbAwxSPhcqA", "1849453757", "modulename");

        yield return(disabledSheet);

        if (disabledSheet.Success && TwitchPlaySettings.data.AllowSheetDisabledModules)
        {
            foreach (var row in disabledSheet.GetRows())
            {
                if (!nameMap.TryGetValue(row["modulename"], out string moduleID))
                {
                    DebugHelper.Log($"Couldn't map \"{row["modulename"]}\" to a module ID when disabling modules from the spreadsheet.");
                    continue;
                }

                unsupportedModules.Add(moduleID);
            }
        }

        // Always disable modules that are marked as "Unplayable"
        foreach (var moduleInfo in modules)
        {
            if (moduleInfo.Compatibility != "Unplayable")
            {
                continue;
            }

            unsupportedModules.Add(moduleInfo.ModuleID);
        }

        // Using the list of unsupported module IDs stored in unsupportedModules, make a Mod Selector profile.
        string profilesPath = Path.Combine(Application.persistentDataPath, "ModProfiles");

        if (Directory.Exists(profilesPath))
        {
            Dictionary <string, object> profileData = new Dictionary <string, object>()
            {
                { "DisabledList", unsupportedModules },
                { "Operation", 1 }
            };

            File.WriteAllText(Path.Combine(profilesPath, "TP_Supported.json"), SettingsConverter.Serialize(profileData));
        }

        alertProgressBar.localScale = Vector3.one;

        // Send a message to chat if any modules aren't marked as having support
        if (supportStatus.Values.Count(status => status) > 0)
        {
            var supportedList = supportStatus.Where(pair => pair.Value).Select(pair => pair.Key).Join(", ");
            IRCConnection.SendMessage($"These modules have TP support: {supportedList}");
            alertText.text = $"These modules have TP support: {supportedList}";
            yield return(new WaitForSeconds(4));
        }
        else
        {
            alertText.text = "Support checks passed succesfully!";
            yield return(new WaitForSeconds(2));
        }

        // Log out the full results of the testing
        DebugHelper.Log($"Support testing results:\n{supportStatus.OrderByDescending(pair => pair.Value).Select(pair => $"{pair.Key} - {(pair.Value ? "" : "Not ")}Supported").Join("\n")}");
    }
    static IEnumerator TestComponents(IEnumerable <BombComponent> untestedComponents)
    {
        GameObject fakeModule = new GameObject();

        gameObjects.Add(fakeModule);
        TwitchModule module = fakeModule.AddComponent <TwitchModule>();

        module.enabled = false;

        List <string>             unsupportedModules = new List <string>();
        Dictionary <string, bool> supportStatus      = new Dictionary <string, bool>();

        ComponentSolverFactory.SilentMode = true;

        // Try to create a ComponentSolver for each module so we can see what modules are supported.
        foreach (BombComponent bombComponent in untestedComponents)
        {
            ComponentSolver solver = null;
            try
            {
                module.BombComponent = bombComponent.GetComponent <BombComponent>();

                solver = ComponentSolverFactory.CreateSolver(module);

                module.StopAllCoroutines();                 // Stop any coroutines to prevent any exceptions or from affecting the next module.
            }
            catch (Exception e)
            {
                DebugHelper.LogException(e, $"Couldn't create a component solver for \"{bombComponent.GetModuleDisplayName()}\" during startup for the following reason:");
            }

            ModuleData.DataHasChanged |= solver != null;

            DebugHelper.Log(solver != null
                                ? $"Found a solver of type \"{solver.GetType().FullName}\" for component \"{bombComponent.GetModuleDisplayName()}\". This module is {(solver.UnsupportedModule ? "not supported" : "supported")} by Twitch Plays."
                                : $"No solver found for component \"{bombComponent.GetModuleDisplayName()}\". This module is not supported by Twitch Plays.");

            string moduleID = bombComponent.GetComponent <KMBombModule>()?.ModuleType ?? bombComponent.GetComponent <KMNeedyModule>()?.ModuleType;
            if (solver?.UnsupportedModule != false && moduleID != null)
            {
                unsupportedModules.Add(moduleID);
            }

            supportStatus[bombComponent.GetModuleDisplayName()] = !(solver?.UnsupportedModule != false && moduleID != null);

            yield return(null);
        }

        ComponentSolverFactory.SilentMode = false;
        ModuleData.WriteDataToFile();
        Object.Destroy(fakeModule);

        // Using the list of unsupported module IDs stored in unsupportedModules, make a Mod Selector profile.
        string profilesPath = Path.Combine(Application.persistentDataPath, "ModProfiles");

        if (Directory.Exists(profilesPath))
        {
            Dictionary <string, object> profileData = new Dictionary <string, object>()
            {
                { "DisabledList", unsupportedModules },
                { "Operation", 1 }
            };

            File.WriteAllText(Path.Combine(profilesPath, "TP_Supported.json"), SettingsConverter.Serialize(profileData));
        }

        alertProgressBar.localScale = Vector3.one;

        // Send a message to chat if any modules aren't marked as having support
        if (supportStatus.Values.Count(status => status) > 0)
        {
            var supportedList = supportStatus.Where(pair => pair.Value).Select(pair => pair.Key).Join(", ");
            IRCConnection.SendMessage($"Let the Scoring Team know that the following modules have TP support: {supportedList}");
            alertText.text = $"These modules have TP support: {supportedList}";
            yield return(new WaitForSeconds(4));
        }
        else
        {
            alertText.text = "Support checks passed succesfully!";
            yield return(new WaitForSeconds(2));
        }

        // Log out the full results of the testing
        DebugHelper.Log($"Support testing results:\n{supportStatus.OrderByDescending(pair => pair.Value).Select(pair => $"{pair.Key} - {(pair.Value ? "" : "Not ")}Supported").Join("\n")}");
    }
Beispiel #4
0
    private void Start()
    {
        if (bombComponent != null)
        {
            headerText.text = (string)CommonReflectedTypeInfo.ModuleDisplayNameField.Invoke(bombComponent, null);
        }

        idText.text            = string.Format("!{0}", _code);
        idTextMultiDecker.text = _code;

        canvasGroup.alpha    = 0.0f;
        highlightGroup.alpha = 0.0f;

        canvasGroupMultiDecker.alpha = bombCommander._multiDecker ? 1.0f : 0.0f;

        unclaimedBackgroundColor = idBannerPrefab.GetComponent <Image>().color;

        try
        {
            _solver = ComponentSolverFactory.CreateSolver(bombCommander, bombComponent, componentType, ircConnection, coroutineCanceller);
            if (_solver != null)
            {
                _solver.Code            = _code;
                _solver.ComponentHandle = this;
                Vector3 pos = canvasGroupMultiDecker.transform.localPosition;
                canvasGroupMultiDecker.transform.localPosition = new Vector3(_solver.statusLightLeft ? -pos.x : pos.x, pos.y, _solver.statusLightBottom ? -pos.z : pos.z);

                /*
                 * Vector3 angle = canvasGroupMultiDecker.transform.eulerAngles;
                 * canvasGroupMultiDecker.transform.localEulerAngles = new Vector3(angle.x, _solver.IDRotation, angle.z);
                 * angle = canvasGroupMultiDecker.transform.localEulerAngles;
                 * canvasGroup.transform.localEulerAngles = new Vector3(angle.x, _solver.IDRotation, angle.z);
                 *
                 * switch ((int) _solver.IDRotation)
                 * {
                 *  case 90:
                 *  case -270:
                 *      switch (direction)
                 *      {
                 *          case Direction.Up:
                 *              direction = Direction.Left;
                 *              break;
                 *          case Direction.Left:
                 *              direction = Direction.Down;
                 *              break;
                 *          case Direction.Down:
                 *              direction = Direction.Right;
                 *              break;
                 *          case Direction.Right:
                 *              direction = Direction.Up;
                 *              break;
                 *      }
                 *      break;
                 *
                 *  case 180:
                 *  case -180:
                 *      switch (direction)
                 *      {
                 *          case Direction.Up:
                 *              direction = Direction.Down;
                 *              break;
                 *          case Direction.Left:
                 *              direction = Direction.Right;
                 *              break;
                 *          case Direction.Down:
                 *              direction = Direction.Up;
                 *              break;
                 *          case Direction.Right:
                 *              direction = Direction.Left;
                 *              break;
                 *      }
                 *      break;
                 *
                 *  case 270:
                 *  case -90:
                 *      switch (direction)
                 *      {
                 *          case Direction.Up:
                 *              direction = Direction.Right;
                 *              break;
                 *          case Direction.Left:
                 *              direction = Direction.Up;
                 *              break;
                 *          case Direction.Down:
                 *              direction = Direction.Left;
                 *              break;
                 *          case Direction.Right:
                 *              direction = Direction.Down;
                 *              break;
                 *      }
                 *      break;
                 * }*/
            }
        }
        catch (NotSupportedException e)
        {
            Debug.Log(e.Message);
            unsupportedPrefab.gameObject.SetActive(true);
            idBannerPrefab.gameObject.SetActive(false);
            canvasGroupMultiDecker.alpha = 0.0f;
        }

        Arrow.gameObject.SetActive(true);
        HighlightArrow.gameObject.SetActive(true);
    }
    private void Start()
    {
        if (bombComponent != null)
        {
            headerText.text = bombComponent.GetModuleDisplayName();
        }

        idText.text            = string.Format("!{0}", Code);
        idTextMultiDecker.text = Code;

        canvasGroup.alpha    = 0.0f;
        highlightGroup.alpha = 0.0f;

        canvasGroupMultiDecker.alpha = bombCommander.multiDecker ? 1.0f : 0.0f;

        unclaimedBackgroundColor = TwitchPlaySettings.data.UnclaimedColor;        //idBannerPrefab.GetComponent<Image>().color;

        try
        {
            _solver = ComponentSolverFactory.CreateSolver(bombCommander, bombComponent, componentType, ircConnection, coroutineCanceller);
            if (_solver != null)
            {
                if (_solver.modInfo.ShouldSerializeunclaimedColor())
                {
                    unclaimedBackgroundColor = _solver.modInfo.unclaimedColor;
                }

                _solver.Code            = Code;
                _solver.ComponentHandle = this;
                Vector3 pos = canvasGroupMultiDecker.transform.localPosition;
                canvasGroupMultiDecker.transform.localPosition = new Vector3(_solver.modInfo.statusLightLeft ? -pos.x : pos.x, pos.y, _solver.modInfo.statusLightDown ? -pos.z : pos.z);
                RectTransform rectTransform = claimedUserMultiDecker.rectTransform;
                rectTransform.anchorMax = rectTransform.anchorMin = new Vector2(_solver.modInfo.statusLightLeft ? 1 : 0, _solver.modInfo.statusLightDown ? 0 : 1);
                rectTransform.pivot     = new Vector2(_solver.modInfo.statusLightLeft ? 0 : 1, _solver.modInfo.statusLightDown ? 0 : 1);

                canvasGroupUnsupported.gameObject.SetActive(_solver.UnsupportedModule);

                idTextUnsupported.text = bombComponent is ModBombComponent
                                        ? $"To solve this\nmodule, use\n!{Code} solve"
                                        : $"To disarm this\nneedy, use\n!{Code} solve";
                if (_solver.UnsupportedModule)
                {
                    _unsupportedComponents.Add(this);
                }

                /*Vector3 angle = canvasGroupMultiDecker.transform.eulerAngles;
                 * canvasGroupMultiDecker.transform.localEulerAngles = new Vector3(angle.x, _solver.modInfo.chatRotation, angle.z);
                 * angle = canvasGroupMultiDecker.transform.localEulerAngles;
                 * canvasGroup.transform.localEulerAngles = new Vector3(angle.x, _solver.modInfo.chatRotation, angle.z);
                 *
                 * switch ((int) _solver.modInfo.chatRotation)
                 * {
                 * case 90:
                 * case -270:
                 * switch (direction)
                 * {
                 * case Direction.Up:
                 * direction = Direction.Left;
                 * break;
                 * case Direction.Left:
                 * direction = Direction.Down;
                 * break;
                 * case Direction.Down:
                 * direction = Direction.Right;
                 * break;
                 * case Direction.Right:
                 * direction = Direction.Up;
                 * break;
                 * }
                 * break;
                 *
                 * case 180:
                 * case -180:
                 * switch (direction)
                 * {
                 * case Direction.Up:
                 * direction = Direction.Down;
                 * break;
                 * case Direction.Left:
                 * direction = Direction.Right;
                 * break;
                 * case Direction.Down:
                 * direction = Direction.Up;
                 * break;
                 * case Direction.Right:
                 * direction = Direction.Left;
                 * break;
                 * }
                 * break;
                 *
                 * case 270:
                 * case -90:
                 * switch (direction)
                 * {
                 * case Direction.Up:
                 * direction = Direction.Right;
                 * break;
                 * case Direction.Left:
                 * direction = Direction.Up;
                 * break;
                 * case Direction.Down:
                 * direction = Direction.Left;
                 * break;
                 * case Direction.Right:
                 * direction = Direction.Down;
                 * break;
                 * }
                 * break;
                 * }*/
            }
        }
        catch (Exception e)
        {
            DebugHelper.LogException(e);
            unsupportedPrefab.gameObject.SetActive(true);
            idBannerPrefab.gameObject.SetActive(false);
            canvasGroupMultiDecker.alpha = 0.0f;
            _unsupportedComponents.Add(this);

            canvasGroupUnsupported.gameObject.SetActive(true);
            idTextUnsupported.gameObject.SetActive(false);

            if (TwitchPlaySettings.data.EnableTwitchPlaysMode && !TwitchPlaySettings.data.EnableInteractiveMode)
            {
                DebugHelper.Log("An unimplemented module was added to a bomb, solving module.");
            }

            if (bombComponent != null)
            {
                if (bombComponent.GetComponent <KMBombModule>() != null)
                {
                    KMBombModule module = bombComponent.GetComponent <KMBombModule>();
                    module.OnPass += delegate
                    {
                        bombCommander.bombSolvedModules++;
                        BombMessageResponder.moduleCameras?.UpdateSolves();
                        OnPass();
                        BombMessageResponder.moduleCameras?.DetachFromModule(bombComponent);
                        return(false);
                    };

                    module.OnStrike += delegate
                    {
                        BombMessageResponder.moduleCameras?.UpdateStrikes();
                        return(false);
                    };
                }
                else if (bombComponent.GetComponent <KMNeedyModule>() != null)
                {
                    bombComponent.GetComponent <KMNeedyModule>().OnStrike += delegate
                    {
                        BombMessageResponder.moduleCameras?.UpdateStrikes();
                        return(false);
                    };
                }
            }
        }

        SetBannerColor(unclaimedBackgroundColor);

        if (!_bombCommanders.Contains(bombCommander))
        {
            _bombCommanders.Add(bombCommander);
        }

        Arrow.gameObject.SetActive(true);
        HighlightArrow.gameObject.SetActive(true);
    }