Upload from upload_mods.ps1

This commit is contained in:
Nathaniel Cosford
2025-06-04 16:13:19 +09:30
commit 5b2208fd14
25 changed files with 1947 additions and 0 deletions

View File

@@ -0,0 +1,294 @@
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
public static class CustomExplosionManager
{
private static Dictionary<int, string> hash_paths = new Dictionary<int, string>();
private static Dictionary<string, ExplosionComponent> hash_components = new Dictionary<string, ExplosionComponent>();
private static Dictionary<string, GameObject> hash_assets = new Dictionary<string, GameObject>();
private static HashSet<GameObject> hash_initialized = new HashSet<GameObject>();
private static List<IExplosionPropertyParser> list_parsers = new List<IExplosionPropertyParser>();
private static Stack<ExplosionValue> last_init_components = new Stack<ExplosionValue>();
public static event Action<PooledBinaryWriter> ClientConnected;
public static event Action<ClientInfo> HandleClientInfo;
public static event Action CleanUp;
public static ExplosionValue LastInitializedComponent
{
get => last_init_components.Count > 0 ? last_init_components.Peek() : null;
}
public static uint NextExplosionIndex { get; set; } = 0;
internal static void OnCleanUp()
{
Log.Out("Custom Explosion Manager cleanup...");
destroyAllParticles();
NextExplosionIndex = 0;
CleanUp?.Invoke();
}
internal static void OnClientConnected(ClientInfo client)
{
var handler = ClientConnected;
if (handler != null)
{
uint count = (uint)ClientConnected.GetInvocationList().Length;
MemoryStream memoryStream = new MemoryStream();
using (PooledBinaryWriter _bw = MemoryPools.poolBinaryWriter.AllocSync(false))
{
_bw.SetBaseStream(memoryStream);
_bw.Write(count);
handler(_bw);
if (HandleClientInfo != null)
HandleClientInfo(client);
}
byte[] data = memoryStream.ToArray();
client.SendPackage(NetPackageManager.GetPackage<NetPackageExplosionSyncOnConnect>().Setup(data));
}
}
internal static void CreatePropertyParsers()
{
var assemblies = ModManager.GetLoadedAssemblies();
string iname = nameof(IExplosionPropertyParser);
foreach (var assembly in assemblies)
{
var types = assembly.GetTypes();
foreach (var type in types)
{
if (type.GetInterface(iname) != null)
{
var parser = Activator.CreateInstance(type) as IExplosionPropertyParser;
list_parsers.Add(parser);
Log.Out("Found custom explosion property parser: " + type.Name);
}
}
}
}
internal static GameObject InitializeParticle(ExplosionComponent component, Vector3 position, Quaternion rotation)
{
GameObject __result = UnityEngine.Object.Instantiate<GameObject>(component.Particle, position, rotation);
__result.AddComponent<NetSyncHelper>();
if (component.TemporaryObjectType != null)
__result.AddComponent(component.TemporaryObjectType);
if (component.ExplosionDamageAreaType != null)
__result.AddComponent(component.ExplosionDamageAreaType);
if (component.AudioPlayerType != null)
{
AudioPlayer audio_script = __result.AddComponent(component.AudioPlayerType) as AudioPlayer;
if (component.SoundName != null)
audio_script.soundName = component.SoundName;
if (component.AudioDuration >= 0)
audio_script.duration = component.AudioDuration;
}
if (component.List_CustomTypes.Count > 0)
foreach (Type customtype in component.List_CustomTypes)
if (customtype != null)
__result.AddComponent(customtype);
AutoRemove remove_script = __result.AddComponent<AutoRemove>();
CustomExplosionManager.addInitializedParticle(__result);
return __result;
}
internal static void PushLastInitComponent(ExplosionValue component)
{
last_init_components.Push(component);
}
internal static void PopLastInitComponent()
{
if (last_init_components.Count > 0)
last_init_components.Pop();
}
private static bool LoadParticleEffect(string fullpath, ExplosionData data, out ExplosionComponent component, string sound_name = null, float duration_audio = -1, List<Type> CustomScriptList = null)
{
component = null;
fullpath = fullpath.Trim();
if (!parsePathString(fullpath, out string path, out string assetname))
return false;
//check if asset is loaded
string path_asset = path + "?" + assetname;
bool flag = hash_assets.TryGetValue(path_asset, out GameObject obj);
if (!flag)
{
//load asset
string path_bundle = ModManager.PatchModPathString(path).TrimStart('#');
Log.Out("Bundle path: " + path_bundle);
AssetBundleManager.Instance.LoadAssetBundle(path_bundle);
obj = AssetBundleManager.Instance.Get<GameObject>(path_bundle, assetname);
if (obj == null)
Log.Error("Failed to load asset " + assetname);
else
hash_assets.Add(path_asset, obj);
}
if (obj == null)
{
Log.Error("Particle not loaded:" + path_asset);
return false;
}
//pair particle with scripts
if (hash_components.Remove(fullpath))
Log.Out("Particle data already exists:" + fullpath + ", now overwriting");
component = new ExplosionComponent(obj, sound_name, duration_audio, data, CustomScriptList);
hash_components.Add(fullpath, component);
return true;
}
//this should get a unique index for each particle
public static int getHashCode(string str)
{
int value = (PlatformIndependentHash.StringToUInt16(str));
while (hash_paths.TryGetValue(value, out string path))
{
if (path == str)
break;
if (value > Int16.MaxValue || (value >= 0 && value < WorldStaticData.prefabExplosions.Length))
value = WorldStaticData.prefabExplosions.Length;
else
value++;
}
return value;
}
private static bool parsePathString(string fullpath, out string path, out string assetname)
{
//get path to asset
path = null;
assetname = null;
if (fullpath == null)
{
Log.Error("Null fullpath parameter:" + fullpath);
return false;
}
int index_path = fullpath.IndexOf('?');
if (index_path <= 0)
{
Log.Error("Particle path does not specify the asset name! fullpath:" + fullpath);
return false;
}
path = fullpath.Substring(0, index_path);
int index_postfix = fullpath.IndexOf('$');
if (index_postfix <= 0)
assetname = fullpath.Substring(index_path + 1);
else
assetname = fullpath.Substring(index_path + 1, index_postfix - index_path - 1);
return true;
}
private static void getTypeListFromString(string str, out List<Type> list_types)
{
list_types = new List<Type>();
if (str == null || str == string.Empty)
return;
string[] array = str.Split(new char[] { '$' });
foreach (string typename in array)
{
if (typename != null)
{
Type type = Type.GetType(typename.Trim());
if (type != null)
{
if (!list_types.Contains(type))
list_types.Add(type);
else
Log.Out("duplicated script type detected: " + type.AssemblyQualifiedName);
}
else
Log.Warning("CustomScriptType not found:" + typename);
}
}
}
public static bool parseParticleData(DynamicProperties _props, out ExplosionComponent component)
{
string str_index = null;
component = null;
_props.ParseString("Explosion.ParticleIndex", ref str_index);
if (str_index != null && str_index.StartsWith("#"))
{
Log.Out("Original path:" + str_index);
int hashed_index = getHashCode(str_index);
_props.Values["Explosion.ParticleIndex"] = hashed_index.ToString();
Log.Out("Hashed index:" + _props.Values["Explosion.ParticleIndex"]);
if (!hash_paths.ContainsKey(hashed_index))
hash_paths.Add(hashed_index, str_index);
bool overwrite = false;
_props.ParseBool("Explosion.Overwrite", ref overwrite);
if (overwrite || !GetCustomParticleComponents(hashed_index, out _))
{
string sound_name = null;
_props.ParseString("Explosion.AudioName", ref sound_name);
float duration_audio = -1;
_props.ParseFloat("Explosion.AudioDuration", ref duration_audio);
bool sync = false;
_props.ParseBool("Explosion.SyncOnConnect", ref sync);
bool observe = false;
_props.ParseBool("Explosion.IsChunkObserver", ref observe);
getTypeListFromString(_props.Values["Explosion.CustomScriptTypes"], out List<Type> list_customtypes);
bool flag = LoadParticleEffect(str_index, new ExplosionData(_props), out component, sound_name, duration_audio, list_customtypes);
if (flag && component != null)
{
component.SyncOnConnect = sync;
foreach (var parser in list_parsers)
if (list_customtypes.Contains(parser.MatchScriptType()) && parser.ParseProperty(_props, out var property))
component.AddCustomProperty(parser.Name(), property);
}
return flag;
}
}
return false;
}
internal static void addInitializedParticle(GameObject obj)
{
hash_initialized.Add(obj);
//Log.Out("Particle initialized:" + obj.name);
}
internal static void removeInitializedParticle(GameObject obj)
{
hash_initialized.Remove(obj);
//Log.Out("Particle removed on destroy:" + obj.name);
}
internal static void destroyAllParticles()
{
foreach (GameObject obj in hash_initialized)
{
Log.Out("Active particle destroyed on disconnect:" + obj.name);
GameObject.Destroy(obj);
}
hash_initialized.Clear();
/*
foreach (var pair in hash_assets)
{
Log.Out("Loaded particle destroyed on disconnect:" + pair.Value.name);
GameObject.Destroy(pair.Value);
}
hash_assets.Clear();
hash_components.Clear();
Log.Out("Loaded particle data cleared on disconnect.");
*/
last_init_components.Clear();
}
public static bool GetCustomParticleComponents(int index, out ExplosionComponent component)
{
component = null;
if (!hash_paths.TryGetValue(index, out string fullpath) || fullpath == null)
return false;
return hash_components.TryGetValue(fullpath, out component);
}
}

