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

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b90734360169d4f6e9a0d45c7e68b868
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 00ae6535975cc4831b66a2a9668ff033
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bf62de139853544faadf65eb92d0d55d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: baf24db2bf904e729e7796721c09e8ad
labels:
- gvh
- gvh_version-1.2.186
- gvhp_exportpath-ExternalDependencyManager/Editor/1.2.186/Google.IOSResolver.pdb
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d13c8602d5e14e43b0e92459754c4315
labels:
- gvh
- gvh_version-1.2.186
- gvhp_exportpath-ExternalDependencyManager/Editor/1.2.186/Google.JarResolver.pdb
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a695eb9f64fe49569a2db0c4246c877d
labels:
- gvh
- gvh_version-1.2.186
- gvhp_exportpath-ExternalDependencyManager/Editor/1.2.186/Google.PackageManagerResolver.pdb
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9f56badf3ca84753b00163c3b632d4e5
labels:
- gvh
- gvh_version-1.2.186
- gvhp_exportpath-ExternalDependencyManager/Editor/1.2.186/Google.VersionHandlerImpl.pdb
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 57f5a82a79ab4b098f09326c8f3c73a6
labels:
- gvh
- gvh_version-1.2.186
- gvh_version-10.4.2
- gvhp_exportpath-ExternalDependencyManager/Editor/Google.VersionHandler.pdb
timeCreated: 1538009133
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 333c08c9aed6c4f9cb7b1d08c7b23dd2
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,106 @@
using UnityEngine;
using UnityEditor;
using System.IO;
namespace WordsToolkit.Editor
{
[InitializeOnLoad]
public static class SentisToInferenceEngineMigrator
{
private const string MIGRATION_KEY = "SentisToInferenceEngineMigrated";
static SentisToInferenceEngineMigrator()
{
if (!SessionState.GetBool(MIGRATION_KEY, false))
{
EditorApplication.delayCall += PerformMigration;
}
}
private static void PerformMigration()
{
bool migrationPerformed = false;
// Force remove any Sentis references from PackageCache
string packageCachePath = Path.Combine(Application.dataPath, "..", "Library", "PackageCache");
if (Directory.Exists(packageCachePath))
{
var sentisDirectories = Directory.GetDirectories(packageCachePath, "com.unity.sentis*");
foreach (var dir in sentisDirectories)
{
try
{
Directory.Delete(dir, true);
Debug.Log($"Removed Sentis package cache: {dir}");
migrationPerformed = true;
}
catch (System.Exception e)
{
Debug.LogWarning($"Could not remove Sentis cache directory {dir}: {e.Message}");
}
}
}
// Clean up any remaining Sentis meta files
CleanupMetaFiles();
if (migrationPerformed)
{
Debug.Log("Sentis to Inference Engine migration completed automatically. Restarting Unity...");
AssetDatabase.Refresh();
// Restart Unity to ensure clean state
EditorApplication.delayCall += () => {
EditorApplication.OpenProject(System.IO.Path.GetDirectoryName(Application.dataPath));
};
}
SessionState.SetBool(MIGRATION_KEY, true);
}
private static void ForceMigrationAndRestart()
{
SessionState.SetBool(MIGRATION_KEY, false);
PerformMigration();
}
private static void RestartUnity()
{
Debug.Log("Restarting Unity...");
EditorApplication.OpenProject(System.IO.Path.GetDirectoryName(Application.dataPath));
}
private static void CleanupMetaFiles()
{
string[] searchPaths = {
Path.Combine(Application.dataPath, "Scripts"),
Path.Combine(Application.dataPath, "WordConnectGameToolkit")
};
foreach (string searchPath in searchPaths)
{
if (Directory.Exists(searchPath))
{
var metaFiles = Directory.GetFiles(searchPath, "*.meta", SearchOption.AllDirectories);
foreach (var metaFile in metaFiles)
{
string content = File.ReadAllText(metaFile);
if (content.Contains("com.unity.sentis"))
{
try
{
content = content.Replace("com.unity.sentis", "com.unity.ai.inference");
File.WriteAllText(metaFile, content);
Debug.Log($"Updated meta file: {metaFile}");
}
catch (System.Exception e)
{
Debug.LogWarning($"Could not update meta file {metaFile}: {e.Message}");
}
}
}
}
}
}
}
}

View File

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

View File

@ -0,0 +1,21 @@
fileFormatVersion: 2
guid: 06fea1744dabf414c8bdadfe687197d6
TrueTypeFontImporter:
externalObjects: {}
serializedVersion: 4
fontSize: 16
forceTextureCase: -2
characterSpacing: 0
characterPadding: 1
includeFontData: 1
fontNames:
- Baloo Bhai
fallbackFontReferences: []
customCharacters:
fontRenderingMode: 0
ascentCalculationMode: 1
useLegacyBoundsCalculation: 0
shouldRoundAdvanceValue: 1
userData:
assetBundleName:
assetBundleVariant:

View File

@ -6882,6 +6882,7 @@ MonoBehaviour:
m_GlyphPairAdjustmentRecords: []
fallbackFontAssets: []
m_FallbackFontAssetTable:
- {fileID: 11400000, guid: cdb8507d60e4b4e5fadb9b1825d39fb0, type: 2}
- {fileID: 11400000, guid: 0dfe64dccfb1419084fb31e94bf08869, type: 2}
- {fileID: 11400000, guid: f18c6f2f696cf48b2a4e92b7f29b7fc3, type: 2}
m_CreationSettings:

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: cdb8507d60e4b4e5fadb9b1825d39fb0
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -88,6 +88,7 @@ GameObject:
- component: {fileID: 4245167539472542765}
- component: {fileID: 4013824183019657187}
- component: {fileID: 8023491363183538939}
- component: {fileID: 1068866132162880213}
m_Layer: 0
m_Name: Coins
m_TagString: Coins
@ -202,6 +203,7 @@ MonoBehaviour:
onClick:
m_PersistentCalls:
m_Calls: []
noSound: 0
--- !u!114 &8023491363183538939
MonoBehaviour:
m_ObjectHideFlags: 0
@ -219,6 +221,21 @@ MonoBehaviour:
associatedResource: {fileID: 11400000, guid: 05af233fe9cfa409abb37d57d2cceaea, type: 2}
fxPrefab: {fileID: 7046139580850344571, guid: 3372b6fd62f2b4e058c6757fe9d4afd3, type: 3}
coinsTextPrefab: {fileID: 6331716406342226620, guid: 4dedea56b3321416b95d34dc8b7efba5, type: 3}
OnAnimationComplete:
m_PersistentCalls:
m_Calls: []
--- !u!114 &1068866132162880213
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1287760599166922580}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c9c6b14262f434e07ad593f7b28fbfba, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &4301976480888807572
GameObject:
m_ObjectHideFlags: 0

View File

@ -222,6 +222,7 @@ GameObject:
- component: {fileID: 4094651174836377014}
- component: {fileID: 5140382344608309896}
- component: {fileID: 3974817099587506368}
- component: {fileID: 7945160288457162381}
m_Layer: 0
m_Name: Gems
m_TagString: Gems
@ -336,6 +337,7 @@ MonoBehaviour:
onClick:
m_PersistentCalls:
m_Calls: []
noSound: 0
--- !u!114 &3974817099587506368
MonoBehaviour:
m_ObjectHideFlags: 0
@ -356,6 +358,18 @@ MonoBehaviour:
OnAnimationComplete:
m_PersistentCalls:
m_Calls: []
--- !u!114 &7945160288457162381
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8282061143723735201}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c9c6b14262f434e07ad593f7b28fbfba, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &8288800362416271104
GameObject:
m_ObjectHideFlags: 0

View File

@ -0,0 +1,14 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 229059528153459db318609c350eea5f, type: 3}
m_Name: IronsourceBannerHandler
m_EditorClassIdentifier:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 796df1b72912f46b09a0545be43c896e
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -15,3 +15,6 @@ MonoBehaviour:
bannedWordsByLanguage:
- languageCode: en
bannedWords: []
- languageCode: tr
bannedWords:
- "\xFCre"

View File

@ -36,5 +36,10 @@ MonoBehaviour:
- language: fr
title:
text:
- language: tr
title: "\u015Eelaleler"
text: "D\xFCnyan\u0131n en y\xFCksek \u015Felalesi Venezuela'daki Angel \u015Eelalesi
Dir. Su 979 metre y\xFCkseklikten d\xFC\u015Fer ve ak\u0131nt\u0131n\u0131n
bir k\u0131sm\u0131 yere ula\u015Fmadan buharla\u015F\u0131r!"
colorsTile: {fileID: 11400000, guid: 63f1377c90d84ec478676a869dc2a2c1, type: 2}
targetExtraWords: 8

View File

@ -77,9 +77,10 @@ MonoBehaviour:
rows: 7
placements: []
specialItems: []
minBounds: {x: 0, y: 0}
maxBounds: {x: 9, y: 6}
serializedGrid:
minBounds: {x: 5, y: 3}
maxBounds: {x: 5, y: 3}
serializedGrid: ' | | | | |
| '
- language: fr
letters:
wordsAmount: 5

View File

@ -84,9 +84,10 @@ MonoBehaviour:
rows: 7
placements: []
specialItems: []
minBounds: {x: 0, y: 0}
maxBounds: {x: 9, y: 6}
serializedGrid:
minBounds: {x: 5, y: 3}
maxBounds: {x: 5, y: 3}
serializedGrid: ' | | | | |
| '
- language: fr
letters:
wordsAmount: 5

View File

@ -98,9 +98,10 @@ MonoBehaviour:
rows: 7
placements: []
specialItems: []
minBounds: {x: 0, y: 0}
maxBounds: {x: 9, y: 6}
serializedGrid:
minBounds: {x: 5, y: 3}
maxBounds: {x: 5, y: 3}
serializedGrid: ' | | | | |
| '
- language: fr
letters:
wordsAmount: 5

View File

@ -120,6 +120,18 @@ MonoBehaviour:
minBounds: {x: 0, y: 0}
maxBounds: {x: 9, y: 6}
serializedGrid:
- language: tr
letters:
wordsAmount: 5
words: []
crosswordData:
columns: 0
rows: 0
placements: []
specialItems: []
minBounds: {x: 0, y: 0}
maxBounds: {x: 0, y: 0}
serializedGrid:
colorsTile: {fileID: 11400000, guid: 530ee400bda75ad44bcc4067e5f57ab8, type: 2}
words: 5
letters: 7

View File

@ -70,9 +70,10 @@ MonoBehaviour:
rows: 7
placements: []
specialItems: []
minBounds: {x: 0, y: 0}
maxBounds: {x: 9, y: 6}
serializedGrid:
minBounds: {x: 5, y: 3}
maxBounds: {x: 5, y: 3}
serializedGrid: ' | | | | |
| '
- language: fr
letters:
wordsAmount: 5

View File

@ -94,37 +94,16 @@ MonoBehaviour:
- language: es
letters: citar
wordsAmount: 4
words:
- citar
- ira
- cat
words: []
crosswordData:
columns: 10
rows: 7
placements:
- word: citar
wordNumber: 1
startPosition: {x: 3, y: 3}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: ira
wordNumber: 2
startPosition: {x: 4, y: 3}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
- word: cat
wordNumber: 3
startPosition: {x: 3, y: 5}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
placements: []
specialItems: []
minBounds: {x: 3, y: 3}
maxBounds: {x: 7, y: 5}
serializedGrid: ' | | | citar | r |
cat | '
minBounds: {x: 5, y: 3}
maxBounds: {x: 5, y: 3}
serializedGrid: ' | | | | |
| '
- language: fr
letters:
wordsAmount: 5
@ -137,9 +116,36 @@ MonoBehaviour:
minBounds: {x: 0, y: 0}
maxBounds: {x: 9, y: 6}
serializedGrid:
- language: tr
letters: ask
wordsAmount: 5
words:
- ask
- sak
crosswordData:
columns: 10
rows: 7
placements:
- word: ask
wordNumber: 1
startPosition: {x: 3, y: 1}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: sAK
wordNumber: 2
startPosition: {x: 4, y: 1}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
specialItems: []
minBounds: {x: 3, y: 1}
maxBounds: {x: 5, y: 3}
serializedGrid: ' | ask | A | K | |
| '
colorsTile: {fileID: 11400000, guid: 63f1377c90d84ec478676a869dc2a2c1, type: 2}
words: 5
letters: 5
letters: 3
min: 3
max: 6
difficulty: 0

View File

@ -100,51 +100,16 @@ MonoBehaviour:
- language: es
letters: cabra
wordsAmount: 5
words:
- cabra
- cara
- bar
- barca
- arca
words: []
crosswordData:
columns: 10
rows: 7
placements:
- word: cabra
wordNumber: 1
startPosition: {x: 3, y: 0}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: cara
wordNumber: 2
startPosition: {x: 3, y: 0}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
- word: bar
wordNumber: 3
startPosition: {x: 1, y: 2}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: barca
wordNumber: 4
startPosition: {x: 1, y: 2}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
- word: arca
wordNumber: 5
startPosition: {x: 3, y: 3}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
placements: []
specialItems: []
minBounds: {x: 1, y: 0}
maxBounds: {x: 7, y: 6}
serializedGrid: ' cabra | a | bar | a arca | r | c
| a '
minBounds: {x: 5, y: 3}
maxBounds: {x: 5, y: 3}
serializedGrid: ' | | | | |
| '
- language: fr
letters:
wordsAmount: 5
@ -157,9 +122,43 @@ MonoBehaviour:
minBounds: {x: 0, y: 0}
maxBounds: {x: 0, y: 0}
serializedGrid:
- language: tr
letters: suz
wordsAmount: 5
words:
- suz
- us
- uz
crosswordData:
columns: 10
rows: 7
placements:
- word: suz
wordNumber: 1
startPosition: {x: 3, y: 2}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: uS
wordNumber: 2
startPosition: {x: 4, y: 2}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
- word: Uz
wordNumber: 3
startPosition: {x: 5, y: 1}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
specialItems: []
minBounds: {x: 3, y: 1}
maxBounds: {x: 5, y: 3}
serializedGrid: ' | U | suz | S | |
| '
colorsTile: {fileID: 11400000, guid: 63f1377c90d84ec478676a869dc2a2c1, type: 2}
words: 5
letters: 5
letters: 3
min: 3
max: 6
difficulty: 0

View File

@ -101,50 +101,15 @@ MonoBehaviour:
- language: es
letters: saldo
wordsAmount: 5
words:
- sol
- sal
- ola
- oda
- osa
words: []
crosswordData:
columns: 10
rows: 7
placements:
- word: sol
wordNumber: 1
startPosition: {x: 5, y: 1}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: sal
wordNumber: 2
startPosition: {x: 5, y: 1}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
- word: ola
wordNumber: 3
startPosition: {x: 4, y: 3}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: oda
wordNumber: 4
startPosition: {x: 4, y: 3}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
- word: osa
wordNumber: 5
startPosition: {x: 2, y: 5}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
placements: []
specialItems: []
minBounds: {x: 2, y: 1}
maxBounds: {x: 7, y: 5}
serializedGrid: ' | sol | a | ola | d | osa
minBounds: {x: 5, y: 3}
maxBounds: {x: 5, y: 3}
serializedGrid: ' | | | | |
| '
- language: fr
letters:
@ -158,6 +123,40 @@ MonoBehaviour:
minBounds: {x: 0, y: 0}
maxBounds: {x: 0, y: 0}
serializedGrid:
- language: tr
letters: "k\xFCre"
wordsAmount: 5
words:
- "k\xFCre"
- "k\xFCr"
- ek
crosswordData:
columns: 10
rows: 7
placements:
- word: ek
wordNumber: 3
startPosition: {x: 4, y: 2}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: "k\xFCre"
wordNumber: 2
startPosition: {x: 3, y: 4}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: "k\xFCr"
wordNumber: 1
startPosition: {x: 5, y: 2}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
specialItems: []
minBounds: {x: 3, y: 2}
maxBounds: {x: 6, y: 4}
serializedGrid: " | | ek | \xFC | k\xFCre
| | "
colorsTile: {fileID: 11400000, guid: 63f1377c90d84ec478676a869dc2a2c1, type: 2}
words: 5
letters: 4

