Files
Fishing2NetTest/Assets/Scripts/Entry.cs
2026-03-06 09:44:00 +08:00

311 lines
10 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections;
using System.Collections.Generic;
using Fantasy;
using Fantasy.Async;
using Fantasy.Entitas;
using Fantasy.Network;
using Newtonsoft.Json;
using SimpleJSON;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
public sealed class EntryComponent : Entity
{
public Entry Entry;
}
public class Entry : MonoBehaviour
{
private static cfg.Tables _tables;
public static cfg.Tables Tables => _tables;
private Scene _scene;
private Session _session;
public GameObject LoginPanel;
public GameObject ChatPanel;
public Text MessageText;
public InputField PrivateText;
public InputField UserName;
public InputField SendMessageText;
public Button LoginButton;
public Button ExitButton;
public Button BroadcastButton;
public Button ChannelButton;
public Button PrivateButton;
public Button SendButton1;
public Button ChatNodeEventButton;
void Start()
{
LoginPanel.SetActive(true);
ChatPanel.SetActive(false);
StartAsync().Coroutine();
LoginButton.onClick.RemoveAllListeners();
LoginButton.onClick.AddListener(() => { OnLoginButtonClick().Coroutine(); });
ExitButton.onClick.RemoveAllListeners();
ExitButton.onClick.AddListener(() => { OnExitButtonClick().Coroutine(); });
SendButton1.onClick.RemoveAllListeners();
SendButton1.onClick.AddListener(() => { OnSendButton1Click().Coroutine(); });
BroadcastButton.onClick.RemoveAllListeners();
BroadcastButton.onClick.AddListener(() => { OnBroadcastButtonClick().Coroutine(); });
ChannelButton.onClick.RemoveAllListeners();
ChannelButton.onClick.AddListener(() => { OnChannelButtonClick().Coroutine(); });
PrivateButton.onClick.RemoveAllListeners();
PrivateButton.onClick.AddListener(() => { OnPrivateButtonClick().Coroutine(); });
}
private async FTask StartAsync()
{
LoadData();
// 1. 初始化 Fantasy 框架
await Fantasy.Platform.Unity.Entry.Initialize();
// 2. 创建一个 Scene (客户端场景)
// Scene 是 Fantasy 框架的核心容器,所有功能都在 Scene 下运行
// SceneRuntimeMode.MainThread 表示在 Unity 主线程运行
_scene = await Scene.Create(SceneRuntimeMode.MainThread);
_scene.AddComponent<EntryComponent>().Entry = this;
}
private async FTask OnLoginButtonClick()
{
// 创建一个连接这里是连接到目标的Gate服务器
_session = _scene.Connect(
"127.0.0.1:20001",
NetworkProtocolType.KCP,
() =>
{
Log.Debug("连接成功!");
_session.AddComponent<SessionHeartbeatComponent>().Start(2000);
},
() => { Log.Debug("连接失败!"); },
() => { Log.Debug("断开连接!"); },
false, 5000);
// 发送登录的请求给服务器
var response = (A2C_LoginResponse)await _session.Call(new C2A_LoginRequest()
{
Username = UserName.text,
Password = UserName.text,
LoginType = 1
});
if (response.ErrorCode != 0)
{
Log.Error($"登录发生错误{response.ErrorCode}");
return;
}
if (!ParseJWT(response.ToKen, out var payload))
{
return;
}
_session = _scene.Connect(
payload.Address,
NetworkProtocolType.KCP,
() =>
{
Log.Debug("连接成功!");
_session.AddComponent<SessionHeartbeatComponent>().Start(2000);
},
() => { Log.Debug("连接失败!"); },
() => { Log.Debug("断开连接!"); },
false, 5000);
// 发送登录请求到Gate服务器
var loginResponse = (G2C_LoginResponse)await _session.Call(new C2G_LoginRequest()
{
ToKen = response.ToKen
});
if (loginResponse.ErrorCode != 0)
{
Log.Error($"登录发生错误{loginResponse.ErrorCode}");
return;
}
LoginPanel.SetActive(false);
ChatPanel.SetActive(true);
Log.Debug("登录成功!");
}
private async FTask OnExitButtonClick()
{
// var response = (G2C_ExitResponse)await _session.Call(new C2G_ExitRequest());
// if (response.ErrorCode != 0)
// {
// Log.Error($"退出游戏错误 ErrorCode:{response.ErrorCode}");
// return;
// }
// LoginPanel.SetActive(true);
// ChatPanel.SetActive(false);
// Log.Debug("退出游戏成功!");
}
private async FTask OnSendButton1Click()
{
await FTask.CompletedTask;
// SendButton1.interactable = false;
// var response = (Chat2C_SendMessageResponse) await _session.Call(new C2Chat_SendMessageRequest());
// if (response.ErrorCode != 0)
// {
// Log.Error($"发送聊天消息失败 ErrorCode:{response.ErrorCode}");
// return;
// }
// Log.Debug("发送聊天消息成功!");
// SendButton1.interactable = true;
}
private async FTask OnBroadcastButtonClick()
{
BroadcastButton.interactable = false;
var tree = ChatTreeFactory.Broadcast(_scene);
tree = tree.AddendPositionNode(SendMessageText.text, "勇者大陆", 121, 131, 111);
var response = (Chat2C_SendMessageResponse)await _session.Call(new C2Chat_SendMessageRequest()
{
ChatInfoTree = tree
});
if (response.ErrorCode != 0)
{
Log.Error($"发送聊天消息失败 ErrorCode:{response.ErrorCode}");
}
BroadcastButton.interactable = true;
}
private async FTask OnChannelButtonClick()
{
ChannelButton.interactable = false;
var tree = ChatTreeFactory.Team(_scene);
tree.ChatChannelId = 1;
// tree = tree.AddendTextNode("你好欢迎来到Fantasy Chat").AddendLinkNode("点击这里http://www.fantasy.com.cn");
var response = (Chat2C_SendMessageResponse)await _session.Call(new C2Chat_SendMessageRequest()
{
ChatInfoTree = tree
});
if (response.ErrorCode != 0)
{
Log.Error($"发送频道聊天消息失败 ErrorCode:{response.ErrorCode}");
}
ChannelButton.interactable = true;
}
private async FTask OnPrivateButtonClick()
{
PrivateButton.interactable = false;
var tree = ChatTreeFactory.Private(_scene);
tree.Target.Add(Convert.ToInt64(PrivateText.text));
// tree = tree.AddendTextNode("你好欢迎来到Fantasy Chat").AddendLinkNode("点击这里http://www.fantasy.com.cn");
var response = (Chat2C_SendMessageResponse)await _session.Call(new C2Chat_SendMessageRequest()
{
ChatInfoTree = tree
});
if (response.ErrorCode != 0)
{
Log.Error($"发送私聊消息失败 ErrorCode:{response.ErrorCode}");
}
PrivateButton.interactable = true;
}
#region Config
private void LoadData()
{
// 一行代码可以加载所有配置。 cfg.Tables 包含所有表的一个实例字段。
_tables = new cfg.Tables(LoadJson);
}
private static JSONNode LoadJson(string file)
{
//var json = File.ReadAllText($"{your_json_dir}/{file}.json", System.Text.Encoding.UTF8);
//Assets/ResRaw/config/tb/tbbait.json
var jsonAsset = AssetDatabase.LoadAssetAtPath<TextAsset>($"Assets/ResRaw/config/tb/{file}.json");
return JSON.Parse(jsonAsset.text);
}
#endregion
#region JWT
public bool ParseJWT(string toKen, out Payload payloadData)
{
payloadData = null;
try
{
// JWT通常是由三个部分组成的,Header,Payload,Signature。
var tokens = toKen.Split('.');
if (tokens.Length != 3)
{
Log.Error("Invalid JWT token");
return false;
}
// JWT的Payload不是标准的Base64格式因为咱们C#的Convert要求是一个标准的Base64格式。
// JWT的Payload是Base64URL格式,它里面的"-"替代成了"+","_"替代成了"/",需要把这些给还原成Base64格式
var basePayload = tokens[1].Replace('-', '+').Replace('_', '/');
// 因为Base64的编码长度需要是4的倍数如果不是的话咱们需要把这个长度用=来填充,使其长度符合要求
switch (basePayload.Length % 4)
{
// case 0:
// {
// // 如果这个余数是0那就表示长度已经是4的倍数那就没必要处理了。
// break;
// }
// case 1:
// {
// // 如果这个余数是1那就表示这个Base64格式是不正确的不是咱们发放的token。
// // 这样情况下,也不需要处理了。
// break;
// }
case 2:
{
basePayload += "==";
break;
}
case 3:
{
basePayload += "=";
break;
}
}
// 将修复后的字符串解码为数组
var basePayloadBytes = Convert.FromBase64String(basePayload);
var payload = System.Text.Encoding.UTF8.GetString(basePayloadBytes);
payloadData =
JsonConvert.DeserializeObject<Payload>(payload); //JsonHelper.Deserialize<Payload>(payload);
return true;
}
catch (Exception e)
{
Log.Error(e);
return false;
}
}
#endregion
}
public sealed class Payload
{
public long aId { get; set; }
public string Address { get; set; }
public uint SceneId { get; set; }
public int exp { get; set; }
public string iss { get; set; }
public string aud { get; set; }
}