Results 1 to 5 of 5
  1. #1
    Join Date
    Aug 2010
    Posts
    108

    Quick fix to get the MMO Project working again

    If you have followed Nelson's videos till the end you know that we are left in a broken state so I took 30 minutes last night to see what was going on. Let me preface this by saying it is a quick hack to get the project running again emulating the behavior of Photon 3.x from the Master Servers prospective. In version 4.x of Photon, servers should communicate with each other through the "S2SPeerBase" derived classes instead of the "ClientPeerBase" derived classes.

    In the last video we upgraded to Photon 4.x and changed the Region Server to use an implementation of the "OutboundS2SPeer" class. The correct way to fix this would be on the Master Server side to use an implementation of the "InboundS2SPeer" class and to change the Master Server "Application" class to switch on the port that the connection is made on in the "CreatePeer" method. Here is an example of what I mean.

    THIS FIRST BLOCK IS AN EXAMPLE!! YOU DO NOT NEED TO CHANGE THIS CODE BLOCK!! IT WILL STILL WORK WITH THESE CHANGES THOUGH!!
    Code:
    using log4net;
    using log4net.Config;
    using MMO.Base;
    using Photon.SocketServer;
    using System.IO;
    
    namespace MMO.Server.Master
    {
        public class Application : ApplicationBase
        {
            private static readonly ILog Log = LogManager.GetLogger(typeof(Application));
    
            private readonly MasterServerContext _application;
    
            public Application()
            {
                _application = new MasterServerContext(new SimpleSerializer());
            }
    
            protected override PeerBase CreatePeer(InitRequest initRequest)
            {
                // Check which peer is connecting here based on the incoming port.
                switch (initRequest.LocalPort)
                {
                    case 5055:
                        return new Peer(_application, initRequest);
                    case 5065: // some other port that is only accessible to region servers calling into the master server
                        //return new ClassThatInheritsFromInboundS2SPeer(_application, initRequest);                    
                    default:
                        return null; // Should log an expection for this connection or create a peer and quick disconnect them
                }
            }
    
            protected override void Setup()
            {
                GlobalContext.Properties["ServerName"] = "Master";
                XmlConfigurator.ConfigureAndWatch(new FileInfo(Path.Combine(BinaryPath, "log4net.config")));
                ExitGames.Logging.LogManager.SetLoggerFactory(ExitGames.Logging.Log4Net.Log4NetLoggerFactory.Instance);
            }
    
            protected override void TearDown()
            {
                _application.Dispose();
            }
        }
    }


    START QUICK FIX!!

    We have to open the connection in the Region Server's "Application" class like before, but this time using the OutboundS2SPeer derived class ("MasterServerPeer"). This is all handled in the last 10 lines of the "ConnectToMasterServer" method.

    Next we need to get rid of the "CreateServerPeer" method as it is no longer called. Basically we are moving this logic into the if block of our connection attempt.

    I have removed the rest of the code for brevity.
    Code:
    using log4net;
    using log4net.Config;
    using MMO.Base;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    using Photon.SocketServer;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Photon.SocketServer.ServerToServer;
    using System.Net;
    using ExitGames.Concurrency.Fibers;
    using MMO.Data;
    using MMO.Data.Entities;
    
    namespace MMO.Server.Region
    {
        public class Application : ApplicationBase
        {
            ...
    
            private void ConnectToMasterServer()
            {
                IPEndPoint endpoint;
                try
                {
                    var addressParts = _application.Config.MasterServer.UdpConnection.Address.Split(':');
                    endpoint = new IPEndPoint(IPAddress.Parse(addressParts[0]), int.Parse(addressParts[1]));
    
                }
                catch (Exception e)
                {
                    throw new InvalidOperationException("Cannot parse Config.MasterServer.UdpConnection.Address", e);
                }
    
                //ConnectToServerUdp(endpoint, _application.Config.MasterServer.UdpConnection.ApplicationName, null, 1, null); // Old connection method
    
                Log.Info($"Connecting to Master Server: {_application.Config.MasterServer.UdpConnection}");
                var peer = new MasterServerPeer(this, _application); // Create a new instance of MasterServerPeer 
                if (peer.ConnectToServerUdp(endpoint, _application.Config.MasterServer.UdpConnection.ApplicationName, null, 1, null)) // If the connection succeeds 
                {
                    Log.Info($"Connected to master server {_application.Config.MasterServer.UdpConnection}"); // Log success 
                    peer.OnDisconnected += () => _fiber.Schedule(ConnectToMasterServer, ServerConnectTimeout); // attach our OnDisconnected event handler / delegate
                }
            }
    
            // THIS IS NOT NEEDED FOR THIS
            //protected override S2SPeerBase CreateServerPeer(InitResponse initResponse, object state)
            //{
            //    Log.Info($"Connected to master server {_application.Config.MasterServer.UdpConnection}");
            //    //var peer = new MasterServerPeer(this, _application);
            //    //peer.OnDisconnected += () => _fiber.Schedule(ConnectToMasterServer, ServerConnectTimeout);
    
            //    return peer;
            //}
    
            ...
        }
    }



    Now that we are connecting at a difference point we need to have the Region Server's "MasterServerPeer" class initiate the "InitContext " request at a different point.

    I have removed the rest of the code for brevity.
    Code:
    using Autofac;
    using log4net;
    using MMO.Base;
    using MMO.Base.Async;
    using MMO.Client.Infrastructure;
    using MMO.Client.Systems;
    using Photon.SocketServer;
    using Photon.SocketServer.ServerToServer;
    using PhotonHostRuntimeInterfaces;
    using System;
    using System.Collections.Generic;
    
    namespace MMO.Server.Region
    {
        public class MasterServerPeer : OutboundS2SPeer, ISystemFactory, IClientTransport
        {
            ...
    
            public MasterServerPeer(Application app, GameServerContext application) : base(app)
            {
                _callbacks = new CallbackByteMap<Action<OperationCode, Dictionary<byte, object>>>();
                _eventHandlers = new Action<EventCode, Dictionary<byte, object>>[byte.MaxValue + 1];
                Listeners = new HashSet<IClientTransportListener>();
    
                _application = application;
                _scope = application.Container.BeginLifetimeScope();
                _componentMap = new ComponentMap();
    
                var operationWriter = new SystemsOperationWriter(_application.Serializer, this);
                _clientSystems = new Client.Systems.ClientSystems(_componentMap, this, operationWriter);
                AddEventReader(new SystemsEventReader(_application.Serializer, _clientSystems, this));
    
                // Move the InitContext request to the OnConnectionEstablished method
                //SendOperation(OperationCode.InitContext, new Dictionary<byte, object> { [(byte)OperationParameter.ContextType] = ContextType.Region });
    
                application.OnDiposed += OnApplicationDisposed;
            }
    
            ...
    
            protected override void OnConnectionEstablished(object responseObject)
            {
                // Here is where we should do that InitContext request
                SendOperation(OperationCode.InitContext, new Dictionary<byte, object> { [(byte)OperationParameter.ContextType] = ContextType.Region });
            }
    
            protected override void OnConnectionFailed(int errorCode, string errorMessage)
            {
            }
        }
    }

  2. #2
    Join Date
    Feb 2015
    Location
    Turkiye
    Posts
    12
    Thanks, i've completed the MMO series and i was wondering how am i achieve upgrading photon version 4. As soon as possible, i'll apply the changes you share. If i find any other improvement, i'll share it too. The Project (even the state of "not completed") seems promising. But it needs some refactoring, changing some techniques, changing some code. I've learnt a lot from it and am considering continuing as much as possible.

  3. #3
    Join Date
    Feb 2014
    Posts
    194
    Ah thanks. At a glance only 2 files need to change from the last Nelson video! Thanks for caring enough to help us
    I will go ahead and complete the vids to the end - I had stopped at the end of the downloadable zips he released.

    After that I will try to get the release version working and see how the newer version of TeamCity copes.

    As an aside I am interested in exactly what Nelson is delivering as his final deliverable. We just don't know how close it will be to the playtest session or if it's just source code of what we already have.

  4. #4
    Join Date
    Feb 2015
    Location
    Turkiye
    Posts
    12
    For those who pursuing personal MMO, i've found very similar free content (photon, unity) : https://www.youtube.com/user/cjrgaming.

  5. #5
    Join Date
    Aug 2010
    Posts
    108
    CJR (Christian Richards) was actually a member here who was displeased with the speed of the MMO class years ago. He went off to build his own. He had some life troubles that caused his project to freeze for a long time too. Haven't checked back on him in a while.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •