Skip to content

Commit 5b33540

Browse files
committed
Merge branch 'main' into fs/hiro-inventory
2 parents 963a8d9 + be5121a commit 5b33540

File tree

1,932 files changed

+200683
-31
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,932 files changed

+200683
-31
lines changed

UnityHiroChallenges/.gitignore

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
2+
# Created by https://www.gitignore.io/api/unity
3+
# Edit at https://www.gitignore.io/?templates=unity
4+
5+
# Jetbrain Rider Cache
6+
.idea/
7+
Assets/Plugins/Editor/JetBrains*
8+
9+
# Visual Studio Code
10+
.vscode/
11+
12+
13+
### Unity ###
14+
/[Ll]ibrary/
15+
/[Tt]emp/
16+
/[Oo]bj/
17+
/[Bb]uild/
18+
/[Bb]uilds/
19+
/[Ll]ogs/
20+
/[Uu]ser[Ss]ettings/
21+
Assets/AssetStoreTools*
22+
# Unity local user project setting
23+
UserSettings/
24+
25+
# Visual Studio cache directory
26+
.vs/
27+
28+
# Autogenerated VS/MD/Consulo solution and project files
29+
ExportedObj/
30+
.consulo/
31+
*.csproj
32+
*.unityproj
33+
*.sln
34+
*.suo
35+
*.tmp
36+
*.user
37+
*.userprefs
38+
*.pidb
39+
*.booproj
40+
*.svd
41+
*.pdb
42+
*.opendb
43+
*.VC.db
44+
45+
# Unity3D generated meta files
46+
*.pidb.meta
47+
*.pdb.meta
48+
49+
# Unity3D Generated File On Crash Reports
50+
sysinfo.txt
51+
52+
# Builds
53+
*.apk
54+
*.unitypackage
55+
56+
# End of https://www.gitignore.io/api/unity

UnityHiroChallenges/Assets/UnityHiroChallenges.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