View File

@@ -0,0 +1,143 @@
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
public struct ExplosionParams
{
public ExplosionParams(int _clrIdx, Vector3 _worldPos, Vector3i _blockPos, Quaternion _rotation, ExplosionData _explosionData, int _playerId, uint _explId)
{
this._clrIdx = _clrIdx;
this._worldPos = _worldPos;
this._blockPos = _blockPos;
this._rotation = _rotation;
this._explosionData = _explosionData;
this._playerId = _playerId;
this._explId = _explId;
}
public ExplosionParams(byte[] _explosionParamsAsArr)
{
_clrIdx = 0;
_worldPos = Vector3.zero;
_blockPos = Vector3i.zero;
_rotation = Quaternion.identity;
_explosionData = default(ExplosionData);
_playerId = -1;
_explId = uint.MaxValue;
using (PooledBinaryReader pooledBinaryReader = MemoryPools.poolBinaryReader.AllocSync(false))
{
pooledBinaryReader.SetBaseStream(new MemoryStream(_explosionParamsAsArr));
read(pooledBinaryReader);
}
}
public void read(PooledBinaryReader _br)
{
_clrIdx = (int)_br.ReadUInt16();
_worldPos = StreamUtils.ReadVector3(_br);
_blockPos = StreamUtils.ReadVector3i(_br);
_rotation = StreamUtils.ReadQuaterion(_br);
_explosionData.Read(_br);
_playerId = _br.ReadInt32();
_explId = _br.ReadUInt32();
}
public void write(PooledBinaryWriter _bw)
{
_bw.Write((ushort)_clrIdx);
StreamUtils.Write(_bw, _worldPos);
StreamUtils.Write(_bw, _blockPos);
StreamUtils.Write(_bw, _rotation);
_explosionData.Write(_bw);
_bw.Write(_playerId);
_bw.Write(_explId);
}
public byte[] ToByteArray()
{
MemoryStream memoryStream = new MemoryStream();
using (PooledBinaryWriter pooledBinaryWriter = MemoryPools.poolBinaryWriter.AllocSync(false))
{
pooledBinaryWriter.SetBaseStream(memoryStream);
write(pooledBinaryWriter);
}
return memoryStream.ToArray();
}
public int _clrIdx;
public Vector3 _worldPos;
public Vector3i _blockPos;
public Quaternion _rotation;
public ExplosionData _explosionData;
public int _playerId;
public uint _explId;
}
public class ExplosionComponent
{
public ExplosionComponent(GameObject obj, string sound_name, float duration_audio, ExplosionData data, List<Type> CustomScriptTypes)
{
this.obj = obj;
this.list_custom = new List<Type>();
foreach (Type type in CustomScriptTypes)
{
if (type == null)
continue;
if ((type.IsSubclassOf(typeof(TemporaryObject)) || type == typeof(TemporaryObject)))
this.TempObjType = type;
else if ((type.IsSubclassOf(typeof(ExplosionDamageArea)) || type == typeof(ExplosionDamageArea)))
this.ExplAreaType = type;
else if ((type.IsSubclassOf(typeof(AudioPlayer)) || type == typeof(AudioPlayer)))
this.AudioType = AudioPlayerType;
else
this.list_custom.Add(type);
}
this.sound_name = sound_name;
this.duration_audio = duration_audio;
this.hash_custom_properties = new Dictionary<string, object>();
this.data = data;
if (this.sound_name != null && this.AudioPlayerType == null)
this.AudioType = typeof(AudioPlayer);
}
private GameObject obj;
private Type TempObjType = null;
private Type ExplAreaType = null;
private Type AudioType = null;
private List<Type> list_custom;
private float duration_audio;
private string sound_name;
private ExplosionData data;
private Dictionary<string, object> hash_custom_properties;
public bool TryGetCustomProperty(string name, out object value)
{
return hash_custom_properties.TryGetValue(name, out value);
}
internal void AddCustomProperty(string name, object value)
{
if(hash_custom_properties.Remove(name))
Log.Out("Custom explosion component property already exists, overwriting: " + name);
hash_custom_properties.Add(name, value);
}
public GameObject Particle { get => obj; }
public Type TemporaryObjectType { get => TempObjType; }
public Type ExplosionDamageAreaType { get => ExplAreaType; }
public Type AudioPlayerType { get => AudioType; }
public List<Type> List_CustomTypes { get => list_custom; }
public float AudioDuration{ get => duration_audio; }
public string SoundName { get => sound_name; }
public ExplosionData BoundExplosionData { get => data; }
public ItemClass BoundItemClass { get; set; }
public bool SyncOnConnect { get; set; } = false;
}
public class ExplosionValue
{
public ExplosionComponent Component { get; set; }
public ExplosionParams CurrentExplosionParams { get; set; }
public ItemValue CurrentItemValue { get; set; }
}

