上一节完成了服务器连接MySQL数据,以及映射关系和部分框架实现,接下来我们实现客户端、服务器端信息通信,实现注册和登录功能。

(一)Unity客户端的实现

1.创建登录注册界面

PhotonServer(三)——实现客户端和服务器的通信(Unity实注册/登录)(上)_Unity3D

2.UI搭建完成后,部署脚本

(1)导入Photon SDK,Common.dll(通信消息所需枚举类和服务器通用,由服务器编译而来)

(2)PhotonEngine类:实现和服务器连接,Connect,接收服务器发送的消息,实现IPhotonPeerListener接口

(3)Request类,单例:实现消息的发送

(4)BaseHandler抽象类:继承此类的脚本实现发送消息实现,接收发送消息服务器返回的信息

(5)BaseEvent抽象类:实现接收服务器发送的消息

(6)LoginPannel类,RegisterPannel类实现登录和注册的UI管理,要挂载到对象上

直接上代码:

PhotonEngine

public class PhotonEngine : MonoBehaviour,IPhotonPeerListener
{
    public static PhotonEngine Instance;
    private static PhotonPeer peer;

    public static PhotonPeer Peer//让外界可以访问我们的PhotonPeer
    {
        get {  return peer;}
    }

    private Dictionary<Common.CodeType, BaseHandler> handleDict = new Dictionary<Common.CodeType, BaseHandler>();
    private Dictionary<Common.EventCode, BaseEvent> eventDict = new Dictionary<EventCode, BaseEvent>();
    private bool IsOnAnewConnect = false;

    [Tooltip("ip:prot")]
    public string Ip_port = "127.0.0.1:4530";//58.216.47.58
    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(this.gameObject);
        }
        else if (Instance != this)
        {
            Destroy(this.gameObject); return;
        }
    }

    private void Start()
    {
        //连接服务器端
        //通过Listender连接服务器端的响应
        //第一个参数 指定一个Licensed(监听器) ,第二个参数使用什么协议
        peer = new PhotonPeer(this, ConnectionProtocol.Tcp);
        StartUp();
    }

    private void Update()
    {
        OnConnecting();      
    }

    private void OnApplicationQuit()
    {
        OnDestroyed();
    }

    public void OnAnewConnect()
    {
        if (IsOnAnewConnect) StartUp();
    }

    public void StartUp()
    {
        //连接 UDP的 Ip地址:端口号,Application的名字
        peer.Connect(Ip_port, "AR_RemoteServer");
    }

    public void OnConnecting()
    {
        peer.Service();//需要一直调用Service方法,时时处理跟服务器端的连接
    }

    public void OnDestroyed()
    {
        //如果peer不等于空并且状态为正在连接
        if ( peer != null && peer.PeerState == PeerStateValue.Connected)
        {
            peer.Disconnect();//断开连接 
        }
    }

    public void InitHandler()
    {

    }

    public void DebugReturn(DebugLevel level, string message)
    {
       
    }

    //如果客户端没有发起请求,但是服务器端向客户端通知一些事情的时候就会通过OnEvent来进行响应 
    public void OnEvent(EventData eventData)
    {
        BaseEvent onEvent = Tool.GetValue<EventCode, BaseEvent>(eventDict, (EventCode)eventData.Code);
        if (onEvent != null) onEvent.OnEvent(eventData);
        else Debug.Log("无此事件");
    }

    //当我们在客户端向服务器端发起请求后,服务器端接受处理这个请求给客户端一个响应就会在这个方法里进行处理
    public void OnOperationResponse(OperationResponse operationResponse)
    {
        BaseHandler handler = Tool.GetValue<CodeType, BaseHandler>(handleDict, (CodeType)operationResponse.OperationCode);
        if (handler != null) handler.OnOperationResponse(operationResponse);
        else Debug.Log("请求错误");
    }

    //如果连接状态发生改变的时候就会触发这个方法。
    //连接状态有五种,
    //正在连接中(PeerStateValue.Connecting),
    //已经连接上(PeerStateValue.Connected),
    //正在断开连接中( PeerStateValue.Disconnecting),
    //已经断开连接(PeerStateValue.Disconnected),
    //正在进行初始化(PeerStateValue.InitializingApplication)
    public void OnStatusChanged(StatusCode statusCode)
    {
        if (statusCode == StatusCode.DisconnectByServerTimeout 
            || statusCode == StatusCode.ExceptionOnConnect 
            || statusCode == StatusCode.DisconnectByServerLogic)
        { 
            GameManager.Instance.OnCreatePeerTip(statusCode + " 服务器异常!");
            IsOnAnewConnect = true;
        }
        else if(statusCode == StatusCode.Connect)
        {
            IsOnAnewConnect = false;
        }
    }

    public void AddHandler(BaseHandler baseHandler)
    {
        handleDict.Add(baseHandler.opCodeType, baseHandler);
    }
    public void RemoveHandler(BaseHandler baseHandler)
    {
        handleDict.Remove(baseHandler.opCodeType);
    }
    public void AddEvent(BaseEvent baseEvent)
    {
        eventDict.Add(baseEvent.eventCode, baseEvent);
    }
    public void RemoveEvent(BaseEvent baseEvent)
    {
        eventDict.Remove(baseEvent.eventCode);
    }
}

