Unity-Tcp-网络聊天功能(二): 登录与注册

news2024/9/20 1:07:13

5.客户端实现注册与登录接口

创建好UI

接下来定义发给客户端的协议等

public class MessageHelper
{
	//发送登录的消息给服务器 1002
    public void SendLoginMsg(string account, string pwd)
    {
        LoginMsgC2S msg = new LoginMsgC2S();
        msg.account = account;
        msg.password = pwd;
        var str = JsonHelper.ToJson(msg);//json格式化注册请求
        SendToServer(1002, str);//发送
    }

    public Action<LoginMsgS2C> loginHandle;
    //处理登录(结果)请求
    private void LoginMsgHandle(byte[] obj)
    {
        var str = Encoding.UTF8.GetString(obj);//将接受的消息从字节转换为string
        LoginMsgS2C msg = JsonHelper.ToObject<LoginMsgS2C>(str);//在从json格式的string转为对应LoginMsgS2C
        loginHandle?.Invoke(msg);//如果处理注册消息的事件有订阅,就执行。
    }
    
    //发送聊天信息给服务器
    public void SendChatMsg(string account, string chat)
    {
        ChatMsgC2S msg = new ChatMsgC2S();
        msg.player = account;
        msg.msg = chat;
        msg.type = 0;
        var str = JsonHelper.ToJson(msg);//json格式化注册请求
        SendToServer(1003, str);//发送
    }

    public Action<ChatMsgS2C> chatHandle;
    //处理聊天(转发)请求
    private void ChatMsgHandle(byte[] obj)
    {
        var str = Encoding.UTF8.GetString(obj);//将接受的消息从字节转换为string
        ChatMsgS2C msg = JsonHelper.ToObject<ChatMsgS2C>(str);//在从json格式的string转为对应ChatMsgS2C
        chatHandle?.Invoke(msg);//如果处理注册消息的事件有订阅,就执行。
    }
    
    //发送注册的消息给服务器 1001
    public void SendRegisterMsg(string account, string email, string pwd)
    {
        RegisterMsgC2S msg = new RegisterMsgC2S();
        msg.account = account;
        msg.email = email;
        msg.password = pwd;
        var str = JsonHelper.ToJson(msg);//json格式化注册请求
        SendToServer(1001, str);//发送
    }

    public Action<RegisterMsgS2C> registerHandle;
    //处理注册(结果)请求
    private void RigisterMsgHandle(byte[] obj)
    {
        var str = Encoding.UTF8.GetString(obj);//将接受的消息从字节转换为string
        RegisterMsgS2C msg = JsonHelper.ToObject<RegisterMsgS2C>(str);//在从json格式的string转为对应RegisterMsgS2C
        registerHandle?.Invoke(msg);//如果处理注册消息的事件有订阅,就执行。
    }
}

//1002
public class LoginMsgC2S
{
    public string account;
    public string password;
}

public class LoginMsgS2C
{
    public string account;
    public string password;
    public int result;//0成功 1失败:账号或密码错误
}

//1001
public class RegisterMsgC2S
{
    public string account;
    public string email;
    public string password;
}

public class RegisterMsgS2C
{
    public string account;
    public string email;
    public string password;
    public int result;//0成功 1失败:已被注册的账号
}

//1003
public class ChatMsgC2S
{
    public string player;
    public string msg;
    public int type;//0世界聊天
}

//服务器转发给所有在线的客户端
public class ChatMsgS2C
{
    public string player;
    public string msg;
    public int type;//0世界聊天
}

创建Unity-Scripts/View/LoginView.cs和ChatView.cs

逻辑:LoginView用于UI界面按钮控制,调用MessageHelper里面的方法,发送和处理消息

public class LoginView : MonoBehaviour
{
    private GameObject register;
    
    //注册相关
    private Button registerBtn;
    private InputField usernameInput_Register;
    private InputField emailInput_Register;
    private InputField passwordInput_Register;
    private Button registerBtn_Register;
    private Button closeBtn_Register;
    
    //登录相关
    private Button loginBtn;
    private InputField usernameInput_Login;
    private InputField passwordInput_Login;
    