UnityHiroChallenges/Assets/UnityHiroChallenges/Editor.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using Nakama;
5+
using Hiro;
6+
using Hiro.Unity;
7+
using UnityEditor;
8+
using UnityEngine;
9+
using UnityEngine.SceneManagement;
10+
using UnityEngine.UIElements;
11+
12+
namespace HiroChallenges.Editor
13+
{
14+
public class AccountSwitcherEditor : EditorWindow
15+
{
16+
[SerializeField] private VisualTreeAsset tree;
17+
18+
private DropdownField accountDropdown;
19+
private Label usernamesLabel;
20+
21+
private readonly SortedDictionary<string, string> accountUsernames = new();
22+
23+
private const string AccountUsernamesKey = "AccountSwitcher_Usernames";
24+
25+
[MenuItem("Tools/Nakama/Account Switcher")]
26+
public static void ShowWindow()
27+
{
28+
var inspectorType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.InspectorWindow");
29+
var window = GetWindow<AccountSwitcherEditor>("Account Switcher", inspectorType);
30+
31+
window.Focus();
32+
}
33+
34+
[MenuItem("Tools/Nakama/Clear Test Accounts")]
35+
public static void ClearSavedAccounts()
36+
{
37+
EditorPrefs.DeleteKey(AccountUsernamesKey);
38+
Debug.Log("Cleared all saved account usernames");
39+
40+
// Refresh any open Account Switcher windows
41+
var windows = Resources.FindObjectsOfTypeAll<AccountSwitcherEditor>();
42+
foreach (var window in windows)
43+
{
44+
window.accountUsernames.Clear();
45+
window.UpdateUsernameLabels();
46+
}
47+
}
48+
49+
private void CreateGUI()
50+
{
51+
tree.CloneTree(rootVisualElement);
52+
53+
accountDropdown = rootVisualElement.Q<DropdownField>("account-dropdown");
54+
accountDropdown.RegisterValueChangedCallback(SwitchAccount);
55+
56+
usernamesLabel = rootVisualElement.Q<Label>("usernames");
57+
58+
// Load saved usernames on startup
59+
LoadAccountUsernames();
60+
UpdateUsernameLabels();
61+
62+
if (!EditorApplication.isPlaying) return;
63+
64+
var rootGameObjects = SceneManager.GetActiveScene().GetRootGameObjects();
65+
foreach (var rootGameObject in rootGameObjects)
66+
{
67+
if (!rootGameObject.TryGetComponent<HiroChallengesController>(out var challengesController)) continue;
68+
69+
if (HiroCoordinator.Instance.GetSystem<NakamaSystem>().Session is Session session)
70+
{
71+
OnControllerInitialized(session);
72+
}
73+
else
74+
{
75+
challengesController.OnInitialized += OnControllerInitialized;
76+
}
77+
}
78+
}
79+
80+
private void OnControllerInitialized(ISession session, HiroChallengesController challengesController = null)
81+
{
82+
accountUsernames[accountDropdown.choices[0]] = session.Username;
83+
UpdateUsernameLabels();
84+
85+
if (challengesController != null)
86+
{
87+
challengesController.OnInitialized -= OnControllerInitialized;
88+
}
89+
}
90+
91+
private void LoadAccountUsernames()
92+
{
93+
var savedUsernames = EditorPrefs.GetString(AccountUsernamesKey, "");
94+
if (string.IsNullOrEmpty(savedUsernames)) return;
95+
96+
try
97+
{
98+
var usernameData = JsonUtility.FromJson<SerializableStringDictionary>(savedUsernames);
99+
accountUsernames.Clear();
100+
101+
foreach (var item in usernameData.items)
102+
{
103+
accountUsernames[item.key] = item.value;
104+
}
105+
}
106+
catch (Exception ex)
107+
{
108+
Debug.LogWarning($"Failed to load saved account usernames: {ex.Message}");
109+
}
110+
}
111+
112+
private void SaveAccountUsernames()
113+
{
114+
try
115+
{
116+
var usernameData = new SerializableStringDictionary();
117+
foreach (var kvp in accountUsernames)
118+
{
119+
usernameData.items.Add(new SerializableKeyValuePair { key = kvp.Key, value = kvp.Value });
120+
}
121+
122+
var json = JsonUtility.ToJson(usernameData);
123+
EditorPrefs.SetString(AccountUsernamesKey, json);
124+
}
125+
catch (Exception ex)
126+
{
127+
Debug.LogWarning($"Failed to save account usernames: {ex.Message}");
128+
}
129+
}
130+
131+
private async void SwitchAccount(ChangeEvent<string> changeEvt)
132+
{
133+
if (!EditorApplication.isPlaying) return;
134+
135+
var previousValue = changeEvt.previousValue;
136+
var newValue = changeEvt.newValue;
137+
138+
var rootGameObjects = SceneManager.GetActiveScene().GetRootGameObjects();
139+
foreach (var rootGameObject in rootGameObjects)
140+
{
141+
if (!rootGameObject.TryGetComponent<HiroChallengesController>(out var challengesController)) continue;
142+
143+
var coordinator = HiroCoordinator.Instance as HiroChallengesCoordinator;
144+
if (coordinator == null) return;
145+
var nakamaSystem = coordinator.GetSystem<NakamaSystem>();
146+
147+
// Save username before switching
148+
if (!string.IsNullOrEmpty(previousValue))
149+
{
150+
accountUsernames[previousValue] = nakamaSystem.Session.Username;
151+
}
152+
153+
try
154+
{
155+
var newSession = await HiroChallengesCoordinator.NakamaAuthorizerFunc(accountDropdown.index)
156+
.Invoke(nakamaSystem.Client);
157+
(nakamaSystem.Session as Session)?.Update(newSession.AuthToken, newSession.RefreshToken);
158+
await nakamaSystem.RefreshAsync();
159+
accountUsernames[newValue] = newSession.Username;
160+
challengesController.SwitchComplete();
161+
162+
SaveAccountUsernames();
163+
break;
164+
}
165+
catch (ApiResponseException e)
166+
{
167+
Debug.LogWarning($"Error authenticating with Device ID: {e.Message}");
168+
return;
169+
}
170+
}
171+
172+
UpdateUsernameLabels();
173+
}
174+
175+
private void UpdateUsernameLabels()
176+
{
177+
var sb = new StringBuilder();
178+
var index = 1;
179+
180+
foreach (var kvp in accountUsernames)
181+
{
182+
sb.Append(index);
183+
sb.Append(": ");
184+
sb.Append(kvp.Value);
185+
sb.AppendLine();
186+
index++;
187+
}
188+
189+
usernamesLabel.text = sb.ToString();
190+
}
191+
192+
[Serializable]
193+
private class SerializableStringDictionary
194+
{
195+
public List<SerializableKeyValuePair> items = new();
196+
}
197+
198+
[Serializable]
199+
private class SerializableKeyValuePair
200+
{
201+
public string key;
202+
public string value;
203+
}
204+
}
205+
}

UnityHiroChallenges/Assets/UnityHiroChallenges/Editor/AccountSwitcher.cs.meta

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<ui:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" noNamespaceSchemaLocation="../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
2+
<ui:VisualElement style="flex-grow: 1; padding-top: 8px; padding-right: 8px; padding-bottom: 0; padding-left: 8px; align-items: stretch; justify-content: flex-start;">
3+
<ui:Label text="Nakama Account Switcher" style="-unity-text-align: upper-center; -unity-font-style: normal; font-size: 24px; margin-bottom: 4px; margin-top: 8px; -unity-font-definition: url(&quot;project://database/Assets/UnityNakamaFriends/HeroicUI/Fonts/Plus_Jakarta_Sans/static/PlusJakartaSans-Bold.ttf?fileID=12800000&amp;guid=b0eab255566194e3c923ef0f1d4571da&amp;type=3#PlusJakartaSans-Bold&quot;); white-space: normal;" />
4+
<ui:Label text="The Account Switcher lets you explore the project as different users without managing multiple builds.&#10;&#10;Use the dropdown to switch between up to four different test accounts. An account will be automatically created the first time you select it.&#10;&#10;Note: Account switching only works during play mode." style="white-space: normal; -unity-font-definition: url(&quot;project://database/Assets/UnityNakamaFriends/HeroicUI/Fonts/Plus_Jakarta_Sans/PlusJakartaSans-VariableFont_wght.ttf?fileID=12800000&amp;guid=fbe3b99011ddc4d419b127c34c0e03ab&amp;type=3#PlusJakartaSans-VariableFont_wght&quot;);" />
5+
<ui:VisualElement style="margin-top: 8px;" />
6+
<ui:DropdownField label="Choose account:" name="account-dropdown" index="0" choices="ACCOUNT 1,ACCOUNT 2,ACCOUNT 3,ACCOUNT 4" style="-unity-font-definition: url(&quot;project://database/Assets/UnityNakamaFriends/HeroicUI/Fonts/Plus_Jakarta_Sans/PlusJakartaSans-VariableFont_wght.ttf?fileID=12800000&amp;guid=fbe3b99011ddc4d419b127c34c0e03ab&amp;type=3#PlusJakartaSans-VariableFont_wght&quot;);" />
7+
<ui:VisualElement name="VisualElement" style="flex-grow: 1; height: 8px; align-items: center; justify-content: flex-start; align-self: flex-start; align-content: flex-start; margin-top: 8px;">
8+
<ui:Label text="Account Usernames" style="-unity-text-align: upper-center; -unity-font-style: bold; white-space: pre; -unity-font-definition: url(&quot;project://database/Assets/UnityNakamaFriends/HeroicUI/Fonts/Plus_Jakarta_Sans/PlusJakartaSans-VariableFont_wght.ttf?fileID=12800000&amp;guid=fbe3b99011ddc4d419b127c34c0e03ab&amp;type=3#PlusJakartaSans-VariableFont_wght&quot;);" />
9+
<ui:Label name="usernames" selectable="true" style="align-self: flex-start;" />
10+
</ui:VisualElement>
11+
</ui:VisualElement>
12+
</ui:UXML>

UnityHiroChallenges/Assets/UnityHiroChallenges/Editor/AccountSwitcher.uxml.meta

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

UnityHiroChallenges/Assets/UnityHiroChallenges/Editor/TutorialInfo.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

UnityHiroChallenges/Assets/UnityHiroChallenges/Editor/TutorialInfo/Icons.meta

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
22 KB
Loading

0 commit comments

Comments
 (0)