View File

@@ -0,0 +1,6 @@
public interface IExplosionPropertyParser
{
bool ParseProperty(DynamicProperties _props, out object property);
System.Type MatchScriptType();
string Name();
}

View File

@@ -0,0 +1,103 @@
using System.Xml;
using System.Xml.Linq;
using UnityEngine;
public class MinEventActionRangedExplosion : MinEventActionBase
{
private ExplosionData _explosionData;
private int itemType = -1;
private ExplosionComponent _explosionComponent;
//private float delay = 0;
private bool _initialized = false;
private bool _useCustomParticle = false;
private int customParticleIndex;
private ItemValue ammoItem;
public override void Execute(MinEventParams _params)
{
bool hasEntity = _params.Self != null;
//int layer = 0;
// if (hasEntity)
// {
// layer = _params.Self.GetModelLayer();
// _params.Self.SetModelLayer(24, false);
// }
GameManager.Instance.ExplosionServer(0, _params.Position, World.worldToBlockPos(_params.Position), hasEntity ? _params.Self.qrotation : Quaternion.identity, _useCustomParticle ? _explosionComponent.BoundExplosionData : _explosionData, hasEntity ? _params.Self.entityId : -1, Delay, false, ammoItem ?? _params.ItemValue);
//if (hasEntity)
//{
// _params.Self.SetModelLayer(layer, false);
//}
}
public override bool CanExecute(MinEventTypes _eventType, MinEventParams _params)
{
if (!base.CanExecute(_eventType, _params))
return false;
if(!_initialized || !_useCustomParticle)
{
if (_useCustomParticle)
{
if (!CustomExplosionManager.GetCustomParticleComponents(customParticleIndex, out _explosionComponent))
return false;
if(_explosionComponent.BoundItemClass != null)
ammoItem = new ItemValue(_explosionComponent.BoundItemClass.Id, false);
}
else
{
if (_params.ItemValue == null)
return false;
if (_params.ItemValue.type == itemType)
return true;
ItemClass itemClass = _params.ItemValue.ItemClass;
string particleIndex = null;
itemClass.Properties.ParseString("Explosion.ParticleIndex", ref particleIndex);
if (string.IsNullOrEmpty(particleIndex))
return false;
if (int.TryParse(particleIndex, out int index))
{
_explosionData = new ExplosionData(itemClass.Properties);
itemType = itemClass.Id;
ammoItem = new ItemValue(itemType, false);
}
else if (CustomExplosionManager.GetCustomParticleComponents(CustomExplosionManager.getHashCode(particleIndex), out _explosionComponent))
{
itemType = itemClass.Id;
if(_explosionComponent.BoundItemClass != null)
ammoItem = new ItemValue(_explosionComponent.BoundItemClass.Id, false);
}
else
{
return false;
}
}
_initialized = true;
}
return true;
}
public override bool ParseXmlAttribute(XAttribute _attribute)
{
bool flag = base.ParseXmlAttribute(_attribute);
if (!flag)
{
string name = _attribute.Name.LocalName;
switch(name)
{
case "particle_index":
customParticleIndex = CustomExplosionManager.getHashCode(_attribute.Value);
_useCustomParticle = true;
flag = true;
break;
//case "delay":
// float.TryParse(_attribute.Value, out delay);
// flag = true;
// break;
}
}
return flag;
}
}