    // Start is called before the first frame update
    void Start()
    {
        register = transform.Find("Register").gameObject;

        //打开注册界面
        registerBtn = transform.Find("RegisterBtn").GetComponent<Button>();
        registerBtn.onClick.AddListener(OpenRegisterView);
        //关闭注册界面
        closeBtn_Register = transform.Find("Register/CloseBtn").GetComponent<Button>();
        closeBtn_Register.onClick.AddListener(CloseRegisterView);

        //注册界面输入框
        usernameInput_Register = transform.Find("Register/UsernameInput/InputField").GetComponent<InputField>();
        emailInput_Register = transform.Find("Register/EmailInput/InputField").GetComponent<InputField>();
        passwordInput_Register = transform.Find("Register/PasswordInput/InputField").GetComponent<InputField>();

        //注册界面-注册按钮
        registerBtn_Register = transform.Find("Register/RegisterBtn").GetComponent<Button>();
        registerBtn_Register.onClick.AddListener(RegisterOnClick);
        
        //登录界面-登录按钮
        loginBtn = transform.Find("LoginBtn").GetComponent<Button>();
        loginBtn.onClick.AddListener(LoginOnClick);

        usernameInput_Login = transform.Find("UsernameInput/InputField").GetComponent<InputField>();
        passwordInput_Login = transform.Find("PasswordInput/InputField").GetComponent<InputField>();
        
        //处理登录结果
        MessageHelper.Instance.loginHandle += LoginHandle;
        MessageHelper.Instance.registerHandle += RegisterHandle;
    }


    // Update is called once per frame
    void Update()
    {
        
    }

    private void CloseRegisterView()
    {
        register.gameObject.SetActive(false);
    }

    private void OpenRegisterView()
    {
        register.gameObject.SetActive(true);
    }

    private void LoginHandle(LoginMsgS2C obj)
    {
        if (obj.result == 0)
        {
            //登录成功将用户信息和返回的用户信息绑定起来,使用PlayerData类
            PlayerData.Instance.LoginMsgS2C = obj;
            Debug.Log("登陆成功");
            //this.gameObject.SetActive(false);
            Destroy(this.gameObject);
            var chatView = Resources.Load<GameObject>("ChatView");
            var chatObj = GameObject.Instantiate<GameObject>(chatView);
            chatObj.AddComponent<ChatView>();
        }
        else
        {
            Tips($"登录失败,错误码:{obj.result}");
        }
    }

    private void RegisterHandle(RegisterMsgS2C obj)
    {
        if (obj.result == 0)
        {
            Debug.Log("注册成功");
            Tips("注册成功");
            register.gameObject.SetActive(false);
            usernameInput_Login.text = obj.account;
            passwordInput_Login.text = obj.password;
        }
        else
        {
            Tips($"注册失败,错误码:{obj.result}");
        }
    }

    private void LoginOnClick()
    {
        if (string.IsNullOrEmpty(usernameInput_Login.text))
        {
            Tips("请输入账号!!!");
            return;
        }
        if (string.IsNullOrEmpty(passwordInput_Login.text))
        {
            Tips("请输入邮箱!!!");
            return;
        }
        //发送数据给服务器
        MessageHelper.Instance.SendLoginMsg(usernameInput_Login.text, passwordInput_Login.text);
    }

    private void RegisterOnClick()
    {
        if (string.IsNullOrEmpty(usernameInput_Register.text))
        {
            Tips("请输入账号!!!");
            return;
        }
        if (string.IsNullOrEmpty(emailInput_Register.text))
        {
            Tips("请输入邮箱!!!");
            return;
        }
        if (string.IsNullOrEmpty(passwordInput_Register.text))
        {
            Tips("请输入密码!!!");
            return;
        }
        //发送数据给服务器
        MessageHelper.Instance.SendRegisterMsg(usernameInput_Register.text, emailInput_Register.text, passwordInput_Register.text);
    }

    private GameObject _tipsObj;
    public void Tips(string str)
    {
        if (_tipsObj != null)
        {
            GameObject.Destroy(_tipsObj);
        }

        var tipsItem = transform.Find("TipsItem").gameObject;
        _tipsObj = GameObject.Instantiate<GameObject>(tipsItem);
        _tipsObj.transform.SetParent(this.transform, false);
        var content = _tipsObj.transform.Find("Text").GetComponent<Text>();
        content.text = str;
        _tipsObj.gameObject.SetActive(true);
        GameObject.Destroy(_tipsObj, 1.5f);
    }

