modify scripts
This commit is contained in:
@ -721,17 +721,27 @@ namespace WordsToolkit.Scripts.Levels.Editor
|
||||
// Handle selection from LevelHierarchyTreeView
|
||||
if (selectedItem != null && selectedItem.type == LevelHierarchyItem.ItemType.Level && selectedItem.levelAsset != null)
|
||||
{
|
||||
// Try to find any available language data in the level
|
||||
string foundLanguage = FindAvailableLanguage(selectedItem.levelAsset);
|
||||
// Use the same language selection logic as the "Open Grid" button
|
||||
// This preserves the user's currently selected language tab
|
||||
string languageCode = LevelEditorUtility.GetLanguageCodeForLevel(selectedItem.levelAsset);
|
||||
|
||||
if (!string.IsNullOrEmpty(foundLanguage))
|
||||
if (!string.IsNullOrEmpty(languageCode))
|
||||
{
|
||||
SetCurrentLevel(selectedItem.levelAsset, foundLanguage);
|
||||
SetCurrentLevel(selectedItem.levelAsset, languageCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set the level anyway but with a default language
|
||||
SetCurrentLevel(selectedItem.levelAsset, "en");
|
||||
// Fallback: try to find any available language data in the level
|
||||
string foundLanguage = FindAvailableLanguage(selectedItem.levelAsset);
|
||||
if (!string.IsNullOrEmpty(foundLanguage))
|
||||
{
|
||||
SetCurrentLevel(selectedItem.levelAsset, foundLanguage);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set the level anyway but with a default language
|
||||
SetCurrentLevel(selectedItem.levelAsset, "en");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (selectedItem == null || selectedItem.type != LevelHierarchyItem.ItemType.Level)
|
||||
@ -767,13 +777,25 @@ namespace WordsToolkit.Scripts.Levels.Editor
|
||||
Level latestLevel = AssetDatabase.LoadAssetAtPath<Level>(path);
|
||||
if (latestLevel != null)
|
||||
{
|
||||
string foundLanguage = FindAvailableLanguage(latestLevel);
|
||||
if (!string.IsNullOrEmpty(foundLanguage))
|
||||
// Use the same language selection logic as the rest of the system
|
||||
string languageCode = LevelEditorUtility.GetLanguageCodeForLevel(latestLevel);
|
||||
if (!string.IsNullOrEmpty(languageCode))
|
||||
{
|
||||
SetCurrentLevel(latestLevel, foundLanguage);
|
||||
Debug.Log($"CrosswordGridWindow: Loaded latest level '{latestLevel.name}' with language '{foundLanguage}' from EditorPrefs");
|
||||
SetCurrentLevel(latestLevel, languageCode);
|
||||
Debug.Log($"CrosswordGridWindow: Loaded latest level '{latestLevel.name}' with language '{languageCode}' from EditorPrefs");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback
|
||||
string foundLanguage = FindAvailableLanguage(latestLevel);
|
||||
if (!string.IsNullOrEmpty(foundLanguage))
|
||||
{
|
||||
SetCurrentLevel(latestLevel, foundLanguage);
|
||||
Debug.Log($"CrosswordGridWindow: Loaded latest level '{latestLevel.name}' with fallback language '{foundLanguage}' from EditorPrefs");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -784,17 +806,26 @@ namespace WordsToolkit.Scripts.Levels.Editor
|
||||
Level selectedLevel = Selection.activeObject as Level;
|
||||
if (selectedLevel != null)
|
||||
{
|
||||
// Try to find any available language data in the level
|
||||
string foundLanguage = FindAvailableLanguage(selectedLevel);
|
||||
|
||||
if (!string.IsNullOrEmpty(foundLanguage))
|
||||
// Use the same language selection logic as the rest of the system
|
||||
string languageCode = LevelEditorUtility.GetLanguageCodeForLevel(selectedLevel);
|
||||
if (!string.IsNullOrEmpty(languageCode))
|
||||
{
|
||||
SetCurrentLevel(selectedLevel, foundLanguage);
|
||||
Debug.Log($"CrosswordGridWindow: Loaded level '{selectedLevel.name}' with language '{foundLanguage}' from project selection");
|
||||
SetCurrentLevel(selectedLevel, languageCode);
|
||||
Debug.Log($"CrosswordGridWindow: Loaded level '{selectedLevel.name}' with language '{languageCode}' from project selection");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"Level '{selectedLevel.name}' has no language data available.");
|
||||
// Fallback
|
||||
string foundLanguage = FindAvailableLanguage(selectedLevel);
|
||||
if (!string.IsNullOrEmpty(foundLanguage))
|
||||
{
|
||||
SetCurrentLevel(selectedLevel, foundLanguage);
|
||||
Debug.Log($"CrosswordGridWindow: Loaded level '{selectedLevel.name}' with fallback language '{foundLanguage}' from project selection");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"Level '{selectedLevel.name}' has no language data available.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -823,23 +854,30 @@ namespace WordsToolkit.Scripts.Levels.Editor
|
||||
|
||||
private string FindAvailableLanguage(Level level)
|
||||
{
|
||||
if (level == null) return null;
|
||||
|
||||
// Try common language codes in order of preference
|
||||
string[] languageCodes = { "en", "eng", "english", "en-US", "en-GB", "es", "fr", "de", "ru", "zh" };
|
||||
|
||||
foreach (string code in languageCodes)
|
||||
if (level == null || level.languages == null || level.languages.Count == 0)
|
||||
return null;
|
||||
|
||||
// First, try to use the currently selected language tab (same as LevelEditorUtility.GetLanguageCodeForLevel)
|
||||
int selectedTabIndex = EditorPrefs.GetInt("WordsToolkit_SelectedLanguageTab", 0);
|
||||
if (selectedTabIndex >= 0 && selectedTabIndex < level.languages.Count)
|
||||
{
|
||||
var languageData = level.GetLanguageData(code);
|
||||
if (languageData != null)
|
||||
var selectedLanguage = level.languages[selectedTabIndex];
|
||||
if (selectedLanguage != null && !string.IsNullOrEmpty(selectedLanguage.language))
|
||||
{
|
||||
return code;
|
||||
return selectedLanguage.language;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: return the first available language
|
||||
for (int i = 0; i < level.languages.Count; i++)
|
||||
{
|
||||
var languageData = level.languages[i];
|
||||
if (languageData != null && !string.IsNullOrEmpty(languageData.language))
|
||||
{
|
||||
return languageData.language;
|
||||
}
|
||||
}
|
||||
|
||||
// If no common languages found, this would require reflection or other means
|
||||
// to get all available languages from the Level object
|
||||
// For now, we'll return null and let the user manually specify
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -851,19 +889,28 @@ namespace WordsToolkit.Scripts.Levels.Editor
|
||||
Level selectedLevel = Selection.activeObject as Level;
|
||||
if (selectedLevel != null)
|
||||
{
|
||||
// Try to find any available language data in the level
|
||||
string foundLanguage = FindAvailableLanguage(selectedLevel);
|
||||
|
||||
if (!string.IsNullOrEmpty(foundLanguage))
|
||||
// Use the same language selection logic as the rest of the system
|
||||
string languageCode = LevelEditorUtility.GetLanguageCodeForLevel(selectedLevel);
|
||||
if (!string.IsNullOrEmpty(languageCode))
|
||||
{
|
||||
SetCurrentLevel(selectedLevel, foundLanguage);
|
||||
Debug.Log($"Loaded level: {selectedLevel.name} with language: {foundLanguage}");
|
||||
SetCurrentLevel(selectedLevel, languageCode);
|
||||
Debug.Log($"Loaded level: {selectedLevel.name} with language: {languageCode}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set the level anyway but with a default language
|
||||
SetCurrentLevel(selectedLevel, "en");
|
||||
Debug.LogWarning($"Level '{selectedLevel.name}' has no language data. Using default language 'en'.");
|
||||
// Fallback: try to find any available language data in the level
|
||||
string foundLanguage = FindAvailableLanguage(selectedLevel);
|
||||
if (!string.IsNullOrEmpty(foundLanguage))
|
||||
{
|
||||
SetCurrentLevel(selectedLevel, foundLanguage);
|
||||
Debug.Log($"Loaded level: {selectedLevel.name} with fallback language: {foundLanguage}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set the level anyway but with a default language
|
||||
SetCurrentLevel(selectedLevel, "en");
|
||||
Debug.LogWarning($"Level '{selectedLevel.name}' has no language data. Using default language 'en'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1023,148 +1070,142 @@ namespace WordsToolkit.Scripts.Levels.Editor
|
||||
if (_currentLevel == null) return;
|
||||
|
||||
var serializedObject = new SerializedObject(_currentLevel);
|
||||
|
||||
|
||||
// Bind letters field (TextField with label)
|
||||
var lettersField = paletteRoot.Q<TextField>("letters-field");
|
||||
if (lettersField != null)
|
||||
var initialValue = languageData.letters ?? "";
|
||||
lettersField.RegisterValueChangedCallback(evt =>
|
||||
{
|
||||
var initialValue = languageData.letters ?? "";
|
||||
lettersField.RegisterValueChangedCallback(evt =>
|
||||
// Don't trigger on initial setup (when previous value is empty and new value matches initial data)
|
||||
if (evt.newValue != evt.previousValue &&
|
||||
!(string.IsNullOrEmpty(evt.previousValue) && evt.newValue == initialValue))
|
||||
{
|
||||
// Don't trigger on initial setup (when previous value is empty and new value matches initial data)
|
||||
if (evt.newValue != evt.previousValue &&
|
||||
!(string.IsNullOrEmpty(evt.previousValue) && evt.newValue == initialValue))
|
||||
// Record undo before changing letters
|
||||
if (_currentLevel != null)
|
||||
{
|
||||
// Record undo before changing letters
|
||||
if (_currentLevel != null)
|
||||
// Ensure grid data is serialized before recording undo
|
||||
var langData = _currentLevel.GetLanguageData(_currentLanguageCode);
|
||||
if (langData?.crosswordData != null)
|
||||
{
|
||||
// Ensure grid data is serialized before recording undo
|
||||
var langData = _currentLevel.GetLanguageData(_currentLanguageCode);
|
||||
if (langData?.crosswordData != null)
|
||||
{
|
||||
langData.crosswordData.SerializeGrid();
|
||||
}
|
||||
|
||||
Undo.RecordObject(_currentLevel, "Change Letters");
|
||||
}
|
||||
|
||||
languageData.letters = evt.newValue;
|
||||
var lettersLength = paletteRoot.Q<IntegerField>("letters-length");
|
||||
if (lettersLength != null)
|
||||
{
|
||||
lettersLength.value = evt.newValue?.Length ?? 0;
|
||||
langData.crosswordData.SerializeGrid();
|
||||
}
|
||||
|
||||
_currentLevel.letters = evt.newValue?.Length ?? 0;
|
||||
EditorUtility.SetDirty(_currentLevel);
|
||||
|
||||
// Generate new words for the updated letters
|
||||
if (!string.IsNullOrEmpty(evt.newValue))
|
||||
{
|
||||
LevelDataEditor.UpdateAvailableWordsForLevel(_currentLevel);
|
||||
RefreshPreviewData();
|
||||
}
|
||||
|
||||
UpdateGridDisplay();
|
||||
Undo.RecordObject(_currentLevel, "Change Letters");
|
||||
}
|
||||
});
|
||||
lettersField.value = initialValue;
|
||||
}
|
||||
|
||||
languageData.letters = evt.newValue;
|
||||
var lettersLength = paletteRoot.Q<IntegerField>("letters-length");
|
||||
if (lettersLength != null)
|
||||
{
|
||||
lettersLength.value = evt.newValue?.Length ?? 0;
|
||||
}
|
||||
|
||||
_currentLevel.letters = evt.newValue?.Length ?? 0;
|
||||
EditorUtility.SetDirty(_currentLevel);
|
||||
|
||||
// Generate new words for the updated letters
|
||||
if (!string.IsNullOrEmpty(evt.newValue))
|
||||
{
|
||||
LevelDataEditor.UpdateAvailableWordsForLevel(_currentLevel);
|
||||
RefreshPreviewData();
|
||||
}
|
||||
|
||||
UpdateGridDisplay();
|
||||
}
|
||||
});
|
||||
lettersField.value = initialValue;
|
||||
|
||||
// Bind letters length field
|
||||
var lettersLength = paletteRoot.Q<TextField>("letters-length");
|
||||
if (lettersLength != null)
|
||||
lettersLength.value = _currentLevel.letters.ToString();
|
||||
lettersLength.RegisterValueChangedCallback(evt =>
|
||||
{
|
||||
lettersLength.value = _currentLevel.letters.ToString();
|
||||
lettersLength.RegisterValueChangedCallback(evt =>
|
||||
if (int.TryParse(evt.newValue, out int value))
|
||||
{
|
||||
if (int.TryParse(evt.newValue, out int value))
|
||||
{
|
||||
_currentLevel.letters = value;
|
||||
EditorUtility.SetDirty(_currentLevel);
|
||||
EditorPrefs.SetInt("WordsToolkit_LettersAmount", value);
|
||||
}
|
||||
});
|
||||
}
|
||||
_currentLevel.letters = value;
|
||||
EditorUtility.SetDirty(_currentLevel);
|
||||
EditorPrefs.SetInt("WordsToolkit_LettersAmount", value);
|
||||
}
|
||||
});
|
||||
|
||||
var generateLettersCheck = paletteRoot.Q<Toggle>("generate-letters-check");
|
||||
generateLettersCheck.value = EditorPrefs.GetBool("WordsToolkit_GenerateLetters", true);
|
||||
generateLettersCheck.RegisterValueChangedCallback(evt => {
|
||||
if (_currentLevel != null)
|
||||
{
|
||||
EditorUtility.SetDirty(_currentLevel);
|
||||
EditorPrefs.SetBool("WordsToolkit_GenerateLetters", evt.newValue);
|
||||
}
|
||||
});
|
||||
// Bind generate button
|
||||
var generateButton = paletteRoot.Q<Button>("generate-button");
|
||||
if (generateButton != null)
|
||||
{
|
||||
generateButton.clicked += () => {
|
||||
if (_currentLevel != null && languageData != null)
|
||||
generateButton.clicked += () => {
|
||||
if (_currentLevel != null && languageData != null)
|
||||
{
|
||||
// Record undo before generating new letters
|
||||
if (_currentLevel != null)
|
||||
{
|
||||
// Record undo before generating new letters
|
||||
if (_currentLevel != null)
|
||||
// Ensure grid data is serialized before recording undo
|
||||
var langData = _currentLevel.GetLanguageData(_currentLanguageCode);
|
||||
if (langData?.crosswordData != null)
|
||||
{
|
||||
// Ensure grid data is serialized before recording undo
|
||||
var langData = _currentLevel.GetLanguageData(_currentLanguageCode);
|
||||
if (langData?.crosswordData != null)
|
||||
{
|
||||
langData.crosswordData.SerializeGrid();
|
||||
}
|
||||
|
||||
Undo.RecordObject(_currentLevel, "Generate Random Letters");
|
||||
langData.crosswordData.SerializeGrid();
|
||||
}
|
||||
|
||||
var modelController = EditorScope.Resolve<IModelController>();
|
||||
string letters = LevelEditorServices.GenerateRandomLetters(languageData, languageData.wordsAmount, _currentLevel.letters);
|
||||
languageData.letters = letters;
|
||||
|
||||
// Update the letters field in the UI
|
||||
if (lettersField != null) lettersField.value = languageData.letters;
|
||||
if (lettersLength != null) lettersLength.value = (languageData.letters?.Length ?? 0).ToString();
|
||||
|
||||
languageData.words = new string[0];
|
||||
EditorUtility.SetDirty(_currentLevel);
|
||||
LevelEditorServices.GenerateAvailableWords(_currentLevel, modelController, languageData);
|
||||
UpdateCrossword(_currentLevel, languageData);
|
||||
LevelDataEditor.NotifyWordsListNeedsUpdate(_currentLevel, languageData.language);
|
||||
|
||||
RefreshPreviewData();
|
||||
UpdateLetterPalette();
|
||||
UpdateGridDisplay();
|
||||
UpdateStatusBar();
|
||||
|
||||
|
||||
Undo.RecordObject(_currentLevel, "Generate Random Letters");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var modelController = EditorScope.Resolve<IModelController>();
|
||||
string letters = LevelEditorServices.GenerateRandomLetters(languageData, languageData.wordsAmount, _currentLevel.letters, generateLettersCheck.value );
|
||||
languageData.letters = letters;
|
||||
|
||||
// Update the letters field in the UI
|
||||
if (lettersField != null) lettersField.value = languageData.letters;
|
||||
if (lettersLength != null) lettersLength.value = (languageData.letters?.Length ?? 0).ToString();
|
||||
|
||||
languageData.words = new string[0];
|
||||
EditorUtility.SetDirty(_currentLevel);
|
||||
LevelEditorServices.GenerateAvailableWords(_currentLevel, modelController, languageData);
|
||||
UpdateCrossword(_currentLevel, languageData);
|
||||
LevelDataEditor.NotifyWordsListNeedsUpdate(_currentLevel, languageData.language);
|
||||
|
||||
RefreshPreviewData();
|
||||
UpdateLetterPalette();
|
||||
UpdateGridDisplay();
|
||||
UpdateStatusBar();
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// Bind grid size controls - columns field
|
||||
var columnsField = paletteRoot.Q<TextField>("columns-field");
|
||||
if (columnsField != null)
|
||||
{
|
||||
columnsField.value = (_previewData?.columns ?? 10).ToString();
|
||||
columnsField.RegisterValueChangedCallback(evt => {
|
||||
if (_previewData != null && int.TryParse(evt.newValue, out int value) && value >= 5 && value <= 50)
|
||||
{
|
||||
_previewData.columns = value;
|
||||
CrosswordPreviewHandler.SavePreviewToLevel(_currentLevel, _currentLanguageCode, _previewData);
|
||||
EditorUtility.SetDirty(_currentLevel);
|
||||
EditorPrefs.SetInt("WordsToolkit_grid_x", value);
|
||||
UpdateGridDisplay();
|
||||
UpdateStatusBar();
|
||||
}
|
||||
});
|
||||
}
|
||||
columnsField.value = (_previewData?.columns ?? 10).ToString();
|
||||
columnsField.RegisterValueChangedCallback(evt => {
|
||||
if (_previewData != null && int.TryParse(evt.newValue, out int value) && value >= 5 && value <= 50)
|
||||
{
|
||||
_previewData.columns = value;
|
||||
CrosswordPreviewHandler.SavePreviewToLevel(_currentLevel, _currentLanguageCode, _previewData);
|
||||
EditorUtility.SetDirty(_currentLevel);
|
||||
EditorPrefs.SetInt("WordsToolkit_grid_x", value);
|
||||
UpdateGridDisplay();
|
||||
UpdateStatusBar();
|
||||
}
|
||||
});
|
||||
|
||||
// Bind grid size controls - rows field
|
||||
var rowsField = paletteRoot.Q<TextField>("rows-field");
|
||||
if (rowsField != null)
|
||||
{
|
||||
rowsField.value = (_previewData?.rows ?? 7).ToString();
|
||||
rowsField.RegisterValueChangedCallback(evt => {
|
||||
if (_previewData != null && int.TryParse(evt.newValue, out int value) && value >= 5 && value <= 50)
|
||||
{
|
||||
_previewData.rows = value;
|
||||
CrosswordPreviewHandler.SavePreviewToLevel(_currentLevel, _currentLanguageCode, _previewData);
|
||||
EditorUtility.SetDirty(_currentLevel);
|
||||
EditorPrefs.SetInt("WordsToolkit_grid_y", value);
|
||||
UpdateGridDisplay();
|
||||
UpdateStatusBar();
|
||||
}
|
||||
});
|
||||
}
|
||||
rowsField.value = (_previewData?.rows ?? 7).ToString();
|
||||
rowsField.RegisterValueChangedCallback(evt => {
|
||||
if (_previewData != null && int.TryParse(evt.newValue, out int value) && value >= 5 && value <= 50)
|
||||
{
|
||||
_previewData.rows = value;
|
||||
CrosswordPreviewHandler.SavePreviewToLevel(_currentLevel, _currentLanguageCode, _previewData);
|
||||
EditorUtility.SetDirty(_currentLevel);
|
||||
EditorPrefs.SetInt("WordsToolkit_grid_y", value);
|
||||
UpdateGridDisplay();
|
||||
UpdateStatusBar();
|
||||
}
|
||||
});
|
||||
|
||||
// Bind Test Level button
|
||||
var testLevelButton = paletteRoot.Q<Button>("test-level-button");
|
||||
@ -1319,8 +1360,11 @@ namespace WordsToolkit.Scripts.Levels.Editor
|
||||
if (_enableEditing && _currentLevel != null)
|
||||
{
|
||||
var buttonsRow = CreateLetterButtonsRow();
|
||||
buttonsRow.style.alignSelf = Align.FlexEnd;
|
||||
letterButtonsContainer.Add(buttonsRow);
|
||||
if (buttonsRow != null)
|
||||
{
|
||||
buttonsRow.style.alignSelf = Align.FlexEnd;
|
||||
letterButtonsContainer.Add(buttonsRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -616,12 +616,16 @@ namespace WordsToolkit.Scripts.Levels.Editor
|
||||
|
||||
if (candidate != null && candidate.isValid)
|
||||
{
|
||||
// Check for problematic overlaps (both position overlaps and missing words)
|
||||
bool hasProblematicOverlaps = LevelEditorServices.CheckForOverlappingWords(candidate.placements, wordsToUse);
|
||||
|
||||
// Create a string representation of the grid for uniqueness checking
|
||||
string gridSignature = GridToString(candidate.grid);
|
||||
|
||||
// Check if this grid layout is unique and has a good word count
|
||||
// Check if this grid layout is unique, has a good word count, and no problematic overlaps
|
||||
if (!generatedGrids.Contains(gridSignature) &&
|
||||
candidate.placements.Count > bestWordCount)
|
||||
candidate.placements.Count > bestWordCount &&
|
||||
!hasProblematicOverlaps)
|
||||
{
|
||||
bestVariant = candidate;
|
||||
bestWordCount = candidate.placements.Count;
|
||||
|
||||
@ -1037,6 +1037,7 @@ namespace WordsToolkit.Scripts.Levels.Editor
|
||||
// Word text field
|
||||
var wordField = new TextField();
|
||||
wordField.name = "word-field";
|
||||
wordField.isReadOnly = true;
|
||||
wordField.style.flexGrow = 1;
|
||||
wordField.style.flexShrink = 1;
|
||||
wordField.style.minWidth = 100;
|
||||
@ -1677,7 +1678,7 @@ namespace WordsToolkit.Scripts.Levels.Editor
|
||||
if (string.IsNullOrEmpty(letters))
|
||||
{
|
||||
// Generate random letters based on language if needed
|
||||
letters = LevelEditorServices.GenerateRandomLetters(languageData, languageData.wordsAmount, lettersAmount);
|
||||
letters = LevelEditorServices.GenerateRandomLetters(languageData, languageData.wordsAmount, lettersAmount, false);
|
||||
lettersProp.stringValue = letters;
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
@ -1778,7 +1779,7 @@ namespace WordsToolkit.Scripts.Levels.Editor
|
||||
|
||||
private void GenerateWordsForLanguage(Level level, LanguageData languageData, IModelController Controller)
|
||||
{
|
||||
string letters = LevelEditorServices.GenerateRandomLetters(languageData, languageData.wordsAmount, level.letters);
|
||||
string letters = LevelEditorServices.GenerateRandomLetters(languageData, languageData.wordsAmount, level.letters, false);
|
||||
languageData.letters = letters;
|
||||
LevelEditorServices.GenerateWordsForLanguage(level, languageData, Controller, false);
|
||||
UpdateCrossword(level, languageData);
|
||||
@ -1970,7 +1971,7 @@ namespace WordsToolkit.Scripts.Levels.Editor
|
||||
{
|
||||
if (!AssetDatabase.IsValidFolder("Assets/WordConnectGameToolkit/Resources"))
|
||||
{
|
||||
AssetDatabase.CreateFolder("Assets/WordsToolkit", "Resources");
|
||||
AssetDatabase.CreateFolder("Assets/WordConnectGameToolkit", "Resources");
|
||||
}
|
||||
AssetDatabase.CreateFolder("Assets/WordConnectGameToolkit/Resources", "Settings");
|
||||
}
|
||||
|
||||
@ -95,7 +95,7 @@ namespace WordsToolkit.Scripts.Levels.Editor
|
||||
$"Processing language: {languageData.language}",
|
||||
(float)processedLanguages / totalLanguages);
|
||||
|
||||
string letters = GenerateRandomLetters(languageData, languageData.wordsAmount, level.letters);
|
||||
string letters = GenerateRandomLetters(languageData, languageData.wordsAmount, level.letters, false);
|
||||
if (!string.IsNullOrEmpty(letters))
|
||||
{
|
||||
languageData.letters = letters;
|
||||
@ -165,10 +165,10 @@ namespace WordsToolkit.Scripts.Levels.Editor
|
||||
|
||||
if (selectedWords.Count == 0)
|
||||
{
|
||||
Debug.LogWarning($"No valid words with {minLettersInWord} to {maxLettersInWord} letters could be generated from '{languageData.letters}' for language {languageData.language}");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Log($"Generated words for language {languageData.language} in level {level.number}");
|
||||
// Shuffle the final list
|
||||
var words = selectedWords.OrderBy(x => UnityEngine.Random.value).ToList();
|
||||
|
||||
@ -192,7 +192,7 @@ namespace WordsToolkit.Scripts.Levels.Editor
|
||||
return model.GetWordsFromSymbols(languageData.letters, languageData.language);
|
||||
}
|
||||
|
||||
public static string GenerateRandomLetters(LanguageData languageData, int count, int lettersAmount)
|
||||
public static string GenerateRandomLetters(LanguageData languageData, int count, int lettersAmount, bool generateLetters)
|
||||
{
|
||||
var controller = EditorScope.Resolve<IModelController>();
|
||||
var bannedWordsService = EditorScope.Resolve<IBannedWordsService>();
|
||||
@ -204,6 +204,19 @@ namespace WordsToolkit.Scripts.Levels.Editor
|
||||
return "";
|
||||
}
|
||||
|
||||
// 30% chance to generate actual random letters instead of finding optimal words
|
||||
if (generateLetters)
|
||||
{
|
||||
string randomLetters = GenerateActualRandomLetters(languageData.language, lettersAmount);
|
||||
|
||||
// Check if these random letters can generate any words
|
||||
var wordsFromRandomLetters = controller.GetWordsFromSymbols(randomLetters, languageData.language);
|
||||
if (wordsFromRandomLetters != null && wordsFromRandomLetters.Count() > 0)
|
||||
{
|
||||
return randomLetters;
|
||||
}
|
||||
}
|
||||
|
||||
var usedWords = LevelEditorServices.GetUsedWords(languageData.language);
|
||||
|
||||
// Try getting words with specified length
|
||||
@ -212,28 +225,38 @@ namespace WordsToolkit.Scripts.Levels.Editor
|
||||
// If no words found with the specified length, try with other lengths
|
||||
if (words.Count == 0)
|
||||
{
|
||||
Debug.LogWarning($"No words with length {lettersAmount} found for language {languageData.language}. Trying other lengths...");
|
||||
// Try with smaller lengths first, then larger
|
||||
for (int offset = 1; offset <= 3; offset++)
|
||||
// Check if model is loaded for this language
|
||||
if (!controller.IsModelLoaded(languageData.language))
|
||||
{
|
||||
// Try smaller length
|
||||
if (lettersAmount - offset > 2)
|
||||
controller.LoadModels();
|
||||
|
||||
// Try again after reloading
|
||||
words = controller.GetWordsWithLength(lettersAmount, languageData.language).Where(w => !usedWords.Contains(w)).ToList();
|
||||
}
|
||||
|
||||
// If still no words found after reloading, try with other lengths
|
||||
if (words.Count == 0)
|
||||
{
|
||||
// Try with smaller lengths first, then larger
|
||||
for (int offset = 1; offset <= 3; offset++)
|
||||
{
|
||||
words = controller.GetWordsWithLength(lettersAmount - offset, languageData.language);
|
||||
// Try smaller length
|
||||
if (lettersAmount - offset > 2)
|
||||
{
|
||||
words = controller.GetWordsWithLength(lettersAmount - offset, languageData.language);
|
||||
if (words.Count > 0) break;
|
||||
}
|
||||
|
||||
// Try larger length
|
||||
words = controller.GetWordsWithLength(lettersAmount + offset, languageData.language);
|
||||
if (words.Count > 0) break;
|
||||
}
|
||||
|
||||
// Try larger length
|
||||
words = controller.GetWordsWithLength(lettersAmount + offset, languageData.language);
|
||||
if (words.Count > 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
// If still no words found, use some default letters
|
||||
if (words.Count == 0)
|
||||
{
|
||||
Debug.LogWarning($"No suitable words found for language {languageData.language}. Using default letters.");
|
||||
|
||||
// Default letter sets by language
|
||||
Dictionary<string, string> defaultLetters = new Dictionary<string, string>
|
||||
{
|
||||
@ -248,7 +271,7 @@ namespace WordsToolkit.Scripts.Levels.Editor
|
||||
}
|
||||
else
|
||||
{
|
||||
return "".Substring(0, Mathf.Min(lettersAmount, 26));
|
||||
return new string('a', lettersAmount);
|
||||
}
|
||||
}
|
||||
|
||||
@ -270,7 +293,6 @@ namespace WordsToolkit.Scripts.Levels.Editor
|
||||
|
||||
if (wordsCount >= count)
|
||||
{
|
||||
Debug.Log($"Found optimal word '{words[i]}' that can generate {wordsCount} words (excluding banned words)");
|
||||
return words[i];
|
||||
}
|
||||
|
||||
@ -281,10 +303,73 @@ namespace WordsToolkit.Scripts.Levels.Editor
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log($"Using best word '{bestWord}' which can generate {maxWordsGenerated} words (excluding banned words)");
|
||||
return bestWord; // Return the word that generated the most derived words
|
||||
}
|
||||
|
||||
private static string GenerateActualRandomLetters(string language, int length)
|
||||
{
|
||||
// Define Latin languages that use vowel/consonant distinction
|
||||
HashSet<string> latinLanguages = new HashSet<string> { "en", "es", "fr", "de", "it", "pt", "nl", "da", "sv", "no" };
|
||||
|
||||
if (latinLanguages.Contains(language))
|
||||
{
|
||||
// For Latin languages, use vowel/consonant distribution
|
||||
string vowels = "aeiou";
|
||||
string consonants = "bcdfghjklmnpqrstvwxyz";
|
||||
|
||||
var result = new List<char>();
|
||||
int vowelCount = Mathf.Max(1, length / 2); // About 1/2 vowels
|
||||
int consonantCount = length - vowelCount;
|
||||
|
||||
// Add vowels
|
||||
for (int i = 0; i < vowelCount; i++)
|
||||
{
|
||||
result.Add(vowels[UnityEngine.Random.Range(0, vowels.Length)]);
|
||||
}
|
||||
|
||||
// Add consonants
|
||||
for (int i = 0; i < consonantCount; i++)
|
||||
{
|
||||
result.Add(consonants[UnityEngine.Random.Range(0, consonants.Length)]);
|
||||
}
|
||||
|
||||
// Shuffle the letters
|
||||
var chars = result.ToArray();
|
||||
for (int i = 0; i < chars.Length; i++)
|
||||
{
|
||||
int randomIndex = UnityEngine.Random.Range(i, chars.Length);
|
||||
(chars[i], chars[randomIndex]) = (chars[randomIndex], chars[i]);
|
||||
}
|
||||
|
||||
return new string(chars);
|
||||
}
|
||||
else
|
||||
{
|
||||
// For non-Latin languages, use default letters without vowel distinction
|
||||
Dictionary<string, string> defaultLetters = new Dictionary<string, string>
|
||||
{
|
||||
{ "ru", "оеаинтсрвлкмдпуяыьгзбчйхжшюцщэфъ" },
|
||||
{ "zh", "一二三四五六七八九十百千万亿" },
|
||||
{ "ja", "あいうえおかきくけこさしすせそたちつてとなにぬねの" },
|
||||
{ "ar", "ابتثجحخدذرزسشصضطظعغفقكلمنهوي" }
|
||||
};
|
||||
|
||||
string letters;
|
||||
if (!defaultLetters.TryGetValue(language, out letters))
|
||||
{
|
||||
letters = "abcdefghijklmnopqrstuvwxyz"; // Fallback to Latin alphabet
|
||||
}
|
||||
|
||||
var result = new List<char>();
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
result.Add(letters[UnityEngine.Random.Range(0, letters.Length)]);
|
||||
}
|
||||
|
||||
return new string(result.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
private static List<string> GetUsedWords(string languageDataLanguage)
|
||||
{
|
||||
// Get all levels in the project
|
||||
@ -503,5 +588,77 @@ namespace WordsToolkit.Scripts.Levels.Editor
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Check for problematic overlapping words
|
||||
public static bool CheckForOverlappingWords(List<WordPlacement> placements, string[] originalWords = null)
|
||||
{
|
||||
// Check for words starting at the same position
|
||||
var sameStartGroups = placements
|
||||
.GroupBy(p => p.startPosition)
|
||||
.Where(g => g.Count() > 1)
|
||||
.ToList();
|
||||
|
||||
bool hasPositionOverlaps = sameStartGroups.Count > 0;
|
||||
|
||||
// Check for same-orientation overlaps (words that overlap along their length)
|
||||
bool hasSameOrientationOverlaps = false;
|
||||
for (int i = 0; i < placements.Count; i++)
|
||||
{
|
||||
for (int j = i + 1; j < placements.Count; j++)
|
||||
{
|
||||
var word1 = placements[i];
|
||||
var word2 = placements[j];
|
||||
|
||||
// Only check words with the same orientation
|
||||
if (word1.isHorizontal == word2.isHorizontal)
|
||||
{
|
||||
if (word1.isHorizontal)
|
||||
{
|
||||
// Both horizontal - check if they're on the same row and overlap
|
||||
if (word1.startPosition.y == word2.startPosition.y)
|
||||
{
|
||||
int word1End = word1.startPosition.x + word1.word.Length - 1;
|
||||
int word2End = word2.startPosition.x + word2.word.Length - 1;
|
||||
|
||||
// Check for overlap
|
||||
bool overlaps = !(word1End < word2.startPosition.x || word2End < word1.startPosition.x);
|
||||
if (overlaps)
|
||||
{
|
||||
hasSameOrientationOverlaps = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Both vertical - check if they're on the same column and overlap
|
||||
if (word1.startPosition.x == word2.startPosition.x)
|
||||
{
|
||||
int word1End = word1.startPosition.y + word1.word.Length - 1;
|
||||
int word2End = word2.startPosition.y + word2.word.Length - 1;
|
||||
|
||||
// Check for overlap
|
||||
bool overlaps = !(word1End < word2.startPosition.y || word2End < word1.startPosition.y);
|
||||
if (overlaps)
|
||||
{
|
||||
hasSameOrientationOverlaps = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasSameOrientationOverlaps) break;
|
||||
}
|
||||
|
||||
// Check if some words are missing from placements (indicating overlaps prevented placement)
|
||||
bool hasMissingWords = false;
|
||||
if (originalWords != null)
|
||||
{
|
||||
hasMissingWords = originalWords.Length > placements.Count;
|
||||
}
|
||||
|
||||
return hasPositionOverlaps || hasSameOrientationOverlaps || hasMissingWords;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4,11 +4,7 @@
|
||||
"references": [
|
||||
"GUID:343deaaf83e0cee4ca978e7df0b80d21",
|
||||
"GUID:d3bf71b33c0c04eb9bc1a8d6513d76bb",
|
||||
"GUID:b0214a6008ed146ff8f122a6a9c2f6cc",
|
||||
"GUID:00dd4a7ac8c24c898083910c81898ecc",
|
||||
"GUID:ac6e78962cfc743b9a5fc5f5a808aa72",
|
||||
"GUID:b25ad8286798741e3b2cc3883283e669",
|
||||
"GUID:75bdbcf23199f4cfb86c610d1d946666"
|
||||
"GUID:b0214a6008ed146ff8f122a6a9c2f6cc"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Unity.Sentis;
|
||||
using Unity.InferenceEngine;
|
||||
using UnityEngine;
|
||||
using ModelAsset = Unity.InferenceEngine.ModelAsset;
|
||||
|
||||
namespace WordsToolkit.Scripts.Levels
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user