基于C#的游戏服务开发 (番外篇)

.NET
465
0
0
2022-12-20
标签   C#

到目前为止,已经完成了服务端框架的底层功能,那么现在测试的方法仅仅是通过在main函数中写一些测试的一些代码,并没有和Unity真正的结合起来,那么接下来就和Unity结合一下,真正的去做一个完整的登陆注册流程.

既然是登录和注册,那么肯定有登录和注册这2个协议:

我们新建一个LoginMsg的脚本:

img

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


public class MsgRegister : MsgBase
{
    public MsgRegister()
    {
        protoName = "MsgRegister";
    }
    //客户端
    public string id = "";
    public string pw = "";

    //服务器返回 -0成功 -1失败
    public int result = 0;

}


public class MsgLogin : MsgBase
{
    public MsgLogin()
    {
        protoName = "MsgLogin";
    }
    //客户端
    public string id = "";
    public string pw = "";

    //服务器返回 -0成功 -1失败
    public int result = 0;
}

public class MsgKick : MsgBase
{
    public MsgKick()
    {
        protoName = "MsgKick";
    }
    //下线原因
    public int reason = 0;
}

接下来要对协议进行处理:

我们起个名字:LoginMsgHandle,注意虽然这个脚本的名字叫这个,但是他也是算一个EventHandler的一个组合类.不要被Unity开发中创建脚本的形式给迷惑了.

img

登录注册以及下线,下线是用来在2个客户端同时登录一个账号的时候需要:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

public partial class MsgHandler
{
    //注册协议处理
    public static void MsgRegister(ClientState c, MsgBase msgBase)
    {
        MsgRegister msg = (MsgRegister)msgBase;
        //执行数据库语法尝试注册
        if (DbManager.Register(msg.id, msg.pw))
        {
            DbManager.CreatPlayer(msg.id);
            msg.result = 0;
        }
        else
        {
            msg.result = 1;
        }
        //将结果返回给客户端
        NetManager.Send(c, msg);
    }

    //登录协议处理
    public static void MsgLogin(ClientState c, MsgBase msgBase)
    {
        MsgLogin msg = (MsgLogin)msgBase;
        //密码校验
        if (!DbManager.CheckPassword(msg.id, msg.pw))
        {
            msg.result = 1;
            NetManager.Send(c, msgBase);
            return;
        }
        //如果已经在线,并在此客户端上又尝试登录
        if (c.player != null)
        {
            msg.result = 1;
            NetManager.Send(c, msgBase);
            return;
        }
        //如果其他客户端登录,踢下线
        if (PlayerManager.isOnline(msg.id))
        {
            //发送踢下线协议
            Player other = PlayerManager.GetPlayer(msg.id);
            MsgKick msgKick = new MsgKick();
            msgKick.reason = 0; 
            other.Send(msgKick);//协议发送
            //断开连接
            NetManager.Close(other.state);
        }
        //获取玩家数据
        PlayerData playerData = DbManager.GetPlayerData(msg.id);
        if (playerData == null)
        {
            msg.result = 1;
            NetManager.Send(c, msg);
            return;
        }
        //构建player
        Player player = new Player(c);
        player.id = msg.id;
        player.data = playerData;
        PlayerManager.AddPlayer(msg.id, player);
        c.player = player;
        //返回协议
        msg.result = 0;
        player.Send(msg); 
    }

    public static void OnDisconnect(ClientState c)
    {
        Console.WriteLine("Close");
        //Player 下线
        if (c.player != null)
        {
            //保存数据
            DbManager.UpdatePlayerData(c.player.id, c.player.data);
            //移除
            PlayerManager.RemovePlayer(c.player.id);
        }
    }
}

到目前为止服务端的功能基本写完,接下来要到Unity中,,写客户端的功能,首先要搭建一个场景,场景布置如下:

img

2个输入框以及登录注册按钮.

新建一个test脚本文件:

流程同样是先连接服务器然后监听一些回调方法.首先是连接服务器以及数据处理的一些方法,这些方法都是之前章节中所写过的,所以这次我们直接复制过来:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Linq;
using TMPro;

public class test : MonoBehaviour
{ 

    private void Start()
    {
        NetManager.Connect("127.0.0.1"8888); 

    }


    private void Update()
    {
        NetManager.Update();
    }

}

还有就是把登录注册的协议也要复制过来:

img

服务器开始的同时运行此脚本,发现连接没有任何问题,接下来就是要做的就是把我们的登录注册协议写进去:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Linq;
using TMPro;

public class test : MonoBehaviour
{
    public TMP_InputField idInput;
    public TMP_InputField pwInput;

    private void Start()
    {
        NetManager.Connect("127.0.0.1"8888);
        NetManager.AddMsgListener("MsgMove", OnMsgMove);
        NetManager.AddEventListener(NetManager.NetEvent.ConnectSucc, OnConnectSucc);
        NetManager.AddEventListener(NetManager.NetEvent.ConnectFail, OnConnectFail);
        NetManager.AddEventListener(NetManager.NetEvent.Close, OnConnectClose);
    }