	private void OnDestroy()
    {
        MessageHelper.Instance.loginHandle -= LoginHandle;
        MessageHelper.Instance.registerHandle -= RegisterHandle;
    }
}

创建Unity-Scripts/PlayerData.cs

public class PlayerData
{
    private static PlayerData instance = new PlayerData();
    public static PlayerData Instance => instance;

    public LoginMsgS2C LoginMsgS2C;
}

测试运行。

6.服务端处理注册与登录业务

将Unity MessageHelper里的消息类C2S、S2C等复制到Server-MessageHelper中

class MessageHelper
{
}

//1002
public class LoginMsgC2S
{
    public string account;
    public string password;
}

public class LoginMsgS2C
{
    public string account;
    public string password;
    public int result;//0成功 1失败:账号或密码错误
}

//1001
public class RegisterMsgC2S
{
    public string account;
    public string email;
    public string password;
}

public class RegisterMsgS2C
{
    public string account;
    public string email;
    public string password;
    public int result;//0成功 1失败:已被注册的账号
}

//1003
public class ChatMsgC2S
{
    public string player;
    public string msg;
    public int type;//0世界聊天
}

//服务器转发给所有在线的客户端
public class ChatMsgS2C
{
    public string player;
    public string msg;
    public int type;//0世界聊天
}

Server-Client理论上需要进入数据库判断有无账号,然后处理业务,这里用一个类Server/PlayerData.cs缓存这些数据,不用数据库了

namespace Server
{
    internal class PlayerData
    {
        private static PlayerData instance = new PlayerData();
        public static PlayerData Instance => instance;//单例
        Dictionary<string, RegisterMsgS2C> userMsg = new Dictionary<string, RegisterMsgS2C>();//缓存注册信息

        //注册后,result=0表示注册成功,将这个注册后的信息返回给客户端
        public RegisterMsgS2C Add(RegisterMsgC2S msgC2S)
        {
            var item = new RegisterMsgS2C();
            userMsg[msgC2S.account] = item;
            item.account = msgC2S.account;
            item.password = msgC2S.password;
            item.result = 0;
            return item;
        }

        //判断是否存在相同的账号
        public bool Contain(string account)
        {
            return userMsg.ContainsKey(account);
        }

        //维护已经登陆的用户
        Dictionary<string, Client> LoginUser = new Dictionary<string, Client>();
        public void AddLoginUser(string account, Client client)
        {
            LoginUser[account] = client;
        }

        public Dictionary<string, Client> GetAllLoginUser()
        {
            return LoginUser;
        }
    }
}
//处理注册请求
private void RegisterMsgHandle(byte[] obj)
{
    var msg = JsonHelper.ToObject<RegisterMsgC2S>(obj);
    RegisterMsgS2C response = null;
    if (PlayerData.Instance.Contain(msg.account))
    {
        response = new RegisterMsgS2C();
        response.result = 1;//已经包含该帐号了
    }
    else
    {
        response = PlayerData.Instance.Add(msg);
    }
    SendToClient(1001, JsonHelper.ToJson(response));
}

//处理登录请求
private void LoginMsgHandle(byte[] obj)
{
    //判断账号和密码是否跟缓存的一直,如果是,返回账号和密码
    var msg = JsonHelper.ToObject<LoginMsgC2S>(obj);
    LoginMsgS2C response = new LoginMsgS2C();
    if (PlayerData.Instance.Contain(msg.account))
    {
        response.result = 0;//已包含该账号
        response.account = msg.account;
        response.password = msg.password;

        //将用户储存起来
        PlayerData.Instance.AddLoginUser(msg.account, this);
    }
    else
    {
        response.result = 1;//账号或密码错误
    }
    SendToClient(1002, JsonHelper.ToJson(response));
}

运行测试,表明服务器收到了Unity客户端的注册信息后,在PlayerData中检测没有账号后,注册了一条数据,并返回给Unity客户端注册成功

