Files
megakoop/UI/Scripts/UGUIMainMenuController.cs
2025-11-01 16:32:34 +01:00

682 lines
28 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using UnityEngine;
using UnityEngine.UI;
#if UNITY_EDITOR
using UnityEditor;
using TMPro;
#else
using TMPro;
#endif
using System.Collections.Generic;
namespace MegaKoop.UI
{
/// <summary>
/// UGUI Main Menu controller (no UI Toolkit). Handles switching panels and basic settings.
/// </summary>
public class UGUIMainMenuController : MonoBehaviour
{
// Panels
[Header("Optional Panel Refs (assign to override auto-find)")]
[SerializeField] private GameObject panelMainRef;
[SerializeField] private GameObject panelSettingsRef;
[SerializeField] private GameObject panelLobbyRef;
private GameObject panelMain;
private GameObject panelSettings;
private GameObject panelLobby;
[Header("Manual Wiring - Main Menu Buttons")]
[SerializeField] private Button btnNewGame;
[SerializeField] private Button btnContinue;
[SerializeField] private Button btnMultiplayer;
[SerializeField] private Button btnSettings;
[SerializeField] private Button btnQuit;
[Header("Manual Wiring - Settings Controls")]
[SerializeField] private TMP_Dropdown ddQuality;
[SerializeField] private Toggle tgFullscreen;
[SerializeField] private TMP_Dropdown ddResolution;
[SerializeField] private Button btnApplySettings;
[SerializeField] private Button btnBackFromSettings;
[SerializeField] private Slider slMaster;
[SerializeField] private Slider slMusic;
[SerializeField] private Slider slSFX;
[SerializeField] private Dropdown ddQualityUI;
[SerializeField] private Dropdown ddResolutionUI;
private void Awake()
{
// Panels (created by UGUIMenuBuilder) najdi i když jsou neaktivní
RefreshPanelReferences();
// Buttons
btnNewGame = EnsureButton(btnNewGame, "Button_NewGame", panelMain ? panelMain.transform : this.transform);
btnContinue = EnsureButton(btnContinue, "Button_Continue", panelMain ? panelMain.transform : this.transform);
btnMultiplayer = EnsureButton(btnMultiplayer, "Button_Multiplayer", panelMain ? panelMain.transform : this.transform);
btnSettings = EnsureButton(btnSettings, "Button_Settings", panelMain ? panelMain.transform : this.transform);
btnQuit = EnsureButton(btnQuit, "Button_Quit", panelMain ? panelMain.transform : this.transform);
// Settings
ddQuality = EnsureDropdown(ddQuality, "Dropdown_Quality", panelSettings ? panelSettings.transform : this.transform);
ddQualityUI = EnsureUIDropdown(ddQualityUI, "Dropdown_Quality", panelSettings ? panelSettings.transform : this.transform);
tgFullscreen = EnsureToggle(tgFullscreen, "Toggle_Fullscreen", panelSettings ? panelSettings.transform : this.transform);
ddResolution = EnsureDropdown(ddResolution, "Dropdown_Resolution", panelSettings ? panelSettings.transform : this.transform);
ddResolutionUI = EnsureUIDropdown(ddResolutionUI, "Dropdown_Resolution", panelSettings ? panelSettings.transform : this.transform);
btnApplySettings = EnsureButton(btnApplySettings, "Button_ApplySettings", panelSettings ? panelSettings.transform : this.transform);
btnBackFromSettings = EnsureButton(btnBackFromSettings, "Button_BackFromSettings", panelSettings ? panelSettings.transform : this.transform);
slMaster = EnsureSlider(slMaster, "Slider_MasterVolume", panelSettings ? panelSettings.transform : this.transform);
slMusic = EnsureSlider(slMusic, "Slider_MusicVolume", panelSettings ? panelSettings.transform : this.transform);
slSFX = EnsureSlider(slSFX, "Slider_SFXVolume", panelSettings ? panelSettings.transform : this.transform);
if (!btnApplySettings && panelSettings) btnApplySettings = FindButtonByLabel("APPLY", panelSettings.transform);
if (!btnBackFromSettings && panelSettings) btnBackFromSettings = FindButtonByLabel("BACK", panelSettings.transform);
WireEvents();
InitializeSettingsUI();
// Ensure initial panels
ShowMainMenu();
}
private Dropdown EnsureUIDropdown(Dropdown existing, string name, Transform scope)
{
if (existing) return existing;
return FindUIDropdown(name, scope);
}
private Dropdown FindUIDropdown(string name, Transform scope = null)
{
if (scope != null)
{
var comps = scope.GetComponentsInChildren<Dropdown>(true);
foreach (var c in comps)
{
if (c && c.name == name) return c;
}
return null;
}
var all = Resources.FindObjectsOfTypeAll<Dropdown>();
foreach (var c in all)
{
if (c && c.name == name && c.gameObject.scene.IsValid() && c.gameObject.scene.isLoaded) return c;
}
return null;
}
// Allow UGUIMenuBuilder to inject panel refs directly
public void SetPanels(GameObject main, GameObject settings, GameObject lobby)
{
panelMainRef = main;
panelSettingsRef = settings;
panelLobbyRef = lobby;
RefreshPanelReferences();
}
public void SetMainMenuButtons(Button newGame, Button continueButton, Button multiplayerButton, Button settingsButton, Button quitButton)
{
btnNewGame = newGame;
btnContinue = continueButton;
btnMultiplayer = multiplayerButton;
btnSettings = settingsButton;
btnQuit = quitButton;
}
public void SetSettingsControls(TMP_Dropdown qualityDropdown, Dropdown legacyQualityDropdown, Toggle fullscreenToggle,
TMP_Dropdown resolutionDropdown, Dropdown legacyResolutionDropdown, Slider masterVolume, Slider musicVolume, Slider sfxVolume,
Button applyButton, Button backButton)
{
ddQuality = qualityDropdown;
ddQualityUI = legacyQualityDropdown;
tgFullscreen = fullscreenToggle;
ddResolution = resolutionDropdown;
ddResolutionUI = legacyResolutionDropdown;
slMaster = masterVolume;
slMusic = musicVolume;
slSFX = sfxVolume;
btnApplySettings = applyButton;
btnBackFromSettings = backButton;
}
private void RefreshPanelReferences()
{
panelMain = panelMainRef ? panelMainRef : (FindAnyInScene("Panel_MainMenu") ?? panelMain);
panelSettings = panelSettingsRef ? panelSettingsRef : (FindAnyInScene("Panel_Settings") ?? panelSettings);
panelLobby = panelLobbyRef ? panelLobbyRef : (FindAnyInScene("Panel_Lobby") ?? panelLobby);
}
private Button EnsureButton(Button existing, string name, Transform scope)
{
if (existing) return existing;
return FindButton(name, scope);
}
private TMP_Dropdown EnsureDropdown(TMP_Dropdown existing, string name, Transform scope)
{
if (existing) return existing;
return FindDropdown(name, scope);
}
private Toggle EnsureToggle(Toggle existing, string name, Transform scope)
{
if (existing) return existing;
return FindToggle(name, scope);
}
private Slider EnsureSlider(Slider existing, string name, Transform scope)
{
if (existing) return existing;
return FindSlider(name, scope);
}
private GameObject FindAnyInScene(string name)
{
// Najde i neaktivní objekty
var all = Resources.FindObjectsOfTypeAll<Transform>();
foreach (var t in all)
{
if (t.hideFlags != HideFlags.None) continue;
var go = t.gameObject;
if (!go.scene.IsValid() || !go.scene.isLoaded) continue;
if (go.name == name) return go;
}
return null;
}
private Button FindButton(string name, Transform scope = null)
{
if (scope != null)
{
var comps = scope.GetComponentsInChildren<Button>(true);
foreach (var c in comps)
{
if (c && c.name == name) return c;
}
return null;
}
var all = Resources.FindObjectsOfTypeAll<Button>();
foreach (var c in all)
{
if (c && c.name == name && c.gameObject.scene.IsValid() && c.gameObject.scene.isLoaded) return c;
}
return null;
}
private TMP_Dropdown FindDropdown(string name, Transform scope = null)
{
if (scope != null)
{
var comps = scope.GetComponentsInChildren<TMP_Dropdown>(true);
foreach (var c in comps)
{
if (c && c.name == name) return c;
}
return null;
}
var all = Resources.FindObjectsOfTypeAll<TMP_Dropdown>();
foreach (var c in all)
{
if (c && c.name == name && c.gameObject.scene.IsValid() && c.gameObject.scene.isLoaded) return c;
}
return null;
}
private Toggle FindToggle(string name, Transform scope = null)
{
if (scope != null)
{
var comps = scope.GetComponentsInChildren<Toggle>(true);
foreach (var c in comps)
{
if (c && c.name == name) return c;
}
return null;
}
var all = Resources.FindObjectsOfTypeAll<Toggle>();
foreach (var c in all)
{
if (c && c.name == name && c.gameObject.scene.IsValid() && c.gameObject.scene.isLoaded) return c;
}
return null;
}
private Slider FindSlider(string name, Transform scope = null)
{
if (scope != null)
{
var comps = scope.GetComponentsInChildren<Slider>(true);
foreach (var c in comps)
{
if (c && c.name == name) return c;
}
return null;
}
var all = Resources.FindObjectsOfTypeAll<Slider>();
foreach (var c in all)
{
if (c && c.name == name && c.gameObject.scene.IsValid() && c.gameObject.scene.isLoaded) return c;
}
return null;
}
private Button FindButtonByLabel(string label, Transform scope)
{
if (!scope) return null;
var btns = scope.GetComponentsInChildren<Button>(true);
for (int i = 0; i < btns.Length; i++)
{
var t = btns[i].GetComponentInChildren<TextMeshProUGUI>(true);
if (t && string.Equals(t.text?.Trim(), label, System.StringComparison.OrdinalIgnoreCase))
return btns[i];
}
return null;
}
private void WireEvents()
{
if (btnNewGame) btnNewGame.onClick.AddListener(OnNewGame); else Debug.LogWarning("[UGUIMainMenu] Button_NewGame not found");
if (btnContinue) btnContinue.onClick.AddListener(OnContinue); else Debug.LogWarning("[UGUIMainMenu] Button_Continue not found");
if (btnMultiplayer) btnMultiplayer.onClick.AddListener(OnOpenMultiplayer); else Debug.LogWarning("[UGUIMainMenu] Button_Multiplayer not found");
if (btnSettings) btnSettings.onClick.AddListener(OnOpenSettings); else Debug.LogWarning("[UGUIMainMenu] Button_Settings not found");
if (btnQuit) btnQuit.onClick.AddListener(OnQuit); else Debug.LogWarning("[UGUIMainMenu] Button_Quit not found");
if (btnApplySettings) btnApplySettings.onClick.AddListener(OnApplySettings); else Debug.LogWarning("[UGUIMainMenu] Button_ApplySettings not found");
if (btnBackFromSettings) btnBackFromSettings.onClick.AddListener(ShowMainMenu); else Debug.LogWarning("[UGUIMainMenu] Button_BackFromSettings not found");
if (ddQuality) ddQuality.onValueChanged.AddListener(i => { Debug.Log("[UGUIMainMenu] Quality changed to index " + i); ddQuality.RefreshShownValue(); });
if (ddResolution) ddResolution.onValueChanged.AddListener(i => { Debug.Log("[UGUIMainMenu] Resolution changed to index " + i); ddResolution.RefreshShownValue(); });
if (ddQualityUI) ddQualityUI.onValueChanged.AddListener(i => { Debug.Log("[UGUIMainMenu] UI Quality changed to index " + i); ddQualityUI.RefreshShownValue(); });
if (ddResolutionUI) ddResolutionUI.onValueChanged.AddListener(i => { Debug.Log("[UGUIMainMenu] UI Resolution changed to index " + i); ddResolutionUI.RefreshShownValue(); });
if (tgFullscreen) tgFullscreen.onValueChanged.AddListener(v => { Debug.Log("[UGUIMainMenu] Fullscreen " + v); });
if (slMaster) slMaster.onValueChanged.AddListener(v => { AudioListener.volume = v / 100f; });
}
private void ShowMainMenu()
{
if (panelMain) panelMain.SetActive(true);
if (panelSettings) panelSettings.SetActive(false);
if (panelLobby) panelLobby.SetActive(false);
}
private void OnOpenMultiplayer()
{
RefreshPanelReferences();
bool showed = false;
if (panelLobby)
{
if (panelMain) panelMain.SetActive(false);
if (panelSettings) panelSettings.SetActive(false);
panelLobby.SetActive(true);
showed = true;
}
UGUIMultiplayerLobbyController lobby;
#if UNITY_2023_1_OR_NEWER
lobby = Object.FindFirstObjectByType<UGUIMultiplayerLobbyController>();
#else
lobby = Object.FindObjectOfType<UGUIMultiplayerLobbyController>();
#endif
if (lobby && showed) lobby.QuickHost(4, true);
if (!showed)
{
Debug.LogError("[UGUIMainMenu] Panel_Lobby not found in scene. Did you run Tools > MegaKoop > Generate UGUI Main Menu?" );
if (panelMain) panelMain.SetActive(true);
}
}
private void OnOpenSettings()
{
if (panelMain) panelMain.SetActive(false);
if (panelSettings) panelSettings.SetActive(true);
if (panelLobby) panelLobby.SetActive(false);
Debug.Log("[UGUIMainMenu] Open Settings");
}
private void OnNewGame()
{
// Co-op only: quick host path
UGUIMultiplayerLobbyController lobby;
#if UNITY_2023_1_OR_NEWER
lobby = Object.FindFirstObjectByType<UGUIMultiplayerLobbyController>();
#else
lobby = Object.FindObjectOfType<UGUIMultiplayerLobbyController>();
#endif
if (lobby)
{
if (panelMain) panelMain.SetActive(false);
if (panelSettings) panelSettings.SetActive(false);
if (panelLobby) panelLobby.SetActive(true);
lobby.QuickHost(4, true);
}
}
private void OnContinue()
{
// Co-op only: join path
UGUIMultiplayerLobbyController lobby;
#if UNITY_2023_1_OR_NEWER
lobby = Object.FindFirstObjectByType<UGUIMultiplayerLobbyController>();
#else
lobby = Object.FindObjectOfType<UGUIMultiplayerLobbyController>();
#endif
if (lobby)
{
if (panelMain) panelMain.SetActive(false);
if (panelSettings) panelSettings.SetActive(false);
if (panelLobby) panelLobby.SetActive(true);
lobby.ShowJoinTabPublic();
}
}
private void OnQuit()
{
#if UNITY_EDITOR
EditorApplication.isPlaying = false;
#else
Application.Quit();
#endif
}
private void ApplySettings()
{
if (ddQuality)
{
QualitySettings.SetQualityLevel(ddQuality.value, true);
}
else if (ddQualityUI)
{
QualitySettings.SetQualityLevel(ddQualityUI.value, true);
}
if (tgFullscreen)
{
Screen.fullScreen = tgFullscreen.isOn;
}
if (ddResolution)
{
if (ddResolution.options != null && ddResolution.options.Count > 0 && ddResolution.value >= 0 && ddResolution.value < ddResolution.options.Count)
{
var opt = ddResolution.options[ddResolution.value].text; // e.g., "1920x1080"
var parts = opt.ToLower().Split('x');
if (parts.Length == 2 && int.TryParse(parts[0], out int w) && int.TryParse(parts[1], out int h))
{
Screen.SetResolution(w, h, Screen.fullScreenMode);
}
}
}
else if (ddResolutionUI)
{
if (ddResolutionUI.options != null && ddResolutionUI.options.Count > 0 && ddResolutionUI.value >= 0 && ddResolutionUI.value < ddResolutionUI.options.Count)
{
var opt = ddResolutionUI.options[ddResolutionUI.value].text;
var parts = opt.ToLower().Split('x');
if (parts.Length == 2 && int.TryParse(parts[0], out int w) && int.TryParse(parts[1], out int h))
{
Screen.SetResolution(w, h, Screen.fullScreenMode);
}
}
}
if (slMaster)
{
AudioListener.volume = slMaster.value / 100f;
}
}
private void OnApplySettings()
{
ApplySettings();
SaveSettings();
ShowMainMenu();
Debug.Log("[UGUIMainMenu] Apply & Back to Main");
}
private void InitializeSettingsUI()
{
if (ddQuality)
{
var names = QualitySettings.names;
if (names != null && names.Length > 0)
{
ddQuality.ClearOptions();
ddQuality.AddOptions(new List<string>(names));
ddQuality.value = Mathf.Clamp(QualitySettings.GetQualityLevel(), 0, ddQuality.options.Count - 1);
ddQuality.RefreshShownValue();
}
ddQuality.interactable = true;
FixDropdownRaycasts(ddQuality);
SetupDropdownTemplateCanvas(ddQuality);
}
else if (ddQualityUI)
{
var names = QualitySettings.names;
if (names != null && names.Length > 0)
{
ddQualityUI.ClearOptions();
ddQualityUI.AddOptions(new List<Dropdown.OptionData>(System.Array.ConvertAll(names, s => new Dropdown.OptionData(s))));
ddQualityUI.value = Mathf.Clamp(QualitySettings.GetQualityLevel(), 0, ddQualityUI.options.Count - 1);
ddQualityUI.RefreshShownValue();
}
if (ddQualityUI.captionText == null)
{
var cap = ddQualityUI.transform.Find("Label");
if (cap) ddQualityUI.captionText = cap.GetComponent<Text>();
}
if (ddQualityUI.itemText == null && ddQualityUI.template)
{
var it = ddQualityUI.template.Find("Item");
if (it)
{
var lbl = it.Find("Item Label");
if (lbl) ddQualityUI.itemText = lbl.GetComponent<Text>();
}
}
ddQualityUI.interactable = true;
FixDropdownRaycasts(ddQualityUI);
SetupDropdownTemplateCanvas(ddQualityUI);
Debug.Log("[UGUIMainMenu] UI Quality options=" + (ddQualityUI.options != null ? ddQualityUI.options.Count : 0));
}
if (ddResolution)
{
var seen = new HashSet<string>();
var opts = new List<string>();
string cur = Screen.currentResolution.width + "x" + Screen.currentResolution.height;
int curIdx = 0;
foreach (var r in Screen.resolutions)
{
string s = r.width + "x" + r.height;
if (seen.Add(s))
{
if (s == cur) curIdx = opts.Count;
opts.Add(s);
}
}
if (opts.Count == 0)
{
opts.Add(cur);
curIdx = 0;
}
ddResolution.ClearOptions();
ddResolution.AddOptions(opts);
ddResolution.value = Mathf.Clamp(curIdx, 0, ddResolution.options.Count - 1);
ddResolution.RefreshShownValue();
ddResolution.interactable = true;
FixDropdownRaycasts(ddResolution);
SetupDropdownTemplateCanvas(ddResolution);
}
else if (ddResolutionUI)
{
var seen = new HashSet<string>();
var opts = new List<string>();
string cur = Screen.currentResolution.width + "x" + Screen.currentResolution.height;
int curIdx = 0;
foreach (var r in Screen.resolutions)
{
string s = r.width + "x" + r.height;
if (seen.Add(s))
{
if (s == cur) curIdx = opts.Count;
opts.Add(s);
}
}
if (opts.Count == 0)
{
opts.Add(cur);
curIdx = 0;
}
ddResolutionUI.ClearOptions();
ddResolutionUI.AddOptions(opts.ConvertAll(o => new Dropdown.OptionData(o)));
ddResolutionUI.value = Mathf.Clamp(curIdx, 0, ddResolutionUI.options.Count - 1);
ddResolutionUI.RefreshShownValue();
ddResolutionUI.interactable = true;
FixDropdownRaycasts(ddResolutionUI);
SetupDropdownTemplateCanvas(ddResolutionUI);
if (ddResolutionUI.captionText == null)
{
var cap = ddResolutionUI.transform.Find("Label");
if (cap) ddResolutionUI.captionText = cap.GetComponent<Text>();
}
if (ddResolutionUI.itemText == null && ddResolutionUI.template)
{
var it = ddResolutionUI.template.Find("Item");
if (it)
{
var lbl = it.Find("Item Label");
if (lbl) ddResolutionUI.itemText = lbl.GetComponent<Text>();
}
}
Debug.Log("[UGUIMainMenu] UI Resolution options=" + (ddResolutionUI.options != null ? ddResolutionUI.options.Count : 0));
}
if (tgFullscreen)
{
tgFullscreen.isOn = Screen.fullScreen;
tgFullscreen.interactable = true;
}
LoadSettings();
}
private void SaveSettings()
{
if (ddQuality) PlayerPrefs.SetInt("QualityLevel", ddQuality.value);
PlayerPrefs.SetInt("Fullscreen", Screen.fullScreen ? 1 : 0);
if (ddResolution && ddResolution.options.Count > 0)
{
var opt = ddResolution.options[ddResolution.value].text;
var parts = opt.Split('x');
if (parts.Length == 2 && int.TryParse(parts[0], out int w) && int.TryParse(parts[1], out int h))
{
PlayerPrefs.SetInt("ResolutionWidth", w);
PlayerPrefs.SetInt("ResolutionHeight", h);
}
}
if (slMaster) PlayerPrefs.SetFloat("MasterVolume", slMaster.value);
if (slMusic) PlayerPrefs.SetFloat("MusicVolume", slMusic.value);
if (slSFX) PlayerPrefs.SetFloat("SFXVolume", slSFX.value);
PlayerPrefs.Save();
}
private void LoadSettings()
{
if (ddQuality && ddQuality.options.Count > 0)
{
int q = PlayerPrefs.GetInt("QualityLevel", QualitySettings.GetQualityLevel());
ddQuality.value = Mathf.Clamp(q, 0, ddQuality.options.Count - 1);
ddQuality.RefreshShownValue();
}
else if (ddQualityUI && ddQualityUI.options.Count > 0)
{
int q = PlayerPrefs.GetInt("QualityLevel", QualitySettings.GetQualityLevel());
ddQualityUI.value = Mathf.Clamp(q, 0, ddQualityUI.options.Count - 1);
ddQualityUI.RefreshShownValue();
}
if (tgFullscreen)
{
bool full = PlayerPrefs.GetInt("Fullscreen", Screen.fullScreen ? 1 : 0) == 1;
tgFullscreen.isOn = full;
}
if (ddResolution && ddResolution.options.Count > 0)
{
int w = PlayerPrefs.GetInt("ResolutionWidth", Screen.currentResolution.width);
int h = PlayerPrefs.GetInt("ResolutionHeight", Screen.currentResolution.height);
string key = w + "x" + h;
int idx = ddResolution.options.FindIndex(o => o.text == key);
if (idx >= 0)
{
ddResolution.value = idx;
ddResolution.RefreshShownValue();
}
}
else if (ddResolutionUI && ddResolutionUI.options.Count > 0)
{
int w = PlayerPrefs.GetInt("ResolutionWidth", Screen.currentResolution.width);
int h = PlayerPrefs.GetInt("ResolutionHeight", Screen.currentResolution.height);
string key = w + "x" + h;
int idx = ddResolutionUI.options.FindIndex(o => o.text == key);
if (idx >= 0)
{
ddResolutionUI.value = idx;
ddResolutionUI.RefreshShownValue();
}
}
if (slMaster)
{
var mv = PlayerPrefs.GetFloat("MasterVolume", 100f);
slMaster.value = mv;
AudioListener.volume = mv / 100f;
}
if (slMusic)
{
slMusic.value = PlayerPrefs.GetFloat("MusicVolume", 80f);
}
if (slSFX)
{
slSFX.value = PlayerPrefs.GetFloat("SFXVolume", 100f);
}
}
private void FixDropdownRaycasts(TMP_Dropdown dd)
{
if (!dd || dd.template == null) return;
var tpl = dd.template;
var vp = tpl.Find("Viewport");
if (vp)
{
var img = vp.GetComponent<Image>();
if (img) img.raycastTarget = false;
}
}
private void SetupDropdownTemplateCanvas(TMP_Dropdown dd)
{
if (!dd || dd.template == null) return;
var tpl = dd.template;
var cv = tpl.GetComponent<Canvas>();
if (cv == null) cv = tpl.gameObject.AddComponent<Canvas>();
cv.overrideSorting = true;
cv.sortingOrder = 5000;
if (!tpl.GetComponent<GraphicRaycaster>()) tpl.gameObject.AddComponent<GraphicRaycaster>();
}
private void FixDropdownRaycasts(Dropdown dd)
{
if (!dd || dd.template == null) return;
var tpl = dd.template;
var vp = tpl.Find("Viewport");
if (vp)
{
var img = vp.GetComponent<Image>();
if (img) img.raycastTarget = false;
}
}
private void SetupDropdownTemplateCanvas(Dropdown dd)
{
if (!dd || dd.template == null) return;
var tpl = dd.template;
var cv = tpl.GetComponent<Canvas>();
if (cv == null) cv = tpl.gameObject.AddComponent<Canvas>();
cv.overrideSorting = true;
cv.sortingOrder = 5000;
if (!tpl.GetComponent<GraphicRaycaster>()) tpl.gameObject.AddComponent<GraphicRaycaster>();
}
}
}