(tools, client, server) feat: Remove gRPC support, add TCP back and reorganized project

This commit is contained in:
2025-08-30 17:07:03 +08:00
parent 8fd5e24865
commit 362aa799b9
28 changed files with 378 additions and 490 deletions

View File

@ -584,7 +584,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
m_IsActive: 0
--- !u!4 &1388451206
Transform:
m_ObjectHideFlags: 0
@ -639,7 +639,7 @@ Transform:
m_GameObject: {fileID: 2036983430}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0.17242, y: 0.05575, z: 0}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
@ -677,7 +677,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
isGlobal: 1
--- !u!1 &2104915506
--- !u!1 &2053271181
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
@ -685,37 +685,37 @@ GameObject:
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2104915508}
- component: {fileID: 2104915507}
- component: {fileID: 2053271183}
- component: {fileID: 2053271182}
m_Layer: 0
m_Name: GrpcClientTest
m_Name: TcpClientTest
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &2104915507
--- !u!114 &2053271182
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2104915506}
m_GameObject: {fileID: 2053271181}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 98c1b145899d4d97bd981b177b5c45a9, type: 3}
m_Script: {fileID: 11500000, guid: e722dcca5e226864b964cd80358a17f9, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!4 &2104915508
m_EditorClassIdentifier: Assembly-CSharp::TcpClientTest
--- !u!4 &2053271183
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2104915506}
m_GameObject: {fileID: 2053271181}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: -0}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
@ -727,6 +727,6 @@ SceneRoots:
m_Roots:
- {fileID: 1057087090}
- {fileID: 613797070}
- {fileID: 2104915508}
- {fileID: 2053271183}
- {fileID: 1388451206}
- {fileID: 2036983432}

View File