View File

@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using UnityEngine;
public class AutoRemove : TrackedBehaviourBase
{
public float lifetime = -1;
protected override void Awake()
{
ExplosionValue value = CustomExplosionManager.LastInitializedComponent;
lifetime = value.CurrentExplosionParams._explosionData.Duration;
if(lifetime > 0)
syncOnConnect = value.Component.SyncOnConnect;
base.Awake();
if (lifetime > 0)
Destroy(gameObject, lifetime);
}
private void Update()
{
if(lifetime > 0)
lifetime -= Time.deltaTime;
}
protected override void OnDestroy()
{
base.OnDestroy();
CustomExplosionManager.removeInitializedParticle(gameObject);
}
protected override void OnClientConnected(PooledBinaryWriter _bw)
{
_bw.Write(lifetime);
}
protected override void OnConnectedToServer(PooledBinaryReader _br)
{
lifetime = _br.ReadSingle();
if (lifetime > 0)
Destroy(gameObject, lifetime);
}
}

View File

@@ -0,0 +1,97 @@
using System;
using System.Collections.Generic;
using UnityEngine;
public class NetSyncHelper : MonoBehaviour
{
public event Action<PooledBinaryWriter> ClientConnected
{
add { list_connect_server_handlers.Add(value); }
remove { list_connect_server_handlers.Remove(value); }
}
public event Action<PooledBinaryReader> ConnectedToServer
{
add { list_connect_client_handlers.Add(value); }
remove { list_connect_client_handlers.Remove(value); }
}
public event Action<PooledBinaryWriter> ExplosionServerInit
{
add { list_init_server_handlers.Add(value); }
remove { list_init_server_handlers.Remove(value); }
}
public event Action<PooledBinaryReader> ExplosionClientInit
{
add { list_init_client_handlers.Add(value); }
remove { list_init_client_handlers.Remove(value); }
}
private List<Action<PooledBinaryWriter>> list_connect_server_handlers = new List<Action<PooledBinaryWriter>>();
private List<Action<PooledBinaryReader>> list_connect_client_handlers = new List<Action<PooledBinaryReader>>();
private List<Action<PooledBinaryWriter>> list_init_server_handlers = new List<Action<PooledBinaryWriter>>();
private List<Action<PooledBinaryReader>> list_init_client_handlers = new List<Action<PooledBinaryReader>>();
public ExplosionParams explParams;
public ItemValue explValue;
public uint explId;
private static Dictionary<uint, NetSyncHelper> hash_helpers = new Dictionary<uint, NetSyncHelper>();
static NetSyncHelper()
{
CustomExplosionManager.CleanUp += hash_helpers.Clear;
}
void Awake()
{
hash_helpers.Add((explId = CustomExplosionManager.LastInitializedComponent.CurrentExplosionParams._explId), this);
if (SingletonMonoBehaviour<ConnectionManager>.Instance.IsServer && CustomExplosionManager.LastInitializedComponent.Component.SyncOnConnect)
{
explParams = CustomExplosionManager.LastInitializedComponent.CurrentExplosionParams;
explValue = CustomExplosionManager.LastInitializedComponent.CurrentItemValue?.Clone();
CustomExplosionManager.ClientConnected += OnClientConnected;
}
}
public static bool TryGetValue(uint id, out NetSyncHelper helper)
{
return hash_helpers.TryGetValue(id, out helper);
}
void OnDestroy()
{
CustomExplosionManager.ClientConnected -= OnClientConnected;
hash_helpers.Remove(explId);
}
void OnClientConnected(PooledBinaryWriter _bw)
{
explParams._worldPos = transform.position + Origin.position;
explParams._rotation = transform.rotation;
byte[] array = explParams.ToByteArray();
_bw.Write((ushort)array.Length);
_bw.Write(array);
_bw.Write(explValue != null);
if (explValue != null)
{
explValue.Write(_bw);
}
foreach (var handler in list_connect_server_handlers)
handler(_bw);
}
public void OnConnectedToServer(PooledBinaryReader _br)
{
foreach (var handler in list_connect_client_handlers)
handler(_br);
}
public void OnExplosionServerInit(PooledBinaryWriter _bw)
{
foreach (var handler in list_init_server_handlers)
handler(_bw);
}
public void OnExplosionClientInit(PooledBinaryReader _br)
{
foreach (var handler in list_init_client_handlers)
handler(_br);
}
}

