初始化

This commit is contained in:
come
2025-07-26 16:56:42 +08:00
parent 8291dbb91c
commit fa81439a8c
2574 changed files with 328492 additions and 2170 deletions

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: b32bd69d879747c8bdf5a3e8c313560c
timeCreated: 1752544984

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 7ae98d1b6ba74880a5bdbd3cefd09faa
timeCreated: 1752544970

View File

@@ -1,59 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using Luban;
namespace cfg
{
public sealed partial class Language : Luban.BeanBase
{
public Language(ByteBuf _buf)
{
Id = _buf.ReadString();
CN = _buf.ReadString();
EN = _buf.ReadString();
}
public static Language DeserializeLanguage(ByteBuf _buf)
{
return new Language(_buf);
}
/// <summary>
/// id
/// </summary>
public readonly string Id;
/// <summary>
/// 中文
/// </summary>
public readonly string CN;
/// <summary>
/// 英文
/// </summary>
public readonly string EN;
public const int __ID__ = -1548945544;
public override int GetTypeId() => __ID__;
public void ResolveRef(Tables tables)
{
}
public override string ToString()
{
return "{ "
+ "id:" + Id + ","
+ "CN:" + CN + ","
+ "EN:" + EN + ","
+ "}";
}
}
}

View File

@@ -1,30 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using Luban;
namespace cfg
{
public partial class Tables
{
public TbLanguage TbLanguage {get; }
public Tables(System.Func<string, ByteBuf> loader)
{
TbLanguage = new TbLanguage(loader("tblanguage"));
ResolveRef();
}
private void ResolveRef()
{
TbLanguage.ResolveRef(this);
}
}
}

View File

@@ -1,52 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using Luban;
namespace cfg
{
public partial class TbLanguage
{
private readonly System.Collections.Generic.Dictionary<string, Language> _dataMap;
private readonly System.Collections.Generic.List<Language> _dataList;
public TbLanguage(ByteBuf _buf)
{
_dataMap = new System.Collections.Generic.Dictionary<string, Language>();
_dataList = new System.Collections.Generic.List<Language>();
for(int n = _buf.ReadSize() ; n > 0 ; --n)
{
Language _v;
_v = global::cfg.Language.DeserializeLanguage(_buf);
_dataList.Add(_v);
_dataMap.Add(_v.Id, _v);
}
}
public System.Collections.Generic.Dictionary<string, Language> DataMap => _dataMap;
public System.Collections.Generic.List<Language> DataList => _dataList;
public Language GetOrDefault(string key) => _dataMap.TryGetValue(key, out var v) ? v : null;
public Language Get(string key) => _dataMap[key];
public Language this[string key] => _dataMap[key];
public void ResolveRef(Tables tables)
{
foreach(var _v in _dataList)
{
_v.ResolveRef(tables);
}
}
}
}

View File

@@ -1,45 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using Luban;
namespace cfg
{
public partial struct vector2
{
public vector2(ByteBuf _buf)
{
X = _buf.ReadFloat();
Y = _buf.ReadFloat();
}
public static vector2 Deserializevector2(ByteBuf _buf)
{
return new vector2(_buf);
}
public readonly float X;
public readonly float Y;
public void ResolveRef(Tables tables)
{
}
public override string ToString()
{
return "{ "
+ "x:" + X + ","
+ "y:" + Y + ","
+ "}";
}
}
}

View File

