mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-09-27 02:36:14 +00:00
提交帧同步案例
This commit is contained in:
18
JNFrame/Assets/Plugins/JNGame/JNGame.cs
Normal file
18
JNFrame/Assets/Plugins/JNGame/JNGame.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Plugins.JNGame.System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Plugins.JNGame
|
||||
{
|
||||
public static class JNGame
|
||||
{
|
||||
public static async UniTask Init(SystemBase[] systems)
|
||||
{
|
||||
foreach (var system in systems)
|
||||
{
|
||||
await system.OnInit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3
JNFrame/Assets/Plugins/JNGame/JNGame.cs.meta
Normal file
3
JNFrame/Assets/Plugins/JNGame/JNGame.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dcd3abba65d143d6ae94ae99517e52d8
|
||||
timeCreated: 1705993958
|
12
JNFrame/Assets/Plugins/JNGame/NSystem.cs
Normal file
12
JNFrame/Assets/Plugins/JNGame/NSystem.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Plugins.JNGame
|
||||
{
|
||||
public static class NSystem
|
||||
{
|
||||
public static void Log(string log)
|
||||
{
|
||||
Debug.Log($"[JNGame] {log}");
|
||||
}
|
||||
}
|
||||
}
|
3
JNFrame/Assets/Plugins/JNGame/NSystem.cs.meta
Normal file
3
JNFrame/Assets/Plugins/JNGame/NSystem.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4bcab7eba2d54139b1aced9ee532b8e6
|
||||
timeCreated: 1705992865
|
8
JNFrame/Assets/Plugins/JNGame/Network.meta
Normal file
8
JNFrame/Assets/Plugins/JNGame/Network.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fc18c90e1c59ed041afa7ffa5030ba23
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
3
JNFrame/Assets/Plugins/JNGame/Network/Action.meta
Normal file
3
JNFrame/Assets/Plugins/JNGame/Network/Action.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd0b2e123a2647faa14dc3c101cb9924
|
||||
timeCreated: 1706264437
|
15
JNFrame/Assets/Plugins/JNGame/Network/Action/NActionEnum.cs
Normal file
15
JNFrame/Assets/Plugins/JNGame/Network/Action/NActionEnum.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace Plugins.JNGame.Network.Action
|
||||
{
|
||||
public enum NActionEnum
|
||||
{
|
||||
Ping = 1, //PING
|
||||
NActionDemo = 2, //Demo 消息
|
||||
NActionDemo2 = 3, //Demo 消息
|
||||
|
||||
NSyncFrameStart = 100, //帧同步开始
|
||||
NSyncFrameEnd = 101, //帧同步结束
|
||||
NSyncFrameBack = 102, //帧同步回调
|
||||
NSyncFrameInput = 103, //帧同步输入
|
||||
NSyncFrameReset = 104, //重置帧同步
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 07d3dc0f03a24e18b4bee8832eef7a47
|
||||
timeCreated: 1706264441
|
8
JNFrame/Assets/Plugins/JNGame/Network/Entity.meta
Normal file
8
JNFrame/Assets/Plugins/JNGame/Network/Entity.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7d3cabfc01539db4dbf0d4961f07368c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
50
JNFrame/Assets/Plugins/JNGame/Network/Entity/JNetParam.cs
Normal file
50
JNFrame/Assets/Plugins/JNGame/Network/Entity/JNetParam.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using Google.Protobuf;
|
||||
using UnityEditor;
|
||||
|
||||
namespace Plugins.JNGame.Network.Entity
|
||||
{
|
||||
public class JNetParam
|
||||
{
|
||||
|
||||
//请求处理 Id (用来找到处理方法)
|
||||
private int _hId;
|
||||
public int HId => _hId;
|
||||
|
||||
//请求Id (请求标识)
|
||||
private int _id;
|
||||
public int ID => _id;
|
||||
|
||||
|
||||
//请求参数
|
||||
private IMessage _data;
|
||||
public IMessage Data => _data;
|
||||
|
||||
|
||||
private byte[] _bytes;
|
||||
|
||||
public byte[] Bytes => _bytes;
|
||||
|
||||
public JNetParam(int id,int hId)
|
||||
{
|
||||
_hId = hId;
|
||||
_id = id;
|
||||
}
|
||||
|
||||
//构造器
|
||||
public static JNetParam Build(int id,int hId){
|
||||
return new JNetParam(id,hId);
|
||||
}
|
||||
|
||||
|
||||
public JNetParam SetData(IMessage data){
|
||||
this._data = data;
|
||||
return this;
|
||||
}
|
||||
public JNetParam SetByte(byte[] bytes){
|
||||
this._bytes = bytes;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f311c8c368584fab839dd72819fc55da
|
||||
timeCreated: 1706004134
|
135
JNFrame/Assets/Plugins/JNGame/Network/JNSocket.cs
Normal file
135
JNFrame/Assets/Plugins/JNGame/Network/JNSocket.cs
Normal file
@@ -0,0 +1,135 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using BestHTTP.WebSocket;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Google.Protobuf;
|
||||
using Plugins.JNGame.Network.Entity;
|
||||
using Plugins.JNGame.Network.Util;
|
||||
using Plugins.JNGame.System;
|
||||
using Plugins.JNGame.Util;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Plugins.JNGame.Network
|
||||
{
|
||||
public abstract class JNSocket : SystemBase
|
||||
{
|
||||
private WebSocket _socket;
|
||||
|
||||
//消息Id
|
||||
int _id = 0;
|
||||
|
||||
private UniTaskCompletionSource _onOpen;
|
||||
|
||||
//创建通知
|
||||
private EventDispatcher _event = new();
|
||||
|
||||
public override async Task OnInit()
|
||||
{
|
||||
await this.OnConnect();
|
||||
}
|
||||
|
||||
private async UniTask OnConnect()
|
||||
{
|
||||
|
||||
var url = $"{await this.GetUrl()}";
|
||||
this._socket = new WebSocket(new Uri(url));
|
||||
|
||||
this._socket.OnOpen += OnOpen;
|
||||
this._socket.OnMessage += OnMessageReceived;
|
||||
this._socket.OnError += OnError;
|
||||
this._socket.OnClosed += OnClosed;
|
||||
this._socket.OnBinary += Onbinary;
|
||||
|
||||
NSystem.Log($"[JNSocket]初始化WebSocket成功,URL:{url}");
|
||||
this._socket.Open();
|
||||
|
||||
//等待连接成功
|
||||
await (this._onOpen = new UniTaskCompletionSource()).Task;
|
||||
|
||||
}
|
||||
|
||||
private void OnOpen(WebSocket websocket)
|
||||
{
|
||||
NSystem.Log($"[JNSocket] OnOpen");
|
||||
this._onOpen.TrySetResult();
|
||||
}
|
||||
|
||||
private void OnMessageReceived(WebSocket websocket, string message)
|
||||
{
|
||||
NSystem.Log($"[JNSocket] OnMessageReceived");
|
||||
}
|
||||
|
||||
private void OnError(WebSocket websocket, Exception ex)
|
||||
{
|
||||
NSystem.Log($"[JNSocket] OnError");
|
||||
}
|
||||
|
||||
private void OnClosed(WebSocket websocket, ushort code, string message)
|
||||
{
|
||||
NSystem.Log($"[JNSocket] OnClosed");
|
||||
}
|
||||
|
||||
private void Onbinary(WebSocket websocket, byte[] data)
|
||||
{
|
||||
|
||||
NSystem.Log($"[JNSocket] Onbinary");
|
||||
Dispatch(NDataUtil.Parse(data));
|
||||
|
||||
}
|
||||
|
||||
//通知消息
|
||||
private void Dispatch(JNetParam data)
|
||||
{
|
||||
|
||||
//发送消息
|
||||
List<Delegate> funs = _event.EventHandlers[$"{data.HId}"];
|
||||
funs.ForEach(fun =>
|
||||
{
|
||||
if (data.Bytes.Length <= 0)
|
||||
{
|
||||
((Action<IMessage>)fun)(null);
|
||||
return;
|
||||
}
|
||||
if(fun.Method.GetParameters().Length == 1 && typeof(IMessage).IsAssignableFrom(fun.Method.GetParameters()[0].ParameterType))
|
||||
{
|
||||
var type = fun.Method.GetParameters()[0].ParameterType;
|
||||
var cType = type.GetProperty("Parser", BindingFlags.Static | BindingFlags.Public);
|
||||
if (cType != null)
|
||||
{
|
||||
var methodInfo = cType.PropertyType.GetMethod("ParseFrom",new[]{ typeof(byte[]) });
|
||||
if (methodInfo != null)
|
||||
{
|
||||
var message = methodInfo.Invoke(cType.GetValue(null), new object[] { data.Bytes });
|
||||
fun.Method.Invoke(fun.Target,new object[]{ message });
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
//外部监听消息
|
||||
public void AddListener<T>(int hId,Action<T> listener) where T : IMessage
|
||||
{
|
||||
_event.AddListener($"{hId}",listener);
|
||||
}
|
||||
|
||||
//删除外部监听
|
||||
public void RemoveListener<T>(int hId,Action<T> listener) where T : IMessage
|
||||
{
|
||||
_event.RemoveListener($"{hId}",listener);
|
||||
}
|
||||
|
||||
protected abstract UniTask<string> GetUrl();
|
||||
|
||||
|
||||
//向服务器发送消息
|
||||
public void Send(int hId,IMessage data = null)
|
||||
{
|
||||
_socket.Send(NDataUtil.Encrypt(JNetParam.Build(this._id++,hId).SetData(data)));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
11
JNFrame/Assets/Plugins/JNGame/Network/JNSocket.cs.meta
Normal file
11
JNFrame/Assets/Plugins/JNGame/Network/JNSocket.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 85daeb9010873c6408e58fd210d7ec47
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
JNFrame/Assets/Plugins/JNGame/Network/Proto.meta
Normal file
8
JNFrame/Assets/Plugins/JNGame/Network/Proto.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 48ddea52cea7e1145b20a9674aeeca02
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
1092
JNFrame/Assets/Plugins/JNGame/Network/Proto/JNSyncMessage.cs
Normal file
1092
JNFrame/Assets/Plugins/JNGame/Network/Proto/JNSyncMessage.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 417922a615a577540b5a5f446a197bdc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,27 @@
|
||||
syntax = "proto3";
|
||||
|
||||
option java_package = "cn.jisol.ngame.proto";
|
||||
|
||||
//帧同步输入
|
||||
message JNFrameInput{
|
||||
int32 nId = 1; //输入的Id
|
||||
optional bytes input = 2; //输入内容
|
||||
}
|
||||
//帧输入列表
|
||||
message JNFrameInputs {
|
||||
repeated JNFrameInput inputs = 1; //输入列表
|
||||
}
|
||||
//帧同步消息
|
||||
message JNFrameInfo {
|
||||
int32 index = 1; //帧数
|
||||
repeated JNFrameInput messages = 2; //消息bytes
|
||||
}
|
||||
//帧同步集合
|
||||
message JNFrameInfos{
|
||||
repeated JNFrameInfo frames = 1; //帧数集
|
||||
}
|
||||
|
||||
//帧同步输入
|
||||
message JNInput {
|
||||
optional string message = 1;
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f5033772dc466fc46a8ac64d8dbc5d00
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
445
JNFrame/Assets/Plugins/JNGame/Network/Proto/NActionMessage.cs
Normal file
445
JNFrame/Assets/Plugins/JNGame/Network/Proto/NActionMessage.cs
Normal file
@@ -0,0 +1,445 @@
|
||||
// <auto-generated>
|
||||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
// source: NActionMessage.proto
|
||||
// </auto-generated>
|
||||
#pragma warning disable 1591, 0612, 3021, 8981
|
||||
#region Designer generated code
|
||||
|
||||
using pb = global::Google.Protobuf;
|
||||
using pbc = global::Google.Protobuf.Collections;
|
||||
using pbr = global::Google.Protobuf.Reflection;
|
||||
using scg = global::System.Collections.Generic;
|
||||
/// <summary>Holder for reflection information generated from NActionMessage.proto</summary>
|
||||
public static partial class NActionMessageReflection {
|
||||
|
||||
#region Descriptor
|
||||
/// <summary>File descriptor for NActionMessage.proto</summary>
|
||||
public static pbr::FileDescriptor Descriptor {
|
||||
get { return descriptor; }
|
||||
}
|
||||
private static pbr::FileDescriptor descriptor;
|
||||
|
||||
static NActionMessageReflection() {
|
||||
byte[] descriptorData = global::System.Convert.FromBase64String(
|
||||
string.Concat(
|
||||
"ChROQWN0aW9uTWVzc2FnZS5wcm90byIvCgtOQWN0aW9uRGVtbxIUCgdtZXNz",
|
||||
"YWdlGAEgASgJSACIAQFCCgoIX21lc3NhZ2UiMAoMTkFjdGlvbkRlbW8yEhQK",
|
||||
"B21lc3NhZ2UYASABKAlIAIgBAUIKCghfbWVzc2FnZUIWChRjbi5qaXNvbC5u",
|
||||
"Z2FtZS5wcm90b2IGcHJvdG8z"));
|
||||
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
|
||||
new pbr::FileDescriptor[] { },
|
||||
new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] {
|
||||
new pbr::GeneratedClrTypeInfo(typeof(global::NActionDemo), global::NActionDemo.Parser, new[]{ "Message" }, new[]{ "Message" }, null, null, null),
|
||||
new pbr::GeneratedClrTypeInfo(typeof(global::NActionDemo2), global::NActionDemo2.Parser, new[]{ "Message" }, new[]{ "Message" }, null, null, null)
|
||||
}));
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
#region Messages
|
||||
public sealed partial class NActionDemo : pb::IMessage<NActionDemo>
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
, pb::IBufferMessage
|
||||
#endif
|
||||
{
|
||||
private static readonly pb::MessageParser<NActionDemo> _parser = new pb::MessageParser<NActionDemo>(() => new NActionDemo());
|
||||
private pb::UnknownFieldSet _unknownFields;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pb::MessageParser<NActionDemo> Parser { get { return _parser; } }
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::NActionMessageReflection.Descriptor.MessageTypes[0]; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||
get { return Descriptor; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public NActionDemo() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
partial void OnConstruction();
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public NActionDemo(NActionDemo other) : this() {
|
||||
message_ = other.message_;
|
||||
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public NActionDemo Clone() {
|
||||
return new NActionDemo(this);
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "message" field.</summary>
|
||||
public const int MessageFieldNumber = 1;
|
||||
private string message_;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public string Message {
|
||||
get { return message_ ?? ""; }
|
||||
set {
|
||||
message_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
|
||||
}
|
||||
}
|
||||
/// <summary>Gets whether the "message" field is set</summary>
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public bool HasMessage {
|
||||
get { return message_ != null; }
|
||||
}
|
||||
/// <summary>Clears the value of the "message" field</summary>
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void ClearMessage() {
|
||||
message_ = null;
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override bool Equals(object other) {
|
||||
return Equals(other as NActionDemo);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public bool Equals(NActionDemo other) {
|
||||
if (ReferenceEquals(other, null)) {
|
||||
return false;
|
||||
}
|
||||
if (ReferenceEquals(other, this)) {
|
||||
return true;
|
||||
}
|
||||
if (Message != other.Message) return false;
|
||||
return Equals(_unknownFields, other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override int GetHashCode() {
|
||||
int hash = 1;
|
||||
if (HasMessage) hash ^= Message.GetHashCode();
|
||||
if (_unknownFields != null) {
|
||||
hash ^= _unknownFields.GetHashCode();
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override string ToString() {
|
||||
return pb::JsonFormatter.ToDiagnosticString(this);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void WriteTo(pb::CodedOutputStream output) {
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
output.WriteRawMessage(this);
|
||||
#else
|
||||
if (HasMessage) {
|
||||
output.WriteRawTag(10);
|
||||
output.WriteString(Message);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(output);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
|
||||
if (HasMessage) {
|
||||
output.WriteRawTag(10);
|
||||
output.WriteString(Message);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(ref output);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public int CalculateSize() {
|
||||
int size = 0;
|
||||
if (HasMessage) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeStringSize(Message);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
size += _unknownFields.CalculateSize();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void MergeFrom(NActionDemo other) {
|
||||
if (other == null) {
|
||||
return;
|
||||
}
|
||||
if (other.HasMessage) {
|
||||
Message = other.Message;
|
||||
}
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void MergeFrom(pb::CodedInputStream input) {
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
input.ReadRawMessage(this);
|
||||
#else
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
|
||||
break;
|
||||
case 10: {
|
||||
Message = input.ReadString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
|
||||
break;
|
||||
case 10: {
|
||||
Message = input.ReadString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
public sealed partial class NActionDemo2 : pb::IMessage<NActionDemo2>
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
, pb::IBufferMessage
|
||||
#endif
|
||||
{
|
||||
private static readonly pb::MessageParser<NActionDemo2> _parser = new pb::MessageParser<NActionDemo2>(() => new NActionDemo2());
|
||||
private pb::UnknownFieldSet _unknownFields;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pb::MessageParser<NActionDemo2> Parser { get { return _parser; } }
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public static pbr::MessageDescriptor Descriptor {
|
||||
get { return global::NActionMessageReflection.Descriptor.MessageTypes[1]; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||
get { return Descriptor; }
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public NActionDemo2() {
|
||||
OnConstruction();
|
||||
}
|
||||
|
||||
partial void OnConstruction();
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public NActionDemo2(NActionDemo2 other) : this() {
|
||||
message_ = other.message_;
|
||||
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public NActionDemo2 Clone() {
|
||||
return new NActionDemo2(this);
|
||||
}
|
||||
|
||||
/// <summary>Field number for the "message" field.</summary>
|
||||
public const int MessageFieldNumber = 1;
|
||||
private string message_;
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public string Message {
|
||||
get { return message_ ?? ""; }
|
||||
set {
|
||||
message_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
|
||||
}
|
||||
}
|
||||
/// <summary>Gets whether the "message" field is set</summary>
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public bool HasMessage {
|
||||
get { return message_ != null; }
|
||||
}
|
||||
/// <summary>Clears the value of the "message" field</summary>
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void ClearMessage() {
|
||||
message_ = null;
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override bool Equals(object other) {
|
||||
return Equals(other as NActionDemo2);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public bool Equals(NActionDemo2 other) {
|
||||
if (ReferenceEquals(other, null)) {
|
||||
return false;
|
||||
}
|
||||
if (ReferenceEquals(other, this)) {
|
||||
return true;
|
||||
}
|
||||
if (Message != other.Message) return false;
|
||||
return Equals(_unknownFields, other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override int GetHashCode() {
|
||||
int hash = 1;
|
||||
if (HasMessage) hash ^= Message.GetHashCode();
|
||||
if (_unknownFields != null) {
|
||||
hash ^= _unknownFields.GetHashCode();
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public override string ToString() {
|
||||
return pb::JsonFormatter.ToDiagnosticString(this);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void WriteTo(pb::CodedOutputStream output) {
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
output.WriteRawMessage(this);
|
||||
#else
|
||||
if (HasMessage) {
|
||||
output.WriteRawTag(10);
|
||||
output.WriteString(Message);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(output);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
|
||||
if (HasMessage) {
|
||||
output.WriteRawTag(10);
|
||||
output.WriteString(Message);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
_unknownFields.WriteTo(ref output);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public int CalculateSize() {
|
||||
int size = 0;
|
||||
if (HasMessage) {
|
||||
size += 1 + pb::CodedOutputStream.ComputeStringSize(Message);
|
||||
}
|
||||
if (_unknownFields != null) {
|
||||
size += _unknownFields.CalculateSize();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void MergeFrom(NActionDemo2 other) {
|
||||
if (other == null) {
|
||||
return;
|
||||
}
|
||||
if (other.HasMessage) {
|
||||
Message = other.Message;
|
||||
}
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
|
||||
}
|
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
public void MergeFrom(pb::CodedInputStream input) {
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
input.ReadRawMessage(this);
|
||||
#else
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
|
||||
break;
|
||||
case 10: {
|
||||
Message = input.ReadString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
|
||||
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
switch(tag) {
|
||||
default:
|
||||
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
|
||||
break;
|
||||
case 10: {
|
||||
Message = input.ReadString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#endregion Designer generated code
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7a64c8e0d9371ec4a8dc561dbfe81026
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,12 @@
|
||||
syntax = "proto3";
|
||||
|
||||
option java_package = "cn.jisol.ngame.proto";
|
||||
|
||||
message NActionDemo {
|
||||
optional string message = 1;
|
||||
}
|
||||
|
||||
message NActionDemo2 {
|
||||
optional string message = 1;
|
||||
}
|
||||
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e48e0afd082b466081556cb81d66935f
|
||||
timeCreated: 1705996154
|
3
JNFrame/Assets/Plugins/JNGame/Network/Util.meta
Normal file
3
JNFrame/Assets/Plugins/JNGame/Network/Util.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f297d4999ae14dd7a046a1faebd6845a
|
||||
timeCreated: 1706004786
|
41
JNFrame/Assets/Plugins/JNGame/Network/Util/NDataUtil.cs
Normal file
41
JNFrame/Assets/Plugins/JNGame/Network/Util/NDataUtil.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Google.Protobuf;
|
||||
using Plugins.JNGame.Network.Entity;
|
||||
using Plugins.JNGame.Util;
|
||||
|
||||
namespace Plugins.JNGame.Network.Util
|
||||
{
|
||||
// 网络数据工具类 [请求Id*4,处理Id*4,...参数数据*N]
|
||||
public static class NDataUtil
|
||||
{
|
||||
|
||||
// 解析
|
||||
public static JNetParam Parse(byte[] data)
|
||||
{
|
||||
|
||||
return JNetParam.Build(
|
||||
ToUtil.Byte4ToInt(data.Skip(0).Take(4).ToArray()),
|
||||
ToUtil.Byte4ToInt(data.Skip(4).Take(4).ToArray()))
|
||||
.SetByte(data.Skip(8).Take(data.Length - 8).ToArray());
|
||||
|
||||
}
|
||||
|
||||
// 编码
|
||||
public static byte[] Encrypt(JNetParam param)
|
||||
{
|
||||
|
||||
byte[] hId = ToUtil.IntToByte4(param.HId);
|
||||
byte[] id = ToUtil.IntToByte4(param.ID);
|
||||
byte[] data = Array.Empty<byte>();
|
||||
if(param.Data != null)
|
||||
data = param.Data.ToByteArray();
|
||||
|
||||
return id.Concat(hId).Concat(data).ToArray();
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8b05544adb2f44b4af8f86b2bc66a035
|
||||
timeCreated: 1706004790
|
8
JNFrame/Assets/Plugins/JNGame/Sync.meta
Normal file
8
JNFrame/Assets/Plugins/JNGame/Sync.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c62692a212dabc44f8d95e345f0d56e7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
JNFrame/Assets/Plugins/JNGame/Sync/Frame.meta
Normal file
8
JNFrame/Assets/Plugins/JNGame/Sync/Frame.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 52334425574c2ff48a058ac3bb6d7419
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
181
JNFrame/Assets/Plugins/JNGame/Sync/Frame/JNSyncFrame.cs
Normal file
181
JNFrame/Assets/Plugins/JNGame/Sync/Frame/JNSyncFrame.cs
Normal file
@@ -0,0 +1,181 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Plugins.JNGame.System;
|
||||
using Plugins.JNGame.Util;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace Plugins.JNGame.Sync.Frame
|
||||
{
|
||||
public abstract class JNSyncFrame : SystemBase
|
||||
{
|
||||
|
||||
//同步时间 (和服务器保持一致)
|
||||
private int _nSyncTime = 67;
|
||||
//大于多少帧进行追帧
|
||||
private int _nMaxFrameBan = 3;
|
||||
//大于多少帧进行快速追帧
|
||||
private int _nMaxFrameLoopBan = 18;
|
||||
//将服务器帧数进行平分
|
||||
private int _nDivideFrame = 3;
|
||||
|
||||
|
||||
//帧队列
|
||||
private List<JNFrameInfo> _nFrameQueue = new();
|
||||
|
||||
//本地帧数
|
||||
private int _nLocalFrame = 0;
|
||||
//运行的帧
|
||||
private int _nFrameRun = 0;
|
||||
|
||||
//暂存帧列表
|
||||
private Dictionary<int,JNFrameInfo> _nFrameTempQueue = new();
|
||||
|
||||
//ID 每添加 JNSyncFrameComponent + 1
|
||||
public Func<int> nSyncID = RandomUtil.Next(0);
|
||||
|
||||
//随机数
|
||||
public Func<double> nRandom = RandomUtil.SyncRandom(100);
|
||||
|
||||
//随机数整数
|
||||
public Func<int, int, int> nRandomInt = RandomUtil.SyncRandomInt(100);
|
||||
|
||||
//是否开始同步
|
||||
Boolean _isStart = false;
|
||||
|
||||
//帧更新
|
||||
int dtTotal = 0;
|
||||
//输入更新
|
||||
int dtInputTotal = 0;
|
||||
|
||||
public override Task OnInit()
|
||||
{
|
||||
Physics.autoSimulation = false;
|
||||
Physics.autoSyncTransforms = false;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
//重置数据
|
||||
public void Reset()
|
||||
{
|
||||
this.nSyncID = RandomUtil.Next(0);
|
||||
this.nRandom = RandomUtil.SyncRandom(100);
|
||||
this.nRandomInt = RandomUtil.SyncRandomInt(100);
|
||||
}
|
||||
|
||||
//更新同步
|
||||
public void Update(int dt)
|
||||
{
|
||||
|
||||
if(!_isStart) return;
|
||||
|
||||
dtTotal += dt;
|
||||
dtInputTotal += dt;
|
||||
|
||||
int nSyncTime = this.DyTime();
|
||||
|
||||
if(nSyncTime > 0){
|
||||
while(nSyncTime != 0 && this.dtTotal > nSyncTime){
|
||||
this.onUpdate();
|
||||
this.dtTotal -= nSyncTime;
|
||||
nSyncTime = this.DyTime();
|
||||
}
|
||||
}else{
|
||||
//追帧运行 保持前端 15 帧 刷新
|
||||
int endTime = DateTime.Now.Millisecond + 66;
|
||||
while(this.DyTime() == 0 && DateTime.Now.Millisecond < endTime){
|
||||
this.onUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//运行帧
|
||||
public void onUpdate()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//自适应间隔时间
|
||||
private int DyTime(){
|
||||
int dt = this._nSyncTime / this._nDivideFrame;
|
||||
int loop = dt;
|
||||
|
||||
//大于nMaxFrameBan 进行 追帧
|
||||
if(this._nFrameQueue.Count > this._nMaxFrameBan) {
|
||||
|
||||
//计算超过的帧数
|
||||
int exceed = this._nFrameQueue.Count - this._nMaxFrameBan;
|
||||
int most = this._nMaxFrameLoopBan - this._nMaxFrameBan;
|
||||
int ldt = ((most - exceed) / most) * dt;
|
||||
|
||||
//自适应追帧算法
|
||||
if(exceed <= this._nMaxFrameLoopBan){
|
||||
loop = ldt;
|
||||
}else{
|
||||
loop = 0;
|
||||
}
|
||||
}else{
|
||||
loop = dt;
|
||||
}
|
||||
return loop;
|
||||
}
|
||||
|
||||
/**
|
||||
* 接收帧数据
|
||||
* @param frame 帧数据
|
||||
* @param isLatestData 是否最新的帧数据
|
||||
*/
|
||||
public void AddInput(JNFrameInfo frame,Boolean isLatestData = false){
|
||||
|
||||
if(isLatestData){
|
||||
//如果推的帧小于本地帧 则 重开
|
||||
if(frame.Index < _nLocalFrame){
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//我需要的下一帧
|
||||
int index = _nLocalFrame + 1;
|
||||
|
||||
//判断接受的帧是否下一帧 如果不是则加入未列入
|
||||
if (frame.Index != index){
|
||||
|
||||
_nFrameTempQueue.Add(frame.Index,frame);
|
||||
|
||||
//在未列入中拿到需要的帧
|
||||
JNFrameInfo tamp = null;
|
||||
|
||||
if ((tamp = _nFrameTempQueue[index]) == null){
|
||||
|
||||
//如果没有则向服务器请求我需要的帧数
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//如果有则覆盖
|
||||
frame = tamp;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//删除临时帧
|
||||
_nFrameTempQueue.Remove(frame.Index);
|
||||
|
||||
_nLocalFrame = index;
|
||||
|
||||
//分帧插入
|
||||
_nFrameQueue.Add(frame);
|
||||
for (var i = 0; i < this._nDivideFrame - 1; index++) {
|
||||
_nFrameQueue.Add(new JNFrameInfo());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//发送帧数据
|
||||
protected abstract void OnSendInput(JNFrameInputs inputs);
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 44e6e0cb968b4bc0a21ed772b81d1c39
|
||||
timeCreated: 1706003302
|
3
JNFrame/Assets/Plugins/JNGame/Sync/Frame/game.meta
Normal file
3
JNFrame/Assets/Plugins/JNGame/Sync/Frame/game.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 240dc802e5754972a9f7590feea56628
|
||||
timeCreated: 1706163840
|
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Plugins.JNGame.Sync.Frame.game
|
||||
{
|
||||
|
||||
//所有帧同步组件的基类
|
||||
public abstract class JNSyncFrameComponent<T> : MonoBehaviour
|
||||
{
|
||||
|
||||
//标识
|
||||
private int _nId;
|
||||
|
||||
//当前输入
|
||||
private T _input;
|
||||
|
||||
//是否有输入
|
||||
public Boolean isInput => this._input == null;
|
||||
|
||||
//是否初始化完成
|
||||
public Boolean isSyncInitSuccess = false;
|
||||
|
||||
|
||||
//清空输入
|
||||
public void ClearInput(){
|
||||
this._input = default(T);
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
//向帧同步获取Id
|
||||
this._nId = GetSync().nSyncID();
|
||||
this.OnSyncLoad();
|
||||
}
|
||||
|
||||
//初始化完成
|
||||
public void OnSyncInitSuccess(){}
|
||||
|
||||
//获取同步类
|
||||
protected abstract JNSyncFrame GetSync();
|
||||
|
||||
//加载
|
||||
public abstract void OnSyncLoad();
|
||||
|
||||
//帧同步
|
||||
public abstract void OnSyncUpdate(int dt,JNFrameInfo frame,Input input = null);
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1a802748c1744ea886c648699b51245f
|
||||
timeCreated: 1706163852
|
8
JNFrame/Assets/Plugins/JNGame/System.meta
Normal file
8
JNFrame/Assets/Plugins/JNGame/System.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 681de402476267c41b0fd0f6fd566e76
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
12
JNFrame/Assets/Plugins/JNGame/System/SystemBase.cs
Normal file
12
JNFrame/Assets/Plugins/JNGame/System/SystemBase.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Plugins.JNGame.System
|
||||
{
|
||||
public abstract class SystemBase
|
||||
{
|
||||
|
||||
public abstract Task OnInit();
|
||||
|
||||
}
|
||||
}
|
11
JNFrame/Assets/Plugins/JNGame/System/SystemBase.cs.meta
Normal file
11
JNFrame/Assets/Plugins/JNGame/System/SystemBase.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 09143922e037a6d41aa2a9e4e2742731
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
JNFrame/Assets/Plugins/JNGame/UI.meta
Normal file
8
JNFrame/Assets/Plugins/JNGame/UI.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f759e05d198dbb4fa441d263f243edb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
3
JNFrame/Assets/Plugins/JNGame/Util.meta
Normal file
3
JNFrame/Assets/Plugins/JNGame/Util.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8a2a6d3b9a20443a8348bd5ba601622d
|
||||
timeCreated: 1706004960
|
74
JNFrame/Assets/Plugins/JNGame/Util/EventDispatcher.cs
Normal file
74
JNFrame/Assets/Plugins/JNGame/Util/EventDispatcher.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Plugins.JNGame.Util
|
||||
{
|
||||
/// <summary>
|
||||
/// 静态事件分发器
|
||||
/// </summary>
|
||||
public class EventDispatcher
|
||||
{
|
||||
public Dictionary<string, List<Delegate>> EventHandlers { get; private set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 添加事件监听器
|
||||
/// </summary>
|
||||
/// <typeparam name="T">事件参数类型</typeparam>
|
||||
/// <param name="eventId">事件标识符</param>
|
||||
/// <param name="listener">事件监听器</param>
|
||||
public void AddListener<T>(string eventId, Action<T> listener)
|
||||
{
|
||||
if (!EventHandlers.ContainsKey(eventId))
|
||||
{
|
||||
EventHandlers[eventId] = new List<Delegate>();
|
||||
}
|
||||
|
||||
EventHandlers[eventId].Add(listener);
|
||||
Debug.Log(eventId+ "AddListener" + EventHandlers[eventId].Count);
|
||||
//eventHandlers[eventId] = (Action<T>)eventHandlers[eventId] + listener;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除事件监听器
|
||||
/// </summary>
|
||||
/// <typeparam name="T">事件参数类型</typeparam>
|
||||
/// <param name="eventId">事件标识符</param>
|
||||
/// <param name="listener">事件监听器</param>
|
||||
public void RemoveListener<T>(string eventId, Action<T> listener)
|
||||
{
|
||||
if (EventHandlers.ContainsKey(eventId))
|
||||
{
|
||||
//eventHandlers[eventId] = (Action<T>)eventHandlers[eventId] - listener;
|
||||
EventHandlers[eventId].Remove(listener);
|
||||
Debug.Log(eventId + "RemoveListener" + EventHandlers[eventId].Count);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分发事件
|
||||
/// </summary>
|
||||
/// <typeparam name="T">事件参数类型</typeparam>
|
||||
/// <param name="eventId">事件标识符</param>
|
||||
/// <param name="args">事件参数</param>
|
||||
public void Dispatch<T>(string eventId, T args)
|
||||
{
|
||||
if (EventHandlers.ContainsKey(eventId) && EventHandlers[eventId] != null)
|
||||
{
|
||||
foreach(Delegate fun in EventHandlers[eventId])
|
||||
{
|
||||
// 确保 fun 实际上是指向一个 Action<T> 类型的函数
|
||||
if (fun.Method.GetParameters().Length == 1 && fun.Method.GetParameters()[0].ParameterType == typeof(T))
|
||||
{
|
||||
((Action<T>)fun)(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
EventHandlers = new();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 311db7dc834c409b81610b20f5510988
|
||||
timeCreated: 1706065209
|
11
JNFrame/Assets/Plugins/JNGame/Util/ProtoUtil.cs
Normal file
11
JNFrame/Assets/Plugins/JNGame/Util/ProtoUtil.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace Plugins.JNGame.Util
|
||||
{
|
||||
|
||||
//Proto工具
|
||||
public class ProtoUtil
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
3
JNFrame/Assets/Plugins/JNGame/Util/ProtoUtil.cs.meta
Normal file
3
JNFrame/Assets/Plugins/JNGame/Util/ProtoUtil.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 37c91935ad854ee1a4b199391df35004
|
||||
timeCreated: 1706006228
|
38
JNFrame/Assets/Plugins/JNGame/Util/RandomUtil.cs
Normal file
38
JNFrame/Assets/Plugins/JNGame/Util/RandomUtil.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
|
||||
namespace Plugins.JNGame.Util
|
||||
{
|
||||
public static class RandomUtil
|
||||
{
|
||||
|
||||
public static Func<double> SyncRandom(int seed,int start = 1)
|
||||
{
|
||||
|
||||
for(var i = 0; i < start; i++){
|
||||
seed = (seed * 9301 + 49297) % 233280;
|
||||
}
|
||||
|
||||
return () =>
|
||||
{
|
||||
seed = (seed * 9301 + 49297) % 233280;
|
||||
var rnd = seed / 233280.0;
|
||||
return 0 + rnd * (1 - 0);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
public static Func<int,int,int> SyncRandomInt(int seed,int start = 1)
|
||||
{
|
||||
var nRandom = SyncRandom(seed, start);
|
||||
|
||||
return (min, max) => (int)(Math.Round(nRandom() * (max - min)) + min);
|
||||
|
||||
}
|
||||
|
||||
public static Func<int> Next(int start)
|
||||
{
|
||||
return () => start++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
3
JNFrame/Assets/Plugins/JNGame/Util/RandomUtil.cs.meta
Normal file
3
JNFrame/Assets/Plugins/JNGame/Util/RandomUtil.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 04c0ca6d0b7f4dfab57c8dca2a3a7b94
|
||||
timeCreated: 1706164470
|
32
JNFrame/Assets/Plugins/JNGame/Util/Singleton.cs
Normal file
32
JNFrame/Assets/Plugins/JNGame/Util/Singleton.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
namespace Plugins.JNGame.Util
|
||||
{
|
||||
public abstract class SingletonUtil<T> where T : Singleton<T>,new() {
|
||||
|
||||
public static T Instance{
|
||||
get{
|
||||
if (Singleton<T>.ins == null)
|
||||
{
|
||||
Singleton<T>.ins = new T();
|
||||
Singleton<T>.ins.Init();
|
||||
}
|
||||
return Singleton<T>.ins;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Clean()
|
||||
{
|
||||
Singleton<T>.ins.Clean();
|
||||
Singleton<T>.ins = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class Singleton<T> {
|
||||
|
||||
public static T ins;
|
||||
|
||||
public virtual void Init(){}
|
||||
public virtual void Clean(){}
|
||||
|
||||
}
|
||||
}
|
3
JNFrame/Assets/Plugins/JNGame/Util/Singleton.cs.meta
Normal file
3
JNFrame/Assets/Plugins/JNGame/Util/Singleton.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 80ef0477d1c9478a8d73b1e6ac21a8b9
|
||||
timeCreated: 1706167436
|
85
JNFrame/Assets/Plugins/JNGame/Util/SingletonScene.cs
Normal file
85
JNFrame/Assets/Plugins/JNGame/Util/SingletonScene.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Be aware this will not prevent a non singleton constructor
|
||||
/// such as `T myT = new T();`
|
||||
/// To prevent that, add `protected T () {}` to your singleton class.
|
||||
///
|
||||
/// As a note, this is made as MonoBehaviour because we need Coroutines.
|
||||
/// </summary>
|
||||
public class SingletonScene<T> : MonoBehaviour where T : MonoBehaviour
|
||||
{
|
||||
private static T _instance;
|
||||
|
||||
private static object _lock = new object();
|
||||
|
||||
public static T Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (applicationIsQuitting)
|
||||
{
|
||||
Debug.LogWarning("[Singleton] Instance '" + typeof(T) +
|
||||
"' already destroyed on application quit." +
|
||||
" Won't create again - returning null.");
|
||||
return null;
|
||||
}
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = (T)FindObjectOfType(typeof(T));
|
||||
|
||||
if (FindObjectsOfType(typeof(T)).Length > 1)
|
||||
{
|
||||
Debug.LogError("[Singleton] Something went really wrong " +
|
||||
" - there should never be more than 1 singleton!" +
|
||||
" Reopening the scene might fix it.");
|
||||
return _instance;
|
||||
}
|
||||
|
||||
if (_instance == null)
|
||||
{
|
||||
GameObject singleton = new GameObject();
|
||||
_instance = singleton.AddComponent<T>();
|
||||
singleton.name = "(singleton) " + typeof(T).ToString();
|
||||
|
||||
DontDestroyOnLoad(singleton);
|
||||
|
||||
Debug.Log("[Singleton] An instance of " + typeof(T) +
|
||||
" is needed in the scene, so '" + singleton +
|
||||
"' was created with DontDestroyOnLoad.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log("[Singleton] Using instance already created: " +
|
||||
_instance.gameObject.name);
|
||||
}
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool applicationIsQuitting = false;
|
||||
|
||||
/// <summary>
|
||||
/// When Unity quits, it destroys objects in a random order.
|
||||
/// In principle, a Singleton is only destroyed when application quits.
|
||||
/// If any script calls Instance after it have been destroyed,
|
||||
/// it will create a buggy ghost object that will stay on the Editor scene
|
||||
/// even after stopping playing the Application. Really bad!
|
||||
/// So, this was made to be sure we're not creating that buggy ghost object.
|
||||
/// </summary>
|
||||
public void OnDestroy()
|
||||
{
|
||||
applicationIsQuitting = true;
|
||||
OnDispose();
|
||||
}
|
||||
|
||||
protected virtual void OnDispose()
|
||||
{
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c9277ee16036443695be9ff1ff09df12
|
||||
timeCreated: 1706168129
|
19
JNFrame/Assets/Plugins/JNGame/Util/ToUtil.cs
Normal file
19
JNFrame/Assets/Plugins/JNGame/Util/ToUtil.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
|
||||
namespace Plugins.JNGame.Util
|
||||
{
|
||||
public class ToUtil
|
||||
{
|
||||
public static int Byte4ToInt(byte[] data)
|
||||
{
|
||||
return BitConverter.ToInt32(data, 0);
|
||||
}
|
||||
|
||||
public static byte[] IntToByte4(int value)
|
||||
{
|
||||
byte[] result = new byte[4];
|
||||
BitConverter.GetBytes(value).CopyTo(result, 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
3
JNFrame/Assets/Plugins/JNGame/Util/ToUtil.cs.meta
Normal file
3
JNFrame/Assets/Plugins/JNGame/Util/ToUtil.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 22d4030ad259466884c3fefc632770f9
|
||||
timeCreated: 1706004960
|
Reference in New Issue
Block a user