Unity3d通过PhotonServer访问MySQL数据库

原文地址: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开启一个客户端

对数据进行验证,发现一切正常!!!


  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要通过令牌访问MySQL数据库,您需要执行以下步骤: 1. 创建一个具有适当权限的数据库用户。可以使用MySQL的管理员账户登录到MySQL服务器,并使用以下命令创建用户: ```sql CREATE USER 'username'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password'; ``` 这将创建一个名为'username'的用户,并将其密码设置为'password'。 2. 授予该用户适当的数据库权限。您可以使用以下命令将特定权限授予用户: ```sql GRANT permission_type ON database_name.* TO 'username'@'localhost'; ``` 在上面的命令中,`permission_type`可以是`SELECT`、`INSERT`、`UPDATE`等,`database_name`是您要授权的数据库名称。 3. 刷新MySQL权限以使更改生效: ```sql FLUSH PRIVILEGES; ``` 4. 使用创建的令牌连接到MySQL数据库。您可以使用Python中的`mysql-connector-python`库来连接MySQL数据库并执行查询。下面是一个示例代码: ```python import mysql.connector cnx = mysql.connector.connect(user='username', password='password', host='localhost', database='database_name') cursor = cnx.cursor() query = "SELECT * FROM table_name;" cursor.execute(query) for row in cursor.fetchall(): print(row) cursor.close() cnx.close() ``` 在上面的代码中,将`username`和`password`替换为您创建的数据库用户的凭据,`localhost`替换为MySQL服务器的主机名,`database_name`替换为您要连接的数据库名称,`table_name`替换为您要查询的表名。 使用以上步骤,您应该能够通过令牌成功访问MySQL数据库。请确保在实际使用中采取适当的安全措施,以保护数据库访问凭据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值