modify scripts

This commit is contained in:
2025-10-17 10:59:23 +08:00
parent 9336ed0d6f
commit 4f782a638e
131 changed files with 79880 additions and 3549 deletions

View File

@ -12,6 +12,7 @@
using UnityEngine;
using UnityEngine.InputSystem;
using WordsToolkit.Scripts.Levels;
namespace WordsToolkit.Scripts.Settings
{
@ -36,7 +37,30 @@ namespace WordsToolkit.Scripts.Settings
public Key SimulateDuplicate = Key.D;
[Header("")]
[Tooltip("Test language, only for editor")]
public SystemLanguage TestLanguage = SystemLanguage.English;
[Tooltip("Test language code, only for editor (e.g., 'en', 'fr', 'es')")]
[HideInInspector] // Hidden because we use custom editor dropdown
public string TestLanguageCode = "en";
/// <summary>
/// Validates if the TestLanguageCode exists in the provided LanguageConfiguration
/// </summary>
public bool IsValidTestLanguage(LanguageConfiguration config)
{
if (config == null || string.IsNullOrEmpty(TestLanguageCode))
return false;
return config.GetLanguageInfo(TestLanguageCode) != null;
}
/// <summary>
/// Gets a valid test language code, falling back to default if current one is invalid
/// </summary>
public string GetValidTestLanguageCode(LanguageConfiguration config)
{
if (IsValidTestLanguage(config))
return TestLanguageCode;
return config?.defaultLanguage ?? "en";
}
}
}

View File

@ -15,8 +15,9 @@ using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
using WordsToolkit.Scripts.Services.Ads.AdUnits;
using WordsToolkit.Scripts.Settings;
namespace WordsToolkit.Scripts.Settings.Editor
namespace WordConnectGameToolkit.Scripts.Settings.Editor
{
[CustomPropertyDrawer(typeof(AdElement))]
public class AdElementDrawer : PropertyDrawer
@ -45,7 +46,24 @@ namespace WordsToolkit.Scripts.Settings.Editor
var adTypeScriptableObject = (AdReference)adTypeScriptableProperty.objectReferenceValue;
if (adTypeScriptableObject != null && adTypeScriptableObject.adType == EAdType.Interstitial)
{
popupField.visible = true;
// Add button to open InterstitialSettings for interstitial ads
var interstitialButton = new Button(() => {
OpenInterstitialSettings();
})
{
text = "Open Interstitial Settings"
};
interstitialButton.style.marginTop = 5;
// Show/hide button and popup field based on ad type
adTypeScriptableField.RegisterValueChangeCallback(evt =>
{
UpdateFieldVisibility(adTypeScriptableProperty, popupField, interstitialButton, root);
});
// Initial visibility setup
UpdateFieldVisibility(adTypeScriptableProperty, popupField, interstitialButton, root);
}
else
{
@ -69,6 +87,46 @@ namespace WordsToolkit.Scripts.Settings.Editor
// Return the root VisualElement
return root;
}
private void UpdateFieldVisibility(SerializedProperty adTypeScriptableProperty, VisualElement popupField, Button interstitialButton, VisualElement root)
{
var adTypeScriptableObject = (AdReference)adTypeScriptableProperty.objectReferenceValue;
if (adTypeScriptableObject != null && adTypeScriptableObject.adType == EAdType.Interstitial)
{
popupField.style.display = DisplayStyle.None; // Hide popup field for interstitials
if (!root.Contains(interstitialButton))
{
root.Add(interstitialButton);
}
}
else
{
popupField.style.display = DisplayStyle.Flex; // Show popup field for other ad types
if (root.Contains(interstitialButton))
{
root.Remove(interstitialButton);
}
}
}
private void OpenInterstitialSettings()
{
// Find InterstitialSettings asset
string[] guids = AssetDatabase.FindAssets("t:InterstitialSettings");
if (guids.Length > 0)
{
string path = AssetDatabase.GUIDToAssetPath(guids[0]);
var interstitialSettings = AssetDatabase.LoadAssetAtPath<InterstitialSettings>(path);
Selection.activeObject = interstitialSettings;
EditorGUIUtility.PingObject(interstitialSettings);
}
else
{
EditorUtility.DisplayDialog("InterstitialSettings Not Found",
"Could not find InterstitialSettings ScriptableObject in the project.", "OK");
}
}
}
}
#endif

