update assets to 1.03

This commit is contained in:
2025-08-04 16:04:54 +08:00
parent f14db75802
commit 0ac6d9882e
23 changed files with 499 additions and 1034 deletions

View File

@ -10,13 +10,17 @@ namespace WordsToolkit.Scripts.Levels.Editor
public static class EditorScope
{
private static IObjectResolver editorContainer;
private static bool isDisposed = false;
public static IObjectResolver Container
{
get
{
if (editorContainer == null)
if (isDisposed || editorContainer == null)
{
if (isDisposed)
return null;
var builder = new ContainerBuilder();
Configure(builder);
editorContainer = builder.Build();
@ -48,7 +52,31 @@ namespace WordsToolkit.Scripts.Levels.Editor
public static T Resolve<T>() where T : class
{
return Container.Resolve<T>();
var container = Container;
if (container == null || isDisposed)
return null;
return container.Resolve<T>();
}
public static void Dispose()
{
isDisposed = true;
if (editorContainer != null)
{
if (editorContainer is global::System.IDisposable disposableContainer)
{
disposableContainer.Dispose();
}
editorContainer = null;
}
}
// Called by Unity when domain is reloading
[UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.SubsystemRegistration)]
private static void Reset()
{
isDisposed = false;
editorContainer = null;
}
}
}

View File

@ -15,6 +15,9 @@ namespace WordsToolkit.Scripts.Levels.Editor.EditorWindows
// Static field to track all windows and handle script recompilation
private static List<LevelManagerWindow> activeWindows = new List<LevelManagerWindow>();
// Static flag to track if Unity is quitting
private static bool isQuitting = false;
// Static event for when hierarchy selection changes - other windows can subscribe to this
public static event Action<LevelHierarchyItem> OnHierarchySelectionChanged;
@ -64,6 +67,9 @@ namespace WordsToolkit.Scripts.Levels.Editor.EditorWindows
activeWindows.Add(this);
}
// Subscribe to Unity quitting event
EditorApplication.quitting += OnUnityQuitting;
// Initialize UI
LevelManagerWindowUI.InitializeUI(this);
@ -82,10 +88,23 @@ namespace WordsToolkit.Scripts.Levels.Editor.EditorWindows
if (!string.IsNullOrEmpty(m_SelectedLanguage))
EditorPrefs.SetString(SELECTED_LANGUAGE_KEY, m_SelectedLanguage);
// Unsubscribe from Unity quitting event
EditorApplication.quitting -= OnUnityQuitting;
// Unregister this window instance
activeWindows.Remove(this);
}
private static void OnUnityQuitting()
{
isQuitting = true;
// Dispose the editor scope container to prevent crashes
EditorScope.Dispose();
}
// Public static property to check if Unity is quitting
public static bool IsQuitting => isQuitting;
private void InitializeTreeView()
{
// Create tree view state if needed

View File

@ -845,20 +845,20 @@ namespace WordsToolkit.Scripts.Levels.Editor
var wordsListContainer = new VisualElement();
wordsListContainer.style.width = new StyleLength(new Length(100, LengthUnit.Percent));
wordsListContainer.style.flexGrow = 1;
// Store reference to the words list container for this language
wordsListElements[langCode] = wordsListContainer;
// Fill words list from the SerializedProperty using ListView
FillWordsList(wordsListContainer, wordsProp, langCode);
wordsContent.Add(wordsListContainer);
// Add Clear Words button
var clearWordsButton = new Button(() =>
{
if (EditorUtility.DisplayDialog("Clear Words",
"Are you sure you want to clear all words and crossword? This action cannot be undone.",
if (EditorUtility.DisplayDialog("Clear Words",
"Are you sure you want to clear all words and crossword? This action cannot be undone.",
"Clear", "Cancel"))
{
serializedObject.Update();
@ -871,7 +871,7 @@ namespace WordsToolkit.Scripts.Levels.Editor
{
previewDataDict[langCode] = null;
}
// Clear the saved crossword data in the level
var languageData = level.GetLanguageData(langCode);
if (languageData != null)
@ -886,10 +886,10 @@ namespace WordsToolkit.Scripts.Levels.Editor
EditorUtility.SetDirty(serializedObject.targetObject);
AssetDatabase.SaveAssets();
// Notify that the level needs update to refresh the crossword
NotifyLevelNeedsUpdate(level);
// Refresh the UI using LevelManagerWindow
EditorWindows.LevelManagerWindow.RefreshInspectorForLevel(level);
}
@ -912,13 +912,13 @@ namespace WordsToolkit.Scripts.Levels.Editor
{
// Clear existing content first
wordsListContainer.Clear();
// Create ListView for words
var wordsListView = new ListView();
wordsListView.name = $"words-listview-{langCode}";
wordsListView.style.flexGrow = 1;
wordsListView.style.height = StyleKeyword.Auto; // Auto height based on content
// Schedule setting the title after the ListView is fully constructed
wordsListView.schedule.Execute(() =>
{
@ -928,7 +928,7 @@ namespace WordsToolkit.Scripts.Levels.Editor
{
var label = sizeField.Q<Label>();
label.text = "Words";
// Set the text input value directly on the TextField
sizeField.value = wordsProp.arraySize.ToString();
}
@ -949,10 +949,10 @@ namespace WordsToolkit.Scripts.Levels.Editor
}
}
}).ExecuteLater(1); // Execute after UI is built
// Bind the ListView to the words property
wordsListView.BindProperty(wordsProp);
// Setup ListView properties
wordsListView.showBorder = true;
wordsListView.showAlternatingRowBackgrounds = AlternatingRowBackground.None;
@ -961,16 +961,16 @@ namespace WordsToolkit.Scripts.Levels.Editor
wordsListView.reorderMode = ListViewReorderMode.Animated;
wordsListView.virtualizationMethod = CollectionVirtualizationMethod.FixedHeight;
wordsListView.fixedItemHeight = 25; // Set a fixed height per item to help with layout
// Set up the make item callback
wordsListView.makeItem = () => CreateWordListItem(langCode);
// Set up the bind item callback
wordsListView.bindItem = (element, index) => BindWordListItem(element, index, wordsProp, langCode);
// Set up the unbind item callback to clean up event handlers
wordsListView.unbindItem = (element, index) => UnbindWordListItem(element, index);
// Add callback for when items are added/removed
wordsListView.itemsAdded += (items) =>
{
@ -981,7 +981,7 @@ namespace WordsToolkit.Scripts.Levels.Editor
// Refresh available words UI when words are added
EditorWindows.LevelManagerWindow.RefreshInspectorForLevel(level);
};
wordsListView.itemsRemoved += (items) =>
{
serializedObject.ApplyModifiedProperties();
@ -1000,7 +1000,7 @@ namespace WordsToolkit.Scripts.Levels.Editor
// Refresh available words UI when words are removed
EditorWindows.LevelManagerWindow.RefreshInspectorForLevel(level);
};
wordsListContainer.Add(wordsListView);
}
@ -1219,20 +1219,21 @@ namespace WordsToolkit.Scripts.Levels.Editor
private void UpdateWordIcon(VisualElement iconContainer, string wordValue, string langCode)
{
iconContainer.Clear();
// Check if word is used in other levels
var usedInLevels = LevelEditorServices.GetUsedInLevels(wordValue, langCode, level);
bool hasWarning = !string.IsNullOrEmpty(wordValue) && usedInLevels.Length > 0;
// Get banned words service for banned status check
var bannedWordsService = EditorScope.Resolve<IBannedWordsService>();
bool isWordBanned = !string.IsNullOrEmpty(wordValue) && bannedWordsService != null && bannedWordsService.IsWordBanned(wordValue, langCode);
// Check if word is duplicate within current level
bool isDuplicate = IsWordDuplicateInLevel(wordValue, langCode);
// Check if word is not known in model controller
bool isWordUnknown = !string.IsNullOrEmpty(wordValue) && Controller != null &&
bool isWordUnknown = !string.IsNullOrEmpty(wordValue)
&& Controller != null &&
!Controller.IsWordKnown(wordValue, langCode);
if (hasWarning || isWordBanned || isDuplicate || isWordUnknown)
@ -1241,7 +1242,7 @@ namespace WordsToolkit.Scripts.Levels.Editor
warningImage.image = warningIcon;
warningImage.style.width = 16;
warningImage.style.height = 16;
// Priority: Banned > Duplicate > Used in other levels
if (isWordBanned && isDuplicate && hasWarning)
{
@ -1264,7 +1265,7 @@ namespace WordsToolkit.Scripts.Levels.Editor
else if (isDuplicate && hasWarning)
{
// Duplicate + used in other levels
string tooltipText = usedInLevels.Length == 1
string tooltipText = usedInLevels.Length == 1
? $"WARNING: This word is DUPLICATED in this level AND already used in level {usedInLevels[0].number}"
: $"WARNING: This word is DUPLICATED in this level AND already used in levels: {string.Join(", ", usedInLevels.OrderBy(l => l.number).Select(l => l.number.ToString()))}";
iconContainer.tooltip = tooltipText;
@ -1285,7 +1286,7 @@ namespace WordsToolkit.Scripts.Levels.Editor
else if (hasWarning)
{
// Only used in other levels
string tooltipText = usedInLevels.Length == 1
string tooltipText = usedInLevels.Length == 1
? $"This word has already been used in level {usedInLevels[0].number}"
: $"This word has already been used in levels: {string.Join(", ", usedInLevels.OrderBy(l => l.number).Select(l => l.number.ToString()))}";
iconContainer.tooltip = tooltipText;
@ -1297,7 +1298,7 @@ namespace WordsToolkit.Scripts.Levels.Editor
iconContainer.tooltip = "This word is not known in the model controller";
warningImage.tintColor = Color.green;
}
iconContainer.Add(warningImage);
}
}