View File

@@ -0,0 +1,42 @@
using System.Collections.Generic;
using UnityEngine;
public class ReverseTrackedBehaviour<T> : TrackedBehaviourBase where T : ReverseTrackedBehaviour<T>
{
protected static Dictionary<object, Dictionary<uint, T>> hash_instances = new Dictionary<object, Dictionary<uint, T>>();
static ReverseTrackedBehaviour()
{
CustomExplosionManager.CleanUp += hash_instances.Clear;
}
protected override void Awake()
{
track = true;
base.Awake();
}
protected override void addRef()
{
if (!hash_instances.ContainsKey(key))
hash_instances.Add(key, new Dictionary<uint, T>());
hash_instances[key].Add(explId, (T)this);
}
protected override void removeRef()
{
var dict = hash_instances[key];
if (dict != null)
{
dict.Remove(explId);
if (dict.Count <= 0)
hash_instances.Remove(key);
}
}
public static bool TryGetValue(uint id, object key, out T controller)
{
controller = null;
if (hash_instances.TryGetValue(key, out var dict))
return dict.TryGetValue(id, out controller);
return false;
}
}

View File

@@ -0,0 +1,124 @@
using UnityEngine;
using UnityEngine.Events;
/// <summary>
/// 计时器
/// <para>ZhangYu 2018-04-08</para>
/// <para>code from: https://segmentfault.com/a/1190000015325310 </para>
/// </summary>
public class Timer : MonoBehaviour
{
// delay in second
public float delay = 0;
// interval in second
public float interval = 1;
// repeat count
public int repeatCount = 1;
// automatically start
public bool autoStart = false;
// automatically destroy
public bool autoDestory = true;
// current time
public float currentTime = 0;
// current count
public int currentCount = 0;
// event when interval reached
public UnityEvent onIntervalEvent;
// event when timer completed
public UnityEvent onCompleteEvent;
// callback delegate
public delegate void TimerCallback(Timer timer);
// last interval time
private float lastTime = 0;
// interval callback
private TimerCallback onIntervalCall;
// complete callback
private TimerCallback onCompleteCall;
private void Start()
{
enabled = autoStart;
}
private void FixedUpdate()
{
if (!enabled) return;
addInterval(Time.deltaTime);
}
/// <summary> add interval </summary>
private void addInterval(float deltaTime)
{
currentTime += deltaTime;
if (currentTime < delay) return;
if (currentTime - lastTime >= interval)
{
currentCount++;
lastTime = currentTime;
if (repeatCount <= 0)
{
// repeate forever
if (currentCount == int.MaxValue) reset();
if (onIntervalCall != null) onIntervalCall(this);
if (onIntervalEvent != null) onIntervalEvent.Invoke();
}
else
{
if (currentCount < repeatCount)
{
if (onIntervalCall != null) onIntervalCall(this);
if (onIntervalEvent != null) onIntervalEvent.Invoke();
}
else
{
stop();
if (onCompleteCall != null) onCompleteCall(this);
if (onCompleteEvent != null) onCompleteEvent.Invoke();
if (autoDestory && !enabled) Destroy(this);
}
}
}
}
public void start()
{
enabled = autoStart = true;
}
public void start(float time, TimerCallback onComplete)
{
start(time, 1, null, onComplete);
}
public void start(float interval, int repeatCount, TimerCallback onComplete)
{
start(interval, repeatCount, null, onComplete);
}
public void start(float interval, int repeatCount, TimerCallback onInterval, TimerCallback onComplete)
{
this.interval = interval;
this.repeatCount = repeatCount;
onIntervalCall = onInterval;
onCompleteCall = onComplete;
reset();
enabled = autoStart = true;
}
public void stop()
{
enabled = autoStart = false;
}
public void reset()
{
lastTime = currentTime = currentCount = 0;
}
public void restart()
{
reset();
start();
}
}