View File

@ -3,8 +3,9 @@ using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
using WordsToolkit.Scripts.Settings;
namespace WordsToolkit.Scripts.Settings.Editor
namespace WordConnectGameToolkit.Scripts.Settings.Editor
{
[CustomPropertyDrawer(typeof(AdSetting))]
public class AdSettingDrawer : PropertyDrawer
@ -18,7 +19,6 @@ namespace WordsToolkit.Scripts.Settings.Editor
var foldout = new Foldout { text = property.displayName, value = false };
root.Add(foldout);
// Add fields to the foldout
var nameField = new PropertyField(property.FindPropertyRelative("name"), "Name");
var enableField = new PropertyField(property.FindPropertyRelative("enable"), "Enable");
var testInEditorField = new PropertyField(property.FindPropertyRelative("testInEditor"), "Test In Editor");

View File

@ -3,11 +3,7 @@
"rootNamespace": "",
"references": [
"GUID:d3bf71b33c0c04eb9bc1a8d6513d76bb",
"GUID:00dd4a7ac8c24c898083910c81898ecc",
"GUID:ac6e78962cfc743b9a5fc5f5a808aa72",
"GUID:b25ad8286798741e3b2cc3883283e669",
"GUID:75bdbcf23199f4cfb86c610d1d946666",
"GUID:b0214a6008ed146ff8f122a6a9c2f6cc"
"GUID:00dd4a7ac8c24c898083910c81898ecc"
],
"includePlatforms": [
"Editor"

View File

@ -0,0 +1,92 @@
using UnityEngine;
using UnityEditor;
using WordsToolkit.Scripts.Settings;
using WordsToolkit.Scripts.Levels;
using System.Linq;
namespace WordsToolkit.Scripts.Settings.Editor
{
[CustomEditor(typeof(DebugSettings))]
public class DebugSettingsEditor : UnityEditor.Editor
{
private LanguageConfiguration languageConfig;
private string[] availableLanguageCodes;
private string[] availableLanguageNames;
private int selectedLanguageIndex = 0;
void OnEnable()
{
LoadLanguageConfiguration();
}
void LoadLanguageConfiguration()
{
// Find LanguageConfiguration asset in the project
var guids = AssetDatabase.FindAssets("t:LanguageConfiguration");
if (guids.Length > 0)
{
var path = AssetDatabase.GUIDToAssetPath(guids[0]);
languageConfig = AssetDatabase.LoadAssetAtPath<LanguageConfiguration>(path);
if (languageConfig != null && languageConfig.languages != null)
{
availableLanguageCodes = languageConfig.languages.Select(l => l.code).ToArray();
availableLanguageNames = languageConfig.languages.Select(l => $"{l.displayName} ({l.code})").ToArray();
// Find current selection
var debugSettings = (DebugSettings)target;
selectedLanguageIndex = global::System.Array.IndexOf(availableLanguageCodes, debugSettings.TestLanguageCode);
if (selectedLanguageIndex < 0) selectedLanguageIndex = 0;
}
}
}
public override void OnInspectorGUI()
{
var debugSettings = (DebugSettings)target;
// Refresh language configuration if it's null or changed
if (languageConfig == null || availableLanguageCodes == null)
{
LoadLanguageConfiguration();
}
serializedObject.Update();
// Draw default fields
EditorGUILayout.PropertyField(serializedObject.FindProperty("enableHotkeys"));
EditorGUILayout.Space();
EditorGUILayout.LabelField("Debug Hotkeys", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(serializedObject.FindProperty("Win"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("Lose"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("Back"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("Restart"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("SimulateDuplicate"));
EditorGUILayout.Space();
EditorGUILayout.LabelField("Language Settings", EditorStyles.boldLabel);
// Custom dropdown for test language
if (languageConfig != null && availableLanguageCodes != null && availableLanguageCodes.Length > 0)
{
EditorGUI.BeginChangeCheck();
selectedLanguageIndex = EditorGUILayout.Popup("Test Language", selectedLanguageIndex, availableLanguageNames);
if (EditorGUI.EndChangeCheck())
{
debugSettings.TestLanguageCode = availableLanguageCodes[selectedLanguageIndex];
EditorUtility.SetDirty(debugSettings);
}
}
else
{
// Fallback to text field if no LanguageConfiguration found
EditorGUILayout.PropertyField(serializedObject.FindProperty("TestLanguageCode"), new GUIContent("Test Language Code"));
EditorGUILayout.HelpBox("No LanguageConfiguration found. Create one to enable language dropdown.", MessageType.Warning);
}
serializedObject.ApplyModifiedProperties();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5c8c4f73793624f5e80582b63c5d77ae
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,128 @@
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
using WordsToolkit.Scripts.Popups;
namespace WordConnectGameToolkit.Scripts.Settings.Editor
{
[CustomPropertyDrawer(typeof(InterstitialAdElement))]
public class InterstitialAdElementDrawer : PropertyDrawer
{
private Popup[] popupPrefabs;
private List<string> popupNames;
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
LoadPopupPrefabs();
var container = new VisualElement();
var adReferenceProperty = property.FindPropertyRelative("adReference");
var elementNameProperty = property.FindPropertyRelative("elementName");
var popupProperty = property.FindPropertyRelative("popup");
var showOnOpenProperty = property.FindPropertyRelative("showOnOpen");
var showOnCloseProperty = property.FindPropertyRelative("showOnClose");
var minLevelProperty = property.FindPropertyRelative("minLevel");
var maxLevelProperty = property.FindPropertyRelative("maxLevel");
var frequencyProperty = property.FindPropertyRelative("frequency");
// Update element name based on ad reference
UpdateElementName(adReferenceProperty, elementNameProperty);
// Ad Reference field
var adReferenceField = new PropertyField(adReferenceProperty);
adReferenceField.RegisterValueChangeCallback(evt =>
{
UpdateElementName(adReferenceProperty, elementNameProperty);
property.serializedObject.ApplyModifiedProperties();
});
container.Add(adReferenceField);
// Popup dropdown
var popupDropdown = new DropdownField("Popup", popupNames, GetPopupIndex(popupProperty.objectReferenceValue as Popup));
popupDropdown.RegisterValueChangedCallback(evt =>
{
int selectedIndex = popupNames.IndexOf(evt.newValue);
if (selectedIndex == 0)
{
popupProperty.objectReferenceValue = null;
}
else if (selectedIndex > 0)
{
popupProperty.objectReferenceValue = popupPrefabs[selectedIndex - 1];
}
popupProperty.serializedObject.ApplyModifiedProperties();
});
container.Add(popupDropdown);
// Show options
var showOnOpenField = new PropertyField(showOnOpenProperty);
container.Add(showOnOpenField);
var showOnCloseField = new PropertyField(showOnCloseProperty);
container.Add(showOnCloseField);
// Level conditions header
var levelHeader = new Label("Level Conditions");
levelHeader.style.unityFontStyleAndWeight = FontStyle.Bold;
levelHeader.style.marginTop = 5;
container.Add(levelHeader);
// Level conditions fields
var minLevelField = new PropertyField(minLevelProperty);
container.Add(minLevelField);
var maxLevelField = new PropertyField(maxLevelProperty);
container.Add(maxLevelField);
var frequencyField = new PropertyField(frequencyProperty);
container.Add(frequencyField);
return container;
}
private void LoadPopupPrefabs()
{
string[] guids = AssetDatabase.FindAssets("t:Prefab");
var popups = guids
.Select(guid => AssetDatabase.GUIDToAssetPath(guid))
.Select(path => AssetDatabase.LoadAssetAtPath<GameObject>(path))
.Where(go => go != null && go.GetComponent<Popup>() != null)
.Select(go => go.GetComponent<Popup>())
.OrderBy(popup => popup.name)
.ToArray();
popupPrefabs = popups;
popupNames = new List<string> { "None (Popup)" };
popupNames.AddRange(popups.Select(popup => popup.name));
}
private int GetPopupIndex(Popup popup)
{
if (popup == null) return 0;
for (int i = 0; i < popupPrefabs.Length; i++)
{
if (popupPrefabs[i] == popup)
return i + 1;
}
return 0;
}
private void UpdateElementName(SerializedProperty adReferenceProperty, SerializedProperty elementNameProperty)
{
if (adReferenceProperty.objectReferenceValue != null)
{
string adRefName = adReferenceProperty.objectReferenceValue.name;
elementNameProperty.stringValue = adRefName;
}
else
{
elementNameProperty.stringValue = "Unnamed";
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 868b5f9431a04f3a81e7484ada3d3f8f
timeCreated: 1756307465

View File

@ -0,0 +1,65 @@
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
using WordsToolkit.Scripts.Settings;
namespace WordConnectGameToolkit.Scripts.Settings.Editor
{
[CustomEditor(typeof(InterstitialSettings))]
public class InterstitialSettingsEditor : UnityEditor.Editor
{
public override VisualElement CreateInspectorGUI()
{
var root = new VisualElement();
var interstitialSettings = (InterstitialSettings)target;
// if (interstitialSettings.interstitials == null || interstitialSettings.interstitials.Length == 0)
{
var helpBox = new HelpBox("InterstitialSettings is empty. Click the button below to populate from AdsSettings.", HelpBoxMessageType.Info);
root.Add(helpBox);
var populateButton = new Button(() =>
{
var adsSettings = FindAdsSettings();
if (adsSettings != null)
{
interstitialSettings.PopulateFromAdsSettings(adsSettings);
EditorUtility.SetDirty(interstitialSettings);
AssetDatabase.SaveAssets();
}
else
{
EditorUtility.DisplayDialog("AdsSettings Not Found",
"Could not find AdsSettings ScriptableObject in the project.", "OK");
}
})
{
text = "Populate from AdsSettings"
};
root.Add(populateButton);
}
CreateDefaultInspector(root);
return root;
}
private void CreateDefaultInspector(VisualElement root)
{
var interstitialsProperty = serializedObject.FindProperty("interstitials");
var interstitialsField = new PropertyField(interstitialsProperty);
interstitialsField.Bind(serializedObject);
root.Add(interstitialsField);
}
private AdsSettings FindAdsSettings()
{
string[] guids = AssetDatabase.FindAssets("t:AdsSettings");
if (guids.Length > 0)
{
string path = AssetDatabase.GUIDToAssetPath(guids[0]);
return AssetDatabase.LoadAssetAtPath<AdsSettings>(path);
}
return null;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 285dda4a69e24274b3b50bd12857b12b
timeCreated: 1756307465

View File

@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using WordsToolkit.Scripts.Popups;
using WordsToolkit.Scripts.Services.Ads.AdUnits;
using WordsToolkit.Scripts.Settings;
namespace WordConnectGameToolkit.Scripts.Settings
{
[CreateAssetMenu(fileName = "InterstitialSettings", menuName = "WordConnectGameToolkit/Settings/InterstitialSettings", order = 1)]
public class InterstitialSettings : ScriptableObject
{
public InterstitialAdElement[] interstitials;
public void PopulateFromAdsSettings(AdsSettings adsSettings)
{
if (adsSettings == null) return;
var interstitialElements = new List<InterstitialAdElement>();
foreach (var adProfile in adsSettings.adProfiles)
{
if (!adProfile.enable) continue;
foreach (var adElement in adProfile.adElements)
{
if (adElement.adReference != null && adElement.adReference.adType == EAdType.Interstitial)
{
var interstitialElement = new InterstitialAdElement
{
elementName = adElement.adReference.name,
adReference = adElement.adReference,
popup = adElement.popup.popup,
showOnOpen = adElement.popup.showOnOpen,
showOnClose = adElement.popup.showOnClose,
};
interstitialElements.Add(interstitialElement);
}
}
}
interstitials = interstitialElements.ToArray();
}
}
[Serializable]
public class InterstitialAdElement
{
[HideInInspector]
public string elementName;
public AdReference adReference;
[Header("Popup that triggers Interstitial ads")]
public Popup popup;
public bool showOnOpen;
public bool showOnClose;
[Header("Level Conditions")]
public int minLevel = 1;
public int maxLevel = 1000;
public int frequency = 1;
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 44ad2bed4c494715ba8ad21e150b03ee
timeCreated: 1756307490