private static IEnumerator InternalRunClient(QNetGameInitializerData data, Action onDone) { // activate loading screen OnClientLoadingInfoUpdated?.Invoke(true, "LOADING LEVEL", $"Loading {data.LevelName}"); OnClientLoadingStart?.Invoke(); yield return(new WaitForSeconds(0.6f)); // wait some time, lol var sw = Stopwatch.StartNew(); // load world fist LastMapState = QNetMapState.Loading; OnMapStateChanged?.Invoke(QNetMapState.Loading); var isLevelLoading = true; QNetLevelLoader.Load(data.LevelName, () => { isLevelLoading = false; }); while (isLevelLoading) { yield return(new WaitForEndOfFrame()); } OnLevelLoaded?.Invoke(data.LevelName); yield return(new WaitForEndOfFrame()); // update lading screen OnClientLoadingInfoUpdated?.Invoke(true, "LOADING WORLD", "Waiting for server."); GameIsInitializing = false; GameInitialized = true; JEMLogger.Log($"QNetUnity ClientRun main work took {sw.Elapsed.Milliseconds:0.00}ms."); onDone?.Invoke(); }
private static void Main() { // clear logger JEMLogger.ClearLoggerDirectory(); JEMLogger.Log("Hello, SMC!"); // check arguments var args = Environment.GetCommandLineArgs(); if (args.Length < 2) { JEMLogger.LogError("Unable to run application. Invalid arguments (0)."); Environment.Exit(0); } if (!File.Exists(args[1])) { JEMLogger.LogError("Unable to run application. Invalid arguments (1)."); Environment.Exit(0); } // run window Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new MainWindow()); }
/// <summary> /// Destroy given object in local world of QNet. /// </summary> /// <param name="obj">Object to destroy.</param> public static void InternalDestroy([NotNull] QNetObjectBehaviour obj) { if (obj == null) { return; } obj.Spawned = false; obj.OnInternalDestroy(); obj.OwnerIdentity = 0; if (_spawnedBehaviours.Contains(obj)) { Destroy(obj.gameObject); _spawnedBehaviours.Remove(obj); // rebuild array SpawnedBehaviours = _spawnedBehaviours.ToArray(); } else if (_predefinedBehaviours.Contains(obj)) { obj.gameObject.SetActive(false); _predefinedBehaviours.Remove(obj); // rebuild array PredefinedBehaviours = _predefinedBehaviours.ToArray(); } else { Destroy(obj.gameObject); JEMLogger.LogError("InvalidQNetObject to destroy"); } }
/// <summary> /// Starts local host based on given configuration. /// </summary> public static void StartHost([NotNull] QNetConfiguration configuration) { //if (!Nickname.IsSet) // throw new InvalidOperationException("QNet is unable to start host while nickname is not set."); if (IsHostActive) { throw new InvalidOperationException( "QNet is unable to start host while there is already active instance of host."); } if (configuration == null) { throw new ArgumentNullException(nameof(configuration)); } JEMLogger.Log("QNet is starting local host."); IsHostActive = true; StartServer(configuration); StartClient(configuration.IpAddress, configuration.Port, string.Empty); Server.SetUpHostServer(Client.OriginalConnection); Client.OnDisconnection += (lostConnection, reason) => { reason = $"(Client) {reason}"; JEMLogger.Log("QNet is stopping host because of client disconnection."); // stop all peers StopCurrentConnection(reason); }; }
private void OnEnable() { if (_t == null) { _t = new Timer(10000); _t.Elapsed += (sender, args) => { if (JEMEditorConfiguration.Configuration.UpdateWorkTime) { if (CurrentCompilation != null) { CurrentSessionTime += 10; CurrentCompilation.SessionTime += 10; var json = JsonConvert.SerializeObject(CurrentCompilation, Formatting.Indented); File.WriteAllText(CompilationNumberFile, json); } } }; _t.Start(); } JEMLogger.Init(); RegisterAnimations(); RefreshLocalData(); JEMEditorConfiguration.Load(); }
/// <summary> /// Saves current configuration. /// </summary> public static void Save() { var file = ResolveConfigurationFile(); JEMLogger.InternalLog($"Saving JEMEditorConfiguration data at {file}"); File.WriteAllText(file, JsonConvert.SerializeObject(Configuration, Formatting.Indented)); }
internal static void OnServerWorldSerialization(QNetMessage message, QNetMessageReader reader, ref bool disallowRecycle) { // CLIENT: server qnet object send ends // server ends sending of serialized objects // now client can starts it's de-serialization but if client is also host, this operation is completely ignored // because all object was serialized at server startup if (QNetManager.IsServerActive) { // ignoring all operations and continuing by sending WORLD_SERIALIZED message JEMLogger.Log("Ignoring QNetObject serialization. (Host)"); QNetManager.Client.Send(QNetLocalChannel.DEFAULT, QNetMessageMethod.ReliableOrdered, QNetUnityLocalHeader.WORLD_SERIALIZED); } else { // run late client world serializer to load all serialized objects from memory JEMLogger.Log("Client received all QNetObjects. Starting serialization."); QNetGameInitializer.RunLateClientWorldSerializer(() => { // send WORLD_SERIALIZED message JEMLogger.Log("QNetObject serialized."); QNetManager.Client.Send(QNetLocalChannel.DEFAULT, QNetMessageMethod.ReliableOrdered, QNetUnityLocalHeader.WORLD_SERIALIZED); }); } }
internal static void OnClientLevelLoaded(QNetMessage message, QNetMessageReader reader, ref bool disallowRecycle) { // SERVER: player loads level if (QNetManager.IsHostActive) { if (QNetManager.Client.ConnectionIdentity == reader.Connection.ConnectionIdentity) { // loaded level message has been send from host client, send only WORLD_SERIALIZATION message QNetManager.Server.Send(reader.Connection, QNetLocalChannel.DEFAULT, QNetMessageMethod.ReliableOrdered, QNetUnityLocalHeader.WORLD_SERIALIZATION); return; } } JEMLogger.Log($"Connection {reader.Connection} loads level. Sending world objects."); // send WORLD_SERIALIZING message to prepare client QNetManager.Server.Send(reader.Connection, QNetLocalChannel.DEFAULT, QNetMessageMethod.ReliableOrdered, QNetUnityLocalHeader.WORLD_SERIALIZING); // send all objects to client QNetServerObjects.SendAllObjectsToConnection(reader.Connection); // send WORLD_SERIALIZATION message to start object loading on client QNetManager.Server.Send(reader.Connection, QNetLocalChannel.DEFAULT, QNetMessageMethod.ReliableOrdered, QNetUnityLocalHeader.WORLD_SERIALIZATION); }
internal static void OnPlayerCreate(QNetMessage message, QNetMessageReader reader, ref bool disallowRecycle) { JEMLogger.Log("QNet is receiving player create event."); // de-serialized message var serializedPlayer = reader.ReadMessage <QNetPlayerSerialized>(); // resolve qNetPlayer var qNetPlayer = QNetPlayer.GetQNetPlayer(serializedPlayer.ConnectionIdentity); if (qNetPlayer == null) { if (QNetManager.IsHostActive) { throw new InvalidOperationException( $"Host is unable to GetQNetPlayer by identity {serializedPlayer.ConnectionIdentity}."); } qNetPlayer = QNetPlayer.CreateQNetPlayer(serializedPlayer.ConnectionIdentity, serializedPlayer.NickName, 0); } if (QNetManager.Client.ConnectionIdentity == serializedPlayer.ConnectionIdentity) { // do something with local player // we can't TagAsReady because WORLD_SERIALIZED message already do this } else { // tag player as ready qNetPlayer.TagAsReady(); } }
/// <summary> /// HTML initialized and ready to work. /// </summary> public void onHTMLReady() { MainWindow.Instance.Invoke((MethodInvoker) delegate { JEMLogger.Log("Www initialized and ready."); MainWindow.InitializeJEMUpdater(); }); }
/// <summary> /// Destroys all QNetPlayers. /// </summary> public static bool DestroyAllQNetPlayers() { JEMLogger.Log("QNetUnity is destroying all QNetPlayers."); while (InternalQNetPlayers.Count > 0) { DestroyQNetPlayer(InternalQNetPlayers[0]); } return(true); }
/// <summary> /// Reads Texture2D from file. /// </summary> public static Texture2D ReadFromFile(string file) { if (!File.Exists(file)) { JEMLogger.InternalLogError($"Unable to read Texture2D from file. File {file} not exists."); return(null); } return(FromBytes(File.ReadAllBytes(file))); }
public void onPlayRequest(string userName, string ram) { SMCConfiguration.Loaded.UserName = userName; if (int.TryParse(ram, out var RAM)) { SMCConfiguration.Loaded.UserRAM = RAM; } else { MessageBox.Show(@"Given RAM is invalid.", @"Oops", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } SMCConfiguration.Save(); if (userName.Length < 3) { MessageBox.Show(@"Given Username is too short.", @"Oops", MessageBoxButtons.OK, MessageBoxIcon.Warning); } else { var executable = $@"{MainWindow.Instance.SMCDownloader.WorkDir}\SMC.MC.exe"; if (!File.Exists(executable)) { var result = MessageBox.Show($@"Target file {executable} not exist. Do you want to run repair process?", @"Oops.", MessageBoxButtons.YesNo, MessageBoxIcon.Error); if (result == DialogResult.Yes) { MainWindow.Instance.SMCDownloader.MakeUpdate(true); } return; } // start game var process = new Process { StartInfo = new ProcessStartInfo { FileName = executable, WorkingDirectory = MainWindow.Instance.SMCDownloader.WorkDir, WindowStyle = ProcessWindowStyle.Normal, Arguments = string.Join(" ", userName, RAM.ToString()) } }; JEMLogger.Log( $"Starting game ({process.StartInfo.FileName} at {process.StartInfo.WorkingDirectory})."); process.Start(); Process.GetCurrentProcess().Kill(); } }
/// <summary> /// Async load scene of given name. /// </summary> /// <param name="sceneName">Name of the scene.</param> /// <param name="sleep"></param> public void Load(string sceneName, float sleep = 0f) { if (IsLoading) { JEMLogger.LogError("JEMSceneLoader was unable to load scene of name " + sceneName + ". Another scene is currently loading."); return; } StartCoroutine(Slave(sceneName, sleep)); }
/// <summary> /// Loads base info about resources that game can load. /// </summary> public static bool LoadResourcesInfo() { var stopwatch = Stopwatch.StartNew(); var cfg = JEMGameResourcesConfiguration.Get(); JEMLogger.Log($"New resources info load process has been started at directory {cfg.PackDirectory}"); if (Directory.Exists(cfg.PackDirectory)) { foreach (var file in Directory.GetFiles(cfg.PackDirectory)) { if (!file.EndsWith(cfg.PackExtension)) { continue; } var fileStopWatch = Stopwatch.StartNew(); JEMLogger.Log($"Reading File -> {file}"); var packName = JEMGameResourcesUtility.ResolveResourceNameFromPath(file); var packDescription = string.Empty; var packInfoFile = JEMGameResourcesUtility.ResolveMapDescPath(file); JEMLogger.Log($"Searching For -> {packInfoFile}"); var packInfoFileInfo = new FileInfo(packInfoFile); if (packInfoFileInfo.Exists) { var lines = File.ReadAllLines(packInfoFile); if (lines.Length != 0) { packName = JEMGameResourcesUtility.ResolveResourceName(lines[0]); var list = new List <string>(lines); list.RemoveAt(0); packDescription = string.Join(Environment.NewLine, list.ToArray()); } } InternalGameResourcePacks.Add(new JEMGameResourcePack(packName, packDescription, file)); fileStopWatch.Stop(); JEMLogger.Log($"TOOK -> {fileStopWatch.Elapsed.TotalSeconds:0.0}s"); } } else { JEMLogger.LogError( $"Unable to load game resources info. Base resources patch `{cfg.PackDirectory}` not exist."); return(false); } stopwatch.Stop(); JEMLogger.Log( $"Resources info loaded in -> {stopwatch.Elapsed.TotalSeconds:0.0}s. Total resources loaded: {InternalGameResourcePacks.Count}"); return(true); }
/// <summary> /// Method run from QNeyHandlerWorldReceiver from message of header WORLD_SERIALIZATION. /// </summary> private static IEnumerator InternalRunLateClientWorldSerializer(Action onDone) { var sw = Stopwatch.StartNew(); // update lading screen OnClientLoadingInfoUpdated?.Invoke(true, "LOADING WORLD", $"DeSerializing {QNetWorldSerializer.SerializedObjectsInMemory} world objects."); // load serialized object in memory var time = DateTime.Now; var isWorldSerializing = true; var worldSerializingLastAction = "not defined"; QNetWorldSerializer.DeSerializeObjectsInMemory(() => { isWorldSerializing = false; }, action => { time = DateTime.Now; worldSerializingLastAction = action; }); while (isWorldSerializing && (DateTime.Now - time).Seconds < DeserializingTimeout) { yield return(new WaitForEndOfFrame()); } if ((DateTime.Now - time).Seconds >= DeserializingTimeout) { ShutdownInitializing(worldSerializingLastAction); yield break; } LastMapState = QNetMapState.Loaded; OnMapStateChanged?.Invoke(QNetMapState.Loaded); // update loading screen OnClientLoadingInfoUpdated?.Invoke(true, "READY", "Setting up player."); GameIsInitializing = false; GameInitialized = true; OnClientLoadingEnd?.Invoke(); // the initialize client OnLoadClientSideContent?.Invoke(); bool isWorldReady = false; OnWorldAndNetworkReady?.Invoke(() => { isWorldReady = true; }); while (!isWorldReady) { yield return(new WaitForEndOfFrame()); } JEMLogger.Log($"QNetUnity ClientLateRun main work took {sw.Elapsed.Milliseconds:0.00}ms."); onDone?.Invoke(); }
private IEnumerator InternalUnload(Action onDone) { JEMLogger.Log($"Unloading level {LevelName}"); var asyncOperation = SceneManager.LoadSceneAsync(NoneLevelName, LoadSceneMode.Single); yield return(asyncOperation); LevelName = null; LevelLoaded = false; IsUnloadingLevel = false; JEMLogger.Log("Level unloaded."); onDone?.Invoke(); }
internal static void OnPlayerDelete(QNetMessage message, QNetMessageReader reader, ref bool disallowRecycle) { JEMLogger.Log("QNet is receiving player delete event."); var connectionIdentity = reader.ReadInt16(); var player = QNetPlayer.GetQNetPlayer(connectionIdentity); if (player == null) { throw new InvalidOperationException("InvalidConnectionIdentityError"); } player.TagAsNotReady(); QNetPlayer.DestroyQNetPlayer(player); }
internal static void Process(string str, bool warn = false) { if (AppConfig.Loaded.LogProcessing) { if (warn) { JEMLogger.LogWarning(str, "PROCESSING"); } else { JEMLogger.Log(str, "PROCESSING"); } } }
private void buttonStart_Click(object sender, EventArgs e) { if (!int.TryParse(textBoxRam.Text, out var ram)) { MessageBox.Show(@"Given RAM is invalid.", @"Oops", MessageBoxButtons.OK, MessageBoxIcon.Error); } else { if (textBoxUsername.Text.Length < 3) { MessageBox.Show(@"Given Username is too short.", @"Oops", MessageBoxButtons.OK, MessageBoxIcon.Warning); } else { var executable = $@"{MainWindow.Instance.SMCDownloader.WorkDir}\SMC.MC.exe"; if (!File.Exists(executable)) { var result = MessageBox.Show($@"Target file {executable} not exist. Do you want to run repair process?", @"Oops.", MessageBoxButtons.YesNo, MessageBoxIcon.Error); if (result == DialogResult.Yes) { MainWindow.Instance.SMCDownloader.MakeUpdate(true); } return; } // start game var process = new Process { StartInfo = new ProcessStartInfo { FileName = executable, WorkingDirectory = MainWindow.Instance.SMCDownloader.WorkDir, WindowStyle = ProcessWindowStyle.Normal, Arguments = string.Join(" ", textBoxUsername.Text, ram.ToString()) } }; JEMLogger.Log( $"Starting game ({process.StartInfo.FileName} at {process.StartInfo.WorkingDirectory})."); process.Start(); SaveLaunchOptions(); Process.GetCurrentProcess().Kill(); } } }
private void Update() { if (www.isDone) { JEMLogger.InternalLog($"Texture {URL} has been received."); EditorApplication.update -= Update; if (www.texture == null) { return; } SaveFile(URL, www.texture); Callback?.Invoke(www.texture); } }
private void SMCDownloader_ShutdownRequest(bool isError, string reason) { Invoke((MethodInvoker) delegate { JEMLogger.LogWarning( $"Shutting down by downloader. Error: {(isError ? "Yes" : "no")} Reason: {reason}"); if (isError) { MessageBox.Show(reason, @"Oops (Downloader)", MessageBoxButtons.OK, MessageBoxIcon.Error); } Environment.Exit(9); }); }
/// <summary> /// Sets current cursor. /// </summary> public static void SetCursorIcon(JEMCursorIconName name) { if (Instance == null) { return; } if (Instance.CursorImage == null) { return; } CurrentCursorIconName = name; switch (CurrentCursorIconName) { case JEMCursorIconName.Default: Instance.CursorImage.sprite = Instance.CursorIconDefault; break; case JEMCursorIconName.Move: Instance.CursorImage.sprite = Instance.CursorIconMove; break; case JEMCursorIconName.Resize: Instance.CursorImage.sprite = Instance.CursorIconResize; break; case JEMCursorIconName.Rotate: Instance.CursorImage.sprite = Instance.CursorIconRotate; break; default: throw new ArgumentOutOfRangeException(); } if (Instance.CursorImage.sprite != null) { return; } if (Instance.CursorIconDefault == null) { return; } JEMLogger.LogWarning($"System was unable to set cursor icon {name}. " + "Target sprite is not set.", JEMLogSource.JEM); Instance.CursorImage.sprite = Instance.CursorIconDefault; Instance.CursorImage.enabled = Instance.CursorImage.sprite != null; }
/// <summary> /// Tags this player as ready. /// An actual loading method. /// </summary> public void TagAsReady() { if (Ready) { if (!QNetManager.IsHostActive) { throw new InvalidOperationException("Unable to tag player as ready while is already ready."); } return; } JEMLogger.Log($"> Tagging player {ToString()} as ready."); Ready = true; JEMLogger.Log("> (Tagging) Initializing player on server side."); if (OnPlayerCustomSpawn != null) { OnPlayerCustomSpawn.Invoke(Connection, out var obj); PlayerObject = obj; } else { var spawnPoint = Vector3.one; var spawnRotation = Quaternion.identity; if (OnPlayerSpawnPosition == null) { QNetSpawnArea.GetRandomSpawnArea().GenerateUnreliablePoint(out spawnPoint, out var spawnForward); spawnRotation = Quaternion.LookRotation(spawnForward); } else { OnPlayerSpawnPosition?.Invoke(this, out spawnPoint, out spawnRotation); } // create player's object PlayerObject = QNetObjectBehaviour.SpawnWithOwner(QNetManager.Database.PlayerPrefab, spawnPoint, spawnRotation, Connection); } // check for errors if (PlayerObject == null) { throw new NullReferenceException("PlayerObject is missing."); } JEMLogger.Log($"> Player {ToString()} is now ready."); }
private static void GenerateOffAssembly(Assembly assembly) { var file = new Uri(assembly.CodeBase).AbsolutePath; JEMLogger.Log($"Generating doc of { Path.GetFileName(file)} ({assembly.GetTypes().Length} unique types to process)", "APP"); var xmlFile = Path.GetDirectoryName(file) + JEMVar.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(file) + ".xml"; var doc = new XmlDocument(); doc.Load(xmlFile); var b = new DocBuilder(assembly, doc, DeployDirectory, ExamplesDirectory); var files = b.Build(); JEMLogger.Log($"Done! ({files.Count} .md files generated)", "APP"); }
internal static void OnClientWorldSerialized(QNetMessage message, QNetMessageReader reader, ref bool disallowRecycle) { // SERVER: player loads all sent qnet objects // prepare this client's controller and send final message so the player can play // we will tag this connection as ready, so the system should send this player to all connections on server including owner // if owner receive it's player instance from server, they will initialize local systems including camera and movement controller var player = QNetPlayer.GetQNetPlayer(reader.Connection); if (player == null) { JEMLogger.LogError("QNet encounter an unexcepted error. Connection QNetPlayer not exists."); QNetManager.Server.CloseConnection(reader.Connection, "QNetUnexceptedError"); } else { player.TagAsReady(); } }
/// <summary> /// Tags this player as not ready. /// An actual unloading method. /// </summary> public void TagAsNotReady() { if (!Ready) { throw new InvalidOperationException("Unable to tag player as not ready while is already not ready."); } JEMLogger.Log($"> Tagging player {ToString()} as not ready."); Ready = false; JEMLogger.Log("> (Tagging) De-Initializing player on server side."); // destroy all owned objects QNetServerObjects.DestroyAllOwnedObjectsOfConnection(Connection); JEMLogger.Log($"> Player {ToString()} is now not ready."); }
/// <summary> /// Prepare new connection. /// Preparing process includes all data that connection need to work with server and base map loading. /// After preparing, connection will receive all QNetObjects that are currently created. /// </summary> public static void PrepareNewConnection(QNetConnection connection) { var qNetPlayer = QNetPlayer.GetQNetPlayer(connection.ConnectionIdentity); if (qNetPlayer == null) { JEMLogger.LogError("Newly received connection don't have his QNetPlayer instance. Disconnecting!"); QNetManager.Server.CloseConnection(connection, "InternalQNetPlayerError"); } else { JEMLogger.Log($"Preparing newly received connection called {qNetPlayer.Nickname}."); var writer = QNetManager.Server.GenerateOutgoingMessage((ushort)QNetUnityLocalHeader.LEVEL_LOADING); writer.WriteString(QNetLevelLoader.LevelName); QNetManager.Server.Send(connection, QNetLocalChannel.DEFAULT, QNetMessageMethod.ReliableOrdered, writer); } }
/// <summary> /// Removes serialized object from memory. /// </summary> public static void RemoveSerializedObjectFromMemory(short objectIdentity) { if (QNetManager.IsHostActive) // if host is active, we will ignore this one { return; } if (WorldIsSerialized) { var qNetObject = QNetObjectBehaviour.GetSpawnedObject(objectIdentity) ?? QNetObjectBehaviour.GetPredefinedObject(objectIdentity); if (qNetObject == null) { JEMLogger.LogError( $"System was trying to destroy de-serialized object but target of identity {objectIdentity} not exists in current world."); } else { InternalDestroySerializedObject(qNetObject); } } else { var serializedObject = default(QNetWorldSerializerObject); for (var index = 0; index < InternalSerializedObjectsInMemory.Count; index++) { if (InternalSerializedObjectsInMemory[index].Object.ObjectIdentity == objectIdentity) { serializedObject = InternalSerializedObjectsInMemory[index]; break; } } if (serializedObject.Equals(default(QNetWorldSerializerObject))) { JEMLogger.LogWarning( $"System was trying to remove object from world serializer memory but target of identity {objectIdentity} not exist."); } else { InternalSerializedObjectsInMemory.Remove(serializedObject); } } }
private IEnumerator InternalDestroySerializedObjects(Action onDone) { JEMLogger.Log($"QNetUnity is destroying {InternalSerializedAndInstancedObjects.Count} serialized objects."); for (var index = 0; index < InternalSerializedAndInstancedObjects.Count; index++) { var obj = InternalSerializedAndInstancedObjects[index]; yield return(InternalDestroySerializedObject(obj)); index--; } IsDeSerializing = false; WorldIsSerialized = false; ClearSerializedObjectsFromMemory(); yield return(null); JEMLogger.Log("All serialized objects has been de-serialized."); onDone?.Invoke(); }