gg.easy.airship 0.1.2159 → 0.1.2161

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/Editor/Accessories/AccessoryCollectionEditorTools.cs +5 -2
  2. package/Editor/BuildMenu.cs +3 -1
  3. package/Editor/Packages/AirshipPackagesWindow.cs +2 -2
  4. package/Editor/Tools/Characters/AirshipCharacterEditor.cs +2 -2
  5. package/Editor/TypescriptServices/Compiler/TypescriptCompilerWatchState.cs +12 -4
  6. package/Editor/TypescriptServices/Editor/AirshipScriptEditorIntegrations.cs +1 -1
  7. package/Runtime/Code/Auth/Socket/SocketManager.cs +16 -0
  8. package/Runtime/Code/Authentication/EasyAuthenticator.cs +33 -3
  9. package/Runtime/Code/Bootstrap/BundleDownloader.cs +6 -11
  10. package/Runtime/Code/Bootstrap/ServerBootstrap.cs +35 -4
  11. package/Runtime/Code/Bootstrap/SignalHandler.cs +1 -1
  12. package/Runtime/Code/Health/AirshipProfileExporter.cs +38 -27
  13. package/Runtime/Code/Http/Internal/InternalHttpManager.cs +7 -4
  14. package/Runtime/Code/Luau/AirshipComponent.cs +8 -1
  15. package/Runtime/Code/Player/PlayerInfo.cs +5 -1
  16. package/Runtime/Code/Player/PlayerManagerBridge.cs +2 -2
  17. package/Runtime/Code/Util/Singleton.cs +1 -2
  18. package/Runtime/Code/VoxelWorld/Editor/VoxelBuilderEditorWindow.cs +0 -2
  19. package/Runtime/DevConsole/Runtime/DevConsoleMono.cs +1 -90
  20. package/ThirdParty/Graphy - Ultimate Stats Monitor/Materials/Timings Graph.mat +97 -0
  21. package/ThirdParty/Graphy - Ultimate Stats Monitor/Materials/Timings Graph.mat.meta +8 -0
  22. package/ThirdParty/Graphy - Ultimate Stats Monitor/Prefab/[Graphy].prefab +2039 -515
  23. package/ThirdParty/Graphy - Ultimate Stats Monitor/Runtime/GraphyManager.cs +16 -0
  24. package/ThirdParty/Graphy - Ultimate Stats Monitor/Runtime/Timings/G_TimingsGraph.cs +195 -0
  25. package/ThirdParty/Graphy - Ultimate Stats Monitor/Runtime/Timings/G_TimingsGraph.cs.meta +3 -0
  26. package/ThirdParty/Graphy - Ultimate Stats Monitor/Runtime/Timings/G_TimingsManager.cs +219 -0
  27. package/ThirdParty/Graphy - Ultimate Stats Monitor/Runtime/Timings/G_TimingsManager.cs.meta +3 -0
  28. package/ThirdParty/Graphy - Ultimate Stats Monitor/Runtime/Timings.meta +3 -0
  29. package/package.json +1 -1