View File

@@ -0,0 +1,43 @@
using System.Collections.Generic;
using UnityEngine;
public class TrackedBehaviour<T> : TrackedBehaviourBase where T : TrackedBehaviour<T>
{
protected static Dictionary<uint, Dictionary<object, T>> hash_instances = new Dictionary<uint, Dictionary<object, T>>();
static TrackedBehaviour()
{
CustomExplosionManager.CleanUp += hash_instances.Clear;
}
protected override void Awake()
{
track = true;
base.Awake();
}
protected override void addRef()
{
if (!hash_instances.ContainsKey(explId))
hash_instances.Add(explId, new Dictionary<object, T>());
hash_instances[explId].Add(key, (T)this);
}
protected override void removeRef()
{
var dict = hash_instances[explId];
if (dict != null)
{
dict.Remove(key);
if (dict.Count <= 0)
hash_instances.Remove(explId);
}
}
public static bool TryGetValue(uint id, object key, out T controller)
{
controller = null;
if (hash_instances.TryGetValue(id, out var dict))
return dict.TryGetValue(key, out controller);
return false;
}
}

View File

@@ -0,0 +1,96 @@
using UnityEngine;
public class TrackedBehaviourBase : MonoBehaviour
{
protected uint explId;
protected bool isServer;
protected object key = null;
protected bool syncOnConnect = false;
protected bool syncOnInit = false;
protected bool track = false;
protected bool handleClientInfo = false;
protected NetSyncHelper helper = null;
protected virtual void Awake()
{
explId = CustomExplosionManager.LastInitializedComponent.CurrentExplosionParams._explId;
if (track)
{
if (key == null)
{
Log.Error("TrackedBehaviourBase: key is not initialized before addRef!");
return;
}
addRef();
}
bool flag = NetSyncHelper.TryGetValue(explId, out helper);
isServer = SingletonMonoBehaviour<ConnectionManager>.Instance.IsServer;
if (flag)
{
if (syncOnConnect)
{
if (isServer)
helper.ClientConnected += OnClientConnected;
else
helper.ConnectedToServer += OnConnectedToServer;
}
if (syncOnInit)
{
if (isServer)
helper.ExplosionServerInit += OnExplosionInitServer;
else
helper.ExplosionClientInit += OnExplosionInitClient;
}
}else
Log.Error("NetSyncHelper not initialized: explId: " + explId);
if (handleClientInfo)
CustomExplosionManager.HandleClientInfo += OnHandleClientInfo;
}
protected virtual void OnDestroy()
{
if (helper != null)
{
if (syncOnConnect)
{
if (isServer)
helper.ClientConnected -= OnClientConnected;
else
helper.ConnectedToServer -= OnConnectedToServer;
}
if (syncOnInit)
{
if (isServer)
helper.ExplosionServerInit -= OnExplosionInitServer;
else
helper.ExplosionClientInit -= OnExplosionInitClient;
}
}
if (handleClientInfo)
CustomExplosionManager.HandleClientInfo -= OnHandleClientInfo;
if (track)
removeRef();
}
protected virtual void addRef()
{
}
protected virtual void removeRef()
{
}
protected virtual void OnClientConnected(PooledBinaryWriter _bw)
{
}
protected virtual void OnConnectedToServer(PooledBinaryReader _br)
{
}
protected virtual void OnExplosionInitServer(PooledBinaryWriter _bw)
{
}
protected virtual void OnExplosionInitClient(PooledBinaryReader _br)
{
}
protected virtual void OnHandleClientInfo(ClientInfo info)
{
}
}