再次注册同样的数据,表示注册失败,返回result = 1

用刚刚的账号登录,就登录成功了

为什么Unity和Server的输出都是乱码呢,因为直接输出的是包体大小+协议id+包体,所以前面是乱码,只输出包体就不会乱码,一下为修改了在send和receive时只输出body内容,输出内容正常。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/190296.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java程序cpu飙高定位

1 定位过程 CPU飙升问题定位的一般步骤是&#xff1a; 首先通过top指令查看当前占用CPU较高的进程PID查看当前进程消耗资源的线程PID&#xff1a;top -Hp PID通过print命令将线程PID转为16进制&#xff0c;根据该16进制值去打印的堆栈日志内查询&#xff0c;查看该线程所驻留…

Plecs电力电子仿真专业教程-第一季

Plecs电力电子仿真专业教程-第一季 第一章 Plecs是什么&#xff1f; 第一节 Plecs简介 Plecs是瑞士Plexim GmbH公司开发的系统级电力电子仿真软件PLECS。PLECS是一个用于电路和控制结合的多功能仿真软件&#xff0c;尤其适用于电力电子和传动系统。不管您是工业领域中的开发…

Lua 面向对象(详解)

Lua 面向对象&#xff08;详解&#xff09; 参考文章&#xff1a; https://blog.csdn.net/linxinfa/article/details/103254828 https://zhuanlan.zhihu.com/p/115159195 https://blog.codingnow.com/cloud/LuaOO https://blog.codingnow.com/2006/06/oo_lua.html Lua的面向对象…

Homekit智能家居DIY-智能插座

WiFi智能插座对于新手接触智能家居产品更加友好&#xff0c;不需要额外购买网关设备 很多智能小配件也给我们得生活带来极大的便捷&#xff0c;智能插座就是其中之一&#xff0c;比如外出忘记关空调&#xff0c;可以拿起手机远程关闭。 简单说就是&#xff1a;插座可以连接wi…

不再一个个试错,这众多的flex属性

流式布局 本篇我们将从流式布局的四大方面入手&#xff0c;旨在认识、了解、以至于掌握其特性及功能。 为什么要用&#xff1f; 在我们抛弃标准流、定位流以及浮动流之后&#xff0c;取而代之的是flex流式布局。以一种更加优雅的方式实现元素布局。 轴的定义 在开始说它的特…

C语言#if、##ifdef、#ifndef的用法详解

假如现在要开发一个C语言程序&#xff0c;让它输出红色的文字&#xff0c;并且要求跨平台&#xff0c;在 Windows 和 Linux 下都能运行&#xff0c;怎么办呢&#xff1f;这个程序的难点在于&#xff0c;不同平台下控制文字颜色的代码不一样&#xff0c;我们必须要能够识别出不同…

2023最新版easyrecovery数据恢复软件免费版测评

大家好&#xff0c;关于easyrecovery数据恢复软件免费版很多朋友都还不太明白&#xff0c;今天小编就来为大家分享关于easyrecovery数据恢复软件免费版下载使用的知识&#xff0c;希望对各位有所帮助&#xff01; EasyRecovery其实是目前为止我用的最喜欢的一款数据恢复软件&a…

C++string的模拟实现(上篇)

目录 一.命名空间的封装与交换函数模板 1.命名空间的封装与类的定义 2.交换函数模板 二.string类的四个重要默认成员函数 1.构造函数的类外定义&#xff1a; 2.析构函数在类外的定义 3.拷贝构造函数在类外的定义 4.赋值运算符重载在类外的定义 5.关于两个string对象…

在线 OJ 项目(一) · 项目介绍 · 进程与线程 · 实现编译运行模块

一、项目介绍二、导入依赖、创建基本项目结构导入依赖创建基本项目结构三、进程、线程的基础知识回顾四、封装操作进程的工具类五、实现 “编译运行” 模块 Task 类六、封装读写文件的方法修改 JDK 版本七、Task 类的实现八、整理一下项目列表一、项目介绍 项目实现一个在线 O…

煤矿AI智能视频分析识别系统 opencv

