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(); }
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")}"); }
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); }