Request

public class Request : Singleton<Request>
{
    private Dictionary<byte, object> data = new Dictionary<byte, object>();

    /// <summary>
    /// 发送登录请求
    /// </summary>
    public void SendLoginRequest(string username, string password)
    {
        data.Clear();
        data.Add((byte)ParameterCode.Username, username);
        data.Add((byte)ParameterCode.Password, password);
        PhotonEngine.Peer.SendOperation((byte)CodeType.LogIn, data, SendOptions.SendReliable);
    }

    /// <summary>
    /// 发送注册请求
    /// </summary>
    public void SendRegisterRequest(string username, string password)
    {
        data.Clear();
        data.Add((byte)ParameterCode.Username, username);
        data.Add((byte)ParameterCode.Password, password);
        PhotonEngine.Peer.SendOperation((byte)CodeType.Register, data, SendOptions.SendReliable);
    }

    /// <summary>
    /// 注销请求
    /// </summary>
    /// <param name="username"></param>
    /// <param name="password"></param>
    public void SendRevampRequest(string username, string password)
    {
        data.Clear();
        data.Add((byte)ParameterCode.Username, username);
        data.Add((byte)ParameterCode.Password, password);
        PhotonEngine.Peer.SendOperation((byte)CodeType.Revamp, data, SendOptions.SendReliable);
    }

    /// <summary>
    /// 用户准备好告诉服务器
    /// </summary>
    /// <param name="username"></param>
    public void SendSyncPlayerQuest(string username)
    {
        data.Clear();
        data.Add((byte)ParameterCode.Username, username);
        PhotonEngine.Peer.SendOperation((byte)CodeType.SyncPlayer, data, SendOptions.SendReliable);
    }
}

BaseHandler

public abstract class BaseHandler : MonoBehaviour
{
    public CodeType opCodeType;
    /// <summary>
    /// 发送请求
    /// </summary>
    public abstract void DefaultRequest();
    /// <summary>
    /// 接收客户端请求服务器返回的消息
    /// </summary>
    /// <param name="response"></param>
    public abstract void OnOperationResponse(OperationResponse response);

    public virtual void Start()
    {
        PhotonEngine.Instance.AddHandler(this);
    }
    public virtual void OnDestroy()
    {
        PhotonEngine.Instance.RemoveHandler(this);
    }
}

BaseEvent

public abstract class BaseEvent : MonoBehaviour
{
    public EventCode eventCode;
    //接收服务器发送消息
    public abstract void OnEvent(EventData eventData);//接收服务器发来的消息
    // Start is called before the first frame update
    protected virtual void Start()
    {
        PhotonEngine.Instance.AddEvent(this);
    }
    protected virtual void OnDestroy()
    {
        PhotonEngine.Instance.RemoveEvent(this);
    }
}

LoginPannel 登录

public class LoginPannel : MonoBehaviour
{
    public Text logText;
    public InputField username_inputField;
    public InputField password_inputField;
    public Button loginBtn;
    private LoginHandler handler;

    private void Awake()
    {
        handler = this.GetComponent<LoginHandler>();
    }

    void Start()
    {
        loginBtn.onClick.AddListener(OnLoginClick);
    }
    //登录
    void OnLoginClick()
    {
        logText.text = "";
        handler.username = username_inputField.text;
        handler.password = password_inputField.text;
        handler.DefaultRequest();
    }

    public void OnLoginedResponse(ReturnCode returnCode)
    {
        if (ReturnCode.Success == (ReturnCode)returnCode)
        {
            SceneManager.LoadSceneAsync(1);
        }
        else if (ReturnCode.Failed == (ReturnCode)returnCode)
        {
            logText.text = "登录失败,用户名或密码错误,请重新登录";
        }
        else if (ReturnCode.HaveLogined == (ReturnCode)returnCode)
        {
            logText.text = "登录失败,用户已经登录!";
        }
    }
}

RegisterPannel  注册

public class RegisterPannel : MonoBehaviour
{
    public Text logText;
    public InputField username_inputField;
    public InputField password_inputField;
    public Button registerBtn;
    private RegisterHandler handler;

    private void Awake()
    {
        handler = this.GetComponent<RegisterHandler>();
    }

    private void Start()
    {
        registerBtn.onClick.AddListener(OnRegisterClick);
    }

    void OnRegisterClick()
    {
        logText.text = "";
        handler.username = username_inputField.text;
        handler.password = password_inputField.text;
        handler.DefaultRequest();
    }

    public void OnRegisterResponse(ReturnCode returnCode)
    {
        if(returnCode == ReturnCode.Success)
        {
            OnReturnClick();
        }
        else if(returnCode == ReturnCode.Failed)
        {
            logText.text = "用户名重复,请重新输入";
        }
    }
}

这一节主要做客户端的代码实现,下节将服务器端的实现