Skip to content

Commit c61d2be

Browse files
v2024.3.1
1 parent 94dc560 commit c61d2be

File tree

297 files changed

+20991
-15592
lines changed

Some content is hidden

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

297 files changed

+20991
-15592
lines changed

Documentation/UPGRADING.md

+42-44
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ All calls into async functions on the new mod.io Unity Plugin provide a single c
1919
This provides a much clearer calling convention and gives a guarantee of one operation completion - one callback invocation, rather than the two callbacks required by async functions in mod.io Unity V1.
2020

2121
Here is an example of the usage with a callback and an await:
22-
```c#
22+
```csharp
2323
void CallbackExample()
2424
{
25-
ModIOUnity.GetMods(filter, (Result result, ModPage modPage)=>
25+
ModIOUnity.GetMods(filter, (ResultAnd<ModPage> response)=>
2626
{
27-
if (result.Succeeded())
27+
if (response.result.Succeeded())
2828
{
2929
// Success
3030
}
@@ -47,8 +47,8 @@ async void AsyncExample()
4747
## Initializing the plugin
4848
Initialization in mod.io Unity V1 was handled mostly statically, pulling the details from the `Resources/modio_settings` asset during static initialization.
4949
Optionally, a developer could set the user data directory by calling `UserDataStorage.SetActiveUser()` as seen in the sample below.
50-
```c#
51-
void modioUnityV1Example()
50+
```csharp
51+
void ModioUnityV1Example()
5252
{
5353
// Optional (Sets the user data directory)
5454
string userProfileIdentifier = "local_game_user_id"; // Local User Account Identifier
@@ -58,7 +58,7 @@ void modioUnityV1Example()
5858
Apart from this, there are no initialization possibilities in mod.io Unity V1.
5959

6060
For the new mod.io Unity Plugin, we have kept an automatic initialization option that pulls the data from the `Resources/mod.io/config` asset, similar to the function of mod.io Unity V1. However, there are also explicit initialization methods and shutdown methods that can be utilized if automatic initialization is disabled in the config asset.
61-
```c#
61+
```csharp
6262
void InitializationExample()
6363
{
6464
string userProfileIdentifier = "local_game_user_id"; // Local User Account Identifier
@@ -74,8 +74,8 @@ mod.io Unity V1 built the synchronization of an authenticated user's subscriptio
7474
This has not changed in the new mod.io Unity Plugin, but the process of keeping that data synchronized is much easier, along with fetching the data for the subscribed mods.
7575

7676
Adding, synchronizing, and retrieving subscription data in mod.io Unity V1 involves chaining multiple calls together.
77-
```c#
78-
void modioUnityV1Example()
77+
```csharp
78+
void ModioUnityV1Example()
7979
{
8080
int newSubModId = 123;
8181
int newUnsubModId = 456;
@@ -102,35 +102,23 @@ void modioUnityV1Example()
102102
```
103103

104104
The new mod.io Unity Plugin streamlines this process by reducing the need for callback chaining, synchronizing immediately for local changes, and removing the need to handle the mod ids.
105-
[FetchUpdates()](https://sdkdocs.mod.io/unity/class_mod_i_o_1_1_mod_i_o_unity.html#aab9e3eb7697f13e4e96273ac50ab79af) is the single synchronization function on the interface, handling all synchronization actions.
106-
```c#
105+
[FetchUpdates()](https://sdkdocs.mod.io/unity/class_mod_i_o_1_1_mod_i_o_unity.html#aab9e3eb7697f13e4e96273ac50ab79af) is the single synchronization function on the interface, handling all synchronization actions and only needing to be run generally once per session (Ideally after you Initialize the plugin).
106+
```csharp
107107
void Example()
108108
{
109-
int newSubModId = 123;
110-
int newUnsubModId = 456;
111-
112-
// Pushes a subscribe attempt directly to the server, returning an error on failure
113-
ModIOUnity.SubscribeToMod(newSubModId,
114-
(Result result) => { /* callback code */ });
115-
// Pushes an unsubscribe attempt directly to the server, returning an error on failure
116-
ModIOUnity.UnsubscribeFromMod(newUnsubModId,
117-
(Result result) => { /* callback code */ });
118-
119109
// Synchronizes the local and server data
120110
ModIOUnity.FetchUpdates(
121-
(Result result) => { /* callback code */ };
122-
// Get Subscribed mod data
123-
SubscribedMod[] subscribedMods = ModIOUnity.GetSubscribedMods(out Result result);
111+
(Result result) => { /* callback code */ });
124112
}
125113
```
126114
Furthermore, the subscribe and unsubscribe operations automatically flag the mod as requiring installation/uninstallation, a responsibility placed on the consumer in mod.io Unity V1. (See below)
127115

128116
## Listing the User's Installed Mods
129-
Like in mod.io Unity V1, the new mod.io Unity Plugin allows the sharing of installed mods across multiple users to save network traffic and storage space.
117+
Likewise in mod.io Unity V1, the new mod.io Unity Plugin allows the sharing of installed mods across multiple users to save network traffic and storage space.
130118

131119
mod.io Unity V1 didn't have a direct method of retrieving the mods installed for the current user. There are a variety of different methods that need to be chained together to retrieve a complete picture of the installed mod data.
132-
```c#
133-
void modioUnityV1Example()
120+
```csharp
121+
void ModioUnityV1Example()
134122
{
135123
// Retrieves a de-identified list of mod directories for mods the user has "enabled"
136124
bool onlyEnabledMods = true;
@@ -157,7 +145,7 @@ void modioUnityV1Example()
157145
```
158146

159147
The new mod.io Unity Plugin makes this much simpler, giving you all the information in a single call, returning a [UserInstalledMod](https://sdkdocs.mod.io/unity/struct_mod_i_o_1_1_user_installed_mod.html) array (and a `Result`).
160-
```c#
148+
```csharp
161149
void Example()
162150
{
163151
UserInstalledMod[] mods = ModIOUnity.GetInstalledModsForUser(out Result result);
@@ -168,8 +156,8 @@ void Example()
168156
The new mod.io Unity Plugin has the business rules of "Subscription = install and update" built into it, such that the download, extract, and uninstall processes are managed automatically by the [Mod Management Loop](https://sdkdocs.mod.io/unity/class_mod_i_o_1_1_mod_i_o_unity.html#aabba78ef1b55e60e2334cc1ba6faf1c3), a process that runs asynchronously to detect changes to the subscriptions and automate mod data management.
169157

170158
mod.io Unity V1 handled the installation and uninstallation of mods in the ModBrowser code, but any developer looking to exclude that code or understand the installation process had a more difficult time.
171-
```c#
172-
void modioUnityV1Example()
159+
```csharp
160+
void ModioUnityV1Example()
173161
{
174162
/// === Add a new subscription and install ===
175163
int newSubModId = 123;
@@ -228,7 +216,7 @@ This is one of the key processes that has been streamlined in the new mod.io Uni
228216

229217
A call to [ModIOUnity.EnableModManagement](https://sdkdocs.mod.io/unity/class_mod_i_o_1_1_mod_i_o_unity.html#aabba78ef1b55e60e2334cc1ba6faf1c3) starts the background process of monitoring for subscription changes, and takes a (nullable) callback for mod management events. This can be disabled at any point with a call to [ModIOUnity.DisableModManagement](https://sdkdocs.mod.io/unity/class_mod_i_o_1_1_mod_i_o_unity.html#a7eda62ae267aa409b6408fd60ed16429).
230218
Any changes invoked locally, and any changes retrieved with [ModIOUnity.FetchUpdates](https://sdkdocs.mod.io/unity/class_mod_i_o_1_1_mod_i_o_unity.html#aab9e3eb7697f13e4e96273ac50ab79af) are automatically queued and actioned.
231-
```c#
219+
```csharp
232220
void Example()
233221
{
234222
ModManagementEventDelegate eventDelegate = (ModManagementEventType eventType, ModId modId, Result eventResult) => { /* handle event */};
@@ -246,10 +234,6 @@ void Example()
246234
// Pushes the unsubcribe action to the server and flags it for uninstallation
247235
ModIOUnity.UnsubscribeFromMod(newUnsubModId, (Result result) => /* callback code */);
248236

249-
// === Fetch remote data and fix installation state ===
250-
// Synchronizes local and server data, flagging install/uninstall operations as required
251-
ModIOUnity.FetchUpdates((Result result) => { /* callback code */ });
252-
253237
// Ends monitoring for changes and disables downloading/extracting/deleting of mod data
254238
ModIOUnity.DisableModManagement();
255239
}
@@ -263,26 +247,40 @@ methods, such as Steam or Xbox.
263247

264248
### Email Authentication
265249
In the V1 Plugin you can authenticate via email in the following way:
266-
```c#
267-
// TODO: EXAMPLE OF EMAIL AUTH IN V1
250+
```csharp
251+
void modioUnityV1_RequestEmailCode(string playerEmail)
252+
{
253+
ModIO.APIClient.SendSecurityCode(
254+
playerEmail,
255+
(APIMessage apiMessage) => { /* callback code */ },
256+
(WebRequestError error) => { /* callback code */ });
257+
}
258+
259+
void modioUnityV1_SubmitSecurityCode(string userSecurityCode)
260+
{
261+
ModIO.UserAccountManagement.AuthenticateWithSecurityCode(
262+
userSecurityCode,
263+
(UserProfile userProfile) => { /* callback code */ },
264+
(WebRequestError error) => { /* callback code */ });
265+
}
268266
```
269267
In the new Plugin you can do it like so:
270-
```c#
271-
async void RequestEmailCode()
268+
```csharp
269+
async void RequestEmailCode(string playerEmail)
272270
{
273-
Result result = await ModIOUnityAsync.RequestAuthenticationEmail("[email protected]");
271+
Result result = await ModIOUnityAsync.RequestAuthenticationEmail(playerEmail);
274272

275273
if (result.Succeeded())
276274
{
277-
Debug.Log("Succeeded to send security code");
275+
Debug.Log("Succeeded in sending security code");
278276
}
279277
else
280278
{
281279
Debug.Log("Failed to send security code to that email address");
282280
}
283281
}
284282

285-
async void SubmitCode(string userSecurityCode)
283+
async void SubmitSecurityCode(string userSecurityCode)
286284
{
287285
Result result = await ModIOUnityAsync.SubmitEmailSecurityCode(userSecurityCode);
288286

@@ -300,15 +298,15 @@ async void SubmitCode(string userSecurityCode)
300298
### Third party Authentication
301299
In the V1 Plugin you can authenticate a user with a third party service
302300
like Steam:
303-
```c#
301+
```csharp
304302
UserAccountManagement.AuthenticateWithSteamEncryptedAppTicket(pTicket,
305303
pcbTicket,
306304
hasUserAcceptedTerms,
307305
onSuccess,
308306
onError);
309307
```
310308
In the new Plugin you can use the following:
311-
```c#
309+
```csharp
312310
ModIOUnity.AuthenticateUserViaSteam(token, email, termsHash, callback);
313311
```
314312
(Note you can use `ModIOUnityAsync` to `await` instead.)
@@ -319,7 +317,7 @@ This is to ensure users view and accept the terms of use.
319317

320318
Here is a complete example getting the TOS hash and Authenticating via Steam:
321319

322-
```c#
320+
```csharp
323321
// Use this to cache the TOS we receive
324322
TermsOfUse termsOfUse;
325323

Editor/ModIO.EditorCode/EditorMenu.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ internal static SettingsAsset GetConfigAsset()
5353

5454
//Find properties and apply default values
5555
SerializedProperty serverSettingsProperty = so.FindProperty("serverSettings");
56-
serverSettingsProperty.FindPropertyRelative("serverURL").stringValue = "https://api.mod.io/v1";;
56+
serverSettingsProperty.FindPropertyRelative("serverURL").stringValue = SettingsAssetEditor.GetURLProduction(0);
5757
serverSettingsProperty.FindPropertyRelative("languageCode").stringValue = "en";
5858

5959
//Apply new values while ensuring the user cannot use "undo" to erase the initial values.
+72-44
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#if UNITY_EDITOR
2+
using System.Text.RegularExpressions;
23
using ModIO.Implementation;
34
using UnityEditor;
45
using UnityEngine;
@@ -39,64 +40,91 @@ public override void OnInspectorGUI()
3940
labelStyle.normal.textColor = Color.white;
4041

4142
EditorGUILayout.LabelField("Server Settings", labelStyle);
42-
if(myTarget.serverSettings.gameId == 0 || string.IsNullOrWhiteSpace(myTarget.serverSettings.gameKey))
43-
{
44-
EditorGUILayout.HelpBox("Once you've created a game profile on mod.io (or test.mod.io) "
45-
+ "you can input the game ID and Key below in order for the plugin "
46-
+ "to retrieve mods and information associated to your game.",
47-
MessageType.Info);
48-
}
4943

50-
EditorGUILayout.PropertyField(serverURL, new GUIContent("Server URL"));
44+
EditorGUILayout.Space();
45+
5146
EditorGUILayout.PropertyField(gameId,new GUIContent("Game ID"));
5247
gameKey.stringValue = EditorGUILayout.PasswordField("API Key", gameKey.stringValue);
53-
EditorGUILayout.PropertyField(languageCode, new GUIContent("Language code"));
5448

49+
if(myTarget.serverSettings.gameId == 0 || string.IsNullOrWhiteSpace(myTarget.serverSettings.gameKey))
50+
{
51+
EditorGUILayout.Space();
5552

56-
EditorGUILayout.Space();
57-
EditorGUILayout.Space();
53+
EditorGUILayout.HelpBox(
54+
"Once you've created a game profile on mod.io (or test.mod.io), enter your game ID and API key above in order for the plugin to retrieve mods and information associated with your game.",
55+
MessageType.Info
56+
);
5857

59-
EditorGUILayout.BeginHorizontal();
60-
if(GUILayout.Button("Insert URL for Test API"))
61-
{
62-
serverURL.stringValue = "https://api.test.mod.io/v1";
58+
EditorGUILayout.Space();
6359

64-
//remove focus from other fields
65-
GUI.FocusControl(null);
66-
}
67-
if(GUILayout.Button("Insert URL for Production API"))
68-
{
69-
serverURL.stringValue = $"https://g-{gameId.intValue}.modapi.io/v1";
70-
//remove focus from other fields
71-
GUI.FocusControl(null);
60+
EditorGUILayout.BeginHorizontal();
61+
62+
EditorGUILayout.PrefixLabel("Locate ID and API Key");
63+
64+
if (GUILayout.Button("test.mod.io"))
65+
{
66+
SetURLTest();
67+
Application.OpenURL("https://test.mod.io/apikey");
68+
}
69+
70+
if (GUILayout.Button("mod.io"))
71+
{
72+
SetURLProduction();
73+
Application.OpenURL("https://mod.io/apikey");
74+
}
75+
76+
EditorGUILayout.EndHorizontal();
77+
78+
EditorGUILayout.Space();
79+
} else {
80+
EditorGUILayout.Space();
81+
82+
EditorGUILayout.PropertyField(serverURL, new GUIContent("Server URL"));
83+
EditorGUILayout.PropertyField(languageCode, new GUIContent("Language code"));
84+
85+
EditorGUILayout.Space();
86+
87+
EditorGUILayout.BeginHorizontal();
88+
89+
if (GUILayout.Button("Insert URL for Test API"))
90+
SetURLTest();
91+
92+
if (GUILayout.Button("Insert URL for Production API"))
93+
SetURLProduction();
94+
95+
EditorGUILayout.EndHorizontal();
7296
}
73-
EditorGUILayout.EndHorizontal();
74-
75-
if(GUILayout.Button("Locate ID and API Key"))
76-
{
77-
if(myTarget.serverSettings.serverURL == "https://api.test.mod.io/v1")
78-
{
79-
Application.OpenURL("https://test.mod.io/apikey");
80-
}
81-
else
82-
{
83-
Application.OpenURL("https://mod.io/apikey");
84-
}
85-
}
8697

87-
// If the gameId has been changed, update the url
88-
if(gameId.intValue != previousGameId)
89-
{
90-
if(myTarget.serverSettings.serverURL != "https://api.test.mod.io/v1"
91-
&& myTarget.serverSettings.serverURL != "https://api-staging.moddemo.io/v1")
92-
{
93-
serverURL.stringValue = $"https://g-{gameId.intValue}.modapi.io/v1";
94-
}
98+
// If the gameId has been changed, update the url
99+
if (gameId.intValue != previousGameId)
100+
{
101+
if (IsURLProduction(serverURL.stringValue))
102+
serverURL.stringValue = GetURLProduction(gameId.intValue);
103+
95104
previousGameId = gameId.intValue;
96105
}
97106

98107
//Save the new values
99108
serializedObject.ApplyModifiedProperties();
109+
110+
return;
111+
112+
void SetURLProduction()
113+
{
114+
serverURL.stringValue = GetURLProduction(gameId.intValue);
115+
GUI.FocusControl(null);
116+
}
117+
118+
void SetURLTest()
119+
{
120+
serverURL.stringValue = GetURLTest(gameId.intValue);
121+
GUI.FocusControl(null);
122+
}
100123
}
124+
125+
internal static string GetURLProduction(int gameId) => $"https://g-{gameId}.modapi.io/v1";
126+
static string GetURLTest(int gameId) => "https://api.test.mod.io/v1";
127+
128+
static bool IsURLProduction(string url) => Regex.IsMatch(url, @"https:\/\/g-\d*.modapi.io\/v1");
101129
}
102130
#endif

0 commit comments

Comments
 (0)