View File

@ -114,51 +114,16 @@ MonoBehaviour:
- language: es
letters: radio
wordsAmount: 5
words:
- ira
- ida
- aro
- oda
- dar
words: []
crosswordData:
columns: 10
rows: 7
placements:
- word: ira
wordNumber: 1
startPosition: {x: 4, y: 1}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: ida
wordNumber: 2
startPosition: {x: 4, y: 1}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
- word: aro
wordNumber: 3
startPosition: {x: 4, y: 3}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: oda
wordNumber: 4
startPosition: {x: 6, y: 3}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
- word: dar
wordNumber: 5
startPosition: {x: 6, y: 4}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
placements: []
specialItems: []
minBounds: {x: 4, y: 1}
maxBounds: {x: 8, y: 5}
serializedGrid: ' | ira | d | aro | dar |
a | '
minBounds: {x: 5, y: 3}
maxBounds: {x: 5, y: 3}
serializedGrid: ' | | | | |
| '
- language: fr
letters:
wordsAmount: 5
@ -171,9 +136,43 @@ MonoBehaviour:
minBounds: {x: 0, y: 0}
maxBounds: {x: 0, y: 0}
serializedGrid:
- language: tr
letters: geri
wordsAmount: 5
words:
- geri
- gir
- eri
crosswordData:
columns: 10
rows: 7
placements:
- word: geri
wordNumber: 1
startPosition: {x: 3, y: 3}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: gir
wordNumber: 3
startPosition: {x: 3, y: 5}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: eri
wordNumber: 2
startPosition: {x: 4, y: 3}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
specialItems: []
minBounds: {x: 3, y: 3}
maxBounds: {x: 6, y: 5}
serializedGrid: ' | | | geri | r |
gir | '
colorsTile: {fileID: 11400000, guid: 63f1377c90d84ec478676a869dc2a2c1, type: 2}
words: 5
letters: 5
letters: 4
min: 3
max: 6
difficulty: 0

View File

@ -109,44 +109,16 @@ MonoBehaviour:
- language: es
letters: motor
wordsAmount: 5
words:
- specialitem
- motor
- moro
- toro
words: []
crosswordData:
columns: 10
rows: 7
placements:
- word: Motor
wordNumber: 1
startPosition: {x: 3, y: 3}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: Moro
wordNumber: 2
startPosition: {x: 3, y: 3}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
- word: toro
wordNumber: 3
startPosition: {x: 0, y: 4}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: SpecialItem
wordNumber: -1
startPosition: {x: 3, y: 3}
isHorizontal: 1
isSpecialItem: 1
specialItemPath: Assets/WordConnectGameToolkit/Sprites/game_ui/in-game-item-1.png
placements: []
specialItems: []
minBounds: {x: 0, y: 3}
maxBounds: {x: 7, y: 6}
serializedGrid: ' | | | Motor |toro |
r | o '
minBounds: {x: 5, y: 3}
maxBounds: {x: 5, y: 3}
serializedGrid: ' | | | | |
| '
- language: fr
letters:
wordsAmount: 5
@ -159,9 +131,50 @@ MonoBehaviour:
minBounds: {x: 0, y: 0}
maxBounds: {x: 0, y: 0}
serializedGrid:
- language: tr
letters: "ko\u015Fa"
wordsAmount: 5
words:
- ok
- "ko\u015Fa"
- ak
- "ka\u015F"
crosswordData:
columns: 10
rows: 7
placements:
- word: Ok
wordNumber: 1
startPosition: {x: 4, y: 1}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: "ko\u015Fa"
wordNumber: 2
startPosition: {x: 3, y: 3}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: ak
wordNumber: 3
startPosition: {x: 3, y: 2}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
- word: "ka\u015F"
wordNumber: 4
startPosition: {x: 5, y: 1}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
specialItems: []
minBounds: {x: 3, y: 1}
maxBounds: {x: 6, y: 3}
serializedGrid: " | Ok | a a | ko\u015Fa |
| | "
colorsTile: {fileID: 11400000, guid: 63f1377c90d84ec478676a869dc2a2c1, type: 2}
words: 5
letters: 5
letters: 4
min: 3
max: 6
difficulty: 0

View File

@ -115,51 +115,15 @@ MonoBehaviour:
- language: es
letters: salir
wordsAmount: 5
words:
- sal
- liar
- ira
- risa
- asir
words: []
crosswordData:
columns: 10
rows: 7
placements:
- word: sal
wordNumber: 1
startPosition: {x: 1, y: 0}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: liar
wordNumber: 2
startPosition: {x: 3, y: 0}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
- word: ira
wordNumber: 3
startPosition: {x: 3, y: 1}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: risa
wordNumber: 4
startPosition: {x: 3, y: 3}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: asir
wordNumber: 5
startPosition: {x: 6, y: 3}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
placements: []
specialItems: []
minBounds: {x: 1, y: 0}
maxBounds: {x: 6, y: 6}
serializedGrid: ' sal | ira | a | risa | s |
i | r '
minBounds: {x: 0, y: 0}
maxBounds: {x: 9, y: 6}
serializedGrid:
- language: fr
letters:
wordsAmount: 5
@ -172,9 +136,50 @@ MonoBehaviour:
minBounds: {x: 0, y: 0}
maxBounds: {x: 0, y: 0}
serializedGrid:
- language: tr
letters: "\xE7al\u0131"
wordsAmount: 5
words:
- al
- "a\xE7"
- "a\xE7\u0131"
- "\xE7al\u0131"
crosswordData:
columns: 10
rows: 7
placements:
- word: al
wordNumber: 2
startPosition: {x: 5, y: 2}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: "\xE7al\u0131"
wordNumber: 3
startPosition: {x: 2, y: 4}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: "a\xE7"
wordNumber: 4
startPosition: {x: 2, y: 3}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
- word: "a\xE7\u0131"
wordNumber: 1
startPosition: {x: 5, y: 2}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
specialItems: []
minBounds: {x: 2, y: 2}
maxBounds: {x: 6, y: 4}
serializedGrid: " | | al | a \xE7 | \xE7al\u0131
| | "
colorsTile: {fileID: 11400000, guid: e8a60425bb67f42618a943883b553d29, type: 2}
words: 5
letters: 5
letters: 4
min: 3
max: 4
difficulty: 0

View File

@ -121,51 +121,16 @@ MonoBehaviour:
- language: es
letters: torpe
wordsAmount: 5
words:
- porte
- tope
- torpe
- reto
- peor
words: []
crosswordData:
columns: 10
rows: 7
placements:
- word: porte
wordNumber: 1
startPosition: {x: 1, y: 0}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: tope
wordNumber: 2
startPosition: {x: 4, y: 0}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
- word: torpe
wordNumber: 3
startPosition: {x: 6, y: 2}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
- word: reto
wordNumber: 4
startPosition: {x: 3, y: 3}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: peor
wordNumber: 5
startPosition: {x: 6, y: 5}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
placements: []
specialItems: []
minBounds: {x: 1, y: 0}
maxBounds: {x: 9, y: 6}
serializedGrid: ' porte | o | p t | reto | r |
peor| e '
minBounds: {x: 5, y: 3}
maxBounds: {x: 5, y: 3}
serializedGrid: ' | | | | |
| '
- language: fr
letters:
wordsAmount: 5
@ -178,6 +143,18 @@ MonoBehaviour:
minBounds: {x: 0, y: 0}
maxBounds: {x: 0, y: 0}
serializedGrid:
- language: tr
letters:
wordsAmount: 5
words: []
crosswordData:
columns: 0
rows: 0
placements: []
specialItems: []
minBounds: {x: 0, y: 0}
maxBounds: {x: 0, y: 0}
serializedGrid:
colorsTile: {fileID: 11400000, guid: e8a60425bb67f42618a943883b553d29, type: 2}
words: 5
letters: 5

View File

@ -107,50 +107,15 @@ MonoBehaviour:
- language: es
letters: coste
wordsAmount: 5
words:
- set
- tos
- seco
- eco
- seto
words: []
crosswordData:
columns: 10
rows: 7
placements:
- word: set
wordNumber: 1
startPosition: {x: 1, y: 1}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: tos
wordNumber: 2
startPosition: {x: 3, y: 1}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
- word: seco
wordNumber: 3
startPosition: {x: 3, y: 3}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: eco
wordNumber: 4
startPosition: {x: 4, y: 3}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
- word: seto
wordNumber: 5
startPosition: {x: 1, y: 5}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
placements: []
specialItems: []
minBounds: {x: 1, y: 1}
maxBounds: {x: 6, y: 5}
serializedGrid: ' | set | o | seco | c | seto
minBounds: {x: 5, y: 3}
maxBounds: {x: 5, y: 3}
serializedGrid: ' | | | | |
| '
- language: fr
letters:
@ -164,9 +129,50 @@ MonoBehaviour:
minBounds: {x: 0, y: 0}
maxBounds: {x: 0, y: 0}
serializedGrid:
- language: tr
letters: arka
wordsAmount: 5
words:
- arka
- ara
- ark
- kar
crosswordData:
columns: 10
rows: 7
placements:
- word: arka
wordNumber: 4
startPosition: {x: 4, y: 1}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: kar
wordNumber: 3
startPosition: {x: 2, y: 2}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: ark
wordNumber: 1
startPosition: {x: 4, y: 3}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: ara
wordNumber: 2
startPosition: {x: 4, y: 1}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
specialItems: []
minBounds: {x: 2, y: 1}
maxBounds: {x: 7, y: 3}
serializedGrid: ' | arka | kar | ark | |
| '
colorsTile: {fileID: 11400000, guid: e8a60425bb67f42618a943883b553d29, type: 2}
words: 5
letters: 5
letters: 4
min: 3
max: 6
difficulty: 0

View File

@ -107,50 +107,15 @@ MonoBehaviour:
- language: es
letters: abuso
wordsAmount: 5
words:
- bus
- boa
- uso
- osa
- abuso
words: []
crosswordData:
columns: 10
rows: 7
placements:
- word: bus
wordNumber: 1
startPosition: {x: 3, y: 1}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: boa
wordNumber: 2
startPosition: {x: 3, y: 1}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
- word: uso
wordNumber: 3
startPosition: {x: 1, y: 2}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: osa
wordNumber: 4
startPosition: {x: 6, y: 2}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
- word: abuso
wordNumber: 5
startPosition: {x: 3, y: 3}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
placements: []
specialItems: []
minBounds: {x: 1, y: 1}
maxBounds: {x: 7, y: 4}
serializedGrid: ' | bus | uso o | abuso | a |
minBounds: {x: 5, y: 3}
maxBounds: {x: 5, y: 3}
serializedGrid: ' | | | | |
| '
- language: fr
letters:
@ -164,9 +129,51 @@ MonoBehaviour:
minBounds: {x: 0, y: 0}
maxBounds: {x: 0, y: 0}
serializedGrid:
- language: tr
letters: faiz
wordsAmount: 5
words:
- faiz
- faz
- iz
- az
- af
crosswordData:
columns: 10
rows: 7
placements:
- word: af
wordNumber: 1
startPosition: {x: 4, y: 1}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: az
wordNumber: 2
startPosition: {x: 5, y: 2}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: faiz
wordNumber: 3
startPosition: {x: 2, y: 3}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: faz
wordNumber: 4
startPosition: {x: 5, y: 1}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
specialItems: []
minBounds: {x: 2, y: 1}
maxBounds: {x: 6, y: 3}
serializedGrid: ' | af | az | faiz | |
| '
colorsTile: {fileID: 11400000, guid: e8a60425bb67f42618a943883b553d29, type: 2}
words: 5
letters: 5
letters: 4
min: 3
max: 6
difficulty: 0

View File

@ -110,51 +110,16 @@ MonoBehaviour:
- language: es
letters: piano
wordsAmount: 5
words:
- pan
- piano
- pino
- poni
- apio
words: []
crosswordData:
columns: 10
rows: 7
placements:
- word: pan
wordNumber: 1
startPosition: {x: 5, y: 2}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
- word: piano
wordNumber: 2
startPosition: {x: 3, y: 3}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: pino
wordNumber: 3
startPosition: {x: 3, y: 3}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
- word: poni
wordNumber: 4
startPosition: {x: 0, y: 4}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: apio
wordNumber: 5
startPosition: {x: 0, y: 6}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
placements: []
specialItems: []
minBounds: {x: 0, y: 2}
maxBounds: {x: 7, y: 6}
serializedGrid: ' | | p | piano |poni n |
n |apio '
minBounds: {x: 5, y: 3}
maxBounds: {x: 5, y: 3}
serializedGrid: ' | | | | |
| '
- language: fr
letters:
wordsAmount: 5
@ -167,9 +132,70 @@ MonoBehaviour:
minBounds: {x: 0, y: 0}
maxBounds: {x: 0, y: 0}
serializedGrid:
- language: tr
letters: "ayn\u0131"
wordsAmount: 5
words:
- "ayn\u0131"
- an
- "an\u0131"
- "ay\u0131"
- yan
crosswordData:
columns: 10
rows: 7
placements:
- word: an
wordNumber: 3
startPosition: {x: 5, y: 2}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: yan
wordNumber: 2
startPosition: {x: 3, y: 3}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: "ay\u0131"
wordNumber: 5
startPosition: {x: 1, y: 5}
isHorizontal: 1
isSpecialItem: 0
specialItemPath:
- word: "ayn\u0131"
wordNumber: 4
startPosition: {x: 3, y: 2}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
- word: "an\u0131"
wordNumber: 1
startPosition: {x: 5, y: 2}
isHorizontal: 0
isSpecialItem: 0
specialItemPath:
specialItems: []
minBounds: {x: 1, y: 2}
maxBounds: {x: 6, y: 5}
serializedGrid: " | | a an | yan | n \u0131
| ay\u0131 | "
- language: new
letters:
wordsAmount: 5
words: []
crosswordData:
columns: 10
rows: 7
placements: []
specialItems: []
minBounds: {x: 5, y: 3}
maxBounds: {x: 5, y: 3}
serializedGrid: ' | | | | |
| '
colorsTile: {fileID: 11400000, guid: e8a60425bb67f42618a943883b553d29, type: 2}
words: 5
letters: 5
letters: 4
min: 3
max: 6
difficulty: 0

View File

@ -7,7 +7,6 @@ DAY : Day
THANKS : Thanks!
LOADING : Loading...
LUCKYSPIN : Lucky Spin
OK : OK
NOADSLABEL1 : Play without ads!
NOADSLABEL2 : Reward videos are optional and available for viewing after purchase
BUY : BUY

View File

@ -7,7 +7,6 @@ DAY : Jour
THANKS : Merci !
LOADING : Chargement...
LUCKYSPIN : Roue de la Fortune
OK : OK
NOADSLABEL1 : Jouez sans publicit<69>s !
NOADSLABEL2 : Les vid<69>os de r<>compense sont optionnelles et disponibles apr<70>s l'achat
BUY : ACHETER

View File