@@ -1,48 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using Luban;
namespace cfg
{
public partial struct vector3
{
public vector3(ByteBuf _buf)
{
X = _buf.ReadFloat();
Y = _buf.ReadFloat();
Z = _buf.ReadFloat();
}
public static vector3 Deserializevector3(ByteBuf _buf)
{
return new vector3(_buf);
}
public readonly float X;
public readonly float Y;
public readonly float Z;
public void ResolveRef(Tables tables)
{
}
public override string ToString()
{
return "{ "
+ "x:" + X + ","
+ "y:" + Y + ","
+ "z:" + Z + ","
+ "}";
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 76805dce6fb46a24d9adcbe822387088
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,51 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using Luban;
namespace cfg
{
public partial struct vector4
{
public vector4(ByteBuf _buf)
{
X = _buf.ReadFloat();
Y = _buf.ReadFloat();
Z = _buf.ReadFloat();
W = _buf.ReadFloat();
}
public static vector4 Deserializevector4(ByteBuf _buf)
{
return new vector4(_buf);
}
public readonly float X;
public readonly float Y;
public readonly float Z;
public readonly float W;
public void ResolveRef(Tables tables)
{
}
public override string ToString()
{
return "{ "
+ "x:" + X + ","
+ "y:" + Y + ","
+ "z:" + Z + ","
+ "w:" + W + ","
+ "}";
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: d8b419c77ca0c9847ab9b9bf509dc546
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,25 +0,0 @@
using UnityEngine;
using UnityEngine.UI;
namespace CreatGame.UI
{
public partial class UIMainView : UIViewBase
{
public override string PrefabPath => "Prefabs/UI/MainView";
/// <summary>
///
/// </summary>
public Button StarBtn;
/// <summary>
///
/// </summary>
public Text StarBtnText;
public override void PreLoad(GameObject view)
{
base.PreLoad(view);
StarBtn = GetGameObject(nameof(StarBtn)).GetComponent<Button>();
StarBtnText = GetGameObject(nameof(StarBtnText)).GetComponent<Text>();
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 8c5ae2248a663cd4f9fc66ca55751f19
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,31 +0,0 @@
using System.Collections;
using CreatGame.UI;
using UnityEditor.VersionControl;
namespace CreatGame
{
public class GameLogic : Singleton<GameLogic>
{
public IEnumerator Start()
{
AssetBundle.AssetBundleManager.Instance.Initialize();
while (true)
{
if (AssetBundle.AssetBundleManager.Instance.IsInitializeAsync)
{
break;
}
yield return null;
}
UIManager.Instance.OpenView<UI.UIMainView>(UILayer.Main);
}
public void Destroy()
{
AssetBundle.AssetBundleManager.Instance.ReleaseAll();
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 8bed5572501d4f149c84589085bec321
timeCreated: 1752463362

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 341fa7946cf046c1ae980f1f3efabbda
timeCreated: 1752547061

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 12e2e1bf012c4e74951a89b77d46f08c
timeCreated: 1752547082

View File

@@ -1,101 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.ResourceManagement.ResourceLocations;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceProviders;
public class AddressableUpdater : MonoBehaviour
{
public string remoteCatalogUrl; // CDN catalog 路径
public Action<float> OnProgressChanged; // 进度更新回调 0~1
public Action<float> OnSpeedChanged; // 下载速度更新 (KB/s)
public Action<float> OnDownloadSizeFetched; // 总下载大小回调 (MB)
public Action OnCompleted; // 下载完成
private float lastDownloadedBytes = 0;
private float updateCheckInterval = 0.5f;
void Start()
{
StartCoroutine(UpdateAddressables());
}
IEnumerator UpdateAddressables()
{
// 1. 初始化 Addressables
var initHandle = Addressables.InitializeAsync();
yield return initHandle;
// 2. 更新 Catalog
var catalogHandle = Addressables.UpdateCatalogs();
yield return catalogHandle;
List<IResourceLocator> catalogs = catalogHandle.Result;
// 3. 获取资源下载大小
var sizeHandle = Addressables.GetDownloadSizeAsync(Addressables.ResourceManager.ResourceProviders);
yield return sizeHandle;
long totalDownloadSize = sizeHandle.Result;
if (totalDownloadSize <= 0)
{
Debug.Log("无需更新");
OnCompleted?.Invoke();
yield break;
}
OnDownloadSizeFetched?.Invoke(totalDownloadSize / (1024f * 1024f)); // MB
// 4. 开始下载所有资源
var downloadHandle = Addressables.DownloadDependenciesAsync(Addressables.ResourceManager.ResourceProviders, true);
StartCoroutine(TrackDownloadProgress(downloadHandle, totalDownloadSize));
yield return downloadHandle;
if (downloadHandle.Status == AsyncOperationStatus.Succeeded)
{
Debug.Log("热更完成!");
OnCompleted?.Invoke();
}
else
{
Debug.LogError("热更失败!");
}
}
IEnumerator TrackDownloadProgress(AsyncOperationHandle handle, long totalSize)
{
float lastTime = Time.realtimeSinceStartup;
float lastDownloaded = 0;
while (!handle.IsDone)
{
float percent = handle.PercentComplete;
OnProgressChanged?.Invoke(percent);
float currentTime = Time.realtimeSinceStartup;
float elapsed = currentTime - lastTime;
if (elapsed >= updateCheckInterval)
{
float currentDownloaded = percent * totalSize;
float speed = (currentDownloaded - lastDownloaded) / elapsed / 1024f; // KB/s
OnSpeedChanged?.Invoke(speed);
lastTime = currentTime;
lastDownloaded = currentDownloaded;
}
yield return null;
}
OnProgressChanged?.Invoke(1f);
OnSpeedChanged?.Invoke(0);
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 2bbf6478f2ed4dd0ac123f2a03fe3695
timeCreated: 1752549280

View File

@@ -1,209 +0,0 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceLocations;
using UnityEngine.U2D;
namespace CreatGame.AssetBundle
{
public class AssetBundleManager : Singleton<AssetBundleManager>
{
private class AssetBundleData
{
public string assetBundleName;
public GameObject assetBundle;
}
/// <summary>
///
/// </summary>
private Dictionary<string, AssetBundleData> m_AssetBundles;
/// <summary>
///
/// </summary>
private Dictionary<string, SpriteAtlas> m_SpriteAtlasCache;
/// <summary>
/// 是否初始化完成
/// </summary>
public bool IsInitializeAsync;
/// <summary>
/// 需要初始化Addressble系统
/// </summary>
public AssetBundleManager()
{
IsInitializeAsync = false;
m_AssetBundles = new Dictionary<string, AssetBundleData>();
m_SpriteAtlasCache = new Dictionary<string, SpriteAtlas>();
Addressables.InitializeAsync();
}
public void Initialize()
{
Addressables.InitializeAsync().Completed += OnInitializeCompleted;
}
/// <summary>
/// 初始化信息回调
/// </summary>
private void OnInitializeCompleted(AsyncOperationHandle<IResourceLocator> operationHandle)
{
if (operationHandle.Status == AsyncOperationStatus.Succeeded)
{
Debug.Log("Addressables initialization succeeded");
#region MyRegion
// IResourceLocator locator = operationHandle.Result;
// foreach (object locatorKey in locator.Keys)
// {
// locator.Locate(locatorKey,typeof(UnityEngine.Object),out IList<IResourceLocation> locations);
// if (locations == null)
// {
// continue;
// }
//
// foreach (var location in locations)
// {
// string key = location.PrimaryKey;
// Addressables.LoadAssetAsync<UnityEngine.Object>(key).Completed += (handle) =>
// {
// if (handle.Status == AsyncOperationStatus.Succeeded)
// {
// Debug.Log("Addressables load asset succeeded");
// var asset = handle.Result;
// GameObject.Instantiate(asset);
// }
// };
// }
// }
#endregion
IsInitializeAsync = true;
}
}
/// <summary>
/// 异步加载资源
/// </summary>
/// <param name="assetBundleName"></param>
/// <param name="callback"></param>
public void LoadGameObjectAsync(string assetBundleName, Action<GameObject> callback)
{
if (m_AssetBundles.TryGetValue(assetBundleName, out var bundle))
{
callback.Invoke(GameObject.Instantiate(bundle.assetBundle));
return;
}
Addressables.LoadAssetAsync<GameObject>(assetBundleName).Completed += (handle) =>
{
if (handle.Status == AsyncOperationStatus.Succeeded)
{
var assetData = CacheAssetBundles(assetBundleName, handle.Result);
Addressables.Release(handle);
callback?.Invoke(GameObject.Instantiate(assetData.assetBundle));
}
else
{
Debug.Log($"assetBundleName = {assetBundleName} 加载失败 Status = {handle.Status}");
callback?.Invoke(null);
}
};
}
/// <summary>
/// 同步等待加载资源
/// </summary>
/// <param name="assetBundleName"></param>
public GameObject LoadGameObject(string assetBundleName)
{
if (m_AssetBundles.TryGetValue(assetBundleName, out var bundle))
{
return GameObject.Instantiate(bundle.assetBundle);
}
var handle = Addressables.LoadAssetAsync<GameObject>(assetBundleName);
handle.WaitForCompletion();
if (handle.Status == AsyncOperationStatus.Succeeded)
{
bundle = CacheAssetBundles(assetBundleName, handle.Result);
Addressables.Release(handle);
return GameObject.Instantiate(bundle.assetBundle);
}
Debug.LogError("资源加载失败");
return null;
}
/// <summary>
/// 缓存加载出来的资源
/// </summary>
/// <param name="bundleName"></param>
/// <param name="bundle"></param>
/// <returns></returns>
private AssetBundleData CacheAssetBundles(string bundleName, GameObject bundle = null)
{
var data = new AssetBundleData(){assetBundleName = bundleName, assetBundle = bundle};
m_AssetBundles.Add(bundleName, data);
return data;
}
/// <summary>
/// 同步加载图集
/// </summary>
/// <param name="atlasName"></param>
/// <returns></returns>
public SpriteAtlas LoadSpriteAtlas(string atlasName)
{
if (m_SpriteAtlasCache.TryGetValue(atlasName, out var atlas))
{
return atlas;
}
var handle = Addressables.LoadAssetAsync<SpriteAtlas>(atlasName);
handle.WaitForCompletion();
if (handle.Status == AsyncOperationStatus.Succeeded)
{
atlas = handle.Result;
Addressables.Release(handle);
m_SpriteAtlasCache.Add(atlasName, atlas);
return atlas;
}
Debug.LogError($"图集加载失败 atlasName = {atlasName} Status = {handle.Status}");
return null;
}
/// <summary>
/// 异步加载图集
/// </summary>
/// <param name="assetBundleName"></param>
/// <param name="callback"></param>
public void LoadSpriteAsync(string atlasName, Action<SpriteAtlas> callback)
{
if (m_SpriteAtlasCache.TryGetValue(atlasName, out var atlas))
{
callback.Invoke(atlas);
return;
}
Addressables.LoadAssetAsync<SpriteAtlas>(atlasName).Completed += (handle) =>
{
if (handle.Status == AsyncOperationStatus.Succeeded)
{
atlas = handle.Result;
Addressables.Release(handle);
m_SpriteAtlasCache.Add(atlasName, atlas);
}
else
{
Debug.LogError($"图集加载失败 atlasName = {atlasName} Status = {handle.Status}");
callback?.Invoke(null);
}
};
}
/// <summary>
/// 释放所有的资源
/// </summary>
public void ReleaseAll()
{
m_AssetBundles.Clear();
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 01bfbdbb68f24f39bf248e1ce2907783
timeCreated: 1752547273

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 726911973e4b4b129678928347fc1de4
timeCreated: 1752547090

View File

@@ -1,35 +0,0 @@
using System.IO;
using System.Net.Mime;
using Luban;
using UnityEngine;
namespace CreatGame
{
/// <summary>
/// 表格
/// </summary>
public class ConfigManager : Singleton<ConfigManager>
{
/// <summary>
///
/// </summary>
private readonly cfg.Tables tables;
/// <summary>
///
/// </summary>
public cfg.Tables Tables => tables;
public ConfigManager()
{
var tablesCtor = typeof(cfg.Tables).GetConstructors()[0];
// 根据cfg.Tables的构造函数的Loader的返回值类型决定使用json还是ByteBuf Loader
System.Delegate loader = new System.Func<string, ByteBuf>(LoadByteBuf);
tables = (cfg.Tables)tablesCtor.Invoke(new object[] {loader});
}
private static ByteBuf LoadByteBuf(string file)
{
return new ByteBuf(File.ReadAllBytes($"{Application.dataPath}/AssetBundle/Config/{file}.bytes"));
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 60fd032406824917a60af497b179c08f
timeCreated: 1752717676

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 8f912db237c54e96b83e9c11a7ab6889
timeCreated: 1752547100

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: f208809c54934f6f911cc29d97c3519a
timeCreated: 1752550099

View File

@@ -1,13 +0,0 @@
namespace CreatGame.UI
{
/// <summary>
/// 窗口层级
/// </summary>
public enum UILayer
{
Main,
Popup,
Notify,
System,
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: a02dc47e9bb442079f60800e51c49b6e
timeCreated: 1752551035

View File

@@ -1,76 +0,0 @@
using UnityEngine;
using CreatGame.AssetBundle;
using System.Collections.Generic;
using UnityEngine.U2D;
namespace CreatGame.UI
{
/// <summary>
/// ui上的资源加载器
/// </summary>
public class UILoader
{
private List<GameObject> m_GameObjectCache = new List<GameObject>();
private List<Sprite> m_SpriteCache = new List<Sprite>();
/// <summary>
/// 同步资源加载
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public GameObject LoadGameObject(string name)
{
var gameObj = AssetBundleManager.Instance.LoadGameObject(name);
if (gameObj == null)
{
return null;
}
m_GameObjectCache.Add(gameObj);
return gameObj;
}
/// <summary>
/// 异步加载预制件
/// </summary>
/// <param name="name"></param>
/// <param name="callback"></param>
public void LoadGameObjectAsync(string name, System.Action<GameObject> callback)
{
AssetBundleManager.Instance.LoadGameObjectAsync(name, (obj) =>
{
if (obj != null)
{
m_GameObjectCache.Add(obj);
}
callback(obj);
});
}
/// <summary>
///
/// </summary>
/// <param name="atlasName"></param>
/// <param name="spriteName"></param>
/// <returns></returns>
public Sprite LoadSprite(string atlasName, string spriteName)
{
var spriteAtlas = AssetBundleManager.Instance.LoadSpriteAtlas(atlasName);
if (spriteAtlas == null)
{
return null;
}
return spriteAtlas.GetSprite(spriteName);
}
public void DisposeGameObjectCache()
{
var count = m_GameObjectCache.Count;
for (int i = 0; i < count; i++)
{
var obj = m_GameObjectCache[0];
m_GameObjectCache.RemoveAt(0);
GameObject.Destroy(obj);
}
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: dd77ddfde9dc430eb31244ee82bc2147
timeCreated: 1753323201

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 0631ad95508b427c96e7748c13e0eb59
timeCreated: 1752550115

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: d2e66ce219a441108094ae188afcc745
timeCreated: 1752663372

View File

@@ -1,20 +0,0 @@
using UnityEngine;
using UnityEngine.UI;
namespace CreatGame.UI
{
public class MainItem : MonoBehaviour
{
public Text text;
void ScrollCellIndex (int idx)
{
string name = "Cell " + idx.ToString ();
if (text != null)
{
text.text = name;
}
gameObject.name = name;
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 391eb6d877254380bf561b14e4be836f
timeCreated: 1752925668

View File

@@ -1,20 +0,0 @@
using System.Collections.Generic;
using UnityEngine;
namespace CreatGame.UI
{
public partial class UIMainView
{
public override void InitView()
{
base.InitView();
StarBtn.onClick.AddListener(OnStarBtnClick);
}
private void OnStarBtnClick()
{
StarBtnText.text = ConfigManager.Instance.Tables.TbLanguage.Get("Main_BtnTitle_Star").CN;
Debug.Log("OnStarBtnClick");
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 19a056c97ef74d2697f0bd0e7efc3651
timeCreated: 1752663384

View File

@@ -1,29 +0,0 @@
using UnityEngine;
namespace CreatGame.UI
{
/// <summary>
/// 通用的导出预制件的基类
/// </summary>
public class UIComponentBase
{
/// <summary>
/// 窗口预制件
/// </summary>
protected GameObject m_ComponentObject;
/// <summary>
/// 导出脚本
/// </summary>
protected UIComponentExport m_ViewExport;
/// <summary>
/// 是否加载完成
/// </summary>
public bool IsPreLoad = false;
public virtual void PreLoad(GameObject obj)
{
m_ComponentObject = obj;
m_ViewExport = obj.GetComponent<UIComponentExport>();
IsPreLoad = true;
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: ba52eedd767b46ae90e720030c75503f
timeCreated: 1752945611

View File

@@ -1,95 +0,0 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using CreatGame.AssetBundle;
namespace CreatGame.UI
{
public class UIManager : Singleton<UIManager>
{
private GameObject m_UIRoot;
private Dictionary<UILayer,GameObject> m_UILayers;
private Dictionary<UILayer, Queue<UIViewBase>> m_Windows;
/// <summary>
///
/// </summary>
public UIManager()
{
m_UIRoot = GameObject.Find("UIRoot");
InitLayer();
m_Windows = new Dictionary<UILayer, Queue<UIViewBase>>();
}
/// <summary>
/// 初始化layer层的预制件
/// </summary>
private void InitLayer()
{
if (m_UIRoot == null)
{
return;
}
m_UILayers = new Dictionary<UILayer, GameObject>();
foreach (var layer in Enum.GetValues(typeof(UILayer)))
{
var layerObj = m_UIRoot.transform.Find(Enum.GetName(typeof(UILayer), layer)).gameObject;
layerObj.transform.SetParent(m_UIRoot.transform);
layerObj.transform.localScale = Vector3.one;
layerObj.transform.localPosition = Vector3.zero;
layerObj.layer = LayerMask.NameToLayer("UI");
m_UILayers.Add((UILayer)layer,layerObj);
}
}
/// <summary>
///
/// </summary>
/// <param name="layer"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public UIViewBase OpenView<T>(UILayer layer) where T : UIViewBase , new()
{
var view = new T();
//加载预制件
AssetBundleManager.Instance.LoadGameObjectAsync(view.PrefabPath, (obj) =>
{
if (obj == null)
{
Debug.LogError($"窗口加载失败{typeof(T).Name}");
return;
}
view.PreLoad(obj);
if (m_UILayers.TryGetValue(layer, out var uiLayer))
{
obj.transform.SetParent(uiLayer.transform);
obj.transform.localPosition = Vector3.zero;
obj.transform.localScale = Vector3.one;
}
view.InitView();
if (m_Windows.ContainsKey(layer) == false)
{
m_Windows.Add(layer, new Queue<UIViewBase>());
}
m_Windows[layer].Enqueue(view);
});
return view;
}
/// <summary>
///
/// </summary>
/// <param name="layer"></param>
public void CloseView(UILayer layer)
{
if (m_Windows.ContainsKey(layer))
{
var view = m_Windows[layer].Dequeue();
view.CloseView();
}
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: b62361e051d040d696ac9c2485f57a3b
timeCreated: 1752550917

View File

@@ -1,49 +0,0 @@
using UnityEngine;
namespace CreatGame.UI
{
public class UIViewBase : UILoader
{
/// <summary>
/// 预制件的Addressables地址
/// 由导出代码自己添加
/// </summary>
public virtual string PrefabPath { get; set; }
/// <summary>
/// 窗口预制件
/// </summary>
protected GameObject m_ViewObject;
/// <summary>
/// 导出脚本
/// </summary>
protected UIViewExport m_ViewExport;
/// <summary>
/// 是否加载完成
/// </summary>
public bool IsPreLoad = false;
/// <summary>
/// 加载窗口的时候需要预先加载的东西
/// </summary>
public virtual void PreLoad(GameObject viewObject)
{
m_ViewObject = viewObject;
m_ViewExport = viewObject.GetComponent<UIViewExport>();
IsPreLoad = true;
}
/// <summary>
/// 初始化界面
/// </summary>
public virtual void InitView()
{
}
/// <summary>
/// 关闭窗口的时候的调用
/// </summary>
public virtual void CloseView()
{
DisposeGameObjectCache();
GameObject.Destroy(m_ViewObject);
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: f48b029bf9fe4664a47a4ede05f4d396
timeCreated: 1752550141

View File

@@ -1,26 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameStar : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
DontDestroyOnLoad(gameObject);
StartCoroutine(CreatGame.GameLogic.Instance.Start());
}
// Update is called once per frame
void Update()
{
}
private void OnDestroy()
{
CreatGame.GameLogic.Instance.Destroy();
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: dab0061814d076f4781a6ca28229dc2b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 574ee34052894bd79966fa8ad35a0335
timeCreated: 1752463436

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 05649470a3a64898bac0e32fd05aac14
timeCreated: 1753497036

View File

@@ -1,92 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace CreatGame
{
public class CoroutineManager : MonoBehaviour
{
#region Instance
private static CoroutineManager _instance;
public static CoroutineManager Instance
{
get
{
if (_instance == null)
{
var gameObj = new GameObject("CoroutineManager");
_instance = gameObj.AddComponent<CoroutineManager>();
DontDestroyOnLoad(gameObj);
}
return _instance;
}
}
#endregion
private ulong coroutineId = 0;
private ulong GetNextId()
{
return ++coroutineId;
}
private Dictionary<ulong,Coroutine> coroutines = new Dictionary<ulong,Coroutine>();
public ulong StartC(IEnumerator routine)
{
var id = GetNextId();
var coroutine = StartCoroutine(routine);
coroutines.Add(id, coroutine);
return id;
}
/// <summary>
///
/// </summary>
/// <param name="time">间隔时间</param>
/// <param name="isFirst">是否立即执行</param>
/// <param name="loop">是否循环</param>
/// <param name="action">方法</param>
public ulong StartC(float time,bool isFirst , bool loop, Action action)
{
var id = StartC(LoopCoroutine(time,isFirst,loop,action));
return id;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
private IEnumerator LoopCoroutine(float time,bool isFirst ,bool loop, Action action)
{
if (isFirst)
{
action.Invoke();
}
while (true)
{
yield return new WaitForSeconds(time);
action.Invoke();
if (!loop)
{
break;
}
}
}
public void StopC(ulong id)
{
if (coroutines.ContainsKey(id))
{
StopCoroutine(coroutines[id]);
coroutines.Remove(id);
}
}
private void OnDestroy()
{
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 7089d863c3ed4fb0bc6d7ddcb8488817
timeCreated: 1753497047

View File

@@ -1,36 +0,0 @@
namespace CreatGame
{
public class Singleton<T> where T : class, new()
{
private static T _instance;
private static readonly object _lock = new object();
[UnityEngine.Scripting.Preserve]
protected Singleton()
{
}
/// <summary>
/// 单例对象(线程安全,双重锁定)
/// </summary>
[UnityEngine.Scripting.Preserve]
public static T Instance
{
get
{
if (_instance == null)
{
lock (_lock)
{
if (_instance == null)
{
_instance = new T();
}
}
}
return _instance;
}
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 06769352e6416554e8adc475a44e9d43
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 07fbcc20f70d4d90bce50c964419e32d
timeCreated: 1752636609

View File

@@ -1,38 +0,0 @@
using System;
using UnityEngine;
using System.Collections.Generic;
namespace CreatGame.UI
{
public class UIComponentExport : MonoBehaviour
{
[Serializable]
public class UIEntry
{
public string key;
public GameObject prefab;
public string selectedComponentName; // 存储选择的组件类型名
}
/// <summary>
///
/// </summary>
public List<UIEntry> entries = new List<UIEntry>();
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public GameObject GetGameObject(string name)
{
for (int i = 0; i < entries.Count; i++)
{
if (entries[i].key == name)
{
return entries[i].prefab;
}
}
return null;
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: d94101161a144f17b4b80530abe93975
timeCreated: 1752945103

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 7741c712b36544fc99b98679783c3129
timeCreated: 1753339331

View File

@@ -1,59 +0,0 @@
using System;
using UnityEngine;
using System.Collections.Generic;
using UnityEngine.UI;
namespace CreatGame.UI
{
public delegate void OnSelectCallback(int index);
/// <summary>
/// 选中列表
/// </summary>
public class UISelectList : MonoBehaviour
{
public OnSelectCallback onSelectCallback;
private List<Button> m_buttonList = new List<Button>();
private void Awake()
{
m_buttonList = new List<Button>();
}
/// <summary>
///
/// </summary>
private void Start()
{
var childCount= transform.childCount;
for (int i = 0; i < childCount; i++)
{
var button = transform.GetChild(i).GetComponent<Button>();
if (button != null)
{
m_buttonList.Add(button);
button.onClick.AddListener(() => { OnClick(button); });
}
}
}
/// <summary>
///
/// </summary>
/// <param name="btn"></param>
private void OnClick(Button btn)
{
onSelectCallback?.Invoke(m_buttonList.IndexOf(btn));
}
public int Count => m_buttonList.Count;
public Transform this[int index]
{
get
{
if (index < 0 || index >= m_buttonList.Count)
{
return null;
}
return m_buttonList[index].transform;
}
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 52241bceb69a4f07be09e3dc319276dc
timeCreated: 1753341533

View File

@@ -1,17 +0,0 @@
using UnityEngine;
namespace CreatGame.UI
{
public class UISelected : MonoBehaviour
{
public int index = -1;
/// <summary>
/// 选中状态
/// </summary>
public GameObject selected;
/// <summary>
/// 未选中状态
/// </summary>
public GameObject unSelected;
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 20f38d816dc54bcb9ef57888b31a481d
timeCreated: 1753339357

View File

@@ -1,29 +0,0 @@
using System;
using UnityEngine;
using System.Collections.Generic;
public class UIViewExport : MonoBehaviour
{
[Serializable]
public class UIEntry
{
public string key;
public GameObject prefab;
public string selectedComponentName; // 存储选择的组件类型名
}
public List<UIEntry> entries = new List<UIEntry>();
public GameObject GetGameObject(string name)
{
for (int i = 0; i < entries.Count; i++)
{
if (entries[i].key == name)
{
return entries[i].prefab;
}
}
return null;
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: d7f07a01cdb5c7c4aa72a3a420035842
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 1dce5d6d618839f4f9e0e9d32c5d0699
guid: 217bb07fcea56ab42b8e338a8d59c9a7
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,99 @@
using UnityEngine;
using System;
#if UNITY_EDITOR
using System.Reflection;
#endif
public static class ConsoleProDebug
{
// Clear the console and the native console
public static void Clear()
{
#if UNITY_EDITOR
if(ConsoleClearMethod != null)
{
ConsoleClearMethod.Invoke(null, null);
}
#endif
}
// Send a log to a specific filter regardless of contents
// Ex: ConsoleProDebug.LogToFilter("Hi", "CustomFilter");
public static void LogToFilter(string inLog, string inFilterName, UnityEngine.Object inContext = null)
{
Debug.Log(inLog + "\nCPAPI:{\"cmd\":\"Filter\", \"name\":\"" + inFilterName + "\"}", inContext);
}
// Send a log as a regular log but change its type in ConsolePro
// Ex: ConsoleProDebug.LogAsType("Hi", "Error");
public static void LogAsType(string inLog, string inTypeName, UnityEngine.Object inContext = null)
{
Debug.Log(inLog + "\nCPAPI:{\"cmd\":\"LogType\", \"name\":\"" + inTypeName + "\"}", inContext);
}
// Watch a variable. This will only produce one log entry regardless of how many times it is logged, allowing you to track variables without spam.
// Ex:
// void Update() {
// ConsoleProDebug.Watch("Player X Position", transform.position.x);
// }
public static void Watch(string inName, string inValue)
{
Debug.Log(inName + " : " + inValue + "\nCPAPI:{\"cmd\":\"Watch\", \"name\":\"" + inName + "\"}");
}
public static void Search(string inText)
{
Debug.Log("\nCPAPI:{\"cmd\":\"Search\", \"text\":\"" + inText + "\"}");
}
#if UNITY_EDITOR
// Reflection calls to access Console Pro from runtime
private static bool _checkedConsoleClearMethod = false;
private static MethodInfo _consoleClearMethod = null;
private static MethodInfo ConsoleClearMethod
{
get
{
if(_consoleClearMethod == null || !_checkedConsoleClearMethod)
{
_checkedConsoleClearMethod = true;
if(ConsoleWindowType == null)
{
return null;
}
_consoleClearMethod = ConsoleWindowType.GetMethod("ClearEntries", BindingFlags.Static | BindingFlags.Public);
}
return _consoleClearMethod;
}
}
private static bool _checkedConsoleWindowType = false;
private static Type _consoleWindowType = null;
private static Type ConsoleWindowType
{
get
{
if(_consoleWindowType == null || !_checkedConsoleWindowType)
{
_checkedConsoleWindowType = true;
Assembly[] assemblies = System.AppDomain.CurrentDomain.GetAssemblies();
for(int iAssembly = 0; iAssembly < assemblies.Length; iAssembly++)
{
Type[] types = assemblies[iAssembly].GetTypes();
for(int iType = 0; iType < types.Length; iType++)
{
if(types[iType].Name == "ConsolePro3Window")
{
_consoleWindowType = types[iType];
}
}
}
}
return _consoleWindowType;
}
}
#endif
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 30f42e8a12eb842acbe9a63057fb00e4
timeCreated: 1469329295
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5de782a9528f04b41a8ba70afba32a61
timeCreated: 1498113024
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 48f786d98d3d1d24296e6825756cf55a
guid: 4bb9fa3b2a6b341a9af20d3b5f03ee13
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: a2284c517ee274c19a6ba4c1a8c96fb6
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 1
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 42130aa0870f6df4bb6217cc2e5805c3
guid: 3f14d07c8a9074483a59436a3caaad09
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,249 @@
// Uncomment to use in Editor
#define USECONSOLEPROREMOTESERVERINEDITOR
// #if (UNITY_WP_8_1 || UNITY_WSA)
// #define UNSUPPORTEDCONSOLEPROREMOTESERVER
// #endif
#if (!UNITY_EDITOR && DEBUG) || (UNITY_EDITOR && USECONSOLEPROREMOTESERVERINEDITOR)
#if !UNSUPPORTEDCONSOLEPROREMOTESERVER
#define USECONSOLEPROREMOTESERVER
#endif
#endif
#if UNITY_EDITOR && !USECONSOLEPROREMOTESERVER
#elif UNSUPPORTEDCONSOLEPROREMOTESERVER
#elif !USECONSOLEPROREMOTESERVER
#else
using System;
using System.Collections.Generic;
#endif
using System.Net;
using System.Net.Sockets;
using UnityEngine;
#if USECONSOLEPROREMOTESERVER
using FlyingWormConsole3.LiteNetLib;
using FlyingWormConsole3.LiteNetLib.Utils;
#endif
namespace FlyingWormConsole3
{
#if USECONSOLEPROREMOTESERVER
public class ConsoleProRemoteServer : MonoBehaviour, INetEventListener
#else
public class ConsoleProRemoteServer : MonoBehaviour
#endif
{
public bool useNATPunch = false;
public int port = 51000;
#if UNITY_EDITOR && !USECONSOLEPROREMOTESERVER
#elif UNSUPPORTEDCONSOLEPROREMOTESERVER
public void Awake()
{
Debug.Log("Console Pro Remote Server is not supported on this platform");
}
#elif !USECONSOLEPROREMOTESERVER
public void Awake()
{
Debug.Log("Console Pro Remote Server is disabled in release mode, please use a Development build or define DEBUG to use it");
}
#else
private NetManager _netServer;
private NetPeer _ourPeer;
private NetDataWriter _dataWriter;
[System.SerializableAttribute]
public class QueuedLog
{
public string timestamp;
public string message;
public string logType;
}
[NonSerializedAttribute]
public List<QueuedLog> logs = new List<QueuedLog>();
private static ConsoleProRemoteServer instance = null;
void Awake()
{
if(instance != null)
{
Destroy(gameObject);
}
instance = this;
DontDestroyOnLoad(gameObject);
Debug.Log("#Remote# Starting Console Pro Server on port : " + port);
_dataWriter = new NetDataWriter();
_netServer = new NetManager(this);
_netServer.Start(port);
_netServer.BroadcastReceiveEnabled = true;
_netServer.UpdateTime = 15;
_netServer.NatPunchEnabled = useNATPunch;
}
void OnDestroy()
{
if(_netServer != null)
{
_netServer.Stop();
}
}
public void OnPeerConnected(NetPeer peer)
{
Debug.Log("#Remote# Connected to " + peer.EndPoint);
_ourPeer = peer;
}
public void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo)
{
Debug.Log("#Remote# Disconnected from " + peer.EndPoint + ", info: " + disconnectInfo.Reason);
if (peer == _ourPeer)
{
_ourPeer = null;
}
}
public void OnNetworkError(IPEndPoint endPoint, SocketError socketError)
{
// throw new NotImplementedException();
}
public void OnNetworkReceive(NetPeer peer, NetPacketReader reader, DeliveryMethod deliveryMethod)
{
// throw new NotImplementedException();
}
public void OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType)
{
if(messageType == UnconnectedMessageType.Broadcast)
{
// Debug.Log("#Remote# Received discovery request. Send discovery response");
_netServer.SendUnconnectedMessage(new byte[] {1}, remoteEndPoint);
}
}
public void OnPeerDisconnected(NetPeer peer, DisconnectReason reason, int socketErrorCode)
{
}
public void OnNetworkLatencyUpdate(NetPeer peer, int latency)
{
}
public void OnConnectionRequest(ConnectionRequest request)
{
// Debug.Log("#Remote# Connection requested, accepting");
request.AcceptIfKey("Console Pro");
}
#if UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9
void OnEnable()
{
Application.RegisterLogCallback(LogCallback);
}
void Update()
{
Application.RegisterLogCallback(LogCallback);
}
void OnDisable()
{
Application.RegisterLogCallback(null);
}
#else
void OnEnable()
{
Application.logMessageReceivedThreaded += LogCallback;
}
void OnDisable()
{
Application.logMessageReceivedThreaded -= LogCallback;
}
#endif
public void LogCallback(string logString, string stackTrace, LogType type)
{
if(!logString.StartsWith("CPIGNORE"))
{
QueueLog(logString, stackTrace, type);
}
}
void QueueLog(string logString, string stackTrace, LogType type)
{
if(logs.Count > 1000)
{
while(logs.Count > 1000)
{
logs.RemoveAt(0);
}
}
#if CSHARP_7_3_OR_NEWER
logString = $"{logString}\n{stackTrace}\n";
logs.Add(new QueuedLog() { message = logString, logType = type.ToString(), timestamp = $"[{DateTime.Now.ToString("HH:mm:ss")}]" } );
#else
logString = logString + "\n" + stackTrace + "\n";
logs.Add(new QueuedLog() { message = logString, logType = type.ToString(), timestamp = "[" + DateTime.Now.ToString("HH:mm:ss") + "]" } );
#endif
}
void LateUpdate()
{
if(_netServer == null)
{
return;
}
_netServer.PollEvents();
if(_ourPeer == null)
{
return;
}
if(logs.Count <= 0)
{
return;
}
string cMessage = "";
foreach(var cLog in logs)
{
cMessage = JsonUtility.ToJson(cLog);
_dataWriter.Reset();
_dataWriter.Put(cMessage);
_ourPeer.Send(_dataWriter, DeliveryMethod.ReliableOrdered);
}
logs.Clear();
}
#endif
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d6bcfaced529e418bb75980b297fda2a
timeCreated: 1437614101
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 2c6bd635eeaa04c228b6d342c4758ad7
folderAsset: yes
timeCreated: 1494014730
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,52 @@
using System.Collections.Generic;
using System.Threading;
namespace FlyingWormConsole3.LiteNetLib
{
internal abstract class BaseChannel
{
protected readonly NetPeer Peer;
protected readonly Queue<NetPacket> OutgoingQueue;
private int _isAddedToPeerChannelSendQueue;
public int PacketsInQueue
{
get { return OutgoingQueue.Count; }
}
protected BaseChannel(NetPeer peer)
{
Peer = peer;
OutgoingQueue = new Queue<NetPacket>(64);
}
public void AddToQueue(NetPacket packet)
{
lock (OutgoingQueue)
{
OutgoingQueue.Enqueue(packet);
}
AddToPeerChannelSendQueue();
}
protected void AddToPeerChannelSendQueue()
{
if (Interlocked.CompareExchange(ref _isAddedToPeerChannelSendQueue, 1, 0) == 0)
{
Peer.AddToReliableChannelSendQueue(this);
}
}
public bool SendAndCheckQueue()
{
bool hasPacketsToSend = SendNextPackets();
if (!hasPacketsToSend)
Interlocked.Exchange(ref _isAddedToPeerChannelSendQueue, 0);
return hasPacketsToSend;
}
protected abstract bool SendNextPackets();
public abstract bool ProcessPacket(NetPacket packet);
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 43eea21323b017e498f0f0f6de63abf7
guid: 763566e7d03d94946afed98596540971
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -0,0 +1,137 @@
using System.Net;
using System.Threading;
using FlyingWormConsole3.LiteNetLib.Utils;
namespace FlyingWormConsole3.LiteNetLib
{
internal enum ConnectionRequestResult
{
None,
Accept,
Reject,
RejectForce
}
public class ConnectionRequest
{
private readonly NetManager _listener;
private int _used;
public readonly NetDataReader Data;
internal ConnectionRequestResult Result { get; private set; }
internal long ConnectionTime;
internal byte ConnectionNumber;
public readonly IPEndPoint RemoteEndPoint;
private bool TryActivate()
{
return Interlocked.CompareExchange(ref _used, 1, 0) == 0;
}
internal void UpdateRequest(NetConnectRequestPacket connRequest)
{
if (connRequest.ConnectionTime >= ConnectionTime)
{
ConnectionTime = connRequest.ConnectionTime;
ConnectionNumber = connRequest.ConnectionNumber;
}
}
internal ConnectionRequest(
long connectionId,
byte connectionNumber,
NetDataReader netDataReader,
IPEndPoint endPoint,
NetManager listener)
{
ConnectionTime = connectionId;
ConnectionNumber = connectionNumber;
RemoteEndPoint = endPoint;
Data = netDataReader;
_listener = listener;
}
public NetPeer AcceptIfKey(string key)
{
if (!TryActivate())
return null;
try
{
if (Data.GetString() == key)
Result = ConnectionRequestResult.Accept;
}
catch
{
NetDebug.WriteError("[AC] Invalid incoming data");
}
if (Result == ConnectionRequestResult.Accept)
return _listener.OnConnectionSolved(this, null, 0, 0);
Result = ConnectionRequestResult.Reject;
_listener.OnConnectionSolved(this, null, 0, 0);
return null;
}
/// <summary>
/// Accept connection and get new NetPeer as result
/// </summary>
/// <returns>Connected NetPeer</returns>
public NetPeer Accept()
{
if (!TryActivate())
return null;
Result = ConnectionRequestResult.Accept;
return _listener.OnConnectionSolved(this, null, 0, 0);
}
public void Reject(byte[] rejectData, int start, int length, bool force)
{
if (!TryActivate())
return;
Result = force ? ConnectionRequestResult.RejectForce : ConnectionRequestResult.Reject;
_listener.OnConnectionSolved(this, rejectData, start, length);
}
public void Reject(byte[] rejectData, int start, int length)
{
Reject(rejectData, start, length, false);
}
public void RejectForce(byte[] rejectData, int start, int length)
{
Reject(rejectData, start, length, true);
}
public void RejectForce()
{
Reject(null, 0, 0, true);
}
public void RejectForce(byte[] rejectData)
{
Reject(rejectData, 0, rejectData.Length, true);
}
public void RejectForce(NetDataWriter rejectData)
{
Reject(rejectData.Data, 0, rejectData.Length, true);
}
public void Reject()
{
Reject(null, 0, 0, false);
}
public void Reject(byte[] rejectData)
{
Reject(rejectData, 0, rejectData.Length, false);
}
public void Reject(NetDataWriter rejectData)
{
Reject(rejectData.Data, 0, rejectData.Length, false);
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: a19e815a8e895d44d8ecd983ec7322a2
guid: 01553ccc867ec43bbb1ae69d3de1ddda
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -0,0 +1,247 @@
using System.Net;
using System.Net.Sockets;
using FlyingWormConsole3.LiteNetLib.Utils;
namespace FlyingWormConsole3.LiteNetLib
{
/// <summary>
/// Type of message that you receive in OnNetworkReceiveUnconnected event
/// </summary>
public enum UnconnectedMessageType
{
BasicMessage,
Broadcast
}
/// <summary>
/// Disconnect reason that you receive in OnPeerDisconnected event
/// </summary>
public enum DisconnectReason
{
ConnectionFailed,
Timeout,
HostUnreachable,
NetworkUnreachable,
RemoteConnectionClose,
DisconnectPeerCalled,
ConnectionRejected,
InvalidProtocol,
UnknownHost,
Reconnect,
PeerToPeerConnection
}
/// <summary>
/// Additional information about disconnection
/// </summary>
public struct DisconnectInfo
{
/// <summary>
/// Additional info why peer disconnected
/// </summary>
public DisconnectReason Reason;
/// <summary>
/// Error code (if reason is SocketSendError or SocketReceiveError)
/// </summary>
public SocketError SocketErrorCode;
/// <summary>
/// Additional data that can be accessed (only if reason is RemoteConnectionClose)
/// </summary>
public NetPacketReader AdditionalData;
}
public interface INetEventListener
{
/// <summary>
/// New remote peer connected to host, or client connected to remote host
/// </summary>
/// <param name="peer">Connected peer object</param>
void OnPeerConnected(NetPeer peer);
/// <summary>
/// Peer disconnected
/// </summary>
/// <param name="peer">disconnected peer</param>
/// <param name="disconnectInfo">additional info about reason, errorCode or data received with disconnect message</param>
void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo);
/// <summary>
/// Network error (on send or receive)
/// </summary>
/// <param name="endPoint">From endPoint (can be null)</param>
/// <param name="socketError">Socket error</param>
void OnNetworkError(IPEndPoint endPoint, SocketError socketError);
/// <summary>
/// Received some data
/// </summary>
/// <param name="peer">From peer</param>
/// <param name="reader">DataReader containing all received data</param>
/// <param name="deliveryMethod">Type of received packet</param>
void OnNetworkReceive(NetPeer peer, NetPacketReader reader, DeliveryMethod deliveryMethod);
/// <summary>
/// Received unconnected message
/// </summary>
/// <param name="remoteEndPoint">From address (IP and Port)</param>
/// <param name="reader">Message data</param>
/// <param name="messageType">Message type (simple, discovery request or response)</param>
void OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType);
/// <summary>
/// Latency information updated
/// </summary>
/// <param name="peer">Peer with updated latency</param>
/// <param name="latency">latency value in milliseconds</param>
void OnNetworkLatencyUpdate(NetPeer peer, int latency);
/// <summary>
/// On peer connection requested
/// </summary>
/// <param name="request">Request information (EndPoint, internal id, additional data)</param>
void OnConnectionRequest(ConnectionRequest request);
}
public interface IDeliveryEventListener
{
/// <summary>
/// On reliable message delivered
/// </summary>
/// <param name="peer"></param>
/// <param name="userData"></param>
void OnMessageDelivered(NetPeer peer, object userData);
}
public interface INtpEventListener
{
/// <summary>
/// Ntp response
/// </summary>
/// <param name="packet"></param>
void OnNtpResponse(NtpPacket packet);
}
public class EventBasedNetListener : INetEventListener, IDeliveryEventListener, INtpEventListener
{
public delegate void OnPeerConnected(NetPeer peer);
public delegate void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo);
public delegate void OnNetworkError(IPEndPoint endPoint, SocketError socketError);
public delegate void OnNetworkReceive(NetPeer peer, NetPacketReader reader, DeliveryMethod deliveryMethod);
public delegate void OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType);
public delegate void OnNetworkLatencyUpdate(NetPeer peer, int latency);
public delegate void OnConnectionRequest(ConnectionRequest request);
public delegate void OnDeliveryEvent(NetPeer peer, object userData);
public delegate void OnNtpResponseEvent(NtpPacket packet);
public event OnPeerConnected PeerConnectedEvent;
public event OnPeerDisconnected PeerDisconnectedEvent;
public event OnNetworkError NetworkErrorEvent;
public event OnNetworkReceive NetworkReceiveEvent;
public event OnNetworkReceiveUnconnected NetworkReceiveUnconnectedEvent;
public event OnNetworkLatencyUpdate NetworkLatencyUpdateEvent;
public event OnConnectionRequest ConnectionRequestEvent;
public event OnDeliveryEvent DeliveryEvent;
public event OnNtpResponseEvent NtpResponseEvent;
public void ClearPeerConnectedEvent()
{
PeerConnectedEvent = null;
}
public void ClearPeerDisconnectedEvent()
{
PeerDisconnectedEvent = null;
}
public void ClearNetworkErrorEvent()
{
NetworkErrorEvent = null;
}
public void ClearNetworkReceiveEvent()
{
NetworkReceiveEvent = null;
}
public void ClearNetworkReceiveUnconnectedEvent()
{
NetworkReceiveUnconnectedEvent = null;
}
public void ClearNetworkLatencyUpdateEvent()
{
NetworkLatencyUpdateEvent = null;
}
public void ClearConnectionRequestEvent()
{
ConnectionRequestEvent = null;
}
public void ClearDeliveryEvent()
{
DeliveryEvent = null;
}
public void ClearNtpResponseEvent()
{
NtpResponseEvent = null;
}
void INetEventListener.OnPeerConnected(NetPeer peer)
{
if (PeerConnectedEvent != null)
PeerConnectedEvent(peer);
}
void INetEventListener.OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo)
{
if (PeerDisconnectedEvent != null)
PeerDisconnectedEvent(peer, disconnectInfo);
}
void INetEventListener.OnNetworkError(IPEndPoint endPoint, SocketError socketErrorCode)
{
if (NetworkErrorEvent != null)
NetworkErrorEvent(endPoint, socketErrorCode);
}
void INetEventListener.OnNetworkReceive(NetPeer peer, NetPacketReader reader, DeliveryMethod deliveryMethod)
{
if (NetworkReceiveEvent != null)
NetworkReceiveEvent(peer, reader, deliveryMethod);
}
void INetEventListener.OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType)
{
if (NetworkReceiveUnconnectedEvent != null)
NetworkReceiveUnconnectedEvent(remoteEndPoint, reader, messageType);
}
void INetEventListener.OnNetworkLatencyUpdate(NetPeer peer, int latency)
{
if (NetworkLatencyUpdateEvent != null)
NetworkLatencyUpdateEvent(peer, latency);
}
void INetEventListener.OnConnectionRequest(ConnectionRequest request)
{
if (ConnectionRequestEvent != null)
ConnectionRequestEvent(request);
}
void IDeliveryEventListener.OnMessageDelivered(NetPeer peer, object userData)
{
if (DeliveryEvent != null)
DeliveryEvent(peer, userData);
}
void INtpEventListener.OnNtpResponse(NtpPacket packet)
{
if (NtpResponseEvent != null)
NtpResponseEvent(packet);
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: b01c530301ff8ad4191edef0fdbb9434
guid: d391f9565d58e44a798d680ec5c11906
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

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

View File

@@ -0,0 +1,41 @@
using FlyingWormConsole3.LiteNetLib.Utils;
using System;
using System.Net;
namespace FlyingWormConsole3.LiteNetLib.Layers
{
public sealed class Crc32cLayer : PacketLayerBase
{
public Crc32cLayer() : base(CRC32C.ChecksumSize)
{
}
public override void ProcessInboundPacket(IPEndPoint endPoint, ref byte[] data, ref int offset, ref int length)
{
if (length < NetConstants.HeaderSize + CRC32C.ChecksumSize)
{
NetDebug.WriteError("[NM] DataReceived size: bad!");
//Set length to 0 to have netManager drop the packet.
length = 0;
return;
}
int checksumPoint = length - CRC32C.ChecksumSize;
if (CRC32C.Compute(data, offset, checksumPoint) != BitConverter.ToUInt32(data, checksumPoint))
{
NetDebug.Write("[NM] DataReceived checksum: bad!");
//Set length to 0 to have netManager drop the packet.
length = 0;
return;
}
length -= CRC32C.ChecksumSize;
}
public override void ProcessOutBoundPacket(IPEndPoint endPoint, ref byte[] data, ref int offset, ref int length)
{
FastBitConverter.GetBytes(data, length, CRC32C.Compute(data, offset, length));
length += CRC32C.ChecksumSize;
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 8fc14253f6e36724eb657932e1084248
guid: 03f6f2696c6e848c69a6af33539c5adc
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -0,0 +1,17 @@
using System.Net;
namespace FlyingWormConsole3.LiteNetLib.Layers
{
public abstract class PacketLayerBase
{
public readonly int ExtraPacketSizeForLayer;
protected PacketLayerBase(int extraPacketSizeForLayer)
{
ExtraPacketSizeForLayer = extraPacketSizeForLayer;
}
public abstract void ProcessInboundPacket(IPEndPoint endPoint, ref byte[] data, ref int offset, ref int length);
public abstract void ProcessOutBoundPacket(IPEndPoint endPoint, ref byte[] data, ref int offset, ref int length);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 20d4d1cdad986436a8f2f4fcc8e3e47d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,60 @@
using System;
using System.Net;
using System.Text;
namespace FlyingWormConsole3.LiteNetLib.Layers
{
public class XorEncryptLayer : PacketLayerBase
{
private byte[] _byteKey;
public XorEncryptLayer() : base(0)
{
}
public XorEncryptLayer(byte[] key) : this()
{
SetKey(key);
}
public XorEncryptLayer(string key) : this()
{
SetKey(key);
}
public void SetKey(string key)
{
_byteKey = Encoding.UTF8.GetBytes(key);
}
public void SetKey(byte[] key)
{
if (_byteKey == null || _byteKey.Length != key.Length)
_byteKey = new byte[key.Length];
Buffer.BlockCopy(key, 0, _byteKey, 0, key.Length);
}
public override void ProcessInboundPacket(IPEndPoint endPoint, ref byte[] data, ref int offset, ref int length)
{
if (_byteKey == null)
return;
var cur = offset;
for (var i = 0; i < length; i++, cur++)
{
data[cur] = (byte)(data[cur] ^ _byteKey[i % _byteKey.Length]);
}
}
public override void ProcessOutBoundPacket(IPEndPoint endPoint, ref byte[] data, ref int offset, ref int length)
{
if (_byteKey == null)
return;
var cur = offset;
for (var i = 0; i < length; i++, cur++)
{
data[cur] = (byte)(data[cur] ^ _byteKey[i % _byteKey.Length]);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0ee39ab3e39a742f59665fde4e2c4f27
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,245 @@
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using FlyingWormConsole3.LiteNetLib.Utils;
namespace FlyingWormConsole3.LiteNetLib
{
public enum NatAddressType
{
Internal,
External
}
public interface INatPunchListener
{
void OnNatIntroductionRequest(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, string token);
void OnNatIntroductionSuccess(IPEndPoint targetEndPoint, NatAddressType type, string token);
}
public class EventBasedNatPunchListener : INatPunchListener
{
public delegate void OnNatIntroductionRequest(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, string token);
public delegate void OnNatIntroductionSuccess(IPEndPoint targetEndPoint, NatAddressType type, string token);
public event OnNatIntroductionRequest NatIntroductionRequest;
public event OnNatIntroductionSuccess NatIntroductionSuccess;
void INatPunchListener.OnNatIntroductionRequest(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, string token)
{
if(NatIntroductionRequest != null)
NatIntroductionRequest(localEndPoint, remoteEndPoint, token);
}
void INatPunchListener.OnNatIntroductionSuccess(IPEndPoint targetEndPoint, NatAddressType type, string token)
{
if (NatIntroductionSuccess != null)
NatIntroductionSuccess(targetEndPoint, type, token);
}
}
/// <summary>
/// Module for UDP NAT Hole punching operations. Can be accessed from NetManager
/// </summary>
public sealed class NatPunchModule
{
struct RequestEventData
{
public IPEndPoint LocalEndPoint;
public IPEndPoint RemoteEndPoint;
public string Token;
}
struct SuccessEventData
{
public IPEndPoint TargetEndPoint;
public NatAddressType Type;
public string Token;
}
class NatIntroduceRequestPacket
{
public IPEndPoint Internal { get; set; }
public string Token { get; set; }
}
class NatIntroduceResponsePacket
{
public IPEndPoint Internal { get; set; }
public IPEndPoint External { get; set; }
public string Token { get; set; }
}
class NatPunchPacket
{
public string Token { get; set; }
public bool IsExternal { get; set; }
}
private readonly NetSocket _socket;
private readonly Queue<RequestEventData> _requestEvents = new Queue<RequestEventData>();
private readonly Queue<SuccessEventData> _successEvents = new Queue<SuccessEventData>();
private readonly NetDataReader _cacheReader = new NetDataReader();
private readonly NetDataWriter _cacheWriter = new NetDataWriter();
private readonly NetPacketProcessor _netPacketProcessor = new NetPacketProcessor(MaxTokenLength);
private INatPunchListener _natPunchListener;
public const int MaxTokenLength = 256;
internal NatPunchModule(NetSocket socket)
{
_socket = socket;
_netPacketProcessor.SubscribeReusable<NatIntroduceResponsePacket>(OnNatIntroductionResponse);
_netPacketProcessor.SubscribeReusable<NatIntroduceRequestPacket, IPEndPoint>(OnNatIntroductionRequest);
_netPacketProcessor.SubscribeReusable<NatPunchPacket, IPEndPoint>(OnNatPunch);
}
internal void ProcessMessage(IPEndPoint senderEndPoint, NetPacket packet)
{
lock (_cacheReader)
{
_cacheReader.SetSource(packet.RawData, NetConstants.HeaderSize, packet.Size);
_netPacketProcessor.ReadAllPackets(_cacheReader, senderEndPoint);
}
}
public void Init(INatPunchListener listener)
{
_natPunchListener = listener;
}
private void Send<T>(T packet, IPEndPoint target) where T : class, new()
{
SocketError errorCode = 0;
_cacheWriter.Reset();
_cacheWriter.Put((byte)PacketProperty.NatMessage);
_netPacketProcessor.Write(_cacheWriter, packet);
_socket.SendTo(_cacheWriter.Data, 0, _cacheWriter.Length, target, ref errorCode);
}
public void NatIntroduce(
IPEndPoint hostInternal,
IPEndPoint hostExternal,
IPEndPoint clientInternal,
IPEndPoint clientExternal,
string additionalInfo)
{
var req = new NatIntroduceResponsePacket
{
Token = additionalInfo
};
//First packet (server) send to client
req.Internal = hostInternal;
req.External = hostExternal;
Send(req, clientExternal);
//Second packet (client) send to server
req.Internal = clientInternal;
req.External = clientExternal;
Send(req, hostExternal);
}
public void PollEvents()
{
if (_natPunchListener == null || (_successEvents.Count == 0 && _requestEvents.Count == 0))
return;
lock (_successEvents)
{
while (_successEvents.Count > 0)
{
var evt = _successEvents.Dequeue();
_natPunchListener.OnNatIntroductionSuccess(
evt.TargetEndPoint,
evt.Type,
evt.Token);
}
}
lock (_requestEvents)
{
while (_requestEvents.Count > 0)
{
var evt = _requestEvents.Dequeue();
_natPunchListener.OnNatIntroductionRequest(evt.LocalEndPoint, evt.RemoteEndPoint, evt.Token);
}
}
}
public void SendNatIntroduceRequest(string host, int port, string additionalInfo)
{
SendNatIntroduceRequest(NetUtils.MakeEndPoint(host, port), additionalInfo);
}
public void SendNatIntroduceRequest(IPEndPoint masterServerEndPoint, string additionalInfo)
{
//prepare outgoing data
string networkIp = NetUtils.GetLocalIp(LocalAddrType.IPv4);
if (string.IsNullOrEmpty(networkIp))
{
networkIp = NetUtils.GetLocalIp(LocalAddrType.IPv6);
}
Send(
new NatIntroduceRequestPacket
{
Internal = NetUtils.MakeEndPoint(networkIp, _socket.LocalPort),
Token = additionalInfo
},
masterServerEndPoint);
}
//We got request and must introduce
private void OnNatIntroductionRequest(NatIntroduceRequestPacket req, IPEndPoint senderEndPoint)
{
lock (_requestEvents)
{
_requestEvents.Enqueue(new RequestEventData
{
LocalEndPoint = req.Internal,
RemoteEndPoint = senderEndPoint,
Token = req.Token
});
}
}
//We got introduce and must punch
private void OnNatIntroductionResponse(NatIntroduceResponsePacket req)
{
NetDebug.Write(NetLogLevel.Trace, "[NAT] introduction received");
// send internal punch
var punchPacket = new NatPunchPacket {Token = req.Token};
Send(punchPacket, req.Internal);
NetDebug.Write(NetLogLevel.Trace, "[NAT] internal punch sent to " + req.Internal);
// hack for some routers
SocketError errorCode = 0;
_socket.Ttl = 2;
_socket.SendTo(new[] { (byte)PacketProperty.Empty }, 0, 1, req.External, ref errorCode);
// send external punch
_socket.Ttl = NetConstants.SocketTTL;
punchPacket.IsExternal = true;
Send(punchPacket, req.External);
NetDebug.Write(NetLogLevel.Trace, "[NAT] external punch sent to " + req.External);
}
//We got punch and can connect
private void OnNatPunch(NatPunchPacket req, IPEndPoint senderEndPoint)
{
//Read info
NetDebug.Write(NetLogLevel.Trace, "[NAT] punch received from {0} - additional info: {1}",
senderEndPoint, req.Token);
//Release punch success to client; enabling him to Connect() to Sender if token is ok
lock (_successEvents)
{
_successEvents.Enqueue(new SuccessEventData
{
TargetEndPoint = senderEndPoint,
Type = req.IsExternal ? NatAddressType.External : NatAddressType.Internal,
Token = req.Token
});
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 11f3508667cc14e3797a49d4695ffdd8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,74 @@
namespace FlyingWormConsole3.LiteNetLib
{
/// <summary>
/// Sending method type
/// </summary>
public enum DeliveryMethod : byte
{
/// <summary>
/// Unreliable. Packets can be dropped, can be duplicated, can arrive without order.
/// </summary>
Unreliable = 4,
/// <summary>
/// Reliable. Packets won't be dropped, won't be duplicated, can arrive without order.
/// </summary>
ReliableUnordered = 0,
/// <summary>
/// Unreliable. Packets can be dropped, won't be duplicated, will arrive in order.
/// </summary>
Sequenced = 1,
/// <summary>
/// Reliable and ordered. Packets won't be dropped, won't be duplicated, will arrive in order.
/// </summary>
ReliableOrdered = 2,
/// <summary>
/// Reliable only last packet. Packets can be dropped (except the last one), won't be duplicated, will arrive in order.
/// Cannot be fragmented
/// </summary>
ReliableSequenced = 3
}
/// <summary>
/// Network constants. Can be tuned from sources for your purposes.
/// </summary>
public static class NetConstants
{
//can be tuned
public const int DefaultWindowSize = 64;
public const int SocketBufferSize = 1024 * 1024; //1mb
public const int SocketTTL = 255;
public const int HeaderSize = 1;
public const int ChanneledHeaderSize = 4;
public const int FragmentHeaderSize = 6;
public const int FragmentedHeaderTotalSize = ChanneledHeaderSize + FragmentHeaderSize;
public const ushort MaxSequence = 32768;
public const ushort HalfMaxSequence = MaxSequence / 2;
//protocol
internal const int ProtocolId = 11;
internal const int MaxUdpHeaderSize = 68;
internal static readonly int[] PossibleMtu =
{
576 - MaxUdpHeaderSize, //minimal (RFC 1191)
1024, //most games standard
1232 - MaxUdpHeaderSize,
1460 - MaxUdpHeaderSize, //google cloud
1472 - MaxUdpHeaderSize, //VPN
1492 - MaxUdpHeaderSize, //Ethernet with LLC and SNAP, PPPoE (RFC 1042)
1500 - MaxUdpHeaderSize //Ethernet II (RFC 1191)
};
internal static readonly int MaxPacketSize = PossibleMtu[PossibleMtu.Length - 1];
//peer specific
public const byte MaxConnectionNumber = 4;
public const int PacketPoolSize = 1000;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 02abb4740bff94f28bdd538839339932
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,92 @@
using System;
using System.Diagnostics;
namespace FlyingWormConsole3.LiteNetLib
{
public class InvalidPacketException : ArgumentException
{
public InvalidPacketException(string message) : base(message)
{
}
}
public class TooBigPacketException : InvalidPacketException
{
public TooBigPacketException(string message) : base(message)
{
}
}
public enum NetLogLevel
{
Warning,
Error,
Trace,
Info
}
/// <summary>
/// Interface to implement for your own logger
/// </summary>
public interface INetLogger
{
void WriteNet(NetLogLevel level, string str, params object[] args);
}
/// <summary>
/// Static class for defining your own LiteNetLib logger instead of Console.WriteLine
/// or Debug.Log if compiled with UNITY flag
/// </summary>
public static class NetDebug
{
public static INetLogger Logger = null;
private static readonly object DebugLogLock = new object();
private static void WriteLogic(NetLogLevel logLevel, string str, params object[] args)
{
lock (DebugLogLock)
{
if (Logger == null)
{
#if UNITY_4 || UNITY_5 || UNITY_5_3_OR_NEWER
UnityEngine.Debug.Log(string.Format(str, args));
#else
Console.WriteLine(str, args);
#endif
}
else
{
Logger.WriteNet(logLevel, str, args);
}
}
}
[Conditional("DEBUG_MESSAGES")]
internal static void Write(string str, params object[] args)
{
WriteLogic(NetLogLevel.Trace, str, args);
}
[Conditional("DEBUG_MESSAGES")]
internal static void Write(NetLogLevel level, string str, params object[] args)
{
WriteLogic(level, str, args);
}
[Conditional("DEBUG_MESSAGES"), Conditional("DEBUG")]
internal static void WriteForce(string str, params object[] args)
{
WriteLogic(NetLogLevel.Trace, str, args);
}
[Conditional("DEBUG_MESSAGES"), Conditional("DEBUG")]
internal static void WriteForce(NetLogLevel level, string str, params object[] args)
{
WriteLogic(level, str, args);
}
internal static void WriteError(string str, params object[] args)
{
WriteLogic(NetLogLevel.Error, str, args);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 78dc00ceb66ac4fdfa8c3957763522ba
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a0197124da84847d8855d5f690b8c653
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,270 @@
using System;
using System.Net;
using FlyingWormConsole3.LiteNetLib.Utils;
namespace FlyingWormConsole3.LiteNetLib
{
internal enum PacketProperty : byte
{
Unreliable,
Channeled,
Ack,
Ping,
Pong,
ConnectRequest,
ConnectAccept,
Disconnect,
UnconnectedMessage,
MtuCheck,
MtuOk,
Broadcast,
Merged,
ShutdownOk,
PeerNotFound,
InvalidProtocol,
NatMessage,
Empty
}
internal sealed class NetPacket
{
private static readonly int LastProperty = Enum.GetValues(typeof(PacketProperty)).Length;
private static readonly int[] HeaderSizes;
static NetPacket()
{
HeaderSizes = new int[LastProperty+1];
for (int i = 0; i < HeaderSizes.Length; i++)
{
switch ((PacketProperty)i)
{
case PacketProperty.Channeled:
case PacketProperty.Ack:
HeaderSizes[i] = NetConstants.ChanneledHeaderSize;
break;
case PacketProperty.Ping:
HeaderSizes[i] = NetConstants.HeaderSize + 2;
break;
case PacketProperty.ConnectRequest:
HeaderSizes[i] = NetConnectRequestPacket.HeaderSize;
break;
case PacketProperty.ConnectAccept:
HeaderSizes[i] = NetConnectAcceptPacket.Size;
break;
case PacketProperty.Disconnect:
HeaderSizes[i] = NetConstants.HeaderSize + 8;
break;
case PacketProperty.Pong:
HeaderSizes[i] = NetConstants.HeaderSize + 10;
break;
default:
HeaderSizes[i] = NetConstants.HeaderSize;
break;
}
}
}
//Header
public PacketProperty Property
{
get { return (PacketProperty)(RawData[0] & 0x1F); }
set { RawData[0] = (byte)((RawData[0] & 0xE0) | (byte)value); }
}
public byte ConnectionNumber
{
get { return (byte)((RawData[0] & 0x60) >> 5); }
set { RawData[0] = (byte) ((RawData[0] & 0x9F) | (value << 5)); }
}
public ushort Sequence
{
get { return BitConverter.ToUInt16(RawData, 1); }
set { FastBitConverter.GetBytes(RawData, 1, value); }
}
public bool IsFragmented
{
get { return (RawData[0] & 0x80) != 0; }
}
public void MarkFragmented()
{
RawData[0] |= 0x80; //set first bit
}
public byte ChannelId
{
get { return RawData[3]; }
set { RawData[3] = value; }
}
public ushort FragmentId
{
get { return BitConverter.ToUInt16(RawData, 4); }
set { FastBitConverter.GetBytes(RawData, 4, value); }
}
public ushort FragmentPart
{
get { return BitConverter.ToUInt16(RawData, 6); }
set { FastBitConverter.GetBytes(RawData, 6, value); }
}
public ushort FragmentsTotal
{
get { return BitConverter.ToUInt16(RawData, 8); }
set { FastBitConverter.GetBytes(RawData, 8, value); }
}
//Data
public byte[] RawData;
public int Size;
//Delivery
public object UserData;
//Pool node
public NetPacket Next;
#if DEBUG_REFCOUNT
public int RefCount = 1;
#endif
public NetPacket(int size)
{
RawData = new byte[size];
Size = size;
}
public NetPacket(PacketProperty property, int size)
{
size += GetHeaderSize(property);
RawData = new byte[size];
Property = property;
Size = size;
}
public static int GetHeaderSize(PacketProperty property)
{
return HeaderSizes[(int)property];
}
public int GetHeaderSize()
{
return HeaderSizes[RawData[0] & 0x1F];
}
public bool Verify()
{
byte property = (byte)(RawData[0] & 0x1F);
if (property > LastProperty)
return false;
int headerSize = HeaderSizes[property];
bool fragmented = (RawData[0] & 0x80) != 0;
return Size >= headerSize && (!fragmented || Size >= headerSize + NetConstants.FragmentHeaderSize);
}
}
internal sealed class NetConnectRequestPacket
{
public const int HeaderSize = 14;
public readonly long ConnectionTime;
public readonly byte ConnectionNumber;
public readonly byte[] TargetAddress;
public readonly NetDataReader Data;
private NetConnectRequestPacket(long connectionTime, byte connectionNumber, byte[] targetAddress, NetDataReader data)
{
ConnectionTime = connectionTime;
ConnectionNumber = connectionNumber;
TargetAddress = targetAddress;
Data = data;
}
public static int GetProtocolId(NetPacket packet)
{
return BitConverter.ToInt32(packet.RawData, 1);
}
public static NetConnectRequestPacket FromData(NetPacket packet)
{
if (packet.ConnectionNumber >= NetConstants.MaxConnectionNumber)
return null;
//Getting new id for peer
long connectionId = BitConverter.ToInt64(packet.RawData, 5);
//Get target address
int addrSize = packet.RawData[13];
if (addrSize != 16 && addrSize != 28)
return null;
byte[] addressBytes = new byte[addrSize];
Buffer.BlockCopy(packet.RawData, 14, addressBytes, 0, addrSize);
// Read data and create request
var reader = new NetDataReader(null, 0, 0);
if (packet.Size > HeaderSize+addrSize)
reader.SetSource(packet.RawData, HeaderSize + addrSize, packet.Size);
return new NetConnectRequestPacket(connectionId, packet.ConnectionNumber, addressBytes, reader);
}
public static NetPacket Make(NetDataWriter connectData, SocketAddress addressBytes, long connectId)
{
//Make initial packet
var packet = new NetPacket(PacketProperty.ConnectRequest, connectData.Length+addressBytes.Size);
//Add data
FastBitConverter.GetBytes(packet.RawData, 1, NetConstants.ProtocolId);
FastBitConverter.GetBytes(packet.RawData, 5, connectId);
packet.RawData[13] = (byte)addressBytes.Size;
for (int i = 0; i < addressBytes.Size; i++)
packet.RawData[14+i] = addressBytes[i];
Buffer.BlockCopy(connectData.Data, 0, packet.RawData, 14+addressBytes.Size, connectData.Length);
return packet;
}
}
internal sealed class NetConnectAcceptPacket
{
public const int Size = 11;
public readonly long ConnectionId;
public readonly byte ConnectionNumber;
public readonly bool IsReusedPeer;
private NetConnectAcceptPacket(long connectionId, byte connectionNumber, bool isReusedPeer)
{
ConnectionId = connectionId;
ConnectionNumber = connectionNumber;
IsReusedPeer = isReusedPeer;
}
public static NetConnectAcceptPacket FromData(NetPacket packet)
{
if (packet.Size > Size)
return null;
long connectionId = BitConverter.ToInt64(packet.RawData, 1);
//check connect num
byte connectionNumber = packet.RawData[9];
if (connectionNumber >= NetConstants.MaxConnectionNumber)
return null;
//check reused flag
byte isReused = packet.RawData[10];
if (isReused > 1)
return null;
return new NetConnectAcceptPacket(connectionId, connectionNumber, isReused == 1);
}
public static NetPacket Make(long connectId, byte connectNum, bool reusedPeer)
{
var packet = new NetPacket(PacketProperty.ConnectAccept, 0);
FastBitConverter.GetBytes(packet.RawData, 1, connectId);
packet.RawData[9] = connectNum;
packet.RawData[10] = (byte)(reusedPeer ? 1 : 0);
return packet;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7aa9ed55f53fa48569ccd0963c50d8da
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,76 @@
using System;
using System.Threading;
namespace FlyingWormConsole3.LiteNetLib
{
internal sealed class NetPacketPool
{
private NetPacket _head;
private int _count;
private readonly object _lock = new object();
public NetPacket GetWithData(PacketProperty property, byte[] data, int start, int length)
{
int headerSize = NetPacket.GetHeaderSize(property);
NetPacket packet = GetPacket(length + headerSize);
packet.Property = property;
Buffer.BlockCopy(data, start, packet.RawData, headerSize, length);
return packet;
}
//Get packet with size
public NetPacket GetWithProperty(PacketProperty property, int size)
{
NetPacket packet = GetPacket(size + NetPacket.GetHeaderSize(property));
packet.Property = property;
return packet;
}
public NetPacket GetWithProperty(PacketProperty property)
{
NetPacket packet = GetPacket(NetPacket.GetHeaderSize(property));
packet.Property = property;
return packet;
}
public NetPacket GetPacket(int size)
{
if (size > NetConstants.MaxPacketSize)
return new NetPacket(size);
NetPacket packet;
lock (_lock)
{
packet = _head;
if (packet == null)
return new NetPacket(size);
_head = _head.Next;
}
Interlocked.Decrement(ref _count);
packet.Size = size;
if (packet.RawData.Length < size)
packet.RawData = new byte[size];
return packet;
}
public void Recycle(NetPacket packet)
{
if (packet.RawData.Length > NetConstants.MaxPacketSize || _count >= NetConstants.PacketPoolSize)
{
//Don't pool big packets. Save memory
return;
}
Interlocked.Increment(ref _count);
//Clean fragmented flag
packet.RawData[0] = 0;
lock (_lock)
{
packet.Next = _head;
_head = packet;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3637381933a4745b996d4dd48cd71efe
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 39ca2e83856ea4ba0a0100a00089e695
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,543 @@
#if UNITY_5_3_OR_NEWER
#define UNITY
#if UNITY_IOS && !UNITY_EDITOR
using UnityEngine;
#endif
#endif
#if NETSTANDARD || NETCOREAPP
using System.Runtime.InteropServices;
#endif
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace FlyingWormConsole3.LiteNetLib
{
#if UNITY_IOS && !UNITY_EDITOR
public class UnitySocketFix : MonoBehaviour
{
internal IPAddress BindAddrIPv4;
internal IPAddress BindAddrIPv6;
internal bool Reuse;
internal IPv6Mode IPv6;
internal int Port;
internal bool Paused;
internal NetSocket Socket;
internal bool ManualMode;
private void Update()
{
if (Socket == null)
Destroy(gameObject);
}
private void OnApplicationPause(bool pause)
{
if (Socket == null)
return;
if (pause)
{
Paused = true;
Socket.Close(true);
}
else if (Paused)
{
if (!Socket.Bind(BindAddrIPv4, BindAddrIPv6, Port, Reuse, IPv6, ManualMode))
{
NetDebug.WriteError("[S] Cannot restore connection \"{0}\",\"{1}\" port {2}", BindAddrIPv4, BindAddrIPv6, Port);
Socket.OnErrorRestore();
}
}
}
}
#endif
internal sealed class NetSocket
{
public const int ReceivePollingTime = 500000; //0.5 second
private Socket _udpSocketv4;
private Socket _udpSocketv6;
private Thread _threadv4;
private Thread _threadv6;
private IPEndPoint _bufferEndPointv4;
private IPEndPoint _bufferEndPointv6;
private readonly NetManager _listener;
private const int SioUdpConnreset = -1744830452; //SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12
private static readonly IPAddress MulticastAddressV6 = IPAddress.Parse("ff02::1");
internal static readonly bool IPv6Support;
#if UNITY_IOS && !UNITY_EDITOR
private UnitySocketFix _unitySocketFix;
public void OnErrorRestore()
{
Close(false);
_listener.OnMessageReceived(null, SocketError.NotConnected, new IPEndPoint(0,0));
}
#endif
public int LocalPort { get; private set; }
public volatile bool IsRunning;
public short Ttl
{
get
{
#if UNITY_SWITCH
return 0;
#else
if (_udpSocketv4.AddressFamily == AddressFamily.InterNetworkV6)
return (short)_udpSocketv4.GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.HopLimit);
return _udpSocketv4.Ttl;
#endif
}
set
{
#if !UNITY_SWITCH
if (_udpSocketv4.AddressFamily == AddressFamily.InterNetworkV6)
_udpSocketv4.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.HopLimit, value);
else
_udpSocketv4.Ttl = value;
#endif
}
}
static NetSocket()
{
#if DISABLE_IPV6 || (!UNITY_EDITOR && ENABLE_IL2CPP && !UNITY_2018_3_OR_NEWER)
IPv6Support = false;
#elif !UNITY_2019_1_OR_NEWER && !UNITY_2018_4_OR_NEWER && (!UNITY_EDITOR && ENABLE_IL2CPP && UNITY_2018_3_OR_NEWER)
string version = UnityEngine.Application.unityVersion;
IPv6Support = Socket.OSSupportsIPv6 && int.Parse(version.Remove(version.IndexOf('f')).Split('.')[2]) >= 6;
#elif UNITY_2018_2_OR_NEWER
IPv6Support = Socket.OSSupportsIPv6;
#elif UNITY
#pragma warning disable 618
IPv6Support = Socket.SupportsIPv6;
#pragma warning restore 618
#else
IPv6Support = Socket.OSSupportsIPv6;
#endif
}
public NetSocket(NetManager listener)
{
_listener = listener;
}
private bool IsActive()
{
#if UNITY_IOS && !UNITY_EDITOR
var unitySocketFix = _unitySocketFix; //save for multithread
if (unitySocketFix != null && unitySocketFix.Paused)
return false;
#endif
return IsRunning;
}
private bool ProcessError(SocketException ex, EndPoint bufferEndPoint)
{
switch (ex.SocketErrorCode)
{
#if UNITY_IOS && !UNITY_EDITOR
case SocketError.NotConnected:
#endif
case SocketError.Interrupted:
case SocketError.NotSocket:
return true;
case SocketError.ConnectionReset:
case SocketError.MessageSize:
case SocketError.TimedOut:
NetDebug.Write(NetLogLevel.Trace, "[R]Ignored error: {0} - {1}",
(int)ex.SocketErrorCode, ex.ToString());
break;
default:
NetDebug.WriteError("[R]Error code: {0} - {1}", (int)ex.SocketErrorCode,
ex.ToString());
_listener.OnMessageReceived(null, ex.SocketErrorCode, (IPEndPoint)bufferEndPoint);
break;
}
return false;
}
public void ManualReceive()
{
ManualReceive(_udpSocketv4, _bufferEndPointv4);
if (_udpSocketv6 != null && _udpSocketv6 != _udpSocketv4)
ManualReceive(_udpSocketv6, _bufferEndPointv6);
}
private bool ManualReceive(Socket socket, EndPoint bufferEndPoint)
{
//Reading data
try
{
int available = socket.Available;
if (available == 0)
return false;
while (available > 0)
{
var packet = _listener.NetPacketPool.GetPacket(NetConstants.MaxPacketSize);
packet.Size = socket.ReceiveFrom(packet.RawData, 0, NetConstants.MaxPacketSize, SocketFlags.None,
ref bufferEndPoint);
NetDebug.Write(NetLogLevel.Trace, "[R]Received data from {0}, result: {1}", bufferEndPoint.ToString(), packet.Size);
_listener.OnMessageReceived(packet, 0, (IPEndPoint)bufferEndPoint);
available -= packet.Size;
}
}
catch (SocketException ex)
{
return ProcessError(ex, bufferEndPoint);
}
catch (ObjectDisposedException)
{
return true;
}
return false;
}
private void ReceiveLogic(object state)
{
Socket socket = (Socket)state;
EndPoint bufferEndPoint = new IPEndPoint(socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0);
while (IsActive())
{
NetPacket packet;
//Reading data
try
{
if (socket.Available == 0 && !socket.Poll(ReceivePollingTime, SelectMode.SelectRead))
continue;
packet = _listener.NetPacketPool.GetPacket(NetConstants.MaxPacketSize);
packet.Size = socket.ReceiveFrom(packet.RawData, 0, NetConstants.MaxPacketSize, SocketFlags.None,
ref bufferEndPoint);
}
catch (SocketException ex)
{
if (ProcessError(ex, bufferEndPoint))
return;
continue;
}
catch (ObjectDisposedException)
{
return;
}
//All ok!
NetDebug.Write(NetLogLevel.Trace, "[R]Received data from {0}, result: {1}", bufferEndPoint.ToString(), packet.Size);
_listener.OnMessageReceived(packet, 0, (IPEndPoint)bufferEndPoint);
}
}
public bool Bind(IPAddress addressIPv4, IPAddress addressIPv6, int port, bool reuseAddress, IPv6Mode ipv6Mode, bool manualMode)
{
if (IsActive())
return false;
bool dualMode = ipv6Mode == IPv6Mode.DualMode && IPv6Support;
_udpSocketv4 = new Socket(
dualMode ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork,
SocketType.Dgram,
ProtocolType.Udp);
if (!BindSocket(_udpSocketv4, new IPEndPoint(dualMode ? addressIPv6 : addressIPv4, port), reuseAddress, ipv6Mode))
return false;
LocalPort = ((IPEndPoint) _udpSocketv4.LocalEndPoint).Port;
#if UNITY_IOS && !UNITY_EDITOR
if (_unitySocketFix == null)
{
var unityFixObj = new GameObject("LiteNetLib_UnitySocketFix");
GameObject.DontDestroyOnLoad(unityFixObj);
_unitySocketFix = unityFixObj.AddComponent<UnitySocketFix>();
_unitySocketFix.Socket = this;
_unitySocketFix.BindAddrIPv4 = addressIPv4;
_unitySocketFix.BindAddrIPv6 = addressIPv6;
_unitySocketFix.Reuse = reuseAddress;
_unitySocketFix.Port = LocalPort;
_unitySocketFix.IPv6 = ipv6Mode;
_unitySocketFix.ManualMode = manualMode;
}
else
{
_unitySocketFix.Paused = false;
}
#endif
if (dualMode)
_udpSocketv6 = _udpSocketv4;
IsRunning = true;
if (!manualMode)
{
_threadv4 = new Thread(ReceiveLogic)
{
Name = "SocketThreadv4(" + LocalPort + ")",
IsBackground = true
};
_threadv4.Start(_udpSocketv4);
}
else
{
_bufferEndPointv4 = new IPEndPoint(IPAddress.Any, 0);
}
//Check IPv6 support
if (!IPv6Support || ipv6Mode != IPv6Mode.SeparateSocket)
return true;
_udpSocketv6 = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);
//Use one port for two sockets
if (BindSocket(_udpSocketv6, new IPEndPoint(addressIPv6, LocalPort), reuseAddress, ipv6Mode))
{
if (manualMode)
{
_bufferEndPointv6 = new IPEndPoint(IPAddress.IPv6Any, 0);
}
else
{
_threadv6 = new Thread(ReceiveLogic)
{
Name = "SocketThreadv6(" + LocalPort + ")",
IsBackground = true
};
_threadv6.Start(_udpSocketv6);
}
}
return true;
}
private bool BindSocket(Socket socket, IPEndPoint ep, bool reuseAddress, IPv6Mode ipv6Mode)
{
//Setup socket
socket.ReceiveTimeout = 500;
socket.SendTimeout = 500;
socket.ReceiveBufferSize = NetConstants.SocketBufferSize;
socket.SendBufferSize = NetConstants.SocketBufferSize;
#if !UNITY || UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
#if NETSTANDARD || NETCOREAPP
if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
#endif
try
{
socket.IOControl(SioUdpConnreset, new byte[] { 0 }, null);
}
catch
{
//ignored
}
#endif
try
{
socket.ExclusiveAddressUse = !reuseAddress;
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, reuseAddress);
}
catch
{
//Unity with IL2CPP throws an exception here, it doesn't matter in most cases so just ignore it
}
if (socket.AddressFamily == AddressFamily.InterNetwork)
{
Ttl = NetConstants.SocketTTL;
#if NETSTANDARD || NETCOREAPP
if(!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
#endif
try { socket.DontFragment = true; }
catch (SocketException e)
{
NetDebug.WriteError("[B]DontFragment error: {0}", e.SocketErrorCode);
}
try { socket.EnableBroadcast = true; }
catch (SocketException e)
{
NetDebug.WriteError("[B]Broadcast error: {0}", e.SocketErrorCode);
}
}
else //IPv6 specific
{
if (ipv6Mode == IPv6Mode.DualMode)
{
try
{
//Disable IPv6 only mode
socket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, false);
}
catch(Exception e)
{
NetDebug.WriteError("[B]Bind exception (dualmode setting): {0}", e.ToString());
}
}
}
//Bind
try
{
socket.Bind(ep);
NetDebug.Write(NetLogLevel.Trace, "[B]Successfully binded to port: {0}", ((IPEndPoint)socket.LocalEndPoint).Port);
//join multicast
if (socket.AddressFamily == AddressFamily.InterNetworkV6)
{
try
{
#if !UNITY
socket.SetSocketOption(
SocketOptionLevel.IPv6,
SocketOptionName.AddMembership,
new IPv6MulticastOption(MulticastAddressV6));
#endif
}
catch (Exception)
{
// Unity3d throws exception - ignored
}
}
}
catch (SocketException bindException)
{
switch (bindException.SocketErrorCode)
{
//IPv6 bind fix
case SocketError.AddressAlreadyInUse:
if (socket.AddressFamily == AddressFamily.InterNetworkV6 && ipv6Mode != IPv6Mode.DualMode)
{
try
{
//Set IPv6Only
socket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, true);
socket.Bind(ep);
}
#if UNITY_2018_3_OR_NEWER
catch (SocketException ex)
{
//because its fixed in 2018_3
NetDebug.WriteError("[B]Bind exception: {0}, errorCode: {1}", ex.ToString(), ex.SocketErrorCode);
#else
catch(SocketException)
{
#endif
return false;
}
return true;
}
break;
//hack for iOS (Unity3D)
case SocketError.AddressFamilyNotSupported:
return true;
}
NetDebug.WriteError("[B]Bind exception: {0}, errorCode: {1}", bindException.ToString(), bindException.SocketErrorCode);
return false;
}
return true;
}
public bool SendBroadcast(byte[] data, int offset, int size, int port)
{
if (!IsActive())
return false;
bool broadcastSuccess = false;
bool multicastSuccess = false;
try
{
broadcastSuccess = _udpSocketv4.SendTo(
data,
offset,
size,
SocketFlags.None,
new IPEndPoint(IPAddress.Broadcast, port)) > 0;
if (_udpSocketv6 != null)
{
multicastSuccess = _udpSocketv6.SendTo(
data,
offset,
size,
SocketFlags.None,
new IPEndPoint(MulticastAddressV6, port)) > 0;
}
}
catch (Exception ex)
{
NetDebug.WriteError("[S][MCAST]" + ex);
return broadcastSuccess;
}
return broadcastSuccess || multicastSuccess;
}
public int SendTo(byte[] data, int offset, int size, IPEndPoint remoteEndPoint, ref SocketError errorCode)
{
if (!IsActive())
return 0;
try
{
var socket = _udpSocketv4;
if (remoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6 && IPv6Support)
socket = _udpSocketv6;
int result = socket.SendTo(data, offset, size, SocketFlags.None, remoteEndPoint);
NetDebug.Write(NetLogLevel.Trace, "[S]Send packet to {0}, result: {1}", remoteEndPoint, result);
return result;
}
catch (SocketException ex)
{
switch (ex.SocketErrorCode)
{
case SocketError.NoBufferSpaceAvailable:
case SocketError.Interrupted:
return 0;
case SocketError.MessageSize: //do nothing
break;
default:
NetDebug.WriteError("[S]" + ex);
break;
}
errorCode = ex.SocketErrorCode;
return -1;
}
catch (Exception ex)
{
NetDebug.WriteError("[S]" + ex);
return -1;
}
}
public void Close(bool suspend)
{
if (!suspend)
{
IsRunning = false;
#if UNITY_IOS && !UNITY_EDITOR
_unitySocketFix.Socket = null;
_unitySocketFix = null;
#endif
}
//cleanup dual mode
if (_udpSocketv4 == _udpSocketv6)
_udpSocketv6 = null;
if (_udpSocketv4 != null)
_udpSocketv4.Close();
if (_udpSocketv6 != null)
_udpSocketv6.Close();
_udpSocketv4 = null;
_udpSocketv6 = null;
if (_threadv4 != null && _threadv4 != Thread.CurrentThread)
_threadv4.Join();
if (_threadv6 != null && _threadv6 != Thread.CurrentThread)
_threadv6.Join();
_threadv4 = null;
_threadv6 = null;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c517b909a8c704eae91d4eccf06bc8a1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show More