煤矿AI智能视频分析识别系统通过opencvpython 深度学习网络模型&#xff0c;对皮带跑偏、撕裂、堆煤、异物、非法运人、有煤无煤状态等异常情况&#xff0c;以及人员工服穿戴、反光衣、安全帽、睡岗离岗、打电话、抽烟等行为进行自动抓拍存档。OpenCV基于C实现&#xff0c;同时…

【正点原子FPGA连载】第二十八章Linux并发与竞争 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

1&#xff09;实验平台&#xff1a;正点原子MPSoC开发板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id692450874670 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第二十八章Linux…

【splishsplash】Houdini粒子的导入与导出

Houdini粒子的导入与导出 Houdini导入到splish 在Houdini中使用file导入任意几何模型 使用points from volume采样点&#xff0c;使其粒子化 使用file导出粒子化之后的模型&#xff0c;后缀写bhclassic 创建json场景文件&#xff08;建议放到MyScences文件夹&#xff09; …

C语言指针是什么?

计算机中所有的数据都必须放在内存中&#xff0c;不同类型的数据占用的字节数不一样&#xff0c;例如 int 占用 4 个字节&#xff0c;char 占用 1 个字节。为了正确地访问这些数据&#xff0c;必须为每个字节都编上号码&#xff0c;就像门牌号、身份证号一样&#xff0c;每个字…

HTTP协议 | 青训营笔记

1、概述 HTTP协议&#xff0c;超文本传输协议 应用层的协议&#xff0c;基于TCP协议&#xff0c;简单可扩展&#xff08;可以自定义header&#xff09; 每个HTTP请求都可以分为请求和响应两个部分 无状态的&#xff08;不知道之前的请求是携带过什么信息&#xff09; 2、协…

【Qt】8.QPainter、高级设置、手动调用绘图事件、绘图设备、文件操作、文件信息

目录 QPainter 代码 widget.h widget.cpp 结果 高级设置 代码 widget.h widget.cpp 结果 手动调用绘图事件 代码 widget.h widget.cpp 结果 绘图设备 代码 widget.h widget.cpp 结果 文件操作 代码 widget.cpp 结果 文件信息 代码 widget.cpp 结果…

一文带你看懂健康管理系统----IPMI

目录 1. IPMI概述 2. IPMI系统设计 3. 主BMC模块设计 5. 从IPMI模块设计 6. 名词解释 6. 代码 1. IPMI概述 智能平台管理接口&#xff08;IPMI&#xff1a;Intelligent Platform Management Interface&#xff09;是一项应用于服务器管理系统设计的标准&#xff0c;由Int…

BSN-DDC基础网络详解(一):基础介绍

BSN-DDC基础网络推出已经一年了&#xff0c;得到了行业应用方和广大开发者的高度认可。一年中BSN产品技术团队也在根据市场业务需求不断更新功能服务&#xff0c;我们将通过本系列文章为大家系统化介绍DDC网络的功能和使用&#xff0c;为感兴趣的朋友提供学习帮助。BSN-DDC基础…

历史与今日的事件

作者简介&#xff1a;一名在校云计算网络运维学生、每天分享网络运维的学习经验、和学习笔记。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 1.2023年1月31日中国最新量子计算机“悟空”即将问世&#xff0c…

【34】C语言 | 动态内存管理

目录 1.为什么存在动态内存分配 2、动态内存函数的介绍 2.1 malloc和free 2.2 calloc 2.3 realloc 1.为什么存在动态内存分配 我们已经掌握的内存开辟方式有: int val 20; //在栈空间上开辟四个字节 char arr[n] {0}; //在栈空间上开辟10个节的连续空间 但是上述的开辟…

mPEG-SS-NHS甲氧基聚乙二醇-二硫键-琥珀酰亚胺酯

mPEG-SS-NHS甲氧基聚乙二醇-双硫键-活性酯 名称&#xff1a;甲氧基聚乙二醇-双硫键-琥珀酰亚胺酯 英文名称&#xff1a;mPEG-SS-NHS 存储条件&#xff1a;-20C&#xff0c;避光&#xff0c;避湿 用 途&#xff1a;仅供科研实验使用&#xff0c;不用于诊治 外观: 固体或粘性…