@ -0,0 +1,77 @@
COINSSHOP : Κατάστημα Νομισμάτων
FREE : ΔΩΡΕΑΝ
BUYTIPS : Αγόρασε Βοήθειες (Tips)
GETFREE : Λάβε Δωρεάν
DAILYREWARD : Καθημερινές Ανταμοιβές
DAY : Ημέρα
THANKS : Ευχαριστούμε!
LOADING : Φορτώνει...
LUCKYSPIN : Τυχερή Περιστροφή
NOADSLABEL1 : Παίξε χωρίς διαφημίσεις!
NOADSLABEL2 : Τα βίντεο ανταμοιβής είναι προαιρετικά και διαθέσιμα για προβολή μετά την αγορά
BUY : ΑΓΟΡΑ
OUTOFLIVES : ΕΞΑΝΤΛΗΘΗΚΑΝ ΟΙ ΖΩΕΣ
REFILLTHELIVES : Αναπλήρωση των ζωών;
OUTOFTIME : ΕΞΑΝΤΛΗΘΗΚΕ Ο ΧΡΟΝΟΣ
REFILLTHETIME : Αναπλήρωση του χρόνου;
GIFT : Δώρο
LEVELCLEARED : ΕΠΙΠΕΔΟ ΟΛΟΚΛΗΡΩΘΗΚΕ!
SETTINGS : Ρυθμίσεις
SHOP : ΚΑΤΑΣΤΗΜΑ
PRIVACY : Απόρρητο
QUITTHEGAME : Έξοδος από το παιχνίδι
DOYOUWANTTOQUIT : Θέλετε πραγματικά να βγείτε;
YES : ΝΑΙ
NO : ΟΧΙ
COMINGSOON : Νέα επίπεδα έρχονται σύντομα. <br>Μείνετε συντονισμένοι για την επόμενη ενημέρωση.
WIN : ΝΙΚΗ
NEXTLEVEL : Επόμενο Επίπεδο
SCORE : Σκορ
POINTS : Πόντοι
REVIVEWITHNEWSHAPES : Αναβίωση με νέα σχήματα;
WHATCHADS : Παρακολούθηση Διαφημίσεων
CONTINUE : Συνέχεια
YOULOSE : Χάσατε...
RETRY : Ξαναπροσπάθησε
ALMOST : Σχεδόν τα καταφέρατε...
ARCADEMODE : ΛΕΙΤΟΥΡΓΙΑ ARCADE
STAGE : ΣΤΑΔΙΟ {stage}
LEVEL : Επίπεδο {level}
MOSTPOPULAR : Πιο Δημοφιλές
BESTOFFER : ΚΑΛΥΤΕΡΗ ΠΡΟΣΦΟΡΑ
NOADS : Κατάργηση Διαφημίσεων
FREESPIN : ΔΩΡΕΑΝ Περιστροφή
SOUNDS : Ήχοι
MUSIC : Μουσική
VIBRATION : Δόνηση
GAMEOVER : Τέλος Παιχνιδιού
YOURSCORE : Το Σκορ σας
BESTSCORE : ΚΑΛΥΤΕΡΟ Σκορ
NEWRECORD : Νέο Ρεκόρ!
EXITGAME : Έξοδος από το Παιχνίδι
ADVENTURE : ΠΕΡΙΠΕΤΕΙΑ
CLASSIC : ΚΛΑΣΙΚΟ
TUTORIAL : Εκμάθηση
RESTORE_PURCHASES : Επαναφορά Αγορών
EXTRAWORDS : Επιπλέον Λέξεις
WORDSNOTINTCLUDEDINTHISLEVEL : Λέξεις που δεν περιλαμβάνονται σε αυτό το επίπεδο
CLAIM : Διεκδίκηση
COINS : ΝΟΜΙΣΜΑΤΑ
GEMS : ΠΕΤΡΑΔΙΑ
TAPTOCOLLECT : ΠΑΤΗΣΤΕ ΓΙΑ ΣΥΛΛΟΓΗ
DAILYREWARDS : ΚΑΘΗΜΕΡΙΝΕΣ ΑΝΤΑΜΟΙΒΕΣ
SPIN : ΠΕΡΙΣΤΡΟΦΗ
SELECTLANGUAGE : ΕΠΙΛΟΓΗ ΓΛΩΣΣΑΣ
AGAIN : ΞΑΝΑ
UNLOCK : Συλλέξτε κάρτες για να ξεκλειδώσετε ενδιαφέροντα στοιχεία (facts)
TipBoosterButton : Εάν κολλήσετε, μπορείτε να χρησιμοποιήσετε μια ΥΠΟΔΕΙΞΗ (HINT)
HammerBoosterButton : Το ΣΦΥΡΙ αποκαλύπτει οποιοδήποτε γράμμα της επιλογής σας
ExtraWordsButton : Βρήκατε μια ΕΠΙΠΛΕΟΝ ΛΕΞΗ!
Extra words are displayed here : Οι επιπλέον λέξεις εμφανίζονται εδώ
GiftButton : Έχετε ξεκλειδώσει ένα ΔΩΡΟ! <br><br> ΞΟΔΕΨΤΕ ΠΕΤΡΑΔΙΑ για να λάβετε μια πολύτιμη ΑΝΤΑΜΟΙΒΗ
ShuffleButton : Το κουμπί ΑΝΑΚΑΤΕΜΑ (SHUFFLE) μπορεί να σας βοηθήσει να βρείτε λέξεις πιο γρήγορα
RedGem : Συνδέστε τη λέξη {word} για να λάβετε ένα ΚΟΚΚΙΝΟ ΠΕΤΡΑΔΙ
GameTutorial : Σύρετε για να συνδέσετε τη λέξη {word} με μία κίνηση
Home : Αρχική
HARD : ΔΥΣΚΟΛΟ
TIMETUT : Λύστε όλες τις λέξεις έγκαιρα για να ΚΕΡΔΙΣΕΤΕ

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 576d9cb2289d541228a31b12421cdab8
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,76 @@
COINSSHOP : Loja de Moedas
FREE : GRÁTIS
BUYTIPS : Comprar Dicas
GETFREE : Obter Grátis
DAILYREWARD : Recompensas Diárias
DAY : Dia
THANKS : Obrigado!
LOADING : Carregando...
LUCKYSPIN : Giro da Sorte
NOADSLABEL1 : Jogue sem anúncios!
NOADSLABEL2 : Vídeos de recompensa são opcionais e disponíveis para visualização após a compra
BUY : COMPRAR
OUTOFLIVES : SEM VIDAS
REFILLTHELIVES : Recarregar as vidas?
OUTOFTIME : SEM TEMPO
REFILLTHETIME : Recarregar o tempo?
GIFT : Presente
LEVELCLEARED : NÍVEL CONCLUÍDO!
SETTINGS : Configurações
SHOP : LOJA
PRIVACY : Privacidade
QUITTHEGAME : Sair do jogo
DOYOUWANTTOQUIT : Você realmente quer sair?
YES : Sim
NO : NÃO
COMINGSOON : Novos níveis em breve. <br>Fique atento à próxima atualização.
WIN : VITÓRIA
NEXTLEVEL : Próximo Nível
SCORE : Pontuação
POINTS : Pontos
REVIVEWITHNEWSHAPES : Reviver com novas formas?
WHATCHADS : Assistir Anúncios
CONTINUE : Continuar
YOULOSE : Você Perdeu...
RETRY : Tentar Novamente
ALMOST : Quase lá...
ARCADEMODE : MODO ARCADE
STAGE : ESTÁGIO {stage}
LEVEL : Nível {level}
MOSTPOPULAR : Mais Popular
BESTOFFER : MELHOR Oferta
NOADS : Remover ADS
FREESPIN : Giro GRÁTIS
SOUNDS : Sons
MUSIC : Música
VIBRATION : Vibração
GAMEOVER : Fim de Jogo
YOURSCORE : Sua Pontuação
BESTSCORE : MELHOR Pontuação
NEWRECORD : Novo Recorde!
EXITGAME : Sair do Jogo
ADVENTURE : AVENTURA
CLASSIC : CLÁSSICO
TUTORIAL : Tutorial
RESTORE_PURCHASES : Restaurar Compras
EXTRAWORDS : Palavras Extras
WORDSNOTINTCLUDEDINTHISLEVEL : Palavras não incluídas neste nível
CLAIM : Reivindicar
COINS : MOEDAS
GEMS : GEMAS
TAPTOCOLLECT : TOQUE PARA COLETAR
DAILYREWARDS : RECOMPENSAS DIÁRIAS
SPIN :GIRO
SELECTLANGUAGE : SELECIONAR LÍNGUA
AGAIN : NOVAMENTE
UNLOCK : Colete cartas para desbloquear fatos interessantes
TipBoosterButton : Se você ficar preso, pode usar uma DICA
HammerBoosterButton : O MARTELO revela qualquer letra da sua escolha
ExtraWordsButton : Você encontrou uma PALAVRA EXTRA! Palavras extras são exibidas aqui
GiftButton : Você desbloqueou um PRESENTE!<br><br> GASTE GEMAS para receber uma RECOMPENSA valiosa
ShuffleButton : O botão EMBARALHAR pode ajudá-lo a encontrar palavras mais rápido
RedGem : Conecte a palavra {word} para obter uma GEMAS VERMELHA
GameTutorial : Deslize para conectar a palavra {word} em um único movimento
Home : Início
HARD : DIFÍCIL
TIMETUT : Resolva todas as palavras a tempo para VENCER

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f3a020d5ed0c44909e7df6a54db58fd9
timeCreated: 1756110934

View File

@ -7,7 +7,6 @@ DAY : День
THANKS : Спасибо!
LOADING : Загрузка...
LUCKYSPIN : Колесо удачи
OK : OK
NOADSLABEL1 : Сделайте эту покупку, чтобы навсегда убрать рекламу
NOADSLABEL2 : Рекламные видео остаются доступными для просмотра по желанию после покупки
BUY : КУПИТЬ

View File

@ -7,7 +7,6 @@ DAY : Día
THANKS : ¡Gracias!
LOADING : Cargando...
LUCKYSPIN : GIRO DE SUERTE
OK : OK
YOURWIN : ¡Has Ganado!
NOADSLABEL1 : Haz esta compra para eliminar los anuncios permanentemente
NOADSLABEL2 : Los videos de recompensa son opcionales y están disponibles después de la compra

View File

@ -0,0 +1,76 @@
COINSSHOP : Jeton Mağazası
FREE : ÜCRETSİZ
BUYTIPS : İpucu Satın Al
GETFREE : Ücretsiz Al
DAILYREWARD : Günlük Ödüller
DAY : Gün
THANKS : Teşekkürler!
LOADING : Yükleniyor...
LUCKYSPIN : Şanslı Çark
NOADSLABEL1 : Reklamsız oyna!
NOADSLABEL2 : Ödül videoları isteğe bağlıdır ve satın alma sonrası izlenebilir
BUY : SATIN AL
OUTOFLIVES : CAN BİTTİ
REFILLTHELIVES : Canları yenile?
OUTOFTIME : SÜRE BİTTİ
REFILLTHETIME : Süreyi yenile?
GIFT : Hediye
LEVELCLEARED : LEVEL TAMAMLANDI!
SETTINGS : Ayarlar
SHOP : MAĞAZA
PRIVACY : Gizlilik
QUITTHEGAME : Oyundan çık
DOYOUWANTTOQUIT : Gerçekten çıkmak istiyor musun?
YES : Evet
NO : HAYIR
COMINGSOON : Yeni levellar yakında. <br>Bir sonraki güncelleme için takipte kalın.
WIN : KAZAN
NEXTLEVEL : Sonraki Level
SCORE : Skor
POINTS : Puan
REVIVEWITHNEWSHAPES : Yeni şekillerle canlan?
WHATCHADS : Reklam İzle
CONTINUE : Devam Et
YOULOSE : Kaybettin...
RETRY : Tekrar Dene
ALMOST : Neredeyse bitti...
ARCADEMODE : ARCADE MODU
STAGE : AŞAMA {stage}
LEVEL : Seviye {level}
MOSTPOPULAR : En Popüler
BESTOFFER : EN İYİ Teklif
NOADS : Reklamları Kaldır
FREESPIN : ÜCRETSİZ Çark
SOUNDS : Sesler
MUSIC : Müzik
VIBRATION : Titreşim
GAMEOVER : Oyun Bitti
YOURSCORE : Skorun
BESTSCORE : EN İYİ Skor
NEWRECORD : Yeni Rekor!
EXITGAME : Oyundan Çık
ADVENTURE : MACERA
CLASSIC : KLASİK
TUTORIAL : Öğretici
RESTORE_PURCHASES : Satın Alımları Geri Yükle
EXTRAWORDS : Ekstra Kelimeler
WORDSNOTINTCLUDEDINTHISLEVEL : Bu levelde bulunmayan kelimeler
CLAIM : Al
COINS : JETONLAR
GEMS : MÜCEVHERLER
TAPTOCOLLECT : ALMAK İÇİN DOKUN
DAILYREWARDS : GÜNLÜK ÖDÜLLER
SPIN : ÇARK
SELECTLANGUAGE : DİL SEÇ
AGAIN : TEKRAR
UNLOCK : İlginç gerçekleri açmak için kartları topla
TipBoosterButton : Takılırsan, İPUCU kullanabilirsin
HammerBoosterButton : ÇEKİÇ seçtiğin herhangi bir harfi açar
ExtraWordsButton : EKSTRA KELİME buldun! Ekstra kelimeler burada gösterilir
GiftButton : Bir HEDİYE açtın!<br><br> Değerli bir ÖDÜL almak için MÜCEVHER HARCA
ShuffleButton : KARIŞTIR butonu kelimeleri daha hızlı bulmanı sağlar
RedGem : {word} kelimesini birleştirerek KIRMIZI MÜCEVHER kazan
GameTutorial : {word} kelimesini tek harekette birleştirmek için kaydır
Home : Ana Sayfa
HARD : ZOR
TIMETUT : Tüm kelimeleri zamanında çözerek KAZAN

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 23172cfae5ce473c93c89484749c57f1
timeCreated: 1755096283

View File

@ -13,7 +13,6 @@ GameObject:
- component: {fileID: 1950329202737063183}
- component: {fileID: 3147130223869816525}
- component: {fileID: 6033270132168065964}
- component: {fileID: 636551701378598401}
m_Layer: 0
m_Name: NoAds
m_TagString: Untagged
@ -150,24 +149,6 @@ MonoBehaviour:
m_PersistentCalls:
m_Calls: []
noSound: 0
--- !u!114 &636551701378598401
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1411125501940549780}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ecf8678021564e0c8ccdb00b43162f58, type: 3}
m_Name:
m_EditorClassIdentifier:
BuyItemButton: {fileID: 6033270132168065964}
price: {fileID: 994560272042212353}
count: {fileID: 0}
discountPercent: {fileID: 0}
productID: {fileID: 11400000, guid: 5a976435f08ad439db8305e3de645368, type: 2}
resource: {fileID: 0}
--- !u!1 &3033206250374185977
GameObject:
m_ObjectHideFlags: 0
@ -1371,6 +1352,7 @@ MonoBehaviour:
- {fileID: 2587162064600910403}
- {fileID: 8029056659159804162}
noAdsProduct: {fileID: 11400000, guid: 5a976435f08ad439db8305e3de645368, type: 2}
noAdsPriceText: {fileID: 994560272042212353}
coinsSound: {fileID: 0}
--- !u!95 &1506187382743174503
Animator:

View File

@ -1119,8 +1119,8 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: -13.999998, y: 205.09991}
m_SizeDelta: {x: 805.3, y: 125.2}
m_AnchoredPosition: {x: 10.214, y: 221.7}
m_SizeDelta: {x: 960.6, y: 125.2}
m_Pivot: {x: 0.50953984, y: 1.5127809}
--- !u!222 &7535087139974686469
CanvasRenderer:
@ -1177,7 +1177,7 @@ MonoBehaviour:
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 52.8
m_fontSize: 59.7
m_fontSizeBase: 32
m_fontWeight: 400
m_enableAutoSizing: 1

View File

@ -269,6 +269,7 @@ MonoBehaviour:
disappearSound: {fileID: 0}
removeAdsButton: {fileID: 1978271021528692323}
productID: {fileID: 11400000, guid: 5a976435f08ad439db8305e3de645368, type: 2}
priceText: {fileID: 5469067225883325548}
--- !u!223 &107975066550012903
Canvas:
m_ObjectHideFlags: 0

View File