    void OnConnectSucc(string err)
    {
        Debug.Log("连接成功...");
    }

    void OnConnectFail(string err)
    {
        Debug.Log("连接失败...");
    }

    void OnConnectClose(string err)
    {
        Debug.Log("连接关闭...");
    }

    //发送注册协议
    public void OnRegister()
    {
        MsgRegister msg = new MsgRegister();
        msg.id = idInput.text;
        msg.pw = pwInput.text;
        NetManager.Send(msg);
        Debug.Log(msg.protoName);
        Debug.Log(msg.id);
        Debug.Log(msg.pw);
    }
    //收到注册协议
    public void OnMsgRegister(MsgBase msgBase)
    {
         MsgRegister msg = msgBase as MsgRegister;        if (msg.result == 0)
        {
            Debug.Log("注册成功");
        }
        else
        {
            Debug.Log("注册失败!");
        }
    }

    //发送登录协议
    public void OnLoginClick()
    {
        MsgLogin msg = new MsgLogin();
        msg.id = idInput.text;
        msg.pw = pwInput.text;
        NetManager.Send(msg);
    }

    //收到登录协议
    public void OnMsgLogin(MsgBase msgBase)
    {
        MsgLogin msg = msgBase as MsgLogin;        if (msg.result == 1)
        {
            Debug.Log("登录成功");
        }
        else
        {
            Debug.Log("登录失败");
        }
    }

    //踢下线
    void OnMsgKick(MsgBase msgBase)
    {
        Debug.Log("被踢下线");
    }


    private void Update()
    {
        NetManager.Update();
    }

然后把输入框赋值一下:

img

我们先尝试运行一下,先输入一个错误的用户名和密码按登录键:

img

发现服务器已经调用成功,接下来我们用正确的账户名和密码登录一下:

img

那么再试试注册的方法:

如果是写一个已经存在的账号:

img

相反,写一个没有注册过的账号:

img

那么再看看数据库中的内容:

img

发现了一个bug,客户端没有打印出状态信息,经检查,是协议名字写错了:

修改一下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Linq;
using TMPro;

public class test : MonoBehaviour
{
    public TMP_InputField idInput;
    public TMP_InputField pwInput;

    private void Start()
    {
        NetManager.Connect("127.0.0.1"8888);
        NetManager.AddMsgListener("MsgMove", OnMsgMove);
        NetManager.AddMsgListener("MsgLogin", OnMsgLogin);
        NetManager.AddMsgListener("MsgRegister", OnMsgRegister);
        NetManager.AddEventListener(NetManager.NetEvent.ConnectSucc, OnConnectSucc);
        NetManager.AddEventListener(NetManager.NetEvent.ConnectFail, OnConnectFail);
        NetManager.AddEventListener(NetManager.NetEvent.Close, OnConnectClose);

    }

    public void Send()
    {
        MsgMove msgMove = new MsgMove
        {
            x = 10,
            y = 2,
            z = -110
        };
        NetManager.Send(msgMove);
    }

    public void OnMsgMove(MsgBase msgBase)
    {
        MsgMove msg = msgBase as MsgMove;
        Debug.Log(msg.protoName);
        Debug.Log(msg.x);
        Debug.Log(msg.y);
        Debug.Log(msg.z);
    }


    void OnConnectSucc(string err)
    {
        Debug.Log("连接成功...");
    }

    void OnConnectFail(string err)
    {
        Debug.Log("连接失败...");
    }

    void OnConnectClose(string err)
    {
        Debug.Log("连接关闭...");
    }

    //发送注册协议
    public void OnRegister()
    {
        MsgRegister msg = new MsgRegister();
        msg.id = idInput.text;
        msg.pw = pwInput.text;
        NetManager.Send(msg);

    }
    //收到注册协议
    public void OnMsgRegister(MsgBase msgBase)
    {
        MsgRegister msg = msgBase as MsgRegister;
        if (msg.result == 0)
        {
            Debug.Log("注册成功");
        }
        else
        {
            Debug.Log("注册失败!");
        }
    }

    //发送登录协议
    public void OnLoginClick()
    {
        MsgLogin msg = new MsgLogin();
        msg.id = idInput.text;
        msg.pw = pwInput.text;
        NetManager.Send(msg); 
    }

    //收到登录协议
    public void OnMsgLogin(MsgBase msgBase)
    {
        MsgLogin msg = msgBase as MsgLogin;
        Debug.Log(msg.result);
        if (msg.result == 1)
        {
            Debug.Log("登录成功");
        }
        else
        {
            Debug.Log("登录失败");
        }
    }

    //踢下线
    void OnMsgKick(MsgBase msgBase)
    {
        Debug.Log("被踢下线");
    }


    private void Update()
    {
        NetManager.Update();
        if (Input.GetKeyDown(KeyCode.A))
        {
            Send();
        }
    }

结果如下:

img

enjoy it !!!

本案例的客户端与服务器源码下载方法:公众号回复 服务器开发 即可.