@ -1,38 +0,0 @@
using Grpc.Net.Client;
using Grpc.Net.Client.Web;
using Protocol;
using System.Net.Http;
using System.Threading.Tasks;
using UnityEngine;
using Utils;
namespace Network
{
public class GrpcClient : Singleton<GrpcClient>
{
// The address must adopt HTTP.
private const string ServerAddress = "http://127.0.0.1:12345";
private readonly GrpcChannel _channel;
private readonly GameService.GameServiceClient _game;
public GrpcClient()
{
var channelOptions = new GrpcChannelOptions
{
HttpHandler = new GrpcWebHandler(GrpcWebMode.GrpcWeb, new HttpClientHandler())
};
_channel = GrpcChannel.ForAddress(ServerAddress, channelOptions);
_game = new GameService.GameServiceClient(_channel);
Application.quitting += () => _channel.ShutdownAsync().Wait();
}
public async Task<LoginResponse> Login(string username, string password)
{
return await _game.LoginAsync(new LoginRequest { Username = username, Password = password });
}
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: bd54dd152e0e4bbda802e9aa04078197
timeCreated: 1752480707

View File

@ -0,0 +1,70 @@
using System;
using System.Net.Sockets;
using System.Threading.Tasks;
using UnityEngine;
using Utils;
namespace Network
{
public class UnityTcpClient : Singleton<UnityTcpClient>, IDisposable
{
private TcpClient _client;
private bool _disposed;
public UnityTcpClient()
{
try
{
_client = new TcpClient();
_client.Connect("127.0.0.1", 12345);
Application.quitting += Dispose;
}
catch (Exception ex)
{
Debug.LogException(ex);
return;
}
}
public async Task<byte[]> SendAndReceiveData(byte[] data)
{
try
{
await using var stream = _client.GetStream();
await stream.WriteAsync(data, 0, data.Length);
var buffer = new byte[1024];
await stream.ReadAsync(buffer);
return buffer;
}
catch (Exception ex)
{
Debug.LogException(ex);
return new byte[0];
}
}
public void Dispose()
{
if (_disposed) return;
try
{
_client.Close();
_client.Dispose();
}
catch (Exception ex)
{
Debug.LogException(ex);
return;
}
finally
{
_client = null;
}
_disposed = true;
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 39f71cfa622a1194b812b7b3cc5b86c1

View File

@ -1,3 +1,4 @@
using System;
using System.Net.Sockets;
using System.Threading.Tasks;
using UnityEngine;
@ -5,24 +6,62 @@ using Utils;
namespace Network
{
public class UnityUdpClient : Singleton<UnityUdpClient>
public class UnityUdpClient : Singleton<UnityUdpClient>, IDisposable
{
private readonly UdpClient _client;
private UdpClient _client;
private bool _disposed;
public UnityUdpClient()
{
_client = new UdpClient();
_client.Connect("127.0.0.1", 12345);
Application.quitting += () => _client.Close();
try
{
_client = new UdpClient();
_client.Connect("127.0.0.1", 12345);
Application.quitting += Dispose;
}
catch (Exception ex)
{
Debug.LogException(ex);
return;
}
}
public async Task<byte[]> SendAndReceiveData(byte[] data)
{
await _client.SendAsync(data, data.Length);
try
{
await _client.SendAsync(data, data.Length);
var result = await _client.ReceiveAsync();
return result.Buffer;
var result = await _client.ReceiveAsync();
return result.Buffer;
}
catch (Exception ex)
{
Debug.LogException(ex);
return new byte[0];
}
}
public void Dispose()
{
if (_disposed) return;
try
{
_client.Close();
_client.Dispose();
}
catch (Exception ex)
{
Debug.LogException(ex);
return;
}
finally
{
_client = null;
}
_disposed = true;
}
}
}

View File

@ -31,10 +31,7 @@ namespace Protocol {
"ZRgBIAEoCRIQCghwYXNzd29yZBgCIAEoCSJKCg5TaWdudXBSZXNwb25zZRIn",
"CgZyZXN1bHQYASABKA4yFy5wcm90b2NvbC5SZXF1ZXN0UmVzdWx0Eg8KB21l",
"c3NhZ2UYAiABKAkqJgoNUmVxdWVzdFJlc3VsdBILCgdTdWNjZXNzEAASCAoE",
"RmFpbBABMoQBCgtHYW1lU2VydmljZRI4CgVMb2dpbhIWLnByb3RvY29sLkxv",
"Z2luUmVxdWVzdBoXLnByb3RvY29sLkxvZ2luUmVzcG9uc2USOwoGU2lnbnVw",
"EhcucHJvdG9jb2wuU2lnbnVwUmVxdWVzdBoYLnByb3RvY29sLlNpZ251cFJl",
"c3BvbnNlYgZwcm90bzM="));
"RmFpbBABYgZwcm90bzM="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Protocol.RequestResult), }, null, new pbr::GeneratedClrTypeInfo[] {

View File

@ -1,195 +0,0 @@
// <auto-generated>
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: message.proto
// </auto-generated>
#pragma warning disable 0414, 1591, 8981, 0612
#region Designer generated code
using grpc = global::Grpc.Core;
namespace Protocol {
public static partial class GameService
{
static readonly string __ServiceName = "protocol.GameService";
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
static void __Helper_SerializeMessage(global::Google.Protobuf.IMessage message, grpc::SerializationContext context)
{
#if !GRPC_DISABLE_PROTOBUF_BUFFER_SERIALIZATION
if (message is global::Google.Protobuf.IBufferMessage)
{
context.SetPayloadLength(message.CalculateSize());
global::Google.Protobuf.MessageExtensions.WriteTo(message, context.GetBufferWriter());
context.Complete();
return;
}
#endif
context.Complete(global::Google.Protobuf.MessageExtensions.ToByteArray(message));
}
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
static class __Helper_MessageCache<T>
{
public static readonly bool IsBufferMessage = global::System.Reflection.IntrospectionExtensions.GetTypeInfo(typeof(global::Google.Protobuf.IBufferMessage)).IsAssignableFrom(typeof(T));
}
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
static T __Helper_DeserializeMessage<T>(grpc::DeserializationContext context, global::Google.Protobuf.MessageParser<T> parser) where T : global::Google.Protobuf.IMessage<T>
{
#if !GRPC_DISABLE_PROTOBUF_BUFFER_SERIALIZATION
if (__Helper_MessageCache<T>.IsBufferMessage)
{
return parser.ParseFrom(context.PayloadAsReadOnlySequence());
}
#endif
return parser.ParseFrom(context.PayloadAsNewBuffer());
}
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
static readonly grpc::Marshaller<global::Protocol.LoginRequest> __Marshaller_protocol_LoginRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Protocol.LoginRequest.Parser));
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
static readonly grpc::Marshaller<global::Protocol.LoginResponse> __Marshaller_protocol_LoginResponse = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Protocol.LoginResponse.Parser));
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
static readonly grpc::Marshaller<global::Protocol.SignupRequest> __Marshaller_protocol_SignupRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Protocol.SignupRequest.Parser));
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
static readonly grpc::Marshaller<global::Protocol.SignupResponse> __Marshaller_protocol_SignupResponse = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Protocol.SignupResponse.Parser));
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
static readonly grpc::Method<global::Protocol.LoginRequest, global::Protocol.LoginResponse> __Method_Login = new grpc::Method<global::Protocol.LoginRequest, global::Protocol.LoginResponse>(
grpc::MethodType.Unary,
__ServiceName,
"Login",
__Marshaller_protocol_LoginRequest,
__Marshaller_protocol_LoginResponse);
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
static readonly grpc::Method<global::Protocol.SignupRequest, global::Protocol.SignupResponse> __Method_Signup = new grpc::Method<global::Protocol.SignupRequest, global::Protocol.SignupResponse>(
grpc::MethodType.Unary,
__ServiceName,
"Signup",
__Marshaller_protocol_SignupRequest,
__Marshaller_protocol_SignupResponse);
/// <summary>Service descriptor</summary>
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{
get { return global::Protocol.MessageReflection.Descriptor.Services[0]; }
}
/// <summary>Base class for server-side implementations of GameService</summary>
[grpc::BindServiceMethod(typeof(GameService), "BindService")]
public abstract partial class GameServiceBase
{
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
public virtual global::System.Threading.Tasks.Task<global::Protocol.LoginResponse> Login(global::Protocol.LoginRequest request, grpc::ServerCallContext context)
{
throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
}
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
public virtual global::System.Threading.Tasks.Task<global::Protocol.SignupResponse> Signup(global::Protocol.SignupRequest request, grpc::ServerCallContext context)
{
throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, ""));
}
}
/// <summary>Client for GameService</summary>
public partial class GameServiceClient : grpc::ClientBase<GameServiceClient>
{
/// <summary>Creates a new client for GameService</summary>
/// <param name="channel">The channel to use to make remote calls.</param>
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
public GameServiceClient(grpc::ChannelBase channel) : base(channel)
{
}
/// <summary>Creates a new client for GameService that uses a custom <c>CallInvoker</c>.</summary>
/// <param name="callInvoker">The callInvoker to use to make remote calls.</param>
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
public GameServiceClient(grpc::CallInvoker callInvoker) : base(callInvoker)
{
}
/// <summary>Protected parameterless constructor to allow creation of test doubles.</summary>
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
protected GameServiceClient() : base()
{
}
/// <summary>Protected constructor to allow creation of configured clients.</summary>
/// <param name="configuration">The client configuration.</param>
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
protected GameServiceClient(ClientBaseConfiguration configuration) : base(configuration)
{
}
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
public virtual global::Protocol.LoginResponse Login(global::Protocol.LoginRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return Login(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
public virtual global::Protocol.LoginResponse Login(global::Protocol.LoginRequest request, grpc::CallOptions options)
{
return CallInvoker.BlockingUnaryCall(__Method_Login, null, options, request);
}
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
public virtual grpc::AsyncUnaryCall<global::Protocol.LoginResponse> LoginAsync(global::Protocol.LoginRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return LoginAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
public virtual grpc::AsyncUnaryCall<global::Protocol.LoginResponse> LoginAsync(global::Protocol.LoginRequest request, grpc::CallOptions options)
{
return CallInvoker.AsyncUnaryCall(__Method_Login, null, options, request);
}
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
public virtual global::Protocol.SignupResponse Signup(global::Protocol.SignupRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return Signup(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
public virtual global::Protocol.SignupResponse Signup(global::Protocol.SignupRequest request, grpc::CallOptions options)
{
return CallInvoker.BlockingUnaryCall(__Method_Signup, null, options, request);
}
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
public virtual grpc::AsyncUnaryCall<global::Protocol.SignupResponse> SignupAsync(global::Protocol.SignupRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return SignupAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
public virtual grpc::AsyncUnaryCall<global::Protocol.SignupResponse> SignupAsync(global::Protocol.SignupRequest request, grpc::CallOptions options)
{
return CallInvoker.AsyncUnaryCall(__Method_Signup, null, options, request);
}
/// <summary>Creates a new instance of client from given <c>ClientBaseConfiguration</c>.</summary>
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
protected override GameServiceClient NewInstance(ClientBaseConfiguration configuration)
{
return new GameServiceClient(configuration);
}
}
/// <summary>Creates service definition that can be registered with a server</summary>
/// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
public static grpc::ServerServiceDefinition BindService(GameServiceBase serviceImpl)
{
return grpc::ServerServiceDefinition.CreateBuilder()
.AddMethod(__Method_Login, serviceImpl.Login)
.AddMethod(__Method_Signup, serviceImpl.Signup).Build();
}
/// <summary>Register service method with a service binder with or without implementation. Useful when customizing the service binding logic.
/// Note: this method is part of an experimental API that can change or be removed without any prior notice.</summary>
/// <param name="serviceBinder">Service methods will be bound by calling <c>AddMethod</c> on this object.</param>
/// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
[global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)]
public static void BindService(grpc::ServiceBinderBase serviceBinder, GameServiceBase serviceImpl)
{
serviceBinder.AddMethod(__Method_Login, serviceImpl == null ? null : new grpc::UnaryServerMethod<global::Protocol.LoginRequest, global::Protocol.LoginResponse>(serviceImpl.Login));
serviceBinder.AddMethod(__Method_Signup, serviceImpl == null ? null : new grpc::UnaryServerMethod<global::Protocol.SignupRequest, global::Protocol.SignupResponse>(serviceImpl.Signup));
}
}
}
#endregion

View File

@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: f2f787a1d94a6ae48b5586f040f0cf1b

View File

@ -1,14 +0,0 @@
using Network;
using UnityEngine;
namespace Test
{
public class GrpcClientTest : MonoBehaviour
{
private async void Start()
{
var loginResult = await GrpcClient.Instance.Login("野兽先辈", "114514");
Debug.Log($"Received login result: {loginResult.Result}");
}
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 98c1b145899d4d97bd981b177b5c45a9
timeCreated: 1752478138

View File

@ -0,0 +1,19 @@
using Network;
using System.Text;
using UnityEngine;
namespace Test
{
public class TcpClientTest : MonoBehaviour
{
private async void Start()
{
var sendBytes = Encoding.UTF8.GetBytes("This is a test string sent via TCP.");
var receivedBytes = await UnityTcpClient.Instance.SendAndReceiveData(sendBytes);
var receivedString = Encoding.UTF8.GetString(receivedBytes);
Debug.Log($"Received string: {receivedString}");
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e722dcca5e226864b964cd80358a17f9

View File

@ -8,7 +8,7 @@ namespace Test
{
private async void Start()
{
var sendBytes = Encoding.UTF8.GetBytes("Test 汉语 and English simultaneously!");
var sendBytes = Encoding.UTF8.GetBytes("This is a test string sent via UDP.");
var receivedBytes = await UnityUdpClient.Instance.SendAndReceiveData(sendBytes);
var receivedString = Encoding.UTF8.GetString(receivedBytes);