using System; using Microsoft.Extensions.Options; using Sfs2X; using Sfs2X.Core; using Sfs2X.Entities; using Sfs2X.Entities.Data; using Sfs2X.Entities.Variables; using Sfs2X.Requests; using Sfs2X.Util; using sodoff.Configuration; namespace sodoff.Services; public class MMOClientService : IHostedService { private readonly IOptions Config; private ConfigData SFSConfig; public SmartFox SFSClient { get; private set; } public bool IsLoggedIn { get; private set; } public User? CurrentUser { get; private set; } public MMOClientService(IOptions config) { Config = config; // set SFSConfig SFSConfig = new ConfigData(); SFSConfig.Host = Config.Value.MMOAdress; SFSConfig.Port = Config.Value.MMOPort; SFSConfig.Zone = "JumpStart"; // set SFSClient SFSClient = new SmartFox(); SFSClient.ThreadSafeMode = false; // this is set to true by default which requires Unity's thread processing stuff } public Task StartAsync(CancellationToken cancellationToken) { // connect and login to mmo server using SFSConfig Console.WriteLine("Starting Connection To MMO Server..."); SFSClient.Connect(SFSConfig); SFSClient.AddEventListener(SFSEvent.CONNECTION, OnConnectionEstablished); SFSClient.AddEventListener(SFSEvent.CONNECTION_LOST, OnConnectionLost); SFSClient.AddEventListener(SFSEvent.LOGIN, OnLogin); // return completed task (SmartFox seems to be completely synchronous) return Task.CompletedTask; } public Task SetRoomVarForRoom(int roomId, RoomVariable var) { if (IsLoggedIn) { Room room = SFSClient.GetRoomById(roomId); if (room != null) room.SetVariable(var); else return Task.CompletedTask; } else throw new InvalidOperationException("MMO Client Was Not Ready"); return Task.CompletedTask; } public Task SendCommandToUser(string userId, string cmd, string[] parameters) { // SFSClient doesn't seem to have a method to send commands to specific users, so we'll make a custom extension endpoint that will handle it ISFSObject obj = SFSObject.NewInstance(); obj.PutUtfString("UID", userId); obj.PutUtfString("CMD", cmd); obj.PutUtfStringArray("ARR", parameters); SFSClient.Send(new ExtensionRequest("SUE", obj)); return Task.CompletedTask; } public Task StopAsync(CancellationToken cancellationToken) { Console.WriteLine("Stopping Connection To MMO Server..."); if(SFSClient.IsConnected) { if(IsLoggedIn) SFSClient.Send(new LogoutRequest()); SFSClient.Disconnect(); } return Task.CompletedTask; } private void OnConnectionEstablished(BaseEvent evt) { bool success = (bool)evt.Params["success"]; if (success) { Console.WriteLine("Connection Established. Sending Login Request..."); SFSClient.Send(new LoginRequest("API")); } } private void OnConnectionLost(BaseEvent evt) { Console.WriteLine($"Connection To The MMO Server Was Lost. Reason - {(string)evt.Params["reason"]}"); Console.WriteLine("MMO Service Currently Not Ready.\nThis Required A Full API Restart For Realtime Communication To Be Reestablished."); } private void OnLogin(BaseEvent evt) { CurrentUser = (User)evt.Params["user"]; IsLoggedIn = CurrentUser != null; Console.WriteLine($"Logged In? - {IsLoggedIn}"); if (IsLoggedIn) Console.WriteLine("MMO Service Ready."); else Console.WriteLine("MMO Service Not Ready."); } }