View File

@@ -0,0 +1,158 @@
using System.Collections.Generic;
using System.IO;
using UnityEngine;
public class NetPackageExplosionParams : NetPackage
{
public NetPackageExplosionParams Setup(int _clrIdx, Vector3 _worldPos, Vector3i _blockPos, Quaternion _rotation, ExplosionData _explosionData, int _entityId, uint _explId, ItemValue _itemValueExplosive, List<BlockChangeInfo> explosionChanges, GameObject particle)
{
clrIdx = _clrIdx;
worldPos = _worldPos;
blockPos = _blockPos;
rotation = _rotation;
explosionData = _explosionData;
entityId = _entityId;
explosionId = _explId;
itemValueExplosive = null;
if(_itemValueExplosive != null)
itemValueExplosive = _itemValueExplosive.Clone();
this.explosionChanges.Clear();
this.explosionChanges.AddRange(explosionChanges);
if(particle != null)
{
if(particle.TryGetComponent<NetSyncHelper>(out var helper))
{
MemoryStream memoryStream = new MemoryStream();
using (PooledBinaryWriter _bw = MemoryPools.poolBinaryWriter.AllocSync(false))
{
_bw.SetBaseStream(memoryStream);
helper.OnExplosionServerInit(_bw);
}
dataToSync = memoryStream.ToArray();
}
}
return this;
}
public override void read(PooledBinaryReader _br)
{
clrIdx = (int)_br.ReadUInt16();
worldPos = StreamUtils.ReadVector3(_br);
blockPos = StreamUtils.ReadVector3i(_br);
rotation = StreamUtils.ReadQuaterion(_br);
int count = (int)_br.ReadUInt16();
explosionData = new ExplosionData(_br.ReadBytes(count));
entityId = _br.ReadInt32();
explosionId = _br.ReadUInt32();
int num = (int)_br.ReadUInt16();
explosionChanges = new List<BlockChangeInfo>(num);
for (int i = 0; i < num; i++)
{
BlockChangeInfo blockChangeInfo = new BlockChangeInfo();
blockChangeInfo.Read(_br);
explosionChanges.Add(blockChangeInfo);
}
if (_br.ReadBoolean())
{
itemValueExplosive = new ItemValue();
itemValueExplosive.Read(_br);
}
ushort bytes = _br.ReadUInt16();
if (bytes > 0)
dataToSync = _br.ReadBytes(bytes);
}
public override void write(PooledBinaryWriter _bw)
{
base.write(_bw);
_bw.Write((ushort)clrIdx);
StreamUtils.Write(_bw, worldPos);
StreamUtils.Write(_bw, blockPos);
StreamUtils.Write(_bw, rotation);
byte[] array = explosionData.ToByteArray();
_bw.Write((ushort)array.Length);
_bw.Write(array);
_bw.Write(entityId);
_bw.Write(explosionId);
_bw.Write((ushort)explosionChanges.Count);
for (int i = 0; i < explosionChanges.Count; i++)
{
explosionChanges[i].Write(_bw);
}
_bw.Write(itemValueExplosive != null);
if (itemValueExplosive != null)
{
itemValueExplosive.Write(_bw);
}
if (dataToSync != null && dataToSync.Length > 0)
{
_bw.Write((ushort)dataToSync.Length);
_bw.Write(dataToSync);
}
else
_bw.Write((ushort)0);
}
public override void ProcessPackage(World _world, GameManager _callbacks)
{
if (_world == null)
{
return;
}
bool isCustom = false;
if(explosionData.ParticleIndex >= WorldStaticData.prefabExplosions.Length)
{
isCustom = CustomExplosionManager.GetCustomParticleComponents(explosionData.ParticleIndex, out ExplosionComponent component) && component != null;
if (isCustom)
{
ExplosionValue value = new ExplosionValue()
{
Component = component,
CurrentExplosionParams = new ExplosionParams(clrIdx, worldPos, blockPos, rotation, explosionData, entityId, explosionId),
CurrentItemValue = itemValueExplosive?.Clone()
};
CustomExplosionManager.PushLastInitComponent(value);
}
}
GameObject result = _callbacks.ExplosionClient(clrIdx, worldPos, rotation, explosionData.ParticleIndex, explosionData.BlastPower, (float)explosionData.EntityRadius, (float)explosionData.BlockDamage, entityId, explosionChanges);
if (isCustom)
{
NetSyncHelper helper = result?.GetComponent<NetSyncHelper>();
if (helper != null && dataToSync != null)
{
using (PooledBinaryReader _br = MemoryPools.poolBinaryReader.AllocSync(false))
{
_br.SetBaseStream(new MemoryStream(dataToSync));
helper.OnExplosionClientInit(_br);
}
}
CustomExplosionManager.PopLastInitComponent();
}
}
public override NetPackageDirection PackageDirection
{
get
{
return NetPackageDirection.ToClient;
}
}
public override int GetLength()
{
return 80 + explosionChanges.Count * 30;
}
private int clrIdx;
private Vector3 worldPos;
private Vector3i blockPos;
private Quaternion rotation;
private ExplosionData explosionData;
private int entityId;
private uint explosionId;
private ItemValue itemValueExplosive;
private List<BlockChangeInfo> explosionChanges = new List<BlockChangeInfo>();
private byte[] dataToSync = null;
}