@@ -132,6 +132,7 @@ public class AccessoryCollectionTools {
132
132
  // }
133
133
 
134
134
 
135
+ #if AIRSHIP_INTERNAL
135
136
  [MenuItem("Airship/Avatar/Create Outfit Accessories from Mesh %f8", true)]
136
137
  [MenuItem("Assets/Create/Airship/Accessories/Create Outfit Accessories from Mesh", true)]
137
138
  private static bool ValidateCreateAccFromMesh(){
@@ -159,14 +160,16 @@ public class AccessoryCollectionTools {
159
160
  return Selection.GetFiltered<GameObject>(AssetModeMask).Length == 1;
160
161
  }
161
162
 
162
- [MenuItem("Airship/Avatar/Create Accessory from Mesh %f8")]
163
- [MenuItem("Assets/Create/Airship/Accessories/Create Accessory from Mesh")]
163
+ [MenuItem("Airship/Avatar/Create Accessory from Mesh %f8", false, 100)]
164
+ [MenuItem("Assets/Create/Airship/Accessories/Create Accessory from Mesh", false, 100)]
164
165
  static void CreateSingleAccFromMesh() {
165
166
  processedPaths.Clear();
166
167
  // defaultMat = AssetDatabase.LoadAssetAtPath<Material>("Assets/AirshipPackages/@Easy/CoreMaterials//MaterialLibrary/Organic/Clay.mat");
167
168
  UnpackSingleObject(Selection.GetFiltered<GameObject>(AssetModeMask)[0]);
168
169
  }
169
170
 
171
+ #endif
172
+
170
173
  private static void UnpackSingleObject(GameObject rootGo){
171
174
  string rootPath = AssetDatabase.GetAssetPath(rootGo.GetInstanceID());
172
175
  string fileName = Path.GetFileNameWithoutExtension(rootPath);
@@ -67,6 +67,8 @@ namespace Editor {
67
67
 
68
68
  FileUtil.DeleteFileOrDirectory("build/StandaloneLinux64");
69
69
 
70
+ // This should probably be NamedBuildTarget.Server (rather than Standalone), but that does cause some issues.
71
+ // We will want to review this again in the future as a possible optimization.
70
72
  PlayerSettings.SetScriptingBackend(NamedBuildTarget.Standalone, ScriptingImplementation.IL2CPP);
71
73
  PlayerSettings.dedicatedServerOptimizations = true;
72
74
  PlayerSettings.insecureHttpOption = InsecureHttpOption.AlwaysAllowed;
@@ -194,7 +196,7 @@ namespace Editor {
194
196
 
195
197
  UserBuildSettings.architecture = OSArchitecture.x64ARM64;
196
198
  PlayerSettings.SplashScreen.show = false;
197
- PlayerSettings.SetScriptingBackend(NamedBuildTarget.Standalone, ScriptingImplementation.IL2CPP);
199
+ PlayerSettings.SetScriptingBackend(NamedBuildTarget.iOS, ScriptingImplementation.IL2CPP);
198
200
  var options = new BuildPlayerOptions();
199
201
  options.scenes = scenes;
200
202
  options.locationPathName = "build/client_ios";
@@ -238,7 +238,7 @@ namespace Editor.Packages {
238
238
  var style = new GUIStyle(EditorStyles.textField);
239
239
 
240
240
  this.addPackageId = EditorGUILayout.TextField("Package ID", this.addPackageId);
241
- EditorGUILayout.LabelField("Example: @Easy/Survival");
241
+ EditorGUILayout.LabelField("Example: @Easy/VoxelWorld");
242
242
  EditorGUILayout.Space(4);
243
243
 
244
244
  var addPackagePressed = GUILayout.Button("Add Package", GUILayout.Width(150));
@@ -288,7 +288,7 @@ namespace Editor.Packages {
288
288
  EditorGUILayout.Space(12);
289
289
  EditorGUILayout.BeginVertical();
290
290
  this.createPackageId = EditorGUILayout.TextField("Package ID", this.createPackageId);
291
- EditorGUILayout.LabelField("Example: @Easy/Survival");
291
+ EditorGUILayout.LabelField("Example: @Easy/VoxelWorld");
292
292
  EditorGUILayout.Space(4);
293
293
  if (GUILayout.Button("Create Package", GUILayout.Width(150))) {
294
294
  EditorCoroutineUtility.StartCoroutineOwnerless(CreateNewLocalSourcePackage(this.createPackageId));
@@ -18,7 +18,7 @@ public class AirshipCharacterEditor : MonoBehaviour {
18
18
  }
19
19
  }
20
20
 
21
- [MenuItem("Assets/Create/Airship/Viewmodel Variant", false, 1)]
21
+ [MenuItem("Assets/Create/Airship/Viewmodel Variant", false, -104)]
22
22
  static void CreateViewmodelVariant() {
23
23
  GameObject source =
24
24
  AssetDatabase.LoadAssetAtPath<GameObject>(
@@ -29,7 +29,7 @@ public class AirshipCharacterEditor : MonoBehaviour {
29
29
  Selection.activeObject = prefab;
30
30
  }
31
31
 
32
- [MenuItem("Assets/Create/Airship/Character Variant", false, 1)]
32
+ [MenuItem("Assets/Create/Airship/Character Variant", false, -105)]
33
33
  static void CreateCharacterVariant() {
34
34
  GameObject source =
35
35
  AssetDatabase.LoadAssetAtPath<GameObject>(
@@ -1,9 +1,11 @@
1
1
  using System;
2
2
  using System.Collections;
3
3
  using System.Collections.Generic;
4
+ using System.ComponentModel;
4
5
  using System.Diagnostics;
5
6
  using System.IO;
6
7
  using System.Threading;
8
+ using UnityEditor;
7
9
  using UnityEngine;
8
10
  using Debug = UnityEngine.Debug;
9
11
 
@@ -65,10 +67,16 @@ namespace Airship.Editor {
65
67
  var fullCommandString = string.Join(" ", argList);
66
68
 
67
69
  TypescriptLogService.Log(TypescriptLogLevel.Information, $"Start process 'node {fullCommandString}'");
68
- var compilerProcess = TypescriptCompilationService.RunNodeCommand(directory, fullCommandString);
69
-
70
- TypescriptCompilationService.AttachWatchOutputToUnityConsole(this, arguments, compilerProcess);
71
- processId = compilerProcess.Id;
70
+
71
+ try {
72
+ var compilerProcess = TypescriptCompilationService.RunNodeCommand(directory, fullCommandString);
73
+ TypescriptCompilationService.AttachWatchOutputToUnityConsole(this, arguments, compilerProcess);
74
+ processId = compilerProcess.Id;
75
+ }
76
+ catch (Win32Exception _) {
77
+ EditorUtility.DisplayDialog("Failed to initialize TypeScript",
78
+ "Ensure you have the latest LTS node.js installed, then restart the editor and Unity Hub", "Ok");
79
+ }
72
80
 
73
81
  TypescriptCompilationServicesState.instance.RegisterWatchCompiler(this);
74
82
  yield return null;
@@ -11,7 +11,7 @@ namespace Airship.Editor {
11
11
  internal static string AirshipComponentTemplate => PosixPath.Join(TemplatePath, "AirshipComponent.ts.txt");
12
12
  internal static string AirshipModuleTemplate => PosixPath.Join(TemplatePath, "AirshipModule.ts.txt");
13
13
 
14
- [MenuItem("Assets/Create/Airship/TypeScript File", false, 2)]
14
+ [MenuItem("Assets/Create/Airship/TypeScript File", false, 50)]
15
15
  private static void CreateNewComponentFile()
16
16
  {
17
17
  ProjectWindowUtil.CreateScriptAssetFromTemplateFile(AirshipComponentTemplate, "AirshipComponent.ts");
@@ -2,6 +2,7 @@ using System;
2
2
  using System.Collections;
3
3
  using System.Collections.Generic;
4
4
  using System.Threading.Tasks;
5
+ using Airship.DevConsole;
5
6
  using Code.Auth;
6
7
  using Code.Http.Internal;
7
8
  using Code.Platform.Shared;
@@ -48,6 +49,21 @@ public class SocketManager : Singleton<SocketManager> {
48
49
  DontDestroyOnLoad(this);
49
50
  }
50
51
 
52
+ private void Start() {
53
+ DevConsole.AddCommand(Command.Create<string>("join", "", "Join a game from given gameId",
54
+ Parameter.Create("gameId", "Game ID of the target game."), async (gameId) => {
55
+ Debug.Log("Requesting transfer to game " + gameId + " ...");
56
+ var packet = $"{{\"gameId\": \"{gameId}\"}}";
57
+ var res = await InternalHttpManager.PostAsync(AirshipPlatformUrl.gameCoordinator + "/transfers/transfer/self", packet);
58
+ if (res.success) {
59
+ Debug.Log("<color=green>Joining...</color>");
60
+ }
61
+ else {
62
+ Debug.LogError("Failed to join game: " + res.error);
63
+ }
64
+ }));
65
+ }
66
+
51
67
  public static async Task<bool> ConnectAsyncInternal() {
52
68
  // print("Connecting to socket with auth token: " + authToken);
53
69
  if (Instance.socket == null) {
@@ -20,6 +20,8 @@ namespace Code.Authentication {
20
20
  public string editorUserId;
21
21
  public string editorUsername;
22
22
  public string editorProfileImageId;
23
+
24
+ public string passkey;
23
25
  }
24
26
  public struct LoginResponseMessage : NetworkMessage
25
27
  {
@@ -32,11 +34,24 @@ namespace Code.Authentication {
32
34
  public string reason;
33
35
  }
34
36
 
37
+ public struct ServerStartupFailureMessage : NetworkMessage {
38
+ public string reason;
39
+ }
40
+
35
41
  public class EasyAuthenticator : NetworkAuthenticator {
42
+ private string passkey = "empty";
43
+
36
44
  readonly HashSet<NetworkConnection> connectionsPendingDisconnect = new HashSet<NetworkConnection>();
37
45
 
38
46
  public int connectionCounter = 0;
39
47
 
48
+ private void Awake() {
49
+ TextAsset passkeyTextFile = Resources.Load<TextAsset>("ConnectPassKey");
50
+ if (passkeyTextFile) {
51
+ this.passkey = passkeyTextFile.text;
52
+ }
53
+ }
54
+
40
55
  public override void OnStartServer() {
41
56
  this.connectionCounter = 0;
42
57
 
@@ -46,6 +61,7 @@ namespace Code.Authentication {
46
61
 
47
62
  public override async void OnStartClient() {
48
63
  NetworkClient.RegisterHandler<KickMessage>(Client_OnKickBroadcast, false);
64
+ NetworkClient.RegisterHandler<ServerStartupFailureMessage>(Client_OnServerStartupFailure, false);
49
65
 
50
66
  //Listen to response from server.
51
67
  NetworkClient.RegisterHandler<LoginResponseMessage>(Client_OnLoginResponseMessage, false);
@@ -53,6 +69,7 @@ namespace Code.Authentication {
53
69
 
54
70
  public override void OnStopClient() {
55
71
  NetworkClient.UnregisterHandler<KickMessage>();
72
+ NetworkClient.UnregisterHandler<ServerStartupFailureMessage>();
56
73
  NetworkClient.UnregisterHandler<LoginResponseMessage>();
57
74
  }
58
75
 
@@ -72,6 +89,7 @@ namespace Code.Authentication {
72
89
  editorUserId = EditorAuthManager.localUser.uid,
73
90
  editorUsername = EditorAuthManager.localUser.username,
74
91
  editorProfileImageId = EditorAuthManager.localUser.profileImageId,
92
+ passkey = this.passkey,
75
93
  });
76
94
  return;
77
95
  }
@@ -91,6 +109,7 @@ namespace Code.Authentication {
91
109
  NetworkClient.Send(new LoginMessage {
92
110
  authToken = authToken,
93
111
  playerVersion = AirshipConst.playerVersion,
112
+ passkey = this.passkey,
94
113
  });
95
114
  return;
96
115
  }
@@ -100,6 +119,7 @@ namespace Code.Authentication {
100
119
  NetworkClient.Send(new LoginMessage {
101
120
  authToken = authToken,
102
121
  playerVersion = AirshipConst.playerVersion,
122
+ passkey = this.passkey,
103
123
  });
104
124
  }
105
125
 
@@ -107,6 +127,10 @@ namespace Code.Authentication {
107
127
  TransferManager.Instance.Disconnect(true, kickMessage.reason);
108
128
  }
109
129
 
130
+ private void Client_OnServerStartupFailure(ServerStartupFailureMessage message) {
131
+ TransferManager.Instance.Disconnect(true, message.reason);
132
+ }
133
+
110
134
  /// <summary>
111
135
  /// Received on server when a client sends the password broadcast message.
112
136
  /// </summary>
@@ -115,6 +139,11 @@ namespace Code.Authentication {
115
139
  private async void Server_OnLoginMessage(NetworkConnectionToClient conn, LoginMessage loginData) {
116
140
  if (connectionsPendingDisconnect.Contains(conn)) return;
117
141
 
142
+ if (loginData.passkey != this.passkey) {
143
+ this.RejectConnection(conn, "Invalid passkey.", true);
144
+ return;
145
+ }
146
+
118
147
  #if UNITY_SERVER
119
148
  Debug.Log("Authenticating " + conn);
120
149
  #endif
@@ -171,10 +200,11 @@ namespace Code.Authentication {
171
200
  if (Application.isEditor && CrossSceneState.IsLocalServer()) {
172
201
  this.connectionCounter++;
173
202
  if (this.connectionCounter == 1 && loginMessage.editorUserId != null) {
203
+ string userId = InternalHttpManager.editorUserId ?? (this.connectionCounter + "");
174
204
  tcs.SetResult(new UserData() {
175
- uid = InternalHttpManager.editorUserId,
205
+ uid = userId,
176
206
  username = loginMessage.editorUsername,
177
- orgRoleName = "Dev",
207
+ orgRoleName = "Owner",
178
208
  profileImageId = loginMessage.editorProfileImageId,
179
209
  });
180
210
  return await tcs.Task;
@@ -182,7 +212,7 @@ namespace Code.Authentication {
182
212
  tcs.SetResult(new UserData() {
183
213
  uid = this.connectionCounter + "",
184
214
  username = "Player" + this.connectionCounter,
185
- orgRoleName = "Dev",
215
+ orgRoleName = "Owner",
186
216
  profileImageId = string.Empty,
187
217
  fullTransferPacket = "{}"
188
218
  });
@@ -220,11 +220,8 @@ public class BundleDownloader : Singleton<BundleDownloader> {
220
220
  }
221
221
 
222
222
  if (!success && RunCore.IsServer()) {
223
- var serverBootstrap = FindAnyObjectByType<ServerBootstrap>();
224
- if (serverBootstrap.IsAgonesEnvironment()) {
225
- Debug.LogError("[SEVERE] Server failed to download bundles. Shutting down!");
226
- serverBootstrap.agones.Shutdown().Wait();
227
- }
223
+ onComplete?.Invoke(false);
224
+ return false;
228
225
  }
229
226
 
230
227
  if (!success && RunCore.IsClient()) {
@@ -268,12 +265,10 @@ public class BundleDownloader : Singleton<BundleDownloader> {
268
265
  if (loadingScreen) {
269
266
  loadingScreen.SetError("Failed to download Main Menu scripts.");
270
267
  }
271
- if (RunCore.IsServer()) {
272
- var serverBootstrap = FindAnyObjectByType<ServerBootstrap>();
273
- if (serverBootstrap.IsAgonesEnvironment()) {
274
- Debug.LogError("[SEVERE] Server failed to download code.zip. Shutting down!");
275
- serverBootstrap.agones.Shutdown().Wait();
276
- }
268
+ if (RunCore.IsServer())
269
+ {
270
+ onComplete?.Invoke(false);
271
+ return false;
277
272
  }
278
273
  } else {
279
274
  File.WriteAllText(Path.Join(package.GetPersistentDataDirectory(), "code_version_" + package.codeVersion + ".txt"), "success");
@@ -7,6 +7,7 @@ using System.Runtime.Serialization;
7
7
  using Agones;
8
8
  using Agones.Model;
9
9
  using Code.Analytics;
10
+ using Code.Authentication;
10
11
  using Code.Bootstrap;
11
12
  using Code.GameBundle;
12
13
  using Code.Http.Internal;
@@ -286,6 +287,7 @@ public class ServerBootstrap : MonoBehaviour
286
287
  }
287
288
  this.airshipJWT = annotations["JWT"];
288
289
  UnityWebRequestProxyHelper.ProxyAuthCredentials = this.airshipJWT;
290
+ InternalHttpManager.authTokenSetTaskCompletionSource.SetResult(true);
289
291
  // Debug.Log("Airship JWT:");
290
292
  // Debug.Log(airshipJWT);
291
293
 
@@ -428,7 +430,15 @@ public class ServerBootstrap : MonoBehaviour
428
430
  if (!RunCore.IsEditor()) {
429
431
  BundleDownloader.Instance.DownloadBundles(startupConfig.CdnUrl, packages.ToArray(), privateBundleFiles, null, gameCodeZipUrl, false,
430
432
  (res) => {
431
- downloadComplete = true;
433
+ if (!res)
434
+ {
435
+ Debug.LogWarning("[Airship]: Failed to download required files. See above logs for details. Shutting down server.");
436
+ ShutdownDueToAssetFailure(1);
437
+ }
438
+ else
439
+ {
440
+ downloadComplete = true;
441
+ }
432
442
  });
433
443
  } else {
434
444
  downloadComplete = true;
@@ -476,13 +486,34 @@ public class ServerBootstrap : MonoBehaviour
476
486
  isServerReady = true;
477
487
  OnServerReady?.Invoke();
478
488
  }
479
-
480
- public void Shutdown() {
489
+
490
+ private void ShutdownInternal(int exitCode = 0) {
481
491
  if (agones && !this.isAgonesShutdownTriggered) {
482
492
  this.isAgonesShutdownTriggered = true;
483
493
  agones.Shutdown();
484
- Application.Quit();
494
+ Application.Quit(exitCode);
495
+ }
496
+ }
497
+
498
+ private void ShutdownDueToAssetFailure(int exitCode = 1) {
499
+ if (NetworkServer.connections != null && NetworkServer.connections.Count > 0) {
500
+ var message = new ServerStartupFailureMessage {
501
+ reason = "Server failed to download required game assets.\n\nIf you are the game developer, ensure your game / packages have all been properly published.\n\nCheck the error console in the Airship Create portal for more details.",
502
+ };
503
+
504
+ foreach (var connection in NetworkServer.connections.Values) {
505
+ if (connection != null) {
506
+ connection.Send(message);
507
+ }
508
+ }
485
509
  }
510
+
511
+ ShutdownInternal(exitCode);
512
+ }
513
+
514
+ public void Shutdown()
515
+ {
516
+ ShutdownInternal(0);
486
517
  }
487
518
 
488
519
  /**
@@ -43,4 +43,4 @@ namespace Code.Bootstrap {
43
43
  }
44
44
  #endif
45
45
  }
46
- }
46
+ }
@@ -88,33 +88,49 @@ namespace Code.Health
88
88
  NetworkClient.RegisterHandler<ClientProfileUploadResponse>(OnClientUploadResponse);
89
89
  }
90
90
 
91
- DevConsole.AddCommand(Command.Create<string, int, bool>(
92
- "profile",
91
+ // Profile without callstacks
92
+ DevConsole.AddCommand(Command.Create<string, int>(
93
+ "profile",
93
94
  "",
94
- "Starts and uploads a profile. Once complete the download link will be printed.",
95
- Parameter.Create("Context", "Options: Server | Client"),
95
+ "Starts and uploads a profile. Once complete the download link will be printed.",
96
+ Parameter.Create("Context", "Options: Server | Client"),
96
97
  Parameter.Create("Duration", "Duration of profile in seconds (max 5s)"),
97
- Parameter.Create("Callstacks", "Enable callstacks for profile (this is laggy)"),
98
- (context, d, callstacks) => {
99
- if (d is < 0 or > 5) {
100
- Debug.LogError("You can only profile for a max of 5s.");
101
- return;
102
- }
98
+ (context, d) => {
99
+ OnProfileCommand(context, d, false);
100
+ }
101
+ ));
103
102
 
104
- if (context.Equals("client", StringComparison.OrdinalIgnoreCase)) {
105
- if (!Debug.isDebugBuild) {
106
- Debug.Log(
107
- "Unable to capture profile log because debug mode is not enabled. Use the development build branch on Steam to enable debug mode.");
108
- return;
109
- }
110
- StartProfiling(d, null, callstacks);
111
- } else if (context.Equals("server", StringComparison.OrdinalIgnoreCase)) {
112
- Debug.Log("Starting a server profile, view server console to monitor progress.");
113
- NetworkClient.Send(new StartServerProfileMessage { DurationSecs = d, CallstacksEnabled = callstacks });
114
- }
103
+ // Deep profile with callstacks
104
+ DevConsole.AddCommand(Command.Create<string, int>(
105
+ "deepprofile",
106
+ "",
107
+ "Starts and uploads a profile with callstacks. Once complete the download link will be printed.",
108
+ Parameter.Create("Context", "Options: Server | Client"),
109
+ Parameter.Create("Duration", "Duration of profile in seconds (max 5s)"),
110
+ (context, d) => {
111
+ OnProfileCommand(context, d, true);
115
112
  }));
116
113
  }
117
114
 
115
+ private void OnProfileCommand(string context, int dur, bool callstacks) {
116
+ if (dur is < 0 or > 5) {
117
+ Debug.LogError("You can only profile for a max of 5s.");
118
+ return;
119
+ }
120
+
121
+ if (context.Equals("client", StringComparison.OrdinalIgnoreCase)) {
122
+ if (!Debug.isDebugBuild) {
123
+ Debug.Log(
124
+ "Unable to capture profile log because debug mode is not enabled. Use the development build branch on Steam to enable debug mode.");
125
+ return;
126
+ }
127
+ StartProfiling(dur, null, callstacks);
128
+ } else if (context.Equals("server", StringComparison.OrdinalIgnoreCase)) {
129
+ Debug.Log("Starting a server profile, view server console to monitor progress.");
130
+ NetworkClient.Send(new StartServerProfileMessage { DurationSecs = dur, CallstacksEnabled = callstacks });
131
+ }
132
+ }
133
+
118
134
  private void Update() {
119
135
  if (Profiler.enabled != lastProfilerEnabled) {
120
136
  lastProfilerEnabled = Profiler.enabled;
@@ -167,12 +183,6 @@ namespace Code.Health
167
183
  }
168
184
 
169
185
  public void StartProfiling(int durationSecs, [CanBeNull] NetworkConnectionToClient profileInitiator, bool enableCallstacks) {
170
- // TODO check that sender is game dev
171
- // if (Profiler.enabled) {
172
- // Debug.LogWarning("Profiler is already running.");
173
- // return;
174
- // }
175
-
176
186
  var date = DateTime.Now.ToString("MM-dd-yyyy h.mm.ss");
177
187
  var fileName = RunCore.IsClient() ? $"Client-Profile-{date}.raw" : $"Server-Profile-{date}.raw";
178
188
  if (!Directory.Exists(Path.Combine(Application.persistentDataPath, "ClientProfiles"))) {
@@ -193,6 +203,7 @@ namespace Code.Health
193
203
  private async void StopProfilingAfterDelay(string logPath, string fileName, float durationSecs, [CanBeNull] NetworkConnectionToClient profileInitiator) {
194
204
  await Task.Delay((int)(durationSecs * 1000));
195
205
  Profiler.enabled = false;
206
+ Profiler.enableBinaryLog = false;
196
207
  Profiler.enableAllocationCallstacks = false;
197
208
  var info = new FileInfo(logPath);
198
209
 
@@ -13,10 +13,13 @@ namespace Code.Http.Internal {
13
13
  public static string editorUserId;
14
14
  public static string editorAuthToken = "";
15
15
  public static string authToken = "";
16
- private static TaskCompletionSource<bool> authTokenSetTaskCompletionSource = new();
16
+ public static TaskCompletionSource<bool> authTokenSetTaskCompletionSource = new();
17
17
 
18
- static InternalHttpManager() {
19
- if (RunCore.IsServer()) {
18
+ // This handles the case when we are a server in editor dedicated mode.
19
+ // In this case, we immediately resolve the task because we will not have any auth token.
20
+ [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
21
+ public static void OnLoad() {
22
+ if (RunCore.IsServer() && !RunCore.IsClient() && RunCore.IsEditor()) {
20
23
  authTokenSetTaskCompletionSource.TrySetResult(true);
21
24
  }
22
25
  }
@@ -27,7 +30,7 @@ namespace Code.Http.Internal {
27
30
  return HttpManager.GetAsync(url, GetHeaders());
28
31
  }
29
32
  #endif
30
-
33
+
31
34
  return authTokenSetTaskCompletionSource.Task.ContinueWith(_ => {
32
35
  return HttpManager.GetAsync(url, GetHeaders());
33
36
  }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap();
@@ -180,7 +180,14 @@ public class AirshipComponent : MonoBehaviour, ITriggerReceiver {
180
180
  script = runtimeScript;
181
181
  }
182
182
  else {
183
- Debug.LogError($"Failed to find code.zip compiled script. Path: {script.m_path.ToLower()}, GameObject: {gameObject.name}", gameObject);
183
+ var isPackage = scriptPath.StartsWith("Assets/AirshipPackage");
184
+ if (script == null) {
185
+ var suggestion = isPackage ? "have you published this package?" : "have you done a full publish of this game?";
186
+ Debug.LogError($"Could not find compiled script from asset bundle '{scriptPath}' for GameObject {gameObject.name} (Missing Script Asset) - {suggestion}", gameObject);
187
+ }
188
+ else {
189
+ Debug.LogError($"Could not find compiled script in code archive '{script.m_path.ToLower()}' for GameObject {gameObject.name} (Missing Runtime Script Code)", gameObject);
190
+ }
184
191
  return;
185
192
  }
186
193
  #endif
@@ -11,6 +11,7 @@ public class PlayerInfoDto {
11
11
  public string username;
12
12
  public string profileImageId;
13
13
  public string orgRoleName;
14
+ public string transferPacket;
14
15
  public GameObject gameObject;
15
16
  }
16
17
 
@@ -21,6 +22,7 @@ public class PlayerInfo : NetworkBehaviour {
21
22
  [SyncVar] public int connectionId;
22
23
  [SyncVar] public string profileImageId;
23
24
  [SyncVar] public string orgRoleName;
25
+ public string transferPacket;
24
26
  public AudioSource voiceChatAudioSource;
25
27
 
26
28
  private void Start() {
@@ -28,13 +30,14 @@ public class PlayerInfo : NetworkBehaviour {
28
30
  PlayerManagerBridge.Instance.AddPlayer(this);
29
31
  }
30
32
 
31
- public void Init(int connectionId, string userId, string username, string profileImageId, string orgRoleName) {
33
+ public void Init(int connectionId, string userId, string username, string profileImageId, string orgRoleName, string transferPacket) {
32
34
  this.gameObject.name = "Player_" + username;
33
35
  this.connectionId = connectionId;
34
36
  this.userId = userId;
35
37
  this.username = username;
36
38
  this.profileImageId = profileImageId;
37
39
  this.orgRoleName = orgRoleName;
40
+ this.transferPacket = transferPacket;
38
41
 
39
42
  this.InitVoiceChat();
40
43
  }
@@ -82,6 +85,7 @@ public class PlayerInfo : NetworkBehaviour {
82
85
  username = this.username,
83
86
  profileImageId = this.profileImageId,
84
87
  orgRoleName = this.orgRoleName,
88
+ transferPacket = this.transferPacket,
85
89
  gameObject = this.gameObject,
86
90
  };
87
91
  }
@@ -176,7 +176,7 @@ namespace Code.Player {
176
176
  var go = Instantiate(this.playerPrefab, Instance.transform.parent);
177
177
 
178
178
  var playerInfo = go.GetComponent<PlayerInfo>();
179
- playerInfo.Init(connectionId, userId, username, profilePictureId, string.Empty);
179
+ playerInfo.Init(connectionId, userId, username, profilePictureId, string.Empty, string.Empty);
180
180
 
181
181
  // var identity = go.GetComponent<NetworkIdentity>();
182
182
  NetworkServer.Spawn(go);
@@ -217,7 +217,7 @@ namespace Code.Player {
217
217
  // #if UNITY_SERVER || true
218
218
  // Debug.Log($"Initializing Player as {userData.username} owned by " + conn);
219
219
  // #endif
220
- playerInfo.Init(conn.connectionId, userData.uid, userData.username, userData.profileImageId, userData.orgRoleName);
220
+ playerInfo.Init(conn.connectionId, userData.uid, userData.username, userData.profileImageId, userData.orgRoleName, userData.fullTransferPacket);
221
221
  } else {
222
222
  #if UNITY_SERVER || true
223
223
  Debug.Log("Missing UserData for " + conn);
@@ -34,8 +34,7 @@ public abstract class Singleton<T> : MonoBehaviour where T : MonoBehaviour
34
34
  go.name = typeof(T).ToString();
35
35
 
36
36
  var coreScene = SceneManager.GetSceneByName("CoreScene");
37
- // if (!coreScene.isLoaded) return null;
38
- if (coreScene.IsValid()) {
37
+ if (coreScene.IsValid() && coreScene.isLoaded) {
39
38
  SceneManager.MoveGameObjectToScene(go, coreScene);
40
39
  }
41
40
 
@@ -131,7 +131,6 @@ namespace Code.Airship.Resources.VoxelRenderer.Editor {
131
131
  //Select this
132
132
  selection.gameObject.SetActive(true);
133
133
  Selection.activeGameObject = selection.gameObject;
134
- Debug.Log("select.1");
135
134
  }
136
135
 
137
136
  if (VoxelWorldEditorToolBase.buttonActive) {
@@ -141,7 +140,6 @@ namespace Code.Airship.Resources.VoxelRenderer.Editor {
141
140
  if (selection) {
142
141
  //Select the world
143
142
  Selection.activeGameObject = world.gameObject;
144
- Debug.Log("select.2");
145
143
  //disable it
146
144
  selection.gameObject.SetActive(false);
147
145