版权声明:本文为博主原创文章,未经博主允许不得转载。blog.liujunliang.com.cn https://blog.csdn.net/qq_33747722/article/details/78324586
原文地址:blog.liujunliang.com.cn
接着上一篇文章内容继续开发
源码下载地址:点击打开链接
上一片篇文章介绍使用NHibernate完成类和数据库表的映射
本文将对NHibernate数据进行简单封装,方便在PhotonServer服务器中进行调用
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();
//解析固定路径配置文件nhibernate.cfg.xml
cfg.Configure();
//映射目标程序集 解析映射文件 Student.xml ......
cfg.AddAssembly(typeof(Student).Assembly);
//获取会话对象
sessionFactory = cfg.BuildSessionFactory();
}
session = sessionFactory.OpenSession();
return session;
}
private set { }
}
//添加行
public static void AddData<T>(T t)
{
using (ISession session = GetSession)
{
using (ITransaction transaction=session.BeginTransaction())
{
GetSession.Save(t);
transaction.Commit();
}
}
}
//添加列
public static void RemoveData<T>(T t)
{
using (ISession session = GetSession)
{
using (ITransaction transaction = session.BeginTransaction())
{
GetSession.Delete(t);
transaction.Commit();
}
}
}
//通过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>
/// 通过名称获取对象
/// </summary>
/// <typeparam name="T">需要获取的对象</typeparam>
/// <param name="dataBaseName">在数据库中的列名称</param>
/// <param name="targetName">获取对象的目标名</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>
/// 得到表内的全部对象
/// </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;
}
}
//查询是否有符合id和姓名相同的对象
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]))//类属性名 属性值
.Add(Restrictions.Eq(arg[2].ToString(), arg[3]))
.UniqueResult<T>();
if (t == null)
{
return false;
}
return true;
}
}
/// <summary>
/// 更新数据表
/// </summary>
/// <typeparam name="T">数据表映射的对象</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();
}
}
}
}
}
在主函数调用
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 = "小张", mScore = 10 };
NHibernateHelper.AddData(sd);
}
}
}
运行程序,一切正常,打开SQLyog,在student数据表中添加一行数据
接下来就是在PhotonServer中调用,来实现与MySQL数据库交互
按图下将类、配置文件集成到类库中(注意需要修改下类和配置文件中的程序集及命名空间)
接下来就是在Unity3d游戏客户端中与PhotonServer通信进而访问本地数据库
在Unity3d客户端上创建UI(这里简单拖入输入框和按钮)
如下图创建脚本
我们的游戏有很多中请求(比如登入、注册请求等等)
所以都继承自BaseRequest
using ExitGames.Client.Photon;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public abstract class BaseRequest : MonoBehaviour
{
[HideInInspector]
//该请求的操作类型
public Collective.OperationMode operationMode = Collective.OperationMode.Default;
public virtual void Start() { }
public abstract void OnOperationRequest();
public abstract void OnOperationResponse(OperationResponse operationResponse);
}
这里博主简单的做了一下登录请求
using ExitGames.Client.Photon;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class LoginRequest : BaseRequest
{
//用户名
private InputField mInputName;
//密码
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>();
//登录按钮点击事件
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)
{
//登录成功
Debug.Log("用户登录成功");
}
else if(resultCode == Collective.OperationResult.FAIL)
{
//登录失败
Debug.Log("登录失败");
}
}
}
最后附上上篇博文GameContext脚本,在这里有些地方发生了更新
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using ExitGames.Client.Photon;
public class GameContext : MonoBehaviour,IPhotonPeerListener
{
/// <summary>
/// 存储操作类型与请求
/// </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)
{
}
//接收服务器发来的事件
public void OnEvent(EventData eventData)
{
switch (eventData.Code)
{
case 0:
//获取事件数据
object value = eventData.Parameters.FirstOrDefault(q => q.Key == 1).Value;
Debug.Log(value.ToString());
break;
default:
break;
}
}
//接收响应数据(客户端发送了请求)
public void OnOperationResponse(OperationResponse operationResponse)
{
BaseRequest request = requestDic.FirstOrDefault(q => q.Key == (Collective.OperationMode)operationResponse.OperationCode).Value;
if (request != null)
{
request.OnOperationResponse(operationResponse);
}
else
{
//获取响应数据失败
Debug.LogError("获取响应数据失败");
}
}
//连接状态发送改变
public void OnStatusChanged(StatusCode statusCode)
{
Debug.Log("数据连接状态发生的改变:" + statusCode);
}
private void Start()
{
//传输协议UDP 、 通过Listener接收服务器端的响应
peer = new PhotonPeer(this, ConnectionProtocol.Udp);
//连接本地服务器
peer.Connect("127.0.0.1:5055", "MYGameServer");
}
private void Update()
{
//和服务器实时保持数据连接
peer.Service();
}
private void OnDestroy()
{
if (peer != null && peer.PeerState == PeerStateValue.Connected)
{
//断开连接
peer.Disconnect();
}
}
public void AddRequest(BaseRequest request)
{
if (request != null)
{
requestDic.Add(request.operationMode, request);
}
else
{
Debug.LogError("添加数据为空");
}
}
public void RemoveRequest(BaseRequest request)
{
if (request != null && requestDic.ContainsValue(request))
{
requestDic.Remove(request.operationMode);
}
else
{
Debug.LogError("移除失败");
}
}
}
其中Collective是生成的一个类库,该类库包含一些在客户端和服务器端都共同使用枚举类型(源码最后一起打包给大家学习)
在服务器端需要处理相似的逻辑
也是创建请求类,将各种请求继承自BaseRequest
在主类中对各中请求类加入到字典容器中,当监听到数据请求时候,寻找到相应的请求类进行对数据库数据操作(增、删、改、查)
并将最终数据返回给客户端(success、fail)
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>(
//类属性名、属性值
"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("验证成功");
}
peer.SendOperationResponse(response, sendParameters);
}
}
}
其中附上上篇文章服务器端的MyGameServer.cs,在这里有所更新(添加字典容器用于将请求类存储)
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
{
//服务器框架主类 框架入口
public class MyGameServer : Photon.SocketServer.ApplicationBase
{
public static Dictionary<byte, object> requestDic = new Dictionary<byte, object>();
//单例模式
public static ILogger LOG = LogManager.GetCurrentClassLogger();
//当有客户端接入时候调用
protected override PeerBase CreatePeer(InitRequest initRequest)
{
LOG.Info("有一个客户端连接进服务器");
AddRequestOperation();
return new ClientPeer(initRequest);
}
//当框架启动时候调用
protected override void Setup()
{
//设置配置文件属性
log4net.GlobalContext.Properties["Photon:ApplicationLogPath"] = Path.Combine(Path.Combine(this.ApplicationRootPath, "bin_Win64"), "log");//设置日志文件存储目录
//日志配置文件
FileInfo logConfigFileInfo = new FileInfo(Path.Combine(this.BinaryPath, "log4net.config"));
if (logConfigFileInfo.Exists)//配置文件存在
{
//设置Photon日志插件为Log4Next
LogManager.SetLoggerFactory(Log4NetLoggerFactory.Instance);
//Log4Next这个插件读取配置文件
XmlConfigurator.ConfigureAndWatch(logConfigFileInfo);
}
LOG.Info("服务器初始化完成");
}
//将含有的交互请求全部添加到字典里
private void AddRequestOperation()
{
requestDic.Clear();
BaseRequest request = new LoginRequest();
requestDic.Add((byte)request.operationMode, request);
}
//当框架停止时候调用
protected override void TearDown()
{
}
}
}
其中客户端类ClientPeer.cs数据监听函数需要修改
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) { }
//该客户端断开连接
protected override void OnDisconnect(DisconnectReason reasonCode, string reasonDetail)
{
}
//该客户端出操作请求
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("获取请求操作失败");
}
}
}
}
将解决方案重新生成一下,用PhotonControl开启MyGameServer
在Unity开启一个客户端
对数据进行验证,发现一切正常!!!