@ -242,8 +242,7 @@ RectTransform:
- {fileID: 3904014851963953829}
- {fileID: 8498546336381412538}
- {fileID: 6912875309253603059}
- {fileID: 389028524070462765}
- {fileID: 7342428514651788858}
- {fileID: 6580947508340125878}
m_Father: {fileID: 4888698260352988140}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
@ -509,18 +508,18 @@ RectTransform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2674760614323516302}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalPosition: {x: 0, y: 0, z: 2664.143}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 4386370085143922448}
- {fileID: 6674073733379322089}
m_Father: {fileID: 2148560976257270264}
m_Father: {fileID: 6580947508340125878}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 255, y: -596}
m_SizeDelta: {x: 436.0297, y: 253.0126}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 253.0126}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &6669546556015746141
CanvasRenderer:
@ -631,6 +630,70 @@ MonoBehaviour:
m_PersistentCalls:
m_Calls: []
noSound: 0
--- !u!1 &5088694231550735736
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 6580947508340125878}
- component: {fileID: 3737039387247353948}
m_Layer: 5
m_Name: Buttons
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &6580947508340125878
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5088694231550735736}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: -2664.143}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 389028524070462765}
- {fileID: 7342428514651788858}
m_Father: {fileID: 2148560976257270264}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 17.165, y: -590.07}
m_SizeDelta: {x: 928.17, y: 253}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &3737039387247353948
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5088694231550735736}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Padding:
m_Left: 0
m_Right: 0
m_Top: 0
m_Bottom: 0
m_ChildAlignment: 4
m_Spacing: 0
m_ChildForceExpandWidth: 1
m_ChildForceExpandHeight: 0
m_ChildControlWidth: 1
m_ChildControlHeight: 0
m_ChildScaleWidth: 0
m_ChildScaleHeight: 0
m_ReverseArrangement: 0
--- !u!1 &5987972094866960005
GameObject:
m_ObjectHideFlags: 0
@ -696,7 +759,7 @@ MonoBehaviour:
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text:
m_text: AGAIN
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 14928a98ac0086a4483452d618f1764c, type: 2}
m_sharedMaterial: {fileID: 2100000, guid: 68c9b8949d6894b4fac4f68f9a6fe10e, type: 2}
@ -723,7 +786,7 @@ MonoBehaviour:
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 32
m_fontSize: 60.25
m_fontSizeBase: 32
m_fontWeight: 400
m_enableAutoSizing: 1
@ -1123,6 +1186,7 @@ GameObject:
- component: {fileID: 4686081452797347009}
- component: {fileID: 7087705036038996266}
- component: {fileID: 1306931333348575190}
- component: {fileID: 3582926535624043061}
m_Layer: 0
m_Name: Buy
m_TagString: Untagged
@ -1138,18 +1202,18 @@ RectTransform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7551346846335541968}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalPosition: {x: 0, y: 0, z: 2664.143}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 8035301690477598643}
- {fileID: 1593944131338580978}
m_Father: {fileID: 2148560976257270264}
m_Father: {fileID: 6580947508340125878}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: -228.9, y: -601}
m_SizeDelta: {x: 436.0297, y: 253.0126}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 253.0126}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &2189947461181701794
CanvasRenderer:
@ -1260,6 +1324,18 @@ MonoBehaviour:
m_PersistentCalls:
m_Calls: []
noSound: 0
--- !u!114 &3582926535624043061
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7551346846335541968}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c9c6b14262f434e07ad593f7b28fbfba, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &7627276145714778815
GameObject:
m_ObjectHideFlags: 0
@ -1442,9 +1518,9 @@ RectTransform:
m_Children: []
m_Father: {fileID: 7342428514651788858}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: -101, y: 13}
m_AnchorMin: {x: 0, y: 0.5}
m_AnchorMax: {x: 0, y: 0.5}
m_AnchoredPosition: {x: 131, y: 13}
m_SizeDelta: {x: 91.1761, y: 103.8394}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &3736785195808042210

View File

@ -741,6 +741,7 @@ RectTransform:
- {fileID: 7560663172583379825}
- {fileID: 2322537657978783918}
- {fileID: 90789140801721391}
- {fileID: 2652648118269143667}
- {fileID: 837921014736427326}
m_Father: {fileID: 7285109989598965343}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
@ -1143,6 +1144,7 @@ MonoBehaviour:
appearSound: {fileID: 0}
disappearSound: {fileID: 0}
privacypolicy: {fileID: 9102471955984009255}
googleUMPConsent: {fileID: 6611547390847006331}
restorePurchase: {fileID: 8408240860258485558}
vibrationSlider: {fileID: 505551677814366046}
--- !u!114 &7505269174666667659
@ -2190,11 +2192,11 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 5342761196953066357, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_text
value: Privacy
value: GDPR
objectReference: {fileID: 0}
- target: {fileID: 5342761196953066357, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: instanceID
value: PRIVACY
value:
objectReference: {fileID: 0}
- target: {fileID: 5342761196953066357, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_fontSize
@ -2294,11 +2296,11 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_AnchoredPosition.x
value: -7
value: -2.8722
objectReference: {fileID: 0}
- target: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_AnchoredPosition.y
value: -761
value: -773
objectReference: {fileID: 0}
- target: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
@ -2421,3 +2423,336 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: c9659348afa04bc6bb30eb6900f94b65, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1001 &8741391224511066416
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 3963225542060995251}
m_Modifications:
- target: {fileID: 968135515561558649, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_AnchorMax.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 968135515561558649, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 968135515561558649, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_AnchorMin.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 968135515561558649, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 968135515561558649, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_SizeDelta.x
value: 77.4014
objectReference: {fileID: 0}
- target: {fileID: 968135515561558649, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_SizeDelta.y
value: 85.2995
objectReference: {fileID: 0}
- target: {fileID: 968135515561558649, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_AnchoredPosition.x
value: 101.2
objectReference: {fileID: 0}
- target: {fileID: 968135515561558649, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_AnchoredPosition.y
value: 95.8
objectReference: {fileID: 0}
- target: {fileID: 1734678026940801168, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Sprite
value:
objectReference: {fileID: 21300000, guid: 7f7bb377a7687438bb5a87d2eff4bfd7, type: 3}
- target: {fileID: 1734678026940801168, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Color.b
value: 0.7764706
objectReference: {fileID: 0}
- target: {fileID: 1734678026940801168, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Color.g
value: 0.57254905
objectReference: {fileID: 0}
- target: {fileID: 1734678026940801168, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Color.r
value: 0.3529412
objectReference: {fileID: 0}
- target: {fileID: 2327761819407891759, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Color.b
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2327761819407891759, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Color.g
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2327761819407891759, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Color.r
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2490286444286461771, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_TargetGraphic
value:
objectReference: {fileID: 3705024337948060229}
- target: {fileID: 2611169328416249915, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Name
value: part1
objectReference: {fileID: 0}
- target: {fileID: 3155086027690401780, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Color.b
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3155086027690401780, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Color.g
value: 0.9686275
objectReference: {fileID: 0}
- target: {fileID: 3155086027690401780, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Color.r
value: 0.9058824
objectReference: {fileID: 0}
- target: {fileID: 4025083493491244185, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Color.b
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4025083493491244185, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Color.g
value: 0.95294124
objectReference: {fileID: 0}
- target: {fileID: 4025083493491244185, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Color.r
value: 0.9058824
objectReference: {fileID: 0}
- target: {fileID: 5342761196953066357, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_text
value: Privacy
objectReference: {fileID: 0}
- target: {fileID: 5342761196953066357, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: instanceID
value: PRIVACY
objectReference: {fileID: 0}
- target: {fileID: 5342761196953066357, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_fontSize
value: 60
objectReference: {fileID: 0}
- target: {fileID: 5342761196953066357, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_fontStyle
value: 4
objectReference: {fileID: 0}
- target: {fileID: 5342761196953066357, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_fontColor.b
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5342761196953066357, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_fontColor.g
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5342761196953066357, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_fontColor.r
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5342761196953066357, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_fontSizeBase
value: 60
objectReference: {fileID: 0}
- target: {fileID: 5342761196953066357, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_enableAutoSizing
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5342761196953066357, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_fontColor32.rgba
value: 4294967295
objectReference: {fileID: 0}
- target: {fileID: 5972637010007008015, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Name
value: icon
objectReference: {fileID: 0}
- target: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Pivot.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Pivot.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_AnchorMax.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_AnchorMax.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_AnchorMin.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_AnchorMin.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_SizeDelta.x
value: 627.1525
objectReference: {fileID: 0}
- target: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_SizeDelta.y
value: 106.1967
objectReference: {fileID: 0}
- target: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_LocalRotation.x
value: -0
objectReference: {fileID: 0}
- target: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_LocalRotation.y
value: -0
objectReference: {fileID: 0}
- target: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_LocalRotation.z
value: -0
objectReference: {fileID: 0}
- target: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_AnchoredPosition.x
value: -8
objectReference: {fileID: 0}
- target: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_AnchoredPosition.y
value: -666.8
objectReference: {fileID: 0}
- target: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7905749766136477480, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Type
value: 1
objectReference: {fileID: 0}
- target: {fileID: 7905749766136477480, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Sprite
value:
objectReference: {fileID: 21300000, guid: 123f05a2a44574111bd629640dbce473, type: 3}
- target: {fileID: 7905749766136477480, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Color.b
value: 1
objectReference: {fileID: 0}
- target: {fileID: 7905749766136477480, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Color.g
value: 1
objectReference: {fileID: 0}
- target: {fileID: 7905749766136477480, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Color.r
value: 1
objectReference: {fileID: 0}
- target: {fileID: 7905749766136477480, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Enabled
value: 1
objectReference: {fileID: 0}
- target: {fileID: 7905749766136477480, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_PixelsPerUnitMultiplier
value: 1.35
objectReference: {fileID: 0}
- target: {fileID: 8001603133226906570, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_AnchorMax.x
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8001603133226906570, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8001603133226906570, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_AnchorMin.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8001603133226906570, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8001603133226906570, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8001603133226906570, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8001603133226906570, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8001603133226906570, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8201212475682522876, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Name
value: UMP
objectReference: {fileID: 0}
- target: {fileID: 8201212475682522876, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_IsActive
value: 1
objectReference: {fileID: 0}
- target: {fileID: 9157385146011294632, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
propertyPath: m_Name
value: part 2
objectReference: {fileID: 0}
m_RemovedComponents:
- {fileID: 7905749766136477480, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
m_RemovedGameObjects:
- {fileID: 808954587397050430, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
- {fileID: 9157385146011294632, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
- {fileID: 2611169328416249915, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
- {fileID: 5972637010007008015, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
--- !u!224 &2652648118269143667 stripped
RectTransform:
m_CorrespondingSourceObject: {fileID: 6746304736006806339, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
m_PrefabInstance: {fileID: 8741391224511066416}
m_PrefabAsset: {fileID: 0}
--- !u!114 &3705024337948060229 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 5342761196953066357, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
m_PrefabInstance: {fileID: 8741391224511066416}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 2bc838cbc2e148b3a5e7578d063ccb18, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!114 &6611547390847006331 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 2490286444286461771, guid: 4a90a7a36be6c3249a0612ab1316c8fc, type: 3}
m_PrefabInstance: {fileID: 8741391224511066416}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c9659348afa04bc6bb30eb6900f94b65, type: 3}
m_Name:
m_EditorClassIdentifier:

View File

@ -0,0 +1,23 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 44ad2bed4c494715ba8ad21e150b03ee, type: 3}
m_Name: AdsInterstitialSettings
m_EditorClassIdentifier:
interstitials:
- elementName: Interstitial
adReference: {fileID: 11400000, guid: f9303f4b583464bc08f45f673b581f90, type: 2}
popup: {fileID: 578949463131755950, guid: a9a2cf415d78749059b02eb227bd4ff0, type: 3}
showOnOpen: 1
showOnClose: 0
minLevel: 1
maxLevel: 1000
frequency: 1

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d40017039bee543bd909a2ec0c80c188
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -14,11 +14,11 @@ MonoBehaviour:
m_EditorClassIdentifier:
adProfiles:
- name: Unity ads iOS
enable: 1
enable: 0
testInEditor: 1
platforms: 1
appId: 5698950
adsHandler: {fileID: 11400000, guid: 60c77287bd6d042938fbd15e5462e051, type: 2}
adsHandler: {fileID: 0}
adElements:
- placementId: Interstitial_iOS
adReference: {fileID: 11400000, guid: f9303f4b583464bc08f45f673b581f90, type: 2}
@ -33,11 +33,11 @@ MonoBehaviour:
showOnOpen: 0
showOnClose: 0
- name: Unity ads banner ios
enable: 1
enable: 0
testInEditor: 1
platforms: 1
appId: 5698950
adsHandler: {fileID: 11400000, guid: 74706189f5004431584663da028f09e5, type: 2}
adsHandler: {fileID: 0}
adElements:
- placementId: Banner_iOS
adReference: {fileID: 11400000, guid: 4396e62ba27584ef79ac362c4948ee63, type: 2}
@ -46,11 +46,11 @@ MonoBehaviour:
showOnOpen: 0
showOnClose: 0
- name: Unity ads Android
enable: 1
enable: 0
testInEditor: 1
platforms: 0
appId: 5870065
adsHandler: {fileID: 11400000, guid: 60c77287bd6d042938fbd15e5462e051, type: 2}
adsHandler: {fileID: 0}
adElements:
- placementId: Interstitial_Android
adReference: {fileID: 11400000, guid: f9303f4b583464bc08f45f673b581f90, type: 2}
@ -65,11 +65,11 @@ MonoBehaviour:
showOnOpen: 0
showOnClose: 0
- name: Unity ads banner android
enable: 1
enable: 0
testInEditor: 1
platforms: 0
appId: 5870065
adsHandler: {fileID: 11400000, guid: 74706189f5004431584663da028f09e5, type: 2}
adsHandler: {fileID: 0}
adElements:
- placementId: Banner_Android
adReference: {fileID: 11400000, guid: 4396e62ba27584ef79ac362c4948ee63, type: 2}
@ -116,7 +116,7 @@ MonoBehaviour:
showOnOpen: 0
showOnClose: 0
- name: admob iOS
enable: 0
enable: 1
testInEditor: 1
platforms: 1
appId: ca-app-pub-1921802893067184~3779034969
@ -135,7 +135,7 @@ MonoBehaviour:
showOnOpen: 0
showOnClose: 0
- name: admob Android
enable: 0
enable: 1
testInEditor: 1
platforms: 0
appId: ca-app-pub-1921802893067184~8049698250
@ -154,7 +154,7 @@ MonoBehaviour:
showOnOpen: 0
showOnClose: 0
- name: Admob banner IOS
enable: 0
enable: 1
testInEditor: 1
platforms: 1
appId: ca-app-pub-1921802893067184~3779034969
@ -167,10 +167,10 @@ MonoBehaviour:
showOnOpen: 0
showOnClose: 0
- name: Admob banner android
enable: 0
enable: 1
testInEditor: 1
platforms: 0
appId: ca-app-pub-1921802893067184~8049698250
appId: ca-app-pub-3940256099942544/6300978111
adsHandler: {fileID: 11400000, guid: 2115921dfa5e14398a54b0ad2a801cec, type: 2}
adElements:
- placementId: ca-app-pub-1921802893067184/7055346637

View File

@ -17,4 +17,5 @@ MonoBehaviour:
Lose: 26
Back: 60
Restart: 32
TestLanguage: 10
SimulateDuplicate: 16
TestLanguageCode: en

View File

@ -2617,7 +2617,6 @@ MonoBehaviour:
m_DeselectOnBackgroundClick: 1
m_PointerBehavior: 0
m_CursorLockBehavior: 0
m_ScrollDeltaPerTick: 6
--- !u!1 &1251246399
GameObject:
m_ObjectHideFlags: 0
@ -5097,7 +5096,7 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 862757017896117680, guid: 62f7a9d47df56401f802404b7d45d912, type: 3}
propertyPath: m_AnchoredPosition.y
value: -233.00012
value: -233.00006
objectReference: {fileID: 0}
- target: {fileID: 862757017896117680, guid: 62f7a9d47df56401f802404b7d45d912, type: 3}
propertyPath: m_LocalEulerAnglesHint.x

View File

@ -11,7 +11,8 @@
"GUID:c98377141161c7746a178fb5cb1af075",
"GUID:75469ad4d38634e559750d17036d5f7c",
"GUID:b0214a6008ed146ff8f122a6a9c2f6cc",
"jp.hadashikick.vcontainer"
"jp.hadashikick.vcontainer",
"GUID:63a57c8b658089e49a173b0f0c4870a7"
],
"includePlatforms": [],
"excludePlatforms": [],

View File

@ -0,0 +1,126 @@
using System;
using UnityEngine;
using UnityEditor;
using System.IO;
namespace WordsToolkit.Scripts.Editor
{
public class CustomModelPostProcessor : AssetPostprocessor
{
private static readonly string SOURCE_PATH = "Assets/WordsToolkit/model/custom";
private static readonly string TARGET_PATH = "Assets/StreamingAssets/WordConnectGameToolkit/model/custom";
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
{
bool hasCustomModelChanges = false;
// Check imported assets
foreach (string assetPath in importedAssets)
{
if (IsCustomModelFile(assetPath))
{
hasCustomModelChanges = true;
break;
}
}
// Check moved assets
if (!hasCustomModelChanges)
{
foreach (string assetPath in movedAssets)
{
if (IsCustomModelFile(assetPath))
{
hasCustomModelChanges = true;
break;
}
}
}
if (hasCustomModelChanges)
{
CopyCustomModelsToStreamingAssets();
}
}
private static bool IsCustomModelFile(string assetPath)
{
return assetPath.StartsWith(SOURCE_PATH) &&
(assetPath.EndsWith(".bin") || assetPath.EndsWith(".json") || assetPath.EndsWith(".txt"));
}
private static void CopyCustomModelsToStreamingAssets()
{
if (!Directory.Exists(SOURCE_PATH))
{
return;
}
// Create target directory
Directory.CreateDirectory(TARGET_PATH);
// Get all custom model files
string[] files = Directory.GetFiles(SOURCE_PATH, "*", SearchOption.AllDirectories);
foreach (string sourceFile in files)
{
// Skip .meta files
if (sourceFile.EndsWith(".meta"))
continue;
// Calculate relative path from source directory
string relativePath = Path.GetRelativePath(SOURCE_PATH, sourceFile);
string targetFile = Path.Combine(TARGET_PATH, relativePath);
// Create target subdirectory if needed
string targetDir = Path.GetDirectoryName(targetFile);
if (!Directory.Exists(targetDir))
{
Directory.CreateDirectory(targetDir);
}
try
{
// Copy file if it doesn't exist or is newer
if (!File.Exists(targetFile) || File.GetLastWriteTime(sourceFile) > File.GetLastWriteTime(targetFile))
{
File.Copy(sourceFile, targetFile, true);
Debug.Log($"[CustomModelPostProcessor] Copied {relativePath} to StreamingAssets");
}
}
catch (Exception e)
{
Debug.LogError($"[CustomModelPostProcessor] Failed to copy {sourceFile}: {e.Message}");
}
}
// Refresh the asset database so Unity sees the new files
AssetDatabase.Refresh();
}
[MenuItem("WordToolkit/Copy Custom Models to StreamingAssets")]
private static void ManualCopyCustomModels()
{
CopyCustomModelsToStreamingAssets();
Debug.Log("[CustomModelPostProcessor] Manual copy completed");
}
[MenuItem("WordToolkit/Clean Custom Models from StreamingAssets")]
private static void CleanCustomModelsFromStreamingAssets()
{
if (Directory.Exists(TARGET_PATH))
{
try
{
Directory.Delete(TARGET_PATH, true);
Debug.Log("[CustomModelPostProcessor] Cleaned custom models from StreamingAssets");
AssetDatabase.Refresh();
}
catch (Exception e)
{
Debug.LogError($"[CustomModelPostProcessor] Failed to clean StreamingAssets: {e.Message}");
}
}
}
}
}

View File

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

View File

@ -23,71 +23,71 @@ namespace WordsToolkit.Scripts.Editor
public static string WordConnect = "WordConnect";
private static string WordConnectPath = "Assets/WordConnectGameToolkit";
[MenuItem(nameof(WordConnect) + "/Settings/Shop settings")]
[MenuItem( nameof(WordConnect) + "/Settings/Shop settings")]
public static void IAPProducts()
{
Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(WordConnectPath + "/Resources/Settings/CoinsShopSettings.asset");
}
[MenuItem(nameof(WordConnect) + "/Settings/Ads settings")]
[MenuItem( nameof(WordConnect) + "/Settings/Ads settings")]
public static void AdsSettings()
{
Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(WordConnectPath + "/Resources/Settings/AdsSettings.asset");
}
//DailyBonusSettings
[MenuItem(nameof(WordConnect) + "/Settings/Daily bonus settings")]
[MenuItem( nameof(WordConnect) + "/Settings/Daily bonus settings")]
public static void DailyBonusSettings()
{
Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(WordConnectPath + "/Resources/Settings/DailyBonusSettings.asset");
}
//GameSettings
[MenuItem(nameof(WordConnect) + "/Settings/Game settings")]
[MenuItem( nameof(WordConnect) + "/Settings/Game settings")]
public static void GameSettings()
{
Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(WordConnectPath + "/Resources/Settings/GameSettings.asset");
}
//SpinSettings
[MenuItem(nameof(WordConnect) + "/Settings/Spin settings")]
[MenuItem( nameof(WordConnect) + "/Settings/Spin settings")]
public static void SpinSettings()
{
Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(WordConnectPath + "/Resources/Settings/SpinSettings.asset");
}
//DebugSettings
[MenuItem(nameof(WordConnect) + "/Settings/Debug settings")]
[MenuItem( nameof(WordConnect) + "/Settings/Debug settings")]
public static void DebugSettings()
{
Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(WordConnectPath + "/Resources/Settings/DebugSettings.asset");
}
[MenuItem(nameof(WordConnect) + "/Settings/Crossword config")]
[MenuItem( nameof(WordConnect) + "/Settings/Crossword config")]
public static void CrosswordConfig()
{
Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(WordConnectPath + "/Resources/Settings/CrosswordConfig.asset");
}
[MenuItem(nameof(WordConnect) + "/Settings/Tutorial settings")]
[MenuItem( nameof(WordConnect) + "/Settings/Tutorial settings")]
public static void TutorialSettings()
{
Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(WordConnectPath + "/Resources/Settings/TutorialSettings.asset");
}
[MenuItem(nameof(WordConnect) + "/Settings/Language configuration")]
[MenuItem( nameof(WordConnect) + "/Settings/Language configuration")]
public static void LanguageConfiguration()
{
Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(WordConnectPath + "/Resources/Settings/LanguageConfiguration.asset");
}
[MenuItem(nameof(WordConnect) + "/Settings/Gift settings")]
[MenuItem( nameof(WordConnect) + "/Settings/Gift settings")]
public static void GiftSettings()
{
Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(WordConnectPath + "/Resources/Settings/GiftSettings.asset");
Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(WordConnectPath + "/Resources/Settings/GiftsSettings.asset");
}
[MenuItem(nameof(WordConnect) + "/Scenes/Main scene &1", priority = 0)]
[MenuItem( nameof(WordConnect) + "/Scenes/Main scene &1", priority = 0)]
public static void MainScene()
{
EditorSceneManager.OpenScene(WordConnectPath + "/Scenes/main.unity");
@ -99,7 +99,7 @@ namespace WordsToolkit.Scripts.Editor
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
}
[MenuItem(nameof(WordConnect) + "/Scenes/Game scene &2")]
[MenuItem( nameof(WordConnect) + "/Scenes/Game scene &2")]
public static void GameScene()
{
var stateManager = Object.FindObjectOfType<StateManager>();
@ -107,7 +107,7 @@ namespace WordsToolkit.Scripts.Editor
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
}
[MenuItem(nameof(WordConnect) + "/Editor/Tile editor", priority = 1)]
[MenuItem( nameof(WordConnect) + "/Editor/Tile editor", priority = 1)]
public static void ColorEditor()
{
string folderPath = WordConnectPath + "/Resources/ColorsTile";
@ -130,44 +130,37 @@ namespace WordsToolkit.Scripts.Editor
EditorGUIUtility.PingObject(tileAsset);
}
[MenuItem(nameof(WordConnect) + "/Documentation/Main", priority = 2)]
[MenuItem( nameof(WordConnect) + "/Documentation/Main", priority = 2)]
public static void MainDoc()
{
Application.OpenURL("https://candy-smith.gitbook.io/main");
}
[MenuItem(nameof(WordConnect) + "/Documentation/ADS/Setup ads")]
[MenuItem( nameof(WordConnect) + "/Documentation/ADS/Setup ads")]
public static void UnityadsDoc()
{
Application.OpenURL("https://candy-smith.gitbook.io/bubble-shooter-toolkit/tutorials/ads-setup/");
}
[MenuItem(nameof(WordConnect) + "/Documentation/Unity IAP (in-apps)")]
[MenuItem( nameof(WordConnect) + "/Documentation/Unity IAP (in-apps)")]
public static void Inapp()
{
Application.OpenURL("https://candy-smith.gitbook.io/main/block-puzzle-game-toolkit/setting-up-in-app-purchase-products");
}
[MenuItem(nameof(WordConnect) + "/NLP/Training Language Model")]
[MenuItem( nameof(WordConnect) + "/NLP/Training Language Model")]
public static void TrainingModel()
{
Application.OpenURL("https://colab.research.google.com/drive/199zNcB3FPfnrD6E7OiwmwCcf27jMnY1b?usp=sharing");
}
[MenuItem(nameof(WordConnect) + "/Reset PlayerPrefs &e")]
[MenuItem( nameof(WordConnect) + "/Reset PlayerPrefs &e")]
private static void ResetPlayerPrefs()
{
GameDataManager.ClearALlData();
PlayerPrefs.DeleteKey("GameState");
Debug.Log("PlayerPrefs are reset");
}
// 🔥 新增菜单项,打开 PrefabBatchViewer 窗口
[MenuItem(nameof(WordConnect) + "/Settings/Prefab Batch Viewer")]
public static void OpenPrefabBatchViewer()
{
PopupPreview.ShowWindow();
}
}
}

View File

@ -23,6 +23,7 @@ namespace WordsToolkit.Scripts.Editor
private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
{
CheckDefines("Assets/GoogleMobileAds", "ADMOB");
CheckUMPAvailable();
CheckDefines("Assets/FacebookSDK", "FACEBOOK");
CheckDefines("Assets/PlayFabSDK", "PLAYFAB");
CheckDefines("Assets/GameSparks", "GAMESPARKS");
@ -41,6 +42,18 @@ namespace WordsToolkit.Scripts.Editor
}
}
private static void CheckUMPAvailable()
{
if (( Directory.Exists("Assets/GoogleMobileAds")))
{
DefineSymbolsUtils.AddSymbol("UMP_AVAILABLE");
}
else
{
DefineSymbolsUtils.DeleteSymbol("UMP_AVAILABLE");
}
}
public static void CheckIronsourceFolder()
{
var str = "Assets/LevelPlay";

View File

@ -26,7 +26,6 @@ namespace WordsToolkit.Scripts.Enums
LanguageChanged,
TileSelected,
PurchaseSucceeded,
PurchaseFailed,
ButtonClicked,
WordAnimated,
ExtraWordClaimed

View File

@ -34,6 +34,7 @@ namespace WordsToolkit.Scripts.GUI.Buttons.Boosts
private CanvasGroup canvasGroup;
private bool isActive;
private bool isAnimating;
protected override void OnEnable()
@ -79,6 +80,12 @@ namespace WordsToolkit.Scripts.GUI.Buttons.Boosts
protected void OnClick()
{
// Prevent clicks during animation
if (isAnimating)
{
return;
}
if (isActive)
{
Refund();
@ -105,6 +112,7 @@ namespace WordsToolkit.Scripts.GUI.Buttons.Boosts
protected virtual void ActivateBoost(bool hideButtons = true)
{
isAnimating = true;
UpdatePriceDisplay();
if(hideButtons)
buttonViewController.HideOtherButtons(this);
@ -117,6 +125,7 @@ namespace WordsToolkit.Scripts.GUI.Buttons.Boosts
protected virtual void DeactivateBoost()
{
isActive = false;
isAnimating = false;
buttonViewController.ShowButtons();
waves.Clear();
waves.Stop();

View File

@ -0,0 +1,17 @@
using UnityEngine;
using WordsToolkit.Scripts.Settings;
namespace WordsToolkit.Scripts.GUI.Labels
{
public class IAPDisabler : MonoBehaviour
{
private void OnEnable()
{
var gameSettings = Resources.Load<GameSettings>("Settings/GameSettings");
if (gameSettings != null && !gameSettings.enableInApps)
{
gameObject.SetActive(false);
}
}
}
}

View File

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

View File

@ -10,6 +10,7 @@
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using DG.Tweening;
using TMPro;
using UnityEngine;
using VContainer;
@ -65,11 +66,7 @@ namespace WordsToolkit.Scripts.GUI
public void ShowLanguageSelector()
{
menuManager.CloseAllPopups();
menuManager.ShowPopup<LanguageSelectionGame>(null, result =>
{
UpdateText();
});
menuManager.ShowPopup<LanguageSelectionGame>(null, result => { UpdateText(); });
}
}
}

View File

@ -23,12 +23,6 @@ namespace WordsToolkit.Scripts.GUI.Tutorials
{
public class TutorialWordSubstitution : TutorialPopupBase
{
[Inject]
protected LevelManager levelManager;
[Inject]
protected GameManager gameManager;
[SerializeField]
private GameObject hand;

View File

@ -28,6 +28,7 @@ namespace WordsToolkit.Scripts.Gameplay
private WordSelectionManager wordSelectionManager;
private bool isSelected = false;
private Color color;
private string originalLetter; // Store the original letter for validation
private void Awake()
{
@ -74,12 +75,13 @@ namespace WordsToolkit.Scripts.Gameplay
public string GetLetter()
{
return letterText.text;
return originalLetter ?? letterText.text;
}
public void SetText(string toString)
{
letterText.text = toString.ToUpper();
originalLetter = toString; // Store the original letter
letterText.text = toString.ToUpper(); // Display in uppercase
}
public void SetColor(Color color)

View File

@ -523,7 +523,7 @@ namespace WordsToolkit.Scripts.Gameplay.Managers
if (string.IsNullOrEmpty(word))
return false;
if (!wordValidator.IsWordKnown(word.ToLower(), gameStateManager.CurrentLanguage))
if (!wordValidator.IsWordKnown(word, gameStateManager.CurrentLanguage))
return false;
bool wasOpened = false;

View File

@ -37,7 +37,6 @@ namespace WordsToolkit.Scripts.Gameplay
private Color[] openColors = new Color[3];
private bool isSelected = false;
private int wordNumber = -1;
private bool isOpen = false;
[Header("Special Item")]
@ -321,6 +320,8 @@ namespace WordsToolkit.Scripts.Gameplay
// Only respond if the tile is selectable and closed
if (!isOpen && levelManager != null && levelManager.hammerMode)
{
// Immediately disable hammer mode to prevent multiple uses
levelManager.hammerMode = false;
// Instead of opening immediately, play hammer animation first
PlayHammerAnimationAndOpen();
}

View File

@ -42,7 +42,6 @@ namespace WordsToolkit.Scripts.Gameplay
private float idleTimer = 0f;
private Vector2 lastPosition;
public Image cursorImage; // Reference to cursor image
private bool isCursorVisible = true;
private float targetAlpha;
private float currentAlpha;

View File

@ -66,7 +66,6 @@ namespace WordsToolkit.Scripts.Gameplay
private CanvasGroup panelCanvasGroup;
[Header("UI References")]
[SerializeField] private float characterSpacing = 30f; // Spacing between characters
public Image backgroundSelectedWord; // Reference to the background image
[SerializeField]
private TextMeshProUGUI selectedWordText;
@ -463,7 +462,7 @@ namespace WordsToolkit.Scripts.Gameplay
if (selectedWordText != null)
{
selectedWordText.color = new Color(selectedWordText.color.r, selectedWordText.color.g, selectedWordText.color.b, 1f);
selectedWordText.text = GetSelectedWord();
selectedWordText.text = GetSelectedWord().ToUpper();
UpdateHorizontalLayout(layout);
}
}

View File

@ -33,7 +33,6 @@ namespace WordsToolkit.Scripts.Gameplay.WordValidator
if (string.IsNullOrEmpty(word))
return false;
word = word.ToLower();
return (modelController != null && modelController.IsWordKnown(word, currentLanguage)) ||
(customWordRepository != null && customWordRepository.ContainsWord(word));
}

View File

@ -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);
}
}
}

View File

@ -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;

View File

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

View File

@ -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;
}
}
}

View File

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

View File

@ -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
{

View File

@ -158,7 +158,17 @@ namespace WordsToolkit.Scripts.Localization
if (Application.isEditor)
{
return _debugSettings.TestLanguage;
// Use TestLanguageCode from DebugSettings and convert to SystemLanguage
try
{
var cultureInfo = new CultureInfo(_debugSettings.TestLanguageCode);
return (SystemLanguage)Enum.Parse(typeof(SystemLanguage), cultureInfo.EnglishName);
}
catch (Exception)
{
Debug.LogWarning($"Failed to parse TestLanguageCode '{_debugSettings.TestLanguageCode}'. Using English as fallback.");
return SystemLanguage.English;
}
}
return Application.systemLanguage;

View File

@ -12,6 +12,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using TMPro;
using UnityEngine;
@ -64,14 +65,24 @@ namespace WordsToolkit.Scripts.Localization
SystemLanguage lang;
if (Application.platform == RuntimePlatform.WindowsEditor || Application.platform == RuntimePlatform.OSXEditor || Application.platform == RuntimePlatform.LinuxEditor)
{
lang = _debugSettings.TestLanguage;
// Use TestLanguageCode from DebugSettings and convert to SystemLanguage
try
{
var cultureInfo = new CultureInfo(_debugSettings.TestLanguageCode);
lang = (SystemLanguage)Enum.Parse(typeof(SystemLanguage), cultureInfo.EnglishName);
}
catch (Exception)
{
Debug.LogWarning($"Failed to parse TestLanguageCode '{_debugSettings.TestLanguageCode}'. Using English as fallback.");
lang = SystemLanguage.English;
}
}
else
{
lang = Application.systemLanguage;
}
return this.Any(i => i.language == lang) ? _debugSettings.TestLanguage : SystemLanguage.English;
return this.Any(i => i.language == lang) ? lang : SystemLanguage.English;
}
public IEnumerable<LanguageObject> GetText(DebugSettings _debugSettings)

View File

@ -3,9 +3,10 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json.Linq;
using Unity.Sentis;
using Unity.InferenceEngine;
using UnityEngine;
using System.Text;
using System.Globalization;
using WordsToolkit.Scripts.Levels;
using WordsToolkit.Scripts.Services;
using WordsToolkit.Scripts.Services.BannedWords;
@ -36,6 +37,32 @@ namespace WordsToolkit.Scripts.NLP
// NOTE: This is now mainly for the old SaveModelBinary method - new architecture uses custom words files
private bool protectBinaryFile = false;
/// <summary>
/// Normalizes text by removing diacritics, accents, and converting to lowercase.
/// This allows word matching to ignore emphasis marks.
/// </summary>
private string NormalizeText(string text)
{
if (string.IsNullOrEmpty(text))
return text;
text = text.ToLower();
var normalizedString = text.Normalize(NormalizationForm.FormD);
var stringBuilder = new StringBuilder();
foreach (var c in normalizedString)
{
var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c);
if (unicodeCategory != UnicodeCategory.NonSpacingMark)
{
stringBuilder.Append(c);
}
}
return stringBuilder.ToString().Normalize(NormalizationForm.FormC);
}
public bool IsModelLoaded(string language = null)
{
language = language ?? (languageService?.GetCurrentLanguageCode() ?? m_DefaultLanguage);
@ -82,6 +109,7 @@ namespace WordsToolkit.Scripts.NLP
public void LoadModels()
{
InitializeFromConfiguration();
foreach (var languagePair in languageModels)
{
LoadModelBin(languagePair.Key, languagePair.Value);
@ -191,29 +219,62 @@ namespace WordsToolkit.Scripts.NLP
LoadCustomWordsFromBinary(language);
}
/// <summary>
/// Loads bytes from StreamingAssets using UnityWebRequest for Android compatibility
/// </summary>
private byte[] LoadStreamingAssetBytes(string path)
{
try
{
#if UNITY_ANDROID && !UNITY_EDITOR
using var request = UnityEngine.Networking.UnityWebRequest.Get(path);
var operation = request.SendWebRequest();
while (!operation.isDone) { }
if (request.result == UnityEngine.Networking.UnityWebRequest.Result.Success)
{
return request.downloadHandler.data;
}
return null;
#else
if (File.Exists(path))
{
return File.ReadAllBytes(path);
}
return null;
#endif
}
catch (Exception e)
{
Debug.LogError($"[ModelController] Exception in LoadStreamingAssetBytes: {e.Message}");
return null;
}
}
/// <summary>
/// Loads custom words from binary file and adds them to the existing vocabulary.
/// Binary file contains ONLY custom words, not the entire model cache.
/// </summary>
private void LoadCustomWordsFromBinary(string language)
{
string path = Path.Combine(Application.dataPath, "WordsToolkit", "model",
string path = Path.Combine(Application.streamingAssetsPath, "WordConnectGameToolkit", "model",
"custom", $"{language}_custom_words.bin");
if (!File.Exists(path))
if (!wordToIndexByLanguage.ContainsKey(language))
{
return;
}
if (!wordToIndexByLanguage.ContainsKey(language))
byte[] fileData = LoadStreamingAssetBytes(path);
if (fileData == null)
{
return;
}
try
{
using var fs = new FileStream(path, FileMode.Open, FileAccess.Read);
using var br = new BinaryReader(fs, Encoding.UTF8);
using var ms = new MemoryStream(fileData);
using var br = new BinaryReader(ms, Encoding.UTF8);
// Read header
if (br.ReadInt32() != 0x43555354) // "CUST" magic number
@ -265,9 +326,11 @@ namespace WordsToolkit.Scripts.NLP
return;
}
string dir = Path.Combine(Application.dataPath, "WordsToolkit", "model", "custom");
string path = Path.Combine(dir, $"{language}_custom_words.bin");
Directory.CreateDirectory(dir);
// Create StreamingAssets folder structure
string streamingAssetsDir = Path.Combine(Application.dataPath, "StreamingAssets");
string modelDir = Path.Combine(streamingAssetsDir, "WordConnectGameToolkit", "model", "custom");
string path = Path.Combine(modelDir, $"{language}_custom_words.bin");
Directory.CreateDirectory(modelDir);
try
{
@ -353,7 +416,8 @@ namespace WordsToolkit.Scripts.NLP
foreach (var pair in wordIndexDict)
{
wordToIndex[pair.Key] = pair.Value;
string normalizedWord = NormalizeText(pair.Key);
wordToIndex[normalizedWord] = pair.Value;
}
@ -379,6 +443,7 @@ namespace WordsToolkit.Scripts.NLP
return null;
}
word = NormalizeText(word);
if (!wordToIndexByLanguage[language].ContainsKey(word))
{
return null;
@ -413,7 +478,8 @@ namespace WordsToolkit.Scripts.NLP
public bool IsWordKnown(string word, string language = null)
{
language = language ?? (languageService?.GetCurrentLanguageCode() ?? m_DefaultLanguage);
if (bannedWordsService.IsWordBanned(word, language))
string normalizedWord = NormalizeText(word);
if (bannedWordsService.IsWordBanned(normalizedWord, language))
{
return false;
}
@ -451,6 +517,8 @@ namespace WordsToolkit.Scripts.NLP
return -1f;
}
word1 = NormalizeText(word1);
word2 = NormalizeText(word2);
float[] vector1 = GetWordVector(word1, language);
float[] vector2 = GetWordVector(word2, language);
@ -466,10 +534,11 @@ namespace WordsToolkit.Scripts.NLP
if (!IsModelLoaded(language))
{
Debug.LogWarning($"[ModelController] AddWord failed  model for '{language}' not loaded.");
Debug.LogWarning($"[ModelController] AddWord failed model for '{language}' not loaded.");
return false;
}
newWord = NormalizeText(newWord);
if (wordToIndexByLanguage[language].ContainsKey(newWord))
{
Debug.LogWarning($"[ModelController] Word '{newWord}' already exists in vocab.");
@ -523,8 +592,8 @@ namespace WordsToolkit.Scripts.NLP
Buffer.BlockCopy(oldBuf, 0, newBuf, 0, oldElems * sizeof(float));
Buffer.BlockCopy(newVector,0, newBuf, oldElems * sizeof(float), dim * sizeof(float));
// Sentis requires a nongeneric NativeTensorArrayFromManagedArray
// Sentis requires (Array, bytesPerElem, length, channels)
// Inference Engine requires a nongeneric NativeTensorArrayFromManagedArray
// Inference Engine requires (Array, bytesPerElem, length, channels)
// ctor args: (Array data, int srcElementOffset, int srcElementSize, int numDestElement)
var newWeights = new NativeTensorArrayFromManagedArray(
newBuf, // managed float[]
@ -638,7 +707,7 @@ namespace WordsToolkit.Scripts.NLP
if (string.IsNullOrEmpty(inputSymbols))
return new List<string>();
inputSymbols = inputSymbols.ToLower();
inputSymbols = NormalizeText(inputSymbols);
Dictionary<char, int> charCounts = new Dictionary<char, int>();
foreach (char c in inputSymbols)
{
@ -702,7 +771,8 @@ namespace WordsToolkit.Scripts.NLP
if (string.IsNullOrEmpty(inputSymbols))
return null;
var symbolSet = new HashSet<char>(inputSymbols.ToLower());
inputSymbols = NormalizeText(inputSymbols);
var symbolSet = new HashSet<char>(inputSymbols);
var bestMatches = wordToIndexByLanguage[language].Keys
.Select(word => new {
@ -855,7 +925,7 @@ namespace WordsToolkit.Scripts.NLP
/// <param name="language">Language to clear, or null to clear all</param>
public void ClearCustomWordsCache(string language = null)
{
string customDir = Path.Combine(Application.dataPath, "WordsToolkit", "model", "custom");
string customDir = Path.Combine(Application.dataPath, "StreamingAssets", "WordConnectGameToolkit", "model", "custom");
if (!Directory.Exists(customDir))
return;

View File

@ -11,14 +11,9 @@
// // THE SOFTWARE.
using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.Serialization;
using WordsToolkit.Scripts.Audio;
using WordsToolkit.Scripts.Data;
using WordsToolkit.Scripts.Enums;
using WordsToolkit.Scripts.GUI;
using WordsToolkit.Scripts.GUI.Labels;
using WordsToolkit.Scripts.Services;
using WordsToolkit.Scripts.Services.IAP;
using WordsToolkit.Scripts.Settings;
using WordsToolkit.Scripts.System;
@ -31,6 +26,8 @@ namespace WordsToolkit.Scripts.Popups
private CoinsShopSettings shopSettings;
public ProductID noAdsProduct;
[SerializeField]
public TextMeshProUGUI noAdsPriceText;
[SerializeField]
private AudioClip coinsSound;
private void OnEnable()
@ -49,11 +46,14 @@ namespace WordsToolkit.Scripts.Popups
}
EventManager.GetEvent<string>(EGameEvent.PurchaseSucceeded).Subscribe(PurchaseSucceded);
EventManager.GetEvent<(string, string)>(EGameEvent.PurchaseFailed).Subscribe(PurchaseFailed);
// Update NoAds price display
UpdateNoAdsPriceDisplay();
}
private void OnDisable()
protected override void OnDisable()
{
base.OnDisable();
EventManager.GetEvent<string>(EGameEvent.PurchaseSucceeded).Unsubscribe(PurchaseSucceded);
}
@ -86,44 +86,6 @@ namespace WordsToolkit.Scripts.Popups
}
}
private void PurchaseFailed((string, string) info)
{
var productId = info.Item1;
var errorMessage = info.Item2;
var errorType = IAPErrorHelper.ParseError(errorMessage);
Debug.LogWarning($"Purchase failed for product {productId}: {errorMessage}, Error Type: {errorType}");
switch (errorType)
{
case IAPErrorType.InvalidProductID:
Debug.LogError($"Invalid product ID: {productId}");
ShowErrorMessage("Invalid product ID. Please try again later.");
break;
case IAPErrorType.UserCancelled:
Debug.LogWarning("Purchase cancelled by user.");
break;
case IAPErrorType.DuplicateTransaction:
Debug.LogWarning($"Duplicate transaction for product {productId}. This usually means the purchase was already completed.");
break;
case IAPErrorType.IAPInitFailed:
Debug.LogError("IAP initialization failed. Please check your IAP settings.");
ShowErrorMessage("IAP initialization failed. Please try again later.");
break;
default:
ShowErrorMessage($"Payment failed: {errorMessage}");
break;
}
}
private void ShowErrorMessage(string message)
{
var popup = menuManager.ShowPopup<MessagePopup>();
if (popup != null)
{
popup.SetMessage(message);
}
}
public void BuyCoins(string id)
{
// StopInteration();
@ -133,5 +95,17 @@ namespace WordsToolkit.Scripts.Popups
iapManager.BuyProduct(id);
#endif
}
private void UpdateNoAdsPriceDisplay()
{
if (noAdsPriceText != null && noAdsProduct != null)
{
var localizedPrice = iapManager.GetProductLocalizedPriceString(noAdsProduct.ID);
if (!string.IsNullOrEmpty(localizedPrice))
{
noAdsPriceText.text = localizedPrice;
}
}
}
}
}

View File

@ -10,6 +10,8 @@
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using TMPro;
using UnityEngine;
using WordsToolkit.Scripts.Enums;
using WordsToolkit.Scripts.GUI;
using WordsToolkit.Scripts.GUI.Buttons;
@ -23,11 +25,16 @@ namespace WordsToolkit.Scripts.Popups
{
public CustomButton removeAdsButton;
public ProductID productID;
[SerializeField]
public TextMeshProUGUI priceText; // Add price display UI element
private void OnEnable()
{
removeAdsButton.onClick.AddListener(RemoveAds);
EventManager.GetEvent<string>(EGameEvent.PurchaseSucceeded).Subscribe(PurchaseSucceeded);
// Set localized price when popup opens
UpdatePriceDisplay();
}
protected override void OnDisable()
@ -49,5 +56,17 @@ namespace WordsToolkit.Scripts.Popups
{
iapManager.BuyProduct(productID.ID);
}
private void UpdatePriceDisplay()
{
if (priceText != null && productID != null)
{
var localizedPrice = iapManager.GetProductLocalizedPriceString(productID.ID);
if (!string.IsNullOrEmpty(localizedPrice))
{
priceText.text = localizedPrice;
}
}
}
}
}

View File

@ -18,6 +18,7 @@ using WordsToolkit.Scripts.GUI;
using WordsToolkit.Scripts.System;
using VContainer;
using WordsToolkit.Scripts.GUI.Buttons;
using WordsToolkit.Scripts.Services;
namespace WordsToolkit.Scripts.Popups
{
@ -26,6 +27,9 @@ namespace WordsToolkit.Scripts.Popups
[SerializeField]
private CustomButton privacypolicy;
[SerializeField]
private CustomButton googleUMPConsent;
[SerializeField]
private Button restorePurchase;
@ -38,6 +42,7 @@ namespace WordsToolkit.Scripts.Popups
protected virtual void OnEnable()
{
privacypolicy?.onClick.AddListener(PrivacyPolicy);
googleUMPConsent?.onClick.AddListener(ReconsiderGoogleUMPConsent);
LoadVibrationLevel();
vibrationSlider.onValueChanged.AddListener(SaveVibrationLevel);
closeButton.onClick.RemoveAllListeners();
@ -94,6 +99,14 @@ namespace WordsToolkit.Scripts.Popups
Close();
}
private void ReconsiderGoogleUMPConsent()
{
StopInteration();
DisablePause();
adsManager.ReconsiderUMPConsent();
Close();
}
private void DisablePause()
{
if (stateManager.CurrentState == EScreenStates.Game)

View File

@ -22,10 +22,11 @@ namespace WordsToolkit.Scripts.Services.Ads.AdUnits
public Action<string> OnShown { get; set; }
public Action<string> OnInitialized { get; set; }
public AdUnit(string placementId, AdReference adReference)
public AdUnit(string placementId, AdReference adReference, AdsHandlerBase adsHandler)
{
PlacementId = placementId;
AdReference = adReference;
AdsHandler = adsHandler;
}
public AdsHandlerBase AdsHandler { get; set; }

View File

@ -10,8 +10,14 @@
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
#if IRONSOURCE
using Unity.Services.LevelPlay;
#endif
using UnityEngine;
using WordsToolkit.Scripts.Services.Ads.AdUnits;
#if UMP_AVAILABLE
using GoogleMobileAds.Ump.Api;
#endif
namespace WordsToolkit.Scripts.Services.Ads.Networks
{
@ -19,14 +25,42 @@ namespace WordsToolkit.Scripts.Services.Ads.Networks
public class IronsourceAdsHandler : AdsHandlerBase
{
private IAdsListener _listener;
#if IRONSOURCE
private LevelPlayInterstitialAd _interstitialAd;
private LevelPlayRewardedAd _rewardedAd;
#endif
private void Init(string _id)
{
#if IRONSOURCE
IronSource.Agent.setManualLoadRewardedVideo(true);
IronSource.Agent.validateIntegration();
IronSource.Agent.init(_id);
LevelPlay.ValidateIntegration();
// Set consent for LevelPlay
SetConsentStatus();
// Register initialization events
LevelPlay.OnInitSuccess += SdkInitializationCompletedEvent;
LevelPlay.OnInitFailed += SdkInitializationFailedEvent;
LevelPlay.Init(_id);
#endif
}
private void SetConsentStatus()
{
#if IRONSOURCE && UMP_AVAILABLE
bool hasConsent = ConsentInformation.CanRequestAds();
Debug.Log($"LevelPlay consent status: {hasConsent}");
// Set consent for GDPR
LevelPlay.SetConsent(hasConsent);
// For CCPA compliance (optional)
LevelPlay.SetMetaData("do_not_sell", hasConsent ? "false" : "true");
#elif IRONSOURCE
// Default to no consent if UMP not available
LevelPlay.SetConsent(false);
Debug.Log("UMP not available - setting LevelPlay consent to false");
#endif
}
@ -34,78 +68,121 @@ namespace WordsToolkit.Scripts.Services.Ads.Networks
{
_listener = listener;
Debug.Log(_listener);
#if IRONSOURCE
//Add Rewarded Video Events
IronSourceInterstitialEvents.onAdReadyEvent += OnInterstitialAdReady;
IronSourceInterstitialEvents.onAdLoadFailedEvent += InterstitialAdLoadFailedEvent;
IronSourceRewardedVideoEvents.onAdReadyEvent += OnRewardedVideoAdReady;
IronSourceRewardedVideoEvents.onAdLoadFailedEvent += RewardedVideoAdShowFailedEvent;
IronSourceRewardedVideoEvents.onAdRewardedEvent += Rewardeded;
IronSourceEvents.onSdkInitializationCompletedEvent += SdkInitializationCompletedEvent;
#endif
}
#if IRONSOURCE
private void Rewardeded(IronSourcePlacement obj, IronSourceAdInfo ironSourceAdInfo)
private void SdkInitializationCompletedEvent(LevelPlayConfiguration config)
{
Debug.Log("Ironsource Rewardeded");
_listener?.OnAdsShowComplete();
}
private void SdkInitializationCompletedEvent()
{
Debug.Log("Ironsource SdkInitializationCompletedEvent");
Debug.Log("LevelPlay SdkInitializationCompletedEvent");
_listener?.OnAdsInitialized();
}
private void InterstitialAdLoadFailedEvent(IronSourceError obj)
private void SdkInitializationFailedEvent(LevelPlayInitError error)
{
Debug.Log("Ironsource InterstitialAdLoadFailedEvent " + obj.getCode() + " " + obj.getDescription());
Debug.Log($"LevelPlay SdkInitializationFailedEvent: {error}");
_listener?.OnInitFailed();
}
// Interstitial event handlers
private void InterstitialAdLoadedEvent(LevelPlayAdInfo adInfo)
{
Debug.Log("LevelPlay OnInterstitialAdReady");
_listener?.OnAdsLoaded(adInfo.AdUnitId);
}
private void InterstitialAdLoadFailedEvent(LevelPlayAdError error)
{
Debug.Log($"LevelPlay InterstitialAdLoadFailedEvent: {error}");
_listener?.OnAdsLoadFailed();
}
private void RewardedVideoAdShowFailedEvent(IronSourceError obj)
private void InterstitialAdDisplayFailedEvent(LevelPlayAdInfo levelPlayAdInfo, LevelPlayAdError levelPlayAdError)
{
Debug.Log("1" + obj.getCode());
Debug.Log("2" + obj.getDescription());
Debug.Log("Ironsource RewardedVideoAdShowFailedEvent " + obj.getCode() + " " + obj.getDescription());
Debug.Log(_listener);
Debug.Log($"LevelPlay InterstitialAdDisplayFailedEvent: {levelPlayAdError}");
_listener?.OnAdsShowFailed();
LevelPlay.SetPauseGame(false);
}
private void OnRewardedVideoAdReady(IronSourceAdInfo obj)
#if LEVELPLAY8
private void InterstitialAdDisplayFailedEvent(LevelPlayAdDisplayInfoError obj)
{
Debug.Log("Ironsource OnRewardedVideoAdReady");
_listener?.OnAdsLoaded(obj.instanceId);
}
private void OnInterstitialAdReady(IronSourceAdInfo obj)
{
Debug.Log("Ironsource OnInterstitialAdReady");
_listener?.OnAdsLoaded(obj.instanceId);
Debug.Log($"LevelPlay InterstitialAdDisplayFailedEvent: {obj}");
_listener?.OnAdsShowFailed();
LevelPlay.SetPauseGame(false);
}
#endif
// Rewarded video event handlers
private void RewardedAdLoadedEvent(LevelPlayAdInfo adInfo)
{
Debug.Log("LevelPlay OnRewardedVideoAdReady");
_listener?.OnAdsLoaded(adInfo.AdUnitId);
}
private void RewardedAdLoadFailedEvent(LevelPlayAdError error)
{
Debug.Log($"LevelPlay RewardedVideoAdLoadFailedEvent: {error}");
_listener?.OnAdsLoadFailed();
}
private void RewardedAdDisplayFailedEvent(LevelPlayAdInfo levelPlayAdInfo, LevelPlayAdError levelPlayAdError)
{
Debug.Log($"LevelPlay RewardedVideoAdShowFailedEvent: {levelPlayAdError}");
_listener?.OnAdsShowFailed();
LevelPlay.SetPauseGame(false);
}
#if LEVELPLAY8
private void RewardedAdDisplayFailedEvent(LevelPlayAdDisplayInfoError obj)
{
Debug.Log($"LevelPlay RewardedAdDisplayFailedEvent: {obj}");
_listener?.OnAdsShowFailed();
LevelPlay.SetPauseGame(false);
}
#endif
private void RewardedAdRewardedEvent(LevelPlayAdInfo adInfo, LevelPlayReward reward)
{
Debug.Log("LevelPlay Rewarded");
_listener?.OnAdsShowComplete();
LevelPlay.SetPauseGame(false);
}
private void InterstitialDisplayedEvent(LevelPlayAdInfo obj)
{
Debug.Log("LevelPlay InterstitialDisplayedEvent");
_listener?.OnAdsShowStart();
LevelPlay.SetPauseGame(false);
}
#endif
public override void Init(string _id, bool adSettingTestMode, IAdsListener listener)
{
Debug.Log("Ironsource Init");
Debug.Log("LevelPlay Init");
Init(_id);
Debug.Log("Ironsource SetListener");
Debug.Log("LevelPlay SetListener");
SetListener(listener);
}
public override void Show(AdUnit adUnit)
{
#if IRONSOURCE
if (adUnit.AdReference.adType == EAdType.Interstitial)
if (adUnit.AdReference.adType == EAdType.Interstitial && _interstitialAd != null)
{
IronSource.Agent.showInterstitial();
if (_interstitialAd.IsAdReady())
{
_interstitialAd.ShowAd();
LevelPlay.SetPauseGame(true);
}
}
else if (adUnit.AdReference.adType == EAdType.Rewarded)
else if (adUnit.AdReference.adType == EAdType.Rewarded && _rewardedAd != null)
{
IronSource.Agent.showRewardedVideo();
if (_rewardedAd.IsAdReady())
{
_rewardedAd.ShowAd();
LevelPlay.SetPauseGame(true);
}
}
_listener?.Show(adUnit);
@ -117,26 +194,43 @@ namespace WordsToolkit.Scripts.Services.Ads.Networks
#if IRONSOURCE
if (adUnit.AdReference.adType == EAdType.Interstitial)
{
IronSource.Agent.loadInterstitial();
_interstitialAd = new LevelPlayInterstitialAd(adUnit.PlacementId);
_interstitialAd.OnAdLoaded += InterstitialAdLoadedEvent;
_interstitialAd.OnAdDisplayed += InterstitialDisplayedEvent;
_interstitialAd.OnAdLoadFailed += InterstitialAdLoadFailedEvent;
_interstitialAd.OnAdDisplayFailed += InterstitialAdDisplayFailedEvent;
_interstitialAd.LoadAd();
}
else if (adUnit.AdReference.adType == EAdType.Rewarded)
{
IronSource.Agent.loadRewardedVideo();
_rewardedAd = new LevelPlayRewardedAd(adUnit.PlacementId);
_rewardedAd.OnAdLoaded += RewardedAdLoadedEvent;
_rewardedAd.OnAdLoadFailed += RewardedAdLoadFailedEvent;
_rewardedAd.OnAdDisplayFailed += RewardedAdDisplayFailedEvent;
_rewardedAd.OnAdRewarded += RewardedAdRewardedEvent;
_rewardedAd.LoadAd();
}
#endif
}
public override bool IsAvailable(AdUnit adUnit)
{
#if IRONSOURCE
if (adUnit.AdReference.adType == EAdType.Interstitial)
{
return IronSource.Agent.isInterstitialReady();
return _interstitialAd != null && _interstitialAd.IsAdReady();
}
if (adUnit.AdReference.adType == EAdType.Rewarded)
{
return IronSource.Agent.isRewardedVideoAvailable();
return _rewardedAd != null && _rewardedAd.IsAdReady();
}
#endif
return false;

View File

@ -10,6 +10,9 @@
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
#if IRONSOURCE
using Unity.Services.LevelPlay;
#endif
using UnityEngine;
using WordsToolkit.Scripts.Services.Ads.AdUnits;
@ -19,65 +22,100 @@ namespace WordsToolkit.Scripts.Services.Ads.Networks
public class IronsourceBannerHandler : AdsHandlerBase
{
private IAdsListener _listener;
#if IRONSOURCE
private LevelPlayBannerAd _bannerAd;
private LevelPlayBannerAd.Config.Builder configBuilder;
#endif
private void Init(string _id)
{
#if IRONSOURCE
IronSource.Agent.validateIntegration();
IronSource.Agent.init(_id);
LevelPlay.ValidateIntegration();
LevelPlay.Init(_id);
#endif
}
private void SetListener(IAdsListener listener)
{
_listener = listener;
#if IRONSOURCE
IronSourceBannerEvents.onAdLoadedEvent += BannerAdLoadedEvent;
IronSourceBannerEvents.onAdLoadFailedEvent += BannerAdLoadFailedEvent;
IronSourceBannerEvents.onAdClickedEvent += BannerAdClickedEvent;
IronSourceBannerEvents.onAdScreenPresentedEvent += BannerAdScreenPresentedEvent;
IronSourceBannerEvents.onAdScreenDismissedEvent += BannerAdScreenDismissedEvent;
IronSourceBannerEvents.onAdLeftApplicationEvent += BannerAdLeftApplicationEvent;
#endif
}
#if IRONSOURCE
private void BannerAdLoadedEvent(IronSourceAdInfo adInfo)
private void BannerAdLoadedEvent(LevelPlayAdInfo adInfo)
{
Debug.Log("IronSource Banner ad loaded");
_listener?.OnAdsLoaded(adInfo.instanceId);
Debug.Log("LevelPlay Banner ad loaded");
_listener?.OnAdsLoaded(adInfo.AdUnitId);
}
private void BannerAdLoadFailedEvent(IronSourceError error)
private void BannerAdLoadFailedEvent(LevelPlayAdError error)
{
Debug.Log($"IronSource Banner ad load failed. Error: {error.getCode()} - {error.getDescription()}");
Debug.Log($"LevelPlay Banner ad load failed. Error: {error}");
_listener?.OnAdsLoadFailed();
}
private void BannerAdClickedEvent(IronSourceAdInfo adInfo)
private void BannerAdClickedEvent(LevelPlayAdInfo adInfo)
{
Debug.Log("IronSource Banner ad clicked");
Debug.Log("LevelPlay Banner ad clicked");
}
private void BannerAdScreenPresentedEvent(IronSourceAdInfo adInfo)
private void BannerAdDisplayedEvent(LevelPlayAdInfo adInfo)
{
Debug.Log("IronSource Banner ad screen presented");
Debug.Log("LevelPlay Banner ad displayed");
}
private void BannerAdScreenDismissedEvent(IronSourceAdInfo adInfo)
private void BannerAdDisplayFailedEvent(LevelPlayAdInfo levelPlayAdInfo, LevelPlayAdError levelPlayAdError)
{
Debug.Log("IronSource Banner ad screen dismissed");
Debug.Log($"LevelPlay Banner ad display failed. Error: {levelPlayAdError}");
}
private void BannerAdLeftApplicationEvent(IronSourceAdInfo adInfo)
#if LEVELPLAY8
private void BannerAdDisplayFailedEvent(LevelPlayAdDisplayInfoError error)
{
Debug.Log("IronSource Banner ad caused app to leave");
Debug.Log($"LevelPlay Banner ad display failed. Error: {error}");
}
#endif
private void BannerAdLeftApplicationEvent(LevelPlayAdInfo adInfo)
{
Debug.Log("LevelPlay Banner ad caused app to leave");
}
private LevelPlayBannerAd GetBannerAd(AdUnit adUnit)
{
configBuilder ??= new LevelPlayBannerAd.Config.Builder();
#if LEVELPLAY9
configBuilder.SetSize(LevelPlayAdSize.BANNER);
#elif LEVELPLAY8
configBuilder.SetSize(com.unity3d.mediation.LevelPlayAdSize.BANNER);
#endif
#if LEVELPLAY9
configBuilder.SetPosition(LevelPlayBannerPosition.BottomCenter);
#elif LEVELPLAY8
configBuilder.SetPosition(com.unity3d.mediation.LevelPlayBannerPosition.BottomCenter);
#endif
configBuilder.SetDisplayOnLoad(true);
#if UNITY_ANDROID
configBuilder.SetRespectSafeArea(true); // Only relevant for Android
#endif
configBuilder.SetPlacementName("bannerPlacement");
configBuilder.SetBidFloor(1.0); // Minimum bid price in USD
var bannerConfig = configBuilder.Build();
var bannerAd = new LevelPlayBannerAd(adUnit.PlacementId, bannerConfig);
bannerAd.OnAdLoaded += BannerAdLoadedEvent;
bannerAd.OnAdLoadFailed += BannerAdLoadFailedEvent;
bannerAd.OnAdClicked += BannerAdClickedEvent;
bannerAd.OnAdDisplayed += BannerAdDisplayedEvent;
bannerAd.OnAdDisplayFailed += BannerAdDisplayFailedEvent;
bannerAd.OnAdLeftApplication += BannerAdLeftApplicationEvent;
return bannerAd;
}
#endif
public override void Init(string _id, bool adSettingTestMode, IAdsListener listener)
{
Debug.Log("IronSource Banner Init");
Debug.Log("LevelPlay Banner Init");
Init(_id);
SetListener(listener);
}
@ -85,22 +123,23 @@ namespace WordsToolkit.Scripts.Services.Ads.Networks
public override void Show(AdUnit adUnit)
{
#if IRONSOURCE
if (adUnit.AdReference.adType == EAdType.Banner)
if (_bannerAd == null)
{
IronSource.Agent.displayBanner();
_bannerAd = GetBannerAd(adUnit);
}
if (adUnit.AdReference.adType == EAdType.Banner && _bannerAd != null)
{
_bannerAd.ShowAd();
_listener?.Show(adUnit);
}
#endif
}
public override void Load(AdUnit adUnit)
{
#if IRONSOURCE
if (adUnit.AdReference.adType == EAdType.Banner)
{
IronSourceBannerSize bannerSize = IronSourceBannerSize.BANNER;
IronSource.Agent.loadBanner(bannerSize, IronSourceBannerPosition.BOTTOM);
}
_bannerAd.LoadAd();
#endif
}
@ -114,9 +153,9 @@ namespace WordsToolkit.Scripts.Services.Ads.Networks
public override void Hide(AdUnit adUnit)
{
#if IRONSOURCE
if (adUnit.AdReference.adType == EAdType.Banner)
if (adUnit.AdReference.adType == EAdType.Banner && _bannerAd != null)
{
IronSource.Agent.hideBanner();
_bannerAd.HideAd();
}
#endif
}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 655355652c9a644febf26cd1a5869bf4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,33 @@
{
"name": "CandySmith.LevelPlay",
"rootNamespace": "",
"references": [
"GUID:00dd4a7ac8c24c898083910c81898ecc",
"GUID:760a4c7888534400e882b82c5b3fba06"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [
{
"name": "com.unity.services.levelplay",
"expression": "[0.0,9.0)",
"define": "LEVELPLAY8"
},
{
"name": "com.unity.services.levelplay",
"expression": "9.0.0",
"define": "LEVELPLAY9"
},
{
"name": "com.unity.services.levelplay",
"expression": "",
"define": "IRONSOURCE"
}
],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 537e7a60660d24526a2d6a89f5f68492
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -12,7 +12,9 @@
using UnityEngine;
using WordsToolkit.Scripts.Services.Ads.AdUnits;
#if UMP_AVAILABLE
using GoogleMobileAds.Ump.Api;
#endif
namespace WordsToolkit.Scripts.Services.Ads.Networks
{
#if UNITY_ADS
@ -28,10 +30,33 @@ namespace WordsToolkit.Scripts.Services.Ads.Networks
public override void Init(string _id, bool adSettingTestMode, IAdsListener listener)
{
SetConsentStatus();
Advertisement.Initialize(_id, adSettingTestMode, this);
this.listener = listener;
}
private void SetConsentStatus()
{
#if UNITY_ADS && UMP_AVAILABLE
bool hasConsent = ConsentInformation.CanRequestAds();
Debug.Log($"Unity Ads consent status: {hasConsent}");
var consentMetaData = new MetaData("gdpr");
consentMetaData.Set("consent", hasConsent);
Advertisement.SetMetaData(consentMetaData);
var privacyMetaData = new MetaData("privacy");
privacyMetaData.Set("mode", "mixed");
Advertisement.SetMetaData(privacyMetaData);
#elif UNITY_ADS
// Default to no consent if UMP not available
var consentMetaData = new MetaData("gdpr");
consentMetaData.Set("consent", false);
Advertisement.SetMetaData(consentMetaData);
Debug.Log("UMP not available - setting Unity Ads consent to false");
#endif
}
public override void Show(AdUnit adUnit)
{
Advertisement.Show(adUnit.PlacementId, this);

View File

@ -12,14 +12,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using VContainer;
using WordConnectGameToolkit.Scripts.Settings;
using WordsToolkit.Scripts.Popups;
using WordsToolkit.Scripts.Services.Ads;
using WordsToolkit.Scripts.Services.Ads.AdUnits;
using WordsToolkit.Scripts.Services.IAP;
using WordsToolkit.Scripts.Settings;
using WordsToolkit.Scripts.System;
#if UMP_AVAILABLE
using GoogleMobileAds.Ump.Api;
#endif
namespace WordsToolkit.Scripts.Services
{
@ -29,6 +34,8 @@ namespace WordsToolkit.Scripts.Services
private readonly List<AdUnit> adUnits = new();
private readonly Dictionary<AdUnit, IAdLifecycleManager> lifecycleManagers = new();
private EPlatforms platforms;
private bool consentInfoUpdateInProgress = false;
private bool adsInitialized = false;
[Inject]
private GameSettings gameSettings;
@ -38,6 +45,8 @@ namespace WordsToolkit.Scripts.Services
[SerializeField]
private ProductID noAdsProduct;
private InterstitialSettings interstitialSettings;
private AdSetting[] adElements;
private void Awake()
{
@ -45,9 +54,86 @@ namespace WordsToolkit.Scripts.Services
{
return;
}
interstitialSettings = Resources.Load<InterstitialSettings>("Settings/AdsInterstitialSettings");
adElements = Resources.Load<AdsSettings>("Settings/AdsSettings").adProfiles;
StartConsentFlow();
}
private void StartConsentFlow()
{
if (consentInfoUpdateInProgress) return;
consentInfoUpdateInProgress = true;
#if UMP_AVAILABLE && (UNITY_ANDROID || UNITY_IOS)
var request = new ConsentRequestParameters();
if (Debug.isDebugBuild || Application.isEditor)
{
var debugSettings = new ConsentDebugSettings
{
DebugGeography = DebugGeography.EEA
};
var testDeviceIds = new List<string>();
// testDeviceIds.Add("YOUR-TEST-DEVICE-ID-HERE"); // Uncomment and add your device ID if needed
if (testDeviceIds.Count > 0)
{
debugSettings.TestDeviceHashedIds = testDeviceIds;
}
request.ConsentDebugSettings = debugSettings;
}
ConsentInformation.Update(request, OnConsentInfoUpdated);
#else
InitializeAds();
#endif
}
#if UMP_AVAILABLE
private void OnConsentInfoUpdated(FormError consentError)
{
consentInfoUpdateInProgress = false;
if (consentError != null)
{
Debug.LogError($"Consent info update failed: {consentError}");
InitializeAds();
return;
}
ConsentForm.LoadAndShowConsentFormIfRequired(OnConsentFormDismissed);
}
private void OnConsentFormDismissed(FormError formError)
{
if (formError != null)
{
Debug.LogError($"Consent form error: {formError}");
}
if (ConsentInformation.CanRequestAds())
{
InitializeAds();
RefreshBannerAds();
}
else
{
Debug.Log("User denied consent or consent not available");
InitializeAds();
}
}
#endif
private void InitializeAds()
{
if (adsInitialized) return;
adsInitialized = true;
platforms = GetPlatform();
var adElements = Resources.Load<AdsSettings>("Settings/AdsSettings").adProfiles;
foreach (var t in adElements)
{
if (t.platforms == platforms && t.enable)
@ -60,7 +146,7 @@ namespace WordsToolkit.Scripts.Services
adList.Add(t);
foreach (var adElement in t.adElements)
{
var adUnit = new AdUnit(adElement.placementId, adElement.adReference);
var adUnit = new AdUnit(adElement.placementId, adElement.adReference, t.adsHandler);
var lifecycleManager = new AdLifecycleManager(t.adsHandler);
lifecycleManagers[adUnit] = lifecycleManager;
adUnits.Add(adUnit);
@ -119,26 +205,72 @@ namespace WordsToolkit.Scripts.Services
private void OnPopupTrigger(Popup popup, bool open)
{
if (IsNoAdsPurchased())
if (IsNoAdsPurchased() || !CanShowAds())
{
return;
}
// Get current level number
int currentLevel = GameDataManager.GetLevelNum();
// Check interstitial ads using InterstitialSettings
if (interstitialSettings != null && interstitialSettings.interstitials != null)
{
foreach (var interstitialElement in interstitialSettings.interstitials)
{
// Check if this interstitial should trigger based on popup
if (((open && interstitialElement.showOnOpen) || (!open && interstitialElement.showOnClose))
&& popup.GetType() == interstitialElement.popup.GetType())
{
var adUnit = adUnits.Find(i => i.AdReference == interstitialElement.adReference);
if (adUnit == null || !adUnit.IsAvailable())
{
adUnit?.Load();
continue;
}
// Check level conditions
if (!IsLevelConditionMet(currentLevel, interstitialElement))
{
continue;
}
// Find placement ID for frequency tracking
string placementId = GetPlacementIdForAdReference(interstitialElement.adReference);
if (placementId == null) continue;
if (!IsFrequencyConditionMet(placementId, interstitialElement.frequency))
{
continue;
}
adUnit.Show();
adUnit.Load();
IncrementAdFrequency(placementId);
return;
}
}
}
// Handle non-interstitial ads (banners, rewarded) using the original logic
foreach (var ad in adList)
{
foreach (var adElement in ad.adElements)
{
if (adElement.adReference.adType == EAdType.Interstitial)
continue; // Skip interstitials as they're handled above
var adUnit = adUnits.Find(i => i.AdReference == adElement.adReference);
if (!lifecycleManagers[adUnit].IsAvailable(adUnit))
if (!adUnit.IsAvailable())
{
lifecycleManagers[adUnit].Load(adUnit);
adUnit.Load();
continue;
}
if (((open && adElement.popup.showOnOpen) || (!open && adElement.popup.showOnClose)) && popup.GetType() == adElement.popup.popup.GetType())
{
lifecycleManagers[adUnit].Show(adUnit);
lifecycleManagers[adUnit].Load(adUnit);
adUnit.Show();
adUnit.Load();
return;
}
}
@ -152,19 +284,48 @@ namespace WordsToolkit.Scripts.Services
public void ShowAdByType(AdReference adRef, Action<string> shown)
{
if (!gameSettings.enableAds)
if (!gameSettings.enableAds || !CanShowAds())
{
shown?.Invoke(null);
return;
}
int currentLevel = GameDataManager.GetLevelNum();
foreach (var adUnit in adUnits)
{
if (adUnit.AdReference == adRef && lifecycleManagers[adUnit].IsAvailable(adUnit))
if (adUnit.AdReference == adRef && adUnit.IsAvailable())
{
// Check level conditions for interstitial ads using InterstitialSettings
if (adRef.adType == EAdType.Interstitial && interstitialSettings != null)
{
var interstitialElement = interstitialSettings.interstitials?.FirstOrDefault(i => i.adReference == adRef);
if (interstitialElement != null)
{
if (!IsLevelConditionMet(currentLevel, interstitialElement))
{
shown?.Invoke(null);
return;
}
string placementId = GetPlacementIdForAdReference(adRef);
if (placementId != null)
{
if (!IsFrequencyConditionMet(placementId, interstitialElement.frequency))
{
shown?.Invoke(null);
return;
}
// Increment frequency counter
IncrementAdFrequency(placementId);
}
}
}
adUnit.OnShown = shown;
lifecycleManagers[adUnit].Show(adUnit);
lifecycleManagers[adUnit].Load(adUnit);
adUnit.Show();
adUnit.Load();
return;
}
}
@ -193,5 +354,70 @@ namespace WordsToolkit.Scripts.Services
}
}
}
private bool IsLevelConditionMet(int currentLevel, InterstitialAdElement popupSetting)
{
return currentLevel >= popupSetting.minLevel && currentLevel <= popupSetting.maxLevel;
}
private bool IsFrequencyConditionMet(string placementId, int frequency)
{
if (frequency <= 1) return true; // Always show if frequency is 1 or less
int adShowCount = PlayerPrefs.GetInt($"AdCount_{placementId}", 0);
return adShowCount % frequency == 0;
}
private void IncrementAdFrequency(string placementId)
{
int currentCount = PlayerPrefs.GetInt($"AdCount_{placementId}", 0);
PlayerPrefs.SetInt($"AdCount_{placementId}", currentCount + 1);
PlayerPrefs.Save();
}
private string GetPlacementIdForAdReference(AdReference adRef)
{
foreach (var ad in adList)
{
foreach (var adElement in ad.adElements)
{
if (adElement.adReference == adRef)
{
return adElement.placementId;
}
}
}
return null;
}
private bool CanShowAds()
{
#if UMP_AVAILABLE
return ConsentInformation.CanRequestAds();
#else
return true;
#endif
}
public void RefreshBannerAds()
{
if (!CanShowAds() || IsNoAdsPurchased()) return;
foreach (var adUnit in adUnits)
{
if (adUnit.AdReference.adType == EAdType.Banner)
{
lifecycleManagers[adUnit].Show(adUnit);
}
}
}
public void ReconsiderUMPConsent()
{
#if UMP_AVAILABLE && (UNITY_ANDROID || UNITY_IOS)
ConsentInformation.Reset();
#endif
StartConsentFlow();
}
}
}

View File

@ -25,7 +25,6 @@ namespace WordsToolkit.Scripts.Services.IAP
private IExtensionProvider extensionProvider;
public static event Action<string> OnSuccessfulPurchase;
public static event Action<(string,string)> OnFailedPurchase;
public static event Action<bool, List<string>> OnRestorePurchasesFinished;
public void InitializePurchasing(IEnumerable<(string productId, ProductTypeWrapper.ProductType productType)> products)
@ -112,24 +111,20 @@ namespace WordsToolkit.Scripts.Services.IAP
{
Debug.Log(string.Format("Purchasing product asychronously: '{0}'", product.definition.id));
storeController.InitiatePurchase(product);
OnFailedPurchase?.Invoke((productId, "Product not found or not available for purchase.")); // debug only
}
else
{
Debug.Log($"BuyProductID: FAIL. Not purchasing product, either is not found or is not available for purchase {productId}");
OnFailedPurchase?.Invoke((productId, "InvalidProductID: product not found or not available for purchase."));
}
}
else
{
Debug.Log("IAPInitFailed: BuyProductID FAIL. Not initialized.");
OnFailedPurchase?.Invoke((productId, "IAPInitFailed: Not initialized."));
Debug.Log("BuyProductID FAIL. Not initialized.");
}
}
catch (Exception e)
{
Debug.Log("BuyProductID: FAIL. Exception during purchase. " + e);
OnFailedPurchase?.Invoke((productId, "Exception during purchase: " + e.Message));
}
}
@ -164,13 +159,11 @@ namespace WordsToolkit.Scripts.Services.IAP
public void OnPurchaseFailed(Product product, PurchaseFailureDescription failureDescription)
{
Debug.Log("OnPurchaseFailed: FAIL. Product: " + product.definition.id + " PurchaseFailureDescription: " + failureDescription);
OnFailedPurchase?.Invoke((product.definition.id, failureDescription.message));
}
public void OnPurchaseFailed(Product i, PurchaseFailureReason p)
{
Debug.Log($"OnPurchaseFailed: FAIL. Product: '{i.definition.id}', PurchaseFailureReason: {p}");
OnFailedPurchase?.Invoke((i.definition.id, p.ToString()));
}
public void OnInitializeFailed(InitializationFailureReason reason)

View File

@ -50,18 +50,12 @@ namespace WordsToolkit.Scripts.Services.IAP
IAPController.OnSuccessfulPurchase += purchaseHandler;
#endif
}
public void SubscribeToPurchaseFailedEvent(Action<(string, string)> purchaseHandler)
{
#if UNITY_PURCHASING
IAPController.OnFailedPurchase += purchaseHandler;
#endif
}
public void UnsubscribeFromPurchaseEvent(Action<string> purchaseHandler)
{
#if UNITY_PURCHASING
#if UNITY_PURCHASING
IAPController.OnSuccessfulPurchase -= purchaseHandler;
#endif
#endif
}
public void BuyProduct(string productId)

View File

@ -13,8 +13,6 @@ namespace WordsToolkit.Scripts.Services.IAP
bool IsProductPurchased(string productId);
void RestorePurchases(Action<bool, List<string>> action);
void SubscribeToPurchaseEvent(Action<string> purchaseHandler);
void SubscribeToPurchaseFailedEvent(Action<(string, string)> purchaseHandler);
void UnsubscribeFromPurchaseEvent(Action<string> purchaseHandler);
}
}

View File

@ -21,5 +21,6 @@ namespace WordsToolkit.Scripts.Services
bool IsRewardedAvailable(AdReference adRef);
void RemoveAds();
bool IsNoAdsPurchased();
void ReconsiderUMPConsent();
}
}

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

Some files were not shown because too many files have changed in this diff Show More