This commit is contained in:
DESKTOP-5RP3AKU\Jisol
2024-01-29 02:28:42 +08:00
parent 68c4d5e811
commit 01a4312761
73 changed files with 13939 additions and 42231 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fc930357ce632e946858ec67d91abbec
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2007 James Newton-King
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: df6c243b942bd4947adac573cff13a2c
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata minClientVersion="2.12">
<id>Newtonsoft.Json</id>
<version>13.0.3</version>
<title>Json.NET</title>
<authors>James Newton-King</authors>
<license type="expression">MIT</license>
<licenseUrl>https://licenses.nuget.org/MIT</licenseUrl>
<icon>packageIcon.png</icon>
<readme>README.md</readme>
<projectUrl>https://www.newtonsoft.com/json</projectUrl>
<iconUrl>https://www.newtonsoft.com/content/images/nugeticon.png</iconUrl>
<description>Json.NET is a popular high-performance JSON framework for .NET</description>
<copyright>Copyright © James Newton-King 2008</copyright>
<tags>json</tags>
<repository type="git" url="https://github.com/JamesNK/Newtonsoft.Json" commit="0a2e291c0d9c0c7675d445703e51750363a549ef" />
<dependencies>
<group targetFramework=".NETFramework2.0" />
<group targetFramework=".NETFramework3.5" />
<group targetFramework=".NETFramework4.0" />
<group targetFramework=".NETFramework4.5" />
<group targetFramework=".NETStandard1.0">
<dependency id="Microsoft.CSharp" version="4.3.0" exclude="Build,Analyzers" />
<dependency id="NETStandard.Library" version="1.6.1" exclude="Build,Analyzers" />
<dependency id="System.ComponentModel.TypeConverter" version="4.3.0" exclude="Build,Analyzers" />
<dependency id="System.Runtime.Serialization.Primitives" version="4.3.0" exclude="Build,Analyzers" />
</group>
<group targetFramework=".NETStandard1.3">
<dependency id="Microsoft.CSharp" version="4.3.0" exclude="Build,Analyzers" />
<dependency id="NETStandard.Library" version="1.6.1" exclude="Build,Analyzers" />
<dependency id="System.ComponentModel.TypeConverter" version="4.3.0" exclude="Build,Analyzers" />
<dependency id="System.Runtime.Serialization.Formatters" version="4.3.0" exclude="Build,Analyzers" />
<dependency id="System.Runtime.Serialization.Primitives" version="4.3.0" exclude="Build,Analyzers" />
<dependency id="System.Xml.XmlDocument" version="4.3.0" exclude="Build,Analyzers" />
</group>
<group targetFramework="net6.0" />
<group targetFramework=".NETStandard2.0" />
</dependencies>
</metadata>
</package>

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b0a0a1a4d7ba7584a9b4e28c710e0082
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,71 @@
# ![Logo](https://raw.githubusercontent.com/JamesNK/Newtonsoft.Json/master/Doc/icons/logo.jpg) Json.NET
[![NuGet version (Newtonsoft.Json)](https://img.shields.io/nuget/v/Newtonsoft.Json.svg?style=flat-square)](https://www.nuget.org/packages/Newtonsoft.Json/)
[![Build status](https://dev.azure.com/jamesnk/Public/_apis/build/status/JamesNK.Newtonsoft.Json?branchName=master)](https://dev.azure.com/jamesnk/Public/_build/latest?definitionId=8)
Json.NET is a popular high-performance JSON framework for .NET
## Serialize JSON
```csharp
Product product = new Product();
product.Name = "Apple";
product.Expiry = new DateTime(2008, 12, 28);
product.Sizes = new string[] { "Small" };
string json = JsonConvert.SerializeObject(product);
// {
// "Name": "Apple",
// "Expiry": "2008-12-28T00:00:00",
// "Sizes": [
// "Small"
// ]
// }
```
## Deserialize JSON
```csharp
string json = @"{
'Name': 'Bad Boys',
'ReleaseDate': '1995-4-7T00:00:00',
'Genres': [
'Action',
'Comedy'
]
}";
Movie m = JsonConvert.DeserializeObject<Movie>(json);
string name = m.Name;
// Bad Boys
```
## LINQ to JSON
```csharp
JArray array = new JArray();
array.Add("Manual text");
array.Add(new DateTime(2000, 5, 23));
JObject o = new JObject();
o["MyArray"] = array;
string json = o.ToString();
// {
// "MyArray": [
// "Manual text",
// "2000-05-23T00:00:00"
// ]
// }
```
## Links
- [Homepage](https://www.newtonsoft.com/json)
- [Documentation](https://www.newtonsoft.com/json/help)
- [NuGet Package](https://www.nuget.org/packages/Newtonsoft.Json)
- [Release Notes](https://github.com/JamesNK/Newtonsoft.Json/releases)
- [Contributing Guidelines](https://github.com/JamesNK/Newtonsoft.Json/blob/master/CONTRIBUTING.md)
- [License](https://github.com/JamesNK/Newtonsoft.Json/blob/master/LICENSE.md)
- [Stack Overflow](https://stackoverflow.com/questions/tagged/json.net)

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 42d2685bdc9ddd746beda77df950387a
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7d179bedf614b06428dd1465558007d1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2ddaa7535a3e2b043ab452a2814a2b75
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: d108b6aba4a2ac948b5d9518117b56b1
labels:
- NuGetForUnity
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 6a88866967307384dba07d45b15b79e6
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

@@ -0,0 +1,123 @@
fileFormatVersion: 2
guid: 5250cfd1e5661ee42a0440106b095129
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 12
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMasterTextureLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Server
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -10,6 +10,7 @@ using Plugins.JNGame.Network.Util;
using Plugins.JNGame.System;
using Plugins.JNGame.Util;
using UnityEngine;
using Object = System.Object;
namespace Plugins.JNGame.Network
{
@@ -87,11 +88,6 @@ namespace Plugins.JNGame.Network
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;
@@ -102,9 +98,17 @@ namespace Plugins.JNGame.Network
if (methodInfo != null)
{
var message = methodInfo.Invoke(cType.GetValue(null), new object[] { data.Bytes });
fun.Method.Invoke(fun.Target,new object[]{ message });
fun.Method.Invoke(fun.Target,new []{ message });
}
}
else
{
fun.Method.Invoke(fun.Target,new [] { (object)null });
}
}
else
{
fun.Method.Invoke(fun.Target,new object[]{ });
}
});
@@ -115,6 +119,11 @@ namespace Plugins.JNGame.Network
{
_event.AddListener($"{hId}",listener);
}
public void AddListener(int hId, global::System.Action listener)
{
_event.AddListener($"{hId}",listener);
}
//删除外部监听
public void RemoveListener<T>(int hId,Action<T> listener) where T : IMessage

View File

@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using Plugins.JNGame.Sync.Frame.game;
using Plugins.JNGame.System;
using Plugins.JNGame.Util;
using UnityEngine;
@@ -22,7 +24,7 @@ namespace Plugins.JNGame.Sync.Frame
//帧队列
private List<JNFrameInfo> _nFrameQueue = new();
private Queue<JNFrameInfo> _nFrameQueue = new();
//本地帧数
private int _nLocalFrame = 0;
@@ -32,6 +34,9 @@ namespace Plugins.JNGame.Sync.Frame
//暂存帧列表
private Dictionary<int,JNFrameInfo> _nFrameTempQueue = new();
//需要同步的Actor
private List<JNSyncFrameComponent<object>> _nSyncActors = new();
//ID 每添加 JNSyncFrameComponent + 1
public Func<int> nSyncID = RandomUtil.Next(0);
@@ -44,6 +49,9 @@ namespace Plugins.JNGame.Sync.Frame
//是否开始同步
Boolean _isStart = false;
//是否请求后台数据
private Boolean _isRequestServerData = false;
//帧更新
int dtTotal = 0;
//输入更新
@@ -56,9 +64,15 @@ namespace Plugins.JNGame.Sync.Frame
return Task.CompletedTask;
}
//开始
public void onStart(){
this._isStart = true;
}
//重置数据
public void Reset()
public void onStop()
{
this._isStart = false;
this.nSyncID = RandomUtil.Next(0);
this.nRandom = RandomUtil.SyncRandom(100);
this.nRandomInt = RandomUtil.SyncRandomInt(100);
@@ -94,7 +108,35 @@ namespace Plugins.JNGame.Sync.Frame
//运行帧
public void onUpdate()
{
if(!(_nFrameQueue.TryDequeue(out var frame))) return;
int dt = this._nSyncTime / this._nDivideFrame;
//拆出输入
Dictionary<int, JNFrameInput> inputs = new();
foreach (var message in frame.Messages)
{
inputs.Add(message.NId,message);
}
//更新帧
this._nSyncActors.ForEach(child =>
{
if (inputs.ContainsKey(child.NID))
{
child.OnSyncUpdate(dt,frame,child.Decoder(inputs[child.NID].Input.ToByteArray()));
}
else
{
child.OnSyncUpdate(dt,frame,null);
}
});
//执行下一帧物理
Physics.Simulate((float)dt / 1000);
Physics.SyncTransforms();
}
//自适应间隔时间
@@ -127,12 +169,16 @@ namespace Plugins.JNGame.Sync.Frame
* @param frame 帧数据
* @param isLatestData 是否最新的帧数据
*/
public void AddInput(JNFrameInfo frame,Boolean isLatestData = false){
public void AddInput(JNFrameInfo frame,Boolean isLatestData = true)
{
if (!_isStart) return;
if(isLatestData){
//如果推的帧小于本地帧 则 重开
if(frame.Index < _nLocalFrame){
Reset();
onStop();
onStart();
return;
}
}
@@ -143,14 +189,31 @@ namespace Plugins.JNGame.Sync.Frame
//判断接受的帧是否下一帧 如果不是则加入未列入
if (frame.Index != index){
_nFrameTempQueue.Add(frame.Index,frame);
_nFrameTempQueue.TryAdd(frame.Index,frame);
//在未列入中拿到需要的帧
JNFrameInfo tamp = null;
if ((tamp = _nFrameTempQueue[index]) == null){
if ((tamp = _nFrameTempQueue.GetValueOrDefault(index,null)) == null){
//如果没有则向服务器请求我需要的帧数
if (!this._isRequestServerData)
{
this._isRequestServerData = true;
//请求
this.OnServerData(this._nLocalFrame, 0).ContinueWith(infos =>
{
foreach (var frameInfo in infos.Frames)
{
this.AddInput(frameInfo,false);
}
this._isRequestServerData = false;
}).Forget();
}
return;
}
else
@@ -167,15 +230,17 @@ namespace Plugins.JNGame.Sync.Frame
_nLocalFrame = index;
//分帧插入
_nFrameQueue.Add(frame);
for (var i = 0; i < this._nDivideFrame - 1; index++) {
_nFrameQueue.Add(new JNFrameInfo());
_nFrameQueue.Enqueue(frame);
for (var i = 0; i < this._nDivideFrame - 1; i++) {
_nFrameQueue.Enqueue(new JNFrameInfo());
}
}
//发送帧数据
protected abstract void OnSendInput(JNFrameInputs inputs);
//获取帧数据
protected abstract UniTask<JNFrameInfos> OnServerData(int start,int end);
}
}

View File

@@ -1,4 +1,6 @@
using System;
using System.Text;
using Newtonsoft.Json;
using UnityEngine;
namespace Plugins.JNGame.Sync.Frame.game
@@ -10,7 +12,8 @@ namespace Plugins.JNGame.Sync.Frame.game
//标识
private int _nId;
public int NID => _nId;
//当前输入
private T _input;
@@ -42,8 +45,21 @@ namespace Plugins.JNGame.Sync.Frame.game
//加载
public abstract void OnSyncLoad();
//解析
public T Decoder(byte[] bytes)
{
return JsonConvert.DeserializeObject<T>(Encoding.UTF8.GetString(bytes));
}
//编码
public byte[] Encoder(T input){
return Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(input));
}
//帧同步
public abstract void OnSyncUpdate(int dt,JNFrameInfo frame,Input input = null);
public abstract void OnSyncUpdate(int dt,JNFrameInfo frame,T input);

View File

@@ -11,6 +11,22 @@ namespace Plugins.JNGame.Util
{
public Dictionary<string, List<Delegate>> EventHandlers { get; private set; } = new();
/// <summary>
/// 添加事件监听器
/// </summary>
/// <param name="eventId">事件标识符</param>
/// <param name="listener">事件监听器</param>
public void AddListener(string eventId, Delegate listener)
{
if (!EventHandlers.ContainsKey(eventId))
{
EventHandlers[eventId] = new List<Delegate>();
}
EventHandlers[eventId].Add(listener);
Debug.Log(eventId+ "AddListener" + EventHandlers[eventId].Count);
}
/// <summary>
/// 添加事件监听器
/// </summary>
@@ -26,7 +42,6 @@ namespace Plugins.JNGame.Util
EventHandlers[eventId].Add(listener);
Debug.Log(eventId+ "AddListener" + EventHandlers[eventId].Count);
//eventHandlers[eventId] = (Action<T>)eventHandlers[eventId] + listener;
}
/// <summary>

View File

@@ -0,0 +1,62 @@
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using Newtonsoft.Json;
using UnityEngine.Networking;
namespace Plugins.JNGame.Util
{
public class JAPIConfig{
public string BaseURL = "http://localhost:8080"; //baseURL 默认HTTP头
public int Timeout = 5000; //超时时间
}
public class JAPIData<T>{
public T Data;
}
/**
* JNGame 的 网络请求类
*/
public class JAPI {
private JAPIConfig _config;
public JAPI(JAPIConfig config = null)
{
if (config == null) config = new JAPIConfig();
this._config = config;
}
public async UniTask<T> Get<T>(string url)
{
var request = UnityWebRequest.Get($"{this._config.BaseURL}/{url}");
return JsonConvert.DeserializeObject<T>((await request.SendWebRequest()).downloadHandler.text);
}
public async UniTask<T> Post<T>(string url,Dictionary<string,string> data)
{
var request = UnityWebRequest.Post($"{this._config.BaseURL}/{url}",data);
return JsonConvert.DeserializeObject<T>((await request.SendWebRequest()).downloadHandler.text);
}
public async UniTask<T> Post<T,TA>(string url,TA data)
{
var request = UnityWebRequest.Post($"{this._config.BaseURL}/{url}",JsonConvert.SerializeObject(data));
return JsonConvert.DeserializeObject<T>((await request.SendWebRequest()).downloadHandler.text);
}
public async UniTask<byte[]> GetByte(string url)
{
var request = UnityWebRequest.Get($"{this._config.BaseURL}/{url}");
return (await request.SendWebRequest()).downloadHandler.data;
}
public async UniTask<byte[]> PostByte(string url,Dictionary<string,string> data)
{
var request = UnityWebRequest.Post($"{this._config.BaseURL}/{url}",data);
return (await request.SendWebRequest()).downloadHandler.data;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fc72d9190d1241f680950baaaf2ec27e
timeCreated: 1706373831

View File

@@ -1,4 +1,5 @@
using Plugins.JNGame.System;
using Plugins.JNGame.Util;
using Script.AppImpl;
namespace Script
@@ -8,6 +9,7 @@ namespace Script
public static JNGSocket Socket = new JNGSocket();
public static JNGSyncFrame Sync = new JNGSyncFrame();
public static JAPI Api = new(new JAPIConfig(){BaseURL = "http://localhost:8080"});
public static SystemBase[] System()
{

View File

@@ -1,4 +1,5 @@
using System.Threading.Tasks;
using System;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using Plugins.JNGame.Network;

View File

@@ -1,4 +1,6 @@
using Plugins.JNGame.Sync.Frame;
using Cysharp.Threading.Tasks;
using Plugins.JNGame.Sync.Frame;
using UnityEngine;
namespace Script.AppImpl
{
@@ -8,5 +10,18 @@ namespace Script.AppImpl
{
throw new System.NotImplementedException();
}
protected override async UniTask<JNFrameInfos> OnServerData(int start, int end)
{
var data = (await App.Api.GetByte($"/sync/frame?start={start}"));
if (data is { Length: > 0 })
{
return JNFrameInfos.Parser.ParseFrom(data);
}
else
{
return new JNFrameInfos();
}
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using Google.Protobuf;
using Plugins.JNGame;
using Plugins.JNGame.Network.Action;
using Script.battle;
@@ -24,7 +25,7 @@ namespace Script
//初始化模式类
await GBattleModeManager.Instance.Open(GBattleMode.Default);
App.Socket.AddListener<NActionDemo>(3,OnNActionDemo);
App.Socket.AddListener(3,OnNActionDemo);
App.Socket.AddListener<JNFrameInfo>((int)NActionEnum.NSyncFrameBack,OnNSyncFrameBack);
//加载成功向服务器发送帧同步消息
@@ -38,14 +39,15 @@ namespace Script
}
public void OnNActionDemo(NActionDemo demo)
public void OnNActionDemo()
{
Debug.Log(demo.Message);
Debug.Log("OnNActionDemo");
}
public void OnNSyncFrameBack(JNFrameInfo info)
{
Debug.Log(info.Index);
App.Sync.AddInput(info);
}
private void Update()

View File

@@ -42,6 +42,8 @@ namespace Script.battle
await Close();
_current = mode;
await LoadScene(mode);
//开始同步
App.Sync.onStart();
}
@@ -50,6 +52,7 @@ namespace Script.battle
{
await UnloadScene(_current);
App.Sync.onStop();
_current = GBattleMode.Not;
}

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Google.Protobuf" version="3.15.8" manuallyInstalled="true" />
<package id="Newtonsoft.Json" version="13.0.3" manuallyInstalled="true" />
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" />
</packages>