Beta Sprint2
catalogue
1.Achievements
2. Some important codes
3. SCRUM meeting
4.Expected tasks and completed tasks
5.Project Burnout Diagram
6.Task Total Change Chart
7. Result presentation
I.SCRUM section
1.Achievements
Recent Task Description | Members | Links |
---|---|---|
Implementation of chat function[6h] | 汪郑贤【832102222_21124744】 | https://github.com/Tyler-Linchenwei/chat |
Implementation of adding friends function[4h] | 邱韦翔【832102209_21125309】 | https://github.com/Tyler-Linchenwei/chat |
Implementation of adding friends function[4h] | 吴正坤【832102209_21126917】 | https://github.com/Tyler-Linchenwei/chat |
Modify database design vulnerabilities【4h】 | 方光贤【832102209_21125929】 | https://github.com/MochNevin/WechatServer |
2. Some important codes
//------------------------------------------------------------
// 偷我的代码就会被拖进黑暗空间
// Copyright © 2023 Molth Nevin. All rights reserved.
//------------------------------------------------------------
using TMPro;
using UnityEngine;
namespace Erinn
{
/// <summary>
/// 表示一个用于显示聊天文本的网格的类
/// </summary>
public sealed class ChatGrid : MonoBehaviour
{
/// <summary>
/// 获取或设置用于显示文本的 TextMeshPro 文本组件
/// </summary>
public TMP_Text TMPText;
}
}
//------------------------------------------------------------
// 偷我的代码就会被拖进黑暗空间
// Copyright © 2023 Molth Nevin. All rights reserved.
//------------------------------------------------------------
using System.Collections.Generic;
using Sirenix.OdinInspector;
using TMPro;
using UnityEngine;
namespace Erinn
{
/// <summary>
/// 表示一个聊天面板的类,用于管理和显示聊天视图
/// </summary>
public sealed class ChatPanel : MonoBehaviour
{
/// <summary>
/// 当前活动的聊天视图
/// </summary>
[HideInInspector] public ChatView Active;
/// <summary>
/// 聊天面板的名称文本
/// </summary>
[LabelText("名称")] public TMP_Text ChatName;
/// <summary>
/// 聊天视图的预制件
/// </summary>
[LabelText("预制件")] public ChatView Prefab;
/// <summary>
/// 聊天视图的对象池
/// </summary>
[LabelText("池")] public Transform Pool;
/// <summary>
/// 存储用户和对应聊天视图的字典
/// </summary>
public Dictionary<string, ChatView> ChatViews;
/// <summary>
/// 在对象被唤醒时调用,用于初始化字典
/// </summary>
public void OnAwake() => ChatViews = new Dictionary<string, ChatView>();
/// <summary>
/// 接收用户的消息并在对应的聊天视图中显示
/// </summary>
/// <param name="username">发送消息的用户名</param>
/// <param name="message">接收到的消息内容</param>
public void Receive(string username, string message)
{
if (!ChatViews.TryGetValue(username, out var chatView))
{
chatView = Instantiate(Prefab, Pool, false);
chatView.Name = username;
ChatViews[username] = chatView;
}
chatView.Receive(message);
}
/// <summary>
/// 切换到指定用户的聊天视图或创建新的视图
/// </summary>
public void Chat()
{
if (Active != null)
{
if (Active.Name == ChatName.text)
return;
Active.gameObject.SetActive(false);
}
if (!ChatViews.TryGetValue(ChatName.text, out var chatView))
{
chatView = Instantiate(Prefab, Pool, false);
chatView.Name = ChatName.text;
ChatViews[ChatName.text] = chatView;
}
Active = chatView;
chatView.gameObject.SetActive(true);
}
}
}
In this code, we first set up a class for the chat panel to manage and display the chat view. Next, we set the text name, prefabricated parts, object pool, and other contents for the chat view. At the same time, we initialized the dictionary that stores users and corresponding chat views and called it when the object is awakened.
//------------------------------------------------------------
// 偷我的代码就会被拖进黑暗空间
// Copyright © 2023 Molth Nevin. All rights reserved.
//------------------------------------------------------------
using Sirenix.OdinInspector;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace Erinn
{
/// <summary>
/// 聊天视图类,用于管理聊天界面的显示与消息发送
/// </summary>
public class ChatView : MonoBehaviour
{
/// <summary>
/// 用户名,隐藏在Inspector面板中
/// </summary>
[HideInInspector] public string Name;
/// <summary>
/// 输入框,用于用户输入消息
/// </summary>
[LabelText("输入框")] public TMP_InputField InputField;
/// <summary>
/// 左侧聊天框,用于显示接收到的消息
/// </summary>
[LabelText("左")] public ChatGrid Left;
/// <summary>
/// 右侧聊天框,用于显示发送的消息
/// </summary>
[LabelText("右")] public ChatGrid Right;
/// <summary>
/// 聊天框对象池,用于聊天框的对象池管理
/// </summary>
[LabelText("池")] public Transform Pool;
/// <summary>
/// 发送按钮,用户点击发送消息
/// </summary>
public Button SendButton;
/// <summary>
/// 在对象被唤醒时调用的方法,设置发送按钮的点击事件监听器
/// </summary>
private void Awake() => SendButton.onClick.AddListener(Send);
/// <summary>
/// 发送消息的方法
/// </summary>
public void Send()
{
if (string.IsNullOrEmpty(InputField.text))
return;
NetworkTransport.Singleton.Send(new MessageChat
{
username = Name,
content = InputField.text
});
var rightChatGrid = Instantiate(Right.gameObject, Pool, false).GetComponent<ChatGrid>();
rightChatGrid.TMPText.text = InputField.text;
InputField.text = "";
}
/// <summary>
/// 接收消息的方法
/// </summary>
/// <param name="message">接收到的消息文本</param>
public void Receive(string message)
{
var leftChatGrid = Instantiate(Left.gameObject, Pool, false).GetComponent<ChatGrid>();
leftChatGrid.TMPText.text = message;
}
}
}
The above code is related to the chat attempt class and is mainly used to manage the display of the chat interface and the sending of messages. Internally, it includes username (hidden in the Inspector panel), input box (for users to input messages), left chat box (for displaying received messages), right chat box (for displaying sent messages), chat box object pool (for managing the object pool of chat boxes), and send button (for users to click to send messages). Finally, methods for receiving and sending messages were set up for later invocation.
//------------------------------------------------------------
// 偷我的代码就会被拖进黑暗空间
// Copyright © 2023 Molth Nevin. All rights reserved.
//------------------------------------------------------------
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace Erinn
{
/// <summary>
/// 好友类,用于表示聊天中的好友对象
/// </summary>
public sealed class Friend : MonoBehaviour
{
/// <summary>
/// 好友的名称显示文本
/// </summary>
public TMP_Text Name;
/// <summary>
/// 用于触发聊天按钮的按钮组件
/// </summary>
public Button chatButton;
/// <summary>
/// 获取主面板中的聊天名称文本组件
/// </summary>
public TMP_Text ChatName => MainPanel.Singleton.ChatName;
/// <summary>
/// 获取主面板中的聊天面板组件
/// </summary>
public ChatPanel chatPanel => MainPanel.Singleton.chatPanel;
/// <summary>
/// 在对象被唤醒时调用的方法,设置聊天按钮的点击事件监听器
/// </summary>
private void Awake() => chatButton.onClick.AddListener(Chat);
/// <summary>
/// 触发聊天的方法
/// </summary>
public void Chat()
{
ChatName.text = Name.text;
chatPanel.Chat();
MainPanel.Singleton.ShowChat();
}
}
}
The above code is related to the friend class, which includes the display text of the friend’s name, a button component for triggering the chat button, the chat name text component in the main panel, and the chat panel component in the main panel. Simultaneously, a click event listener has been set up, which can be used to trigger related chat methods.
//------------------------------------------------------------
// 偷我的代码就会被拖进黑暗空间
// Copyright © 2023 Molth Nevin. All rights reserved.
//------------------------------------------------------------
using System.Net;
using MemoryPack;
using Sirenix.OdinInspector;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace Erinn
{
/// <summary>
/// 主面板类,用于管理聊天客户端的主界面和相关操作
/// </summary>
public sealed class MainPanel : MonoSingleton<MainPanel>, IRpcCallback
{
/// <summary>
/// 服务器地址
/// </summary>
[LabelText("地址")] public string Address = "127.0.0.1";
/// <summary>
/// 服务器端口
/// </summary>
[LabelText("端口")] public uint Port = 7777;
/// <summary>
/// 登录提示文本
/// </summary>
[Header("")] [LabelText("登录提示")] public TMP_Text loginTip;
/// <summary>
/// 登录邮箱输入框
/// </summary>
[LabelText("登录邮箱")] public TMP_InputField loginEmail;
/// <summary>
/// 登录密码输入框
/// </summary>
[LabelText("登录密码")] public TMP_InputField loginUserpassword;
/// <summary>
/// 注册提示文本
/// </summary>
[LabelText("注册提示")] public TMP_Text registerTip;
/// <summary>
/// 注册邮箱输入框
/// </summary>
[LabelText("注册邮箱")] public TMP_InputField registerEmail;
/// <summary>
/// 注册用户名输入框
/// </summary>
[LabelText("注册用户名")] public TMP_InputField registerUsername;
/// <summary>
/// 注册密码输入框
/// </summary>
[LabelText("注册密码")] public TMP_InputField registerUserpassword;
/// <summary>
/// 注册验证码输入框
/// </summary>
[LabelText("注册验证码")] public TMP_InputField registerEmailcode;
/// <summary>
/// 登录面板游戏对象
/// </summary>
[Header("")] [LabelText("登录")] public GameObject LoginPanel;
/// <summary>
/// 注册面板游戏对象
/// </summary>
[LabelText("注册")] public GameObject RegisterPanel;
/// <summary>
/// 分组面板游戏对象
/// </summary>
[LabelText("组")] public GameObject GroupPanel;
/// <summary>
/// 好友预制体
/// </summary>
[Header("")] [LabelText("朋友")] public Friend FriendPrefab;
/// <summary>
/// 好友对象池的父物体
/// </summary>
[LabelText("朋友池")] public Transform FriendPool;
/// <summary>
/// 待处理好友预制体
/// </summary>
[Header("")] [LabelText("待处理好友预制件")] public PendingFriend PendingFriendPrefab;
/// <summary>
/// 待处理好友对象池的父物体
/// </summary>
[LabelText("待处理好友池")] public Transform PendingPool;
/// <summary>
/// 聊天面板组件
/// </summary>
[Header("")] [LabelText("聊天面板")] public ChatPanel ChatPanel;
/// <summary>
/// 输入好友名称的输入框
/// </summary>
[LabelText("好友名称")] public TMP_InputField FriendInput;
/// <summary>
/// 登录按钮
/// </summary>
[LabelText("登录按钮")] public Button LoginButton;
/// <summary>
/// 通讯录按钮
/// </summary>
[LabelText("通讯录按钮")] public Button TongXunLu;
/// <summary>
/// 注册按钮
/// </summary>
[LabelText("注册按钮")] public Button RegisterButton;
/// <summary>
/// 发送验证码按钮
/// </summary>
[LabelText("发送验证码按钮")] public Button SendEmailcodeButton;
/// <summary>
/// 发送好友请求按钮
/// </summary>
[LabelText("发送好友请求按钮")] public Button SendFriendButton;
/// <summary>
/// 通讯录面板的游戏对象
/// </summary>
[LabelText("通讯录面板")] public GameObject TongXunLuPanelGo;
/// <summary>
/// 聊天名称显示文本
/// </summary>
[LabelText("聊天名称")] public TMP_Text ChatName;
/// <summary>
/// 聊天面板组件
/// </summary>
[LabelText("聊天面板组件")] public ChatPanel chatPanel;
/// <summary>
/// 在对象启动时调用的方法,初始化相关组件和事件监听器
/// </summary>
private void Start()
{
chatPanel.OnAwake();
NetworkTransport.Singleton.Master.RegisterHandlers(this, typeof(MainPanel));
NetworkTransport.Singleton.Connect(IPAddress.Parse(Address), Port);
LoginButton.onClick.AddListener(Login);
TongXunLu.onClick.AddListener(GetFriends);
TongXunLu.onClick.AddListener(GetPendingFriends);
RegisterButton.onClick.AddListener(Register);
SendEmailcodeButton.onClick.AddListener(SendEmailcode);
SendFriendButton.onClick.AddListener(SendFriend);
}
/// <summary>
/// 在聊天面板中显示
/// </summary>
public void ShowChat()
{
TongXunLuPanelGo.SetActive(false);
chatPanel.gameObject.SetActive(true);
}
/// <summary>
/// 处理聊天消息的方法
/// </summary>
[Rpc]
private void OnMessageChat(MessageChat message)
{
ChatPanel.Receive(message.username, message.content);
}
/// <summary>
/// 处理获取好友列表的方法
/// </summary>
[Rpc]
private void OnGetFriends(ResponseGetFriends response)
{
for (var i = 0; i < FriendPool.childCount; ++i)
{
Destroy(FriendPool.GetChild(i).gameObject);
}
for (var i = 0; i < response.friends.Count; ++i)
{
var a = Instantiate(FriendPrefab.gameObject, FriendPool, false).GetComponent<Friend>();
a.Name.text = response.friends[i];
}
}
/// <summary>
/// 处理获取待处理好友列表的方法
/// </summary>
[Rpc]
private void OnGetPendingFriends(ResponseGetPendingFriends response)
{
for (var i = 0; i < PendingPool.childCount; ++i)
{
Destroy(PendingPool.GetChild(i).gameObject);
}
for (var i = 0; i < response.friends.Count; ++i)
{
var a = Instantiate(PendingFriendPrefab.gameObject, PendingPool, false).GetComponent<PendingFriend>();
a.Name.text = response.friends[i];
}
}
/// <summary>
/// 处理登录响应的方法
/// </summary>
[Rpc]
private void OnResponseLogin(ResponseLogin response)
{
loginTip.text = response.Message;
if (response.Success)
{
LoginPanel.SetActive(false);
RegisterPanel.SetActive(false);
GroupPanel.SetActive(true);
}
}
/// <summary>
/// 获取好友列表的方法
/// </summary>
public void GetFriends()
{
Send(new RequestGetFriends());
}
/// <summary>
/// 获取待处理好友列表的方法
/// </summary>
public void GetPendingFriends()
{
Send(new RequestGetPendingFriends());
}
/// <summary>
/// 发送好友请求的方法
/// </summary>
public void SendFriend()
{
var username = FriendInput.text;
if (string.IsNullOrEmpty(username))
return;
Send(new RequestFriend { username = username });
}
/// <summary>
/// 处理注册响应的方法
/// </summary>
[Rpc]
private void OnResponseRegister(ResponseRegister response) => registerTip.text = response.Message;
/// <summary>
/// 发送网络消息的通用方法
/// </summary>
private void Send<T>(T value) where T : struct, INetworkMessage, IMemoryPackable<T> => NetworkTransport.Singleton.Master.Send(value);
/// <summary>
/// 处理登录的方法
/// </summary>
public void Login()
{
var email = loginEmail.text;
var userpassword = loginUserpassword.text;
Send(new RequestLogin { email = email, userpassword = userpassword });
}
/// <summary>
/// 处理注册的方法
/// </summary>
public void Register()
{
var email = registerEmail.text;
var username = registerUsername.text;
var userpassword = registerUserpassword.text;
var emailcode = registerEmailcode.text;
Send(new RequestRegister { email = email, username = username, userpassword = userpassword, emailcode = emailcode });
}
/// <summary>
/// 发送验证码的方法
/// </summary>
public void SendEmailcode()
{
var email = registerEmail.text;
Send(new RequestSendCode { email = email });
}
}
}
The above code sets up the main interface for managing chat clients and the main panel class for related operations. Internally, there are settings such as server address, server port, login display text, login email input box, login password input box, etc. And methods for processing chat messages, methods for obtaining friend lists, methods for obtaining pending friend lists, methods for processing login responses, methods for obtaining friend lists, etc
//------------------------------------------------------------
// 偷我的代码就会被拖进黑暗空间
// Copyright © 2023 Molth Nevin. All rights reserved.
//------------------------------------------------------------
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace Erinn
{
/// <summary>
/// 待处理好友类,用于表示待处理的好友请求
/// </summary>
public sealed class PendingFriend : MonoBehaviour
{
/// <summary>
/// 待处理好友的名称显示文本
/// </summary>
public TMP_Text Name;
/// <summary>
/// 接受好友请求的按钮组件
/// </summary>
public Button AcceptButton;
/// <summary>
/// 拒绝好友请求的按钮组件
/// </summary>
public Button RejectButton;
/// <summary>
/// 在对象被唤醒时调用的方法,设置接受和拒绝按钮的点击事件监听器
/// </summary>
private void Awake()
{
AcceptButton.onClick.AddListener(Accept);
RejectButton.onClick.AddListener(Reject);
}
/// <summary>
/// 接受好友请求的方法
/// </summary>
public void Accept() => NetworkTransport.Singleton.Send(new MessageUpdateFriend
{
username = Name.text,
accepted = true
});
/// <summary>
/// 拒绝好友请求的方法
/// </summary>
public void Reject() => NetworkTransport.Singleton.Send(new MessageUpdateFriend
{
username = Name.text,
accepted = false
});
}
}
The above is a pending friend class used to represent pending friend requests, which includes the name display text of the pending friend, a button component to accept friend requests, and a button component to reject friend requests. And a click event listener for accept and reject buttons, which calls relevant methods when the object is awakened. Finally, there are methods for accepting friend requests and methods for rejecting friend requests.
3. SCRUM meeting
PM report
4.Expected tasks and completed tasks
Project | Time |
---|---|
Overall expected tasks for the near-term project | 5 tasks with an estimated total time of 240 hours |
Basic UI design for chat interface | completed in 40 hours |
UI interface optimization | completed in 32 hours |
Implementation of adding friend related functions | completed in 40 hours |
Implementation of chat function | completed in 48 hours |
5.Project Burnout Diagram
6.Task Total Change Chart
From setting the total amount of tasks before the start of the task to gradually deepening the project, we found that the tasks we initially set were too general and not detailed enough. And there are still some unfinished functions before some tasks. Based on the original expected tasks, we have added more detailed task descriptions and some new tasks.
7. Result presentation
aaa