Source download address: Click Open Link
The previous article described mapping classes and database tables using NHibernate
This article will simply encapsulate NHibernate data for easy invocation in PhotonServer server.
using NHibernate; using NHibernate.Cfg; using MyGameServer.Domain; using NHibernate.Criterion; using System.Collections.Generic; namespace MyGameServer.Helper { public static class NHibernateHelper { private static ISessionFactory sessionFactory = null; private static ISession session = null; public static ISession GetSession { get { if (sessionFactory == null) { Configuration cfg = new Configuration(); //Resolve the fixed path configuration file nhibernate.cfg.xml cfg.Configure(); //Mapping target assembly parses mapping file Student.xml... cfg.AddAssembly(typeof(Student).Assembly); //Getting session objects sessionFactory = cfg.BuildSessionFactory(); } session = sessionFactory.OpenSession(); return session; } private set { } } //add rows public static void AddData<T>(T t) { using (ISession session = GetSession) { using (ITransaction transaction=session.BeginTransaction()) { GetSession.Save(t); transaction.Commit(); } } } //Adding columns public static void RemoveData<T>(T t) { using (ISession session = GetSession) { using (ITransaction transaction = session.BeginTransaction()) { GetSession.Delete(t); transaction.Commit(); } } } //Obtaining objects by ID public static T GetDataById<T>(int id) { using (ISession session = GetSession) { using (ITransaction transaction = session.BeginTransaction()) { T t = session.Get<T>(id); transaction.Commit(); return t; } } } /// <summary> /// Getting objects by name /// </summary> /// <typeparam name="T"> objects to be retrieved </typeparam> /// <param name="dataBaseName">Column name in database </param> /// <param name="targetName">Get the object's target name</param> /// <returns></returns> public static T GetDataByName<T>(string dataBaseName, string targetName) { using (ISession session = GetSession) { T t = session.CreateCriteria(typeof(T)).Add(Restrictions.Eq(dataBaseName, targetName)).UniqueResult<T>(); return t; } } /// <summary> /// Get all the objects in the table /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public static ICollection<T> GetAllUsers<T>() { using (ISession session = GetSession) { IList<T> ts = session.CreateCriteria(typeof(T)).List<T>(); return ts; } } //Query for objects with the same id and name public static bool VerifyUser<T>(params object[] arg) { using (ISession session = GetSession) { T t = session .CreateCriteria(typeof(T)) .Add(Restrictions.Eq(arg[0].ToString(), arg[1]))//Class attribute name attribute value .Add(Restrictions.Eq(arg[2].ToString(), arg[3])) .UniqueResult<T>(); if (t == null) { return false; } return true; } } /// <summary> /// Update data table /// </summary> /// <typeparam name="T">Objects mapped by datasheets </typeparam> /// <param name="t"></param> public static void UpdateData<T>(T t) { using (ISession session = GetSession) { using (ITransaction transaction=session.BeginTransaction()) { session.Update(t); transaction.Commit(); } } } } }
Call in main function
using NHibernate; using NHibernate.Cfg; using LJL.Domain; using LJL.Helper; namespace LJL { class Program { static void Main(string[] args) { Student sd = new Student { mID = 6, mName = "Xiao Zhang", mScore = 10 }; NHibernateHelper.AddData(sd); } } }
Run the program. Everything is OK. Open SQLyog and add a row of data to the student table.
Next, call it in PhotonServer to interact with MySQL database
Integrate classes and configuration files into class libraries as shown below (note that you need to modify assemblies and namespaces in the following classes and configuration files)
The next step is to communicate with PhotonServer in the Unity3d game client and access the local database.
Create UI on Unity3d client (here simply drag in input boxes and buttons)
Create the script as shown below
Our game has many requests (such as login, registration, etc.)
So they all inherit from BaseRequest
using ExitGames.Client.Photon; using System.Collections; using System.Collections.Generic; using UnityEngine; public abstract class BaseRequest : MonoBehaviour { [HideInInspector] //The operation type of the request public Collective.OperationMode operationMode = Collective.OperationMode.Default; public virtual void Start() { } public abstract void OnOperationRequest(); public abstract void OnOperationResponse(OperationResponse operationResponse); }
Here the blogger simply makes a login request
using ExitGames.Client.Photon; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class LoginRequest : BaseRequest { //User name private InputField mInputName; //Password private InputField mInputPassword; public override void Start() { operationMode = Collective.OperationMode.LOGIN; GameContext.GetInstance.AddRequest(this); mInputName = GameObject.Find("IDInputField").GetComponent<InputField>(); mInputPassword = GameObject.Find("NameInputField").GetComponent<InputField>(); //Logon button click event GameObject.Find("LoginButton").GetComponent<Button>().onClick.AddListener(() => { OnOperationRequest(); }); } public override void OnOperationRequest() { GameContext.GetInstance.peer.OpCustom( (byte)this.operationMode, new Dictionary<byte, object> { { (byte)Collective.ParameterMode.NAME, mInputName.text }, { (byte)Collective.ParameterMode.PASSWORD, mInputPassword.text } }, true ); } public override void OnOperationResponse(OperationResponse operationResponse) { Collective.OperationResult resultCode = (Collective.OperationResult)operationResponse.ReturnCode; if (resultCode == Collective.OperationResult.SUCCESS) { //Successful login Debug.Log("User logged in successfully"); } else if(resultCode == Collective.OperationResult.FAIL) { //Logon failure Debug.Log("Logon failure"); } } }
Finally, I attach the GameContext script of the previous blog post, where some updates have taken place.
using System.Linq; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using ExitGames.Client.Photon; public class GameContext : MonoBehaviour,IPhotonPeerListener { /// <summary> /// Storage Operations Types and Requests /// </summary> public Dictionary<Collective.OperationMode, BaseRequest> requestDic = new Dictionary<Collective.OperationMode, BaseRequest>(); public PhotonPeer peer; private static GameContext _instance; public static GameContext GetInstance { get { if (_instance == null) { _instance = GameObject.Find("GameContext").GetComponent<GameContext>(); } return _instance; } } public void DebugReturn(DebugLevel level, string message) { } //Receiving events from the server public void OnEvent(EventData eventData) { switch (eventData.Code) { case 0: //Getting event data object value = eventData.Parameters.FirstOrDefault(q => q.Key == 1).Value; Debug.Log(value.ToString()); break; default: break; } } //Receive response data (client sends request) public void OnOperationResponse(OperationResponse operationResponse) { BaseRequest request = requestDic.FirstOrDefault(q => q.Key == (Collective.OperationMode)operationResponse.OperationCode).Value; if (request != null) { request.OnOperationResponse(operationResponse); } else { //Failed to obtain response data Debug.LogError("Failed to obtain response data"); } } //Connection status send change public void OnStatusChanged(StatusCode statusCode) { Debug.Log("Changes in data connection status:" + statusCode); } private void Start() { //Transport Protocol UDP, Receiving Server-side Responses through Listener peer = new PhotonPeer(this, ConnectionProtocol.Udp); //Connect to local server peer.Connect("127.0.0.1:5055", "MYGameServer"); } private void Update() { //Keep data connection with server in real time peer.Service(); } private void OnDestroy() { if (peer != null && peer.PeerState == PeerStateValue.Connected) { //Disconnect peer.Disconnect(); } } public void AddRequest(BaseRequest request) { if (request != null) { requestDic.Add(request.operationMode, request); } else { Debug.LogError("Add empty data"); } } public void RemoveRequest(BaseRequest request) { if (request != null && requestDic.ContainsValue(request)) { requestDic.Remove(request.operationMode); } else { Debug.LogError("Removal failure"); } } }
Collective is a generated class library, which contains some enumeration types that are used together on both client and server sides (source code is packaged last for everyone to learn)
Similar logic needs to be handled on the server side
It also creates request classes to inherit various requests from BaseRequest
In the main class, request classes are added to the dictionary container. When listening for data requests, the corresponding request classes are found to operate on database data (add, delete, change, check).
And return the final data to the client (success, fail ure)
BaseRequest.cs
using Photon.SocketServer; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MyGameServer.Request { public abstract class BaseRequest { public Collective.OperationMode operationMode = Collective.OperationMode.DEDAULF; public abstract void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters, ClientPeer peer); } }
LoginRequest.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using MyGameServer.Request; using Photon.SocketServer; using MyGameServer.Helper; using MyGameServer.Domain; namespace MyGameServer.Request { public class LoginRequest : BaseRequest { public LoginRequest() { operationMode = Collective.OperationMode.LOGIN; } public override void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters, ClientPeer peer) { Dictionary<byte, object> parameterDic = operationRequest.Parameters; bool result = NHibernateHelper.VerifyUser<Student>( //Class attribute name, attribute value "mID", int.Parse(parameterDic.FirstOrDefault(q => q.Key == (byte)Collective.ParameterMode.NAME).Value.ToString()), "mName", parameterDic.FirstOrDefault(q => q.Key == (byte)Collective.ParameterMode.PASSWORD).Value.ToString() ); MyGameServer.LOG.Info(parameterDic.FirstOrDefault(q => q.Key == (byte)Collective.ParameterMode.NAME).Value.ToString()); MyGameServer.LOG.Info(parameterDic.FirstOrDefault(q => q.Key == (byte)Collective.ParameterMode.PASSWORD).Value.ToString()); OperationResponse response = new OperationResponse(operationRequest.OperationCode); response.ReturnCode = (short)Collective.OperationResult.FAIL; if (result) { response.ReturnCode = (short)Collective.OperationResult.SUCCESS; MyGameServer.LOG.Info("Verification success"); } peer.SendOperationResponse(response, sendParameters); } } }
Attached is MyGameServer.cs on the server side of the article, which is updated here (adding a dictionary container to store the request class)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Photon.SocketServer; using System.IO; using ExitGames.Logging; using ExitGames.Logging.Log4Net; using log4net.Config; using MyGameServer.Domain; using MyGameServer.Helper; using MyGameServer.Request; namespace MyGameServer { //Server Framework Main Class Framework Entry public class MyGameServer : Photon.SocketServer.ApplicationBase { public static Dictionary<byte, object> requestDic = new Dictionary<byte, object>(); //Singleton pattern public static ILogger LOG = LogManager.GetCurrentClassLogger(); //Called when there is client access protected override PeerBase CreatePeer(InitRequest initRequest) { LOG.Info("There is a client connected to the server"); AddRequestOperation(); return new ClientPeer(initRequest); } //Called when the framework starts protected override void Setup() { //Setting profile properties log4net.GlobalContext.Properties["Photon:ApplicationLogPath"] = Path.Combine(Path.Combine(this.ApplicationRootPath, "bin_Win64"), "log");//Setting up the log file storage directory //Log Profile FileInfo logConfigFileInfo = new FileInfo(Path.Combine(this.BinaryPath, "log4net.config")); if (logConfigFileInfo.Exists)//Configuration file exists { //Set the Photon Log Plug-in to Log4Next LogManager.SetLoggerFactory(Log4NetLoggerFactory.Instance); //Log4Next plug-in reads configuration files XmlConfigurator.ConfigureAndWatch(logConfigFileInfo); } LOG.Info("Server initialization completed"); } //Add all the interactive requests contained to the dictionary private void AddRequestOperation() { requestDic.Clear(); BaseRequest request = new LoginRequest(); requestDic.Add((byte)request.operationMode, request); } //Called when the framework stops protected override void TearDown() { } } }
The client class ClientPeer.cs data listening function needs to be modified.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Photon.SocketServer; using PhotonHostRuntimeInterfaces; using MyGameServer.Request; namespace MyGameServer { public class ClientPeer : Photon.SocketServer.ClientPeer { public ClientPeer(InitRequest ir) : base(ir) { } //The client disconnects protected override void OnDisconnect(DisconnectReason reasonCode, string reasonDetail) { } //The client requests operation protected override void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters) { BaseRequest request = (BaseRequest)MyGameServer.requestDic.FirstOrDefault(q => q.Key == (byte)operationRequest.OperationCode).Value; if (request != null) { request.OnOperationRequest(operationRequest, sendParameters, this); } else { MyGameServer.LOG.Info("Failure to obtain request operation"); } } } }
Regenerate the solution and open MyGameServer with PhotonControl
Open a client in Unity
Verify the data and find that everything is normal!!!