11using UnityEditor ;
22using UnityEngine ;
33using System ;
4+ using System . Collections . Generic ;
45using System . Threading . Tasks ;
56using UnityEngine . Networking ;
67using Newtonsoft . Json ;
7- using ChainSafe . GamingSdk . Editor ;
88using System . IO ;
9+ using System . Linq ;
910using System . Text ;
1011using ChainSafe . Gaming . UnityPackage ;
12+ using Microsoft . IdentityModel . Tokens ;
13+ using UnityEditor . Experimental . GraphView ;
14+ using UnityEngine . Events ;
15+ using ChainInfo = ChainSafe . Gaming . UnityPackage . Model ;
1116
1217/// <summary>
1318/// Allows the developer to alter chain configuration via GUI
1419/// </summary>
1520public class ChainSafeServerSettings : EditorWindow
1621{
22+ #region Fields
23+
24+ // Default values
1725 private const string ProjectIdPrompt = "Please enter your project ID" ;
18- private const string ChainIdPrompt = "Please enter your chain ID" ;
19- private const string ChainPrompt = "Please enter your chain i.e Ethereum, Binance, Cronos" ;
20- private const string NetworkPrompt = "Please enter your network i.e Mainnet, Testnet" ;
21- private const string SymbolPrompt = "Please enter your chain's native symbol i.e Eth, Cro" ;
22- private const string RpcPrompt = "Please enter your RPC endpoint" ;
23-
26+ private const string ChainIdDefault = "11155111" ;
27+ private const string ChainDefault = "Ethereum" ;
28+ private const string NetworkDefault = "Sepolia" ;
29+ private const string SymbolDefault = "Seth" ;
30+ private const string RpcDefault = "https://rpc.sepolia.org" ;
31+
32+ // Chain values
2433 private string projectID ;
2534 private string chainID ;
2635 private string chain ;
2736 private string network ;
2837 private string symbol ;
2938 private string rpc ;
39+ private string newRpc ;
3040
3141 Texture2D logo = null ;
42+
43+ // Search window
44+ private StringListSearchProvider searchProvider ;
45+ private ISearchWindowProvider _searchWindowProviderImplementation ;
46+ public UnityEvent onDropDownChange ;
47+ private int previousNetworkDropdownIndex ;
48+ private List < ChainInfo . Root > chainList ;
49+ private int selectedChainIndex ;
50+ private int selectedRpcIndex ;
51+
52+ #endregion
3253
33- // Checks if data is already entered
54+ #region Methods
55+
56+ /// <summary>
57+ /// Checks if data is already entered, sets default values if not
58+ /// </summary>
3459 void Awake ( )
3560 {
61+ // Get saved settings or revert to default
3662 var projectConfig = ProjectConfigUtilities . Load ( ) ;
37-
3863 projectID = string . IsNullOrEmpty ( projectConfig ? . ProjectId ) ? ProjectIdPrompt : projectConfig . ProjectId ;
39- chainID = string . IsNullOrEmpty ( projectConfig ? . ChainId ) ? ChainIdPrompt : projectConfig . ChainId ;
40- chain = string . IsNullOrEmpty ( projectConfig ? . Chain ) ? ChainPrompt : projectConfig . Chain ;
41- network = string . IsNullOrEmpty ( projectConfig ? . Network ) ? NetworkPrompt : projectConfig . Network ;
42- symbol = string . IsNullOrEmpty ( projectConfig ? . Symbol ) ? SymbolPrompt : projectConfig . Symbol ;
43- rpc = string . IsNullOrEmpty ( projectConfig ? . Rpc ) ? RpcPrompt : projectConfig . Rpc ;
64+ chainID = string . IsNullOrEmpty ( projectConfig ? . ChainId ) ? ChainIdDefault : projectConfig . ChainId ;
65+ chain = string . IsNullOrEmpty ( projectConfig ? . Chain ) ? ChainDefault : projectConfig . Chain ;
66+ network = string . IsNullOrEmpty ( projectConfig ? . Network ) ? NetworkDefault : projectConfig . Network ;
67+ symbol = string . IsNullOrEmpty ( projectConfig ? . Symbol ) ? SymbolDefault : projectConfig . Symbol ;
68+ rpc = string . IsNullOrEmpty ( projectConfig ? . Rpc ) ? RpcDefault : projectConfig . Rpc ;
69+ // Search menu
70+ onDropDownChange = new UnityEvent ( ) ;
71+ onDropDownChange . AddListener ( UpdateServerMenuInfo ) ;
72+ // Fetch supported chains
73+ FetchSupportedChains ( ) ;
74+ }
75+
76+ /// <summary>
77+ /// Updates the values in the server settings area when an item is selected
78+ /// </summary>
79+ public void UpdateServerMenuInfo ( )
80+ {
81+ // Get the selected chain index
82+ selectedChainIndex = Array . FindIndex ( chainList . ToArray ( ) , x => x . name == chain ) ;
83+
84+ // Check if the selectedChainIndex is valid
85+ if ( selectedChainIndex >= 0 && selectedChainIndex < chainList . Count )
86+ {
87+ // Set chain values
88+ network = chainList [ selectedChainIndex ] . chain ;
89+ chainID = chainList [ selectedChainIndex ] . chainId . ToString ( ) ;
90+ symbol = chainList [ selectedChainIndex ] . nativeCurrency . symbol ;
91+ // Ensure that the selectedRpcIndex is within bounds
92+ selectedRpcIndex = Mathf . Clamp ( selectedRpcIndex , 0 , chainList [ selectedChainIndex ] . rpc . Count - 1 ) ;
93+ // Set the rpc
94+ rpc = chainList [ selectedChainIndex ] . rpc [ selectedRpcIndex ] ;
95+ }
96+ else
97+ {
98+ // Handle the case where the selected chain is not found
99+ Debug . LogError ( "Selected chain not found in the chainList." ) ;
100+ }
101+ }
102+
103+ /// <summary>
104+ /// Fetches the supported EVM chains list from Chainlist's github json
105+ /// </summary>
106+ private async void FetchSupportedChains ( )
107+ {
108+ using UnityWebRequest webRequest = UnityWebRequest . Get ( "https://chainid.network/chains.json" ) ;
109+ await EditorUtilities . SendAndWait ( webRequest ) ;
110+ if ( webRequest . result != UnityWebRequest . Result . Success )
111+ {
112+ Debug . LogError ( "Error Getting Supported Chains: " + webRequest . error ) ;
113+ return ;
114+ }
115+ var json = webRequest . downloadHandler . text ;
116+ chainList = JsonConvert . DeserializeObject < List < ChainInfo . Root > > ( json ) ;
117+ chainList = chainList . OrderBy ( x => x . name ) . ToList ( ) ;
44118 }
45119
46120 // Initializes window
@@ -51,17 +125,21 @@ public static void ShowWindow()
51125 GetWindow ( typeof ( ChainSafeServerSettings ) ) ;
52126 }
53127
54- // Called when menu is opened, loads Chainsafe Logo
55- void OnEnable ( )
128+ /// <summary>
129+ /// Called when menu is opened, loads Chainsafe Logo
130+ /// </summary>
131+ private void OnEnable ( )
56132 {
57133 if ( ! logo )
58134 {
59135 logo = AssetDatabase . LoadAssetAtPath < Texture2D > ( "Packages/io.chainsafe.web3-unity/Editor/Textures/ChainSafeLogo.png" ) ;
60136 }
61137 }
62138
63- // Displayed content
64- void OnGUI ( )
139+ /// <summary>
140+ /// Displayed content
141+ /// </summary>
142+ private void OnGUI ( )
65143 {
66144 // Image
67145 EditorGUILayout . BeginVertical ( "box" ) ;
@@ -72,14 +150,48 @@ void OnGUI()
72150 GUILayout . Label ( "Here you can enter all the information needed to get your game started on the blockchain!" , EditorStyles . label ) ;
73151 // Inputs
74152 projectID = EditorGUILayout . TextField ( "Project ID" , projectID ) ;
75- chainID = EditorGUILayout . TextField ( "Chain ID" , chainID ) ;
76- chain = EditorGUILayout . TextField ( "Chain" , chain ) ;
77- network = EditorGUILayout . TextField ( "Network" , network ) ;
78- symbol = EditorGUILayout . TextField ( "Symbol" , symbol ) ;
79- rpc = EditorGUILayout . TextField ( "RPC" , rpc ) ;
80-
153+ // Search menu
154+ // Null check to stop the recursive loop before the web request has completed
155+ if ( chainList == null ) return ;
156+ // Set string array from chainList to pass into the menu
157+ string [ ] chainOptions = chainList . Select ( x => x . name ) . ToArray ( ) ;
158+ // Display the dynamically updating Popup
159+ EditorGUILayout . BeginHorizontal ( ) ;
160+ EditorGUILayout . PrefixLabel ( "Select Chain" ) ;
161+ // Show the network drop down menu
162+ if ( GUILayout . Button ( chain , EditorStyles . popup ) )
163+ {
164+ searchProvider = CreateInstance < StringListSearchProvider > ( ) ;
165+ searchProvider . Initialize ( chainOptions , x => { chain = x ; } ) ;
166+ SearchWindow . Open ( new SearchWindowContext ( GUIUtility . GUIToScreenPoint ( Event . current . mousePosition ) ) , searchProvider ) ;
167+ }
168+ EditorGUILayout . EndHorizontal ( ) ;
169+ network = EditorGUILayout . TextField ( "Network: " , network ) ;
170+ chainID = EditorGUILayout . TextField ( "Chain ID: " , chainID ) ;
171+ symbol = EditorGUILayout . TextField ( "Symbol: " , symbol ) ;
172+ EditorGUILayout . BeginHorizontal ( ) ;
173+ EditorGUILayout . PrefixLabel ( "Select RPC" ) ;
174+ // Remove "https://" so the user doesn't have to click through 2 levels for the rpc options
175+ string [ ] rpcOptions = chainList [ selectedChainIndex ] . rpc . Where ( rpc => rpc . StartsWith ( "https" ) ) . Select ( rpc => rpc . Substring ( 8 ) ) . ToArray ( ) ;
176+ string selectedRpc = rpcOptions [ selectedRpcIndex ] ;
177+ // Show the rpc drop down menu
178+ if ( GUILayout . Button ( selectedRpc , EditorStyles . popup ) )
179+ {
180+ searchProvider = CreateInstance < StringListSearchProvider > ( ) ;
181+ searchProvider . Initialize ( rpcOptions , x =>
182+ {
183+ selectedRpcIndex = Array . IndexOf ( rpcOptions , x ) ;
184+ // Add "https://" back
185+ rpc = "https://" + x ;
186+ } ) ;
187+ SearchWindow . Open ( new SearchWindowContext ( GUIUtility . GUIToScreenPoint ( Event . current . mousePosition ) ) , searchProvider ) ;
188+ }
189+ EditorGUILayout . EndHorizontal ( ) ;
190+ // Allows for a custom rpc
191+ rpc = EditorGUILayout . TextField ( "RPC: " , rpc ) ;
192+ GUILayout . Label ( "If you're using a custom RPC it will override the selection above" , EditorStyles . boldLabel ) ;
193+
81194 // Buttons
82-
83195 // Register
84196 if ( GUILayout . Button ( "Need To Register?" ) )
85197 {
@@ -106,7 +218,11 @@ void OnGUI()
106218 }
107219 GUILayout . Label ( "Reminder: Your ProjectID Must Be Valid To Save & Build With Our SDK. You Can Register For One On Our Website At Dashboard.Gaming.Chainsafe.io" , EditorStyles . label ) ;
108220 }
109-
221+
222+ /// <summary>
223+ /// Validates the project ID via ChainSafe's backend & writes values to the network js file, static so it can be called externally
224+ /// </summary>
225+ /// <param name="projectID"></param>
110226 static async void ValidateProjectID ( string projectID )
111227 {
112228 try
@@ -124,8 +240,11 @@ static async void ValidateProjectID(string projectID)
124240 Debug . LogException ( e ) ;
125241 }
126242 }
127-
128- internal static async Task < bool > ValidateProjectIDAsync ( string projectID )
243+
244+ /// <summary>
245+ /// Validates the project ID via ChainSafe's backend
246+ /// </summary>
247+ private static async Task < bool > ValidateProjectIDAsync ( string projectID )
129248 {
130249 var form = new WWWForm ( ) ;
131250 form . AddField ( "projectId" , projectID ) ;
@@ -153,7 +272,10 @@ internal static async Task<bool> ValidateProjectIDAsync(string projectID)
153272 Debug . LogError ( dbgProjectIDMessage ) ;
154273 return false ;
155274 }
156-
275+
276+ /// <summary>
277+ /// Writes values to the network js file
278+ /// </summary>
157279 public static void WriteNetworkFile ( )
158280 {
159281 Debug . Log ( "Updating network.js..." ) ;
@@ -207,4 +329,6 @@ private class ValidateProjectIDResponse
207329 [ JsonProperty ( "response" ) ]
208330 public bool Response { get ; set ; }
209331 }
210- }
332+
333+ #endregion
334+ }
0 commit comments