提交修改

This commit is contained in:
Bob.Song
2026-03-06 09:44:00 +08:00
parent e125bb869e
commit db7bc90fe2
3631 changed files with 9050 additions and 395938 deletions

311
Assets/Scripts/Entry.cs Normal file
View File

@@ -0,0 +1,311 @@
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; }
}