View File

@@ -0,0 +1,77 @@
using System.IO;
using UnityEngine;
using XMLData.Item;
public class NetPackageExplosionSyncOnConnect : NetPackage
{
public NetPackageExplosionSyncOnConnect Setup(byte[] data)
{
this.data = data != null ? data : new byte[0];
return this;
}
public override void read(PooledBinaryReader _br)
{
int bytes = _br.ReadInt32();
data = _br.ReadBytes(bytes);
}
public override void write(PooledBinaryWriter _bw)
{
base.write(_bw);
_bw.Write(data.Length);
_bw.Write(data);
}
public override void ProcessPackage(World _world, GameManager _callbacks)
{
if (_world == null)
{
return;
}
using (PooledBinaryReader _br = MemoryPools.poolBinaryReader.AllocSync(false))
{
_br.SetBaseStream(new MemoryStream(data));
uint count = _br.ReadUInt32();
for(int i = 0; i < count; ++i)
{
int bytes = (int)_br.ReadUInt16();
ExplosionParams explParams = new ExplosionParams(_br.ReadBytes(bytes));
ItemValue explValue = null;
if (_br.ReadBoolean())
{
explValue = new ItemValue();
explValue.Read(_br);
}
CustomExplosionManager.GetCustomParticleComponents(explParams._explosionData.ParticleIndex, out ExplosionComponent component);
ExplosionValue value = new ExplosionValue()
{
Component = component,
CurrentExplosionParams = explParams,
CurrentItemValue = explValue?.Clone()
};
CustomExplosionManager.PushLastInitComponent(value);
GameObject obj = CustomExplosionManager.InitializeParticle(component, explParams._worldPos - Origin.position, explParams._rotation);
obj.GetComponent<NetSyncHelper>().OnConnectedToServer(_br);
}
CustomExplosionManager.PopLastInitComponent();
}
}
public override NetPackageDirection PackageDirection
{
get
{
return NetPackageDirection.ToClient;
}
}
public override int GetLength()
{
return 8 + data.Length;
}
private byte[] data;
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
public static class PlatformIndependentHash
{
public static int StringToInt32(string str)
{
byte[] encoded = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(str));
return BitConverter.ToInt32(encoded, 0);
}
public static UInt16 StringToUInt16(string str)
{
byte[] encoded = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(str));
return (UInt16)BitConverter.ToUInt32(encoded, 0);
}
}

View File

@@ -0,0 +1,31 @@
using System.IO;
using UnityEngine;
public static class StreamUtilsCompressed
{
public static void Write(BinaryWriter _bw, Vector3 vec)
{
_bw.Write(Mathf.FloatToHalf(vec.x));
_bw.Write(Mathf.FloatToHalf(vec.y));
_bw.Write(Mathf.FloatToHalf(vec.z));
}
public static Vector3 ReadHalfVector3(BinaryReader _br)
{
return new Vector3(Mathf.HalfToFloat(_br.ReadUInt16()), Mathf.HalfToFloat(_br.ReadUInt16()), Mathf.HalfToFloat(_br.ReadUInt16()));
}
public static void Write(BinaryWriter _bw, Quaternion rot)
{
_bw.Write(Mathf.FloatToHalf(rot.x));
_bw.Write(Mathf.FloatToHalf(rot.y));
_bw.Write(Mathf.FloatToHalf(rot.z));
_bw.Write(Mathf.FloatToHalf(rot.w));
}
public static Quaternion ReadHalfQuaternion(BinaryReader _br)
{
return new Quaternion(Mathf.HalfToFloat(_br.ReadUInt16()), Mathf.HalfToFloat(_br.ReadUInt16()), Mathf.HalfToFloat(_br.ReadUInt16()), Mathf.HalfToFloat(_br.ReadUInt16()));
}
}