diff --git a/Source/Client/MultiplayerAPIBridge.cs b/Source/Client/MultiplayerAPIBridge.cs index a6a05727..e3eebd2a 100644 --- a/Source/Client/MultiplayerAPIBridge.cs +++ b/Source/Client/MultiplayerAPIBridge.cs @@ -1,7 +1,9 @@ using System; using System.Reflection; +using HarmonyLib; using Multiplayer.API; using Multiplayer.Client; +using Multiplayer.Client.Patches; // ReSharper disable once CheckNamespace namespace Multiplayer.Common @@ -21,6 +23,10 @@ public class MultiplayerAPIBridge : IAPI public bool IsExecutingSyncCommandIssuedBySelf => TickPatch.currentExecutingCmdIssuedBySelf; + public bool CanUseDevMode => Client.Multiplayer.GameComp.LocalPlayerDataOrNull?.canUseDevMode ?? false; + + public bool InInterface => Client.Multiplayer.InInterface; + public void WatchBegin() { SyncFieldUtil.FieldWatchPrefix(); @@ -90,6 +96,16 @@ public ISyncMethod RegisterSyncMethod(MethodInfo method, SyncType[] argTypes) return Sync.RegisterSyncMethod(method, argTypes); } + public ISyncMethod RegisterSyncMethodLambda(Type parentType, string parentMethod, int lambdaOrdinal, Type[] parentArgs = null, ParentMethodType parentMethodType = ParentMethodType.Normal) + { + return SyncMethod.Lambda(parentType, parentMethod, lambdaOrdinal, parentArgs, (MethodType)parentMethodType); + } + + public ISyncMethod RegisterSyncMethodLambdaInGetter(Type parentType, string parentMethod, int lambdaOrdinal) + { + return SyncMethod.LambdaInGetter(parentType, parentMethod, lambdaOrdinal); + } + public ISyncDelegate RegisterSyncDelegate(Type inType, string nestedType, string methodName, string[] fields, Type[] args = null) { return Sync.RegisterSyncDelegate(inType, nestedType, methodName, fields, args); @@ -100,6 +116,21 @@ public ISyncDelegate RegisterSyncDelegate(Type type, string nestedType, string m return Sync.RegisterSyncDelegate(type, nestedType, method); } + public ISyncDelegate RegisterSyncDelegateLambda(Type parentType, string parentMethod, int lambdaOrdinal, Type[] parentArgs = null, ParentMethodType parentMethodType = ParentMethodType.Normal) + { + return SyncDelegate.Lambda(parentType, parentMethod, lambdaOrdinal, parentArgs, (MethodType)parentMethodType); + } + + public ISyncDelegate RegisterSyncDelegateLambdaInGetter(Type parentType, string parentMethod, int lambdaOrdinal) + { + return SyncDelegate.LambdaInGetter(parentType, parentMethod, lambdaOrdinal); + } + + public ISyncDelegate RegisterSyncDelegateLocalFunc(Type parentType, string parentMethod, string localFuncName, Type[] parentArgs = null) + { + return SyncDelegate.LocalFunc(parentType, parentMethod, localFuncName, parentArgs); + } + public void RegisterSyncWorker(SyncWorkerDelegate syncWorkerDelegate, Type targetType = null, bool isImplicit = false, bool shouldConstruct = false) { Sync.RegisterSyncWorker(syncWorkerDelegate, targetType, isImplicit: isImplicit, shouldConstruct: shouldConstruct); @@ -119,5 +150,7 @@ public void RegisterPauseLock(PauseLockDelegate pauseLock) { AsyncTimeComp.pauseLocks.Add(pauseLock); } + + public void RegisterDefaultLetterChoice(MethodInfo method, Type letterType = null) => CloseDialogsForExpiredLetters.RegisterDefaultLetterChoice(method, letterType); } } diff --git a/Source/Client/Syncing/Handler/SyncDelegate.cs b/Source/Client/Syncing/Handler/SyncDelegate.cs index 7ea39b02..77c67d8b 100644 --- a/Source/Client/Syncing/Handler/SyncDelegate.cs +++ b/Source/Client/Syncing/Handler/SyncDelegate.cs @@ -23,6 +23,7 @@ public class SyncDelegate : SyncMethod, ISyncDelegate private string[] allowedNull; private string[] cancelIfNull; private string[] removeNullsFromLists; + private string[] exposeFields; public SyncDelegate(Type delegateType, MethodInfo method, string[] inPaths) : base(delegateType, null, method, null) @@ -64,13 +65,18 @@ protected override void WriteTarget(object target, object[] args, SyncMethodWrit for (int i = 0; i < fieldPaths.Length; i++) { var val = target.GetPropertyOrField(fieldPaths[i]); - var type = fieldTypes[i]; var path = fieldPaths[i]; if (fieldTransformers[i] is SyncTransformer tr) writer(tr.Writer.DynamicInvoke(val, target, args), tr.NetworkType, path); else if (!fieldTypes[i].IsCompilerGenerated()) + { + var type = (SyncType)fieldTypes[i]; + if (exposeFields != null && exposeFields.Contains(path)) + type.expose = true; + writer(val, type, path); + } } } @@ -129,14 +135,14 @@ public ISyncDelegate RemoveNullsFromLists(params string[] listFields) return this; } - public ISyncMethod TransformField(string field, Serializer serializer) + public ISyncDelegate TransformField(string field, Serializer serializer, bool skipTypeCheck = false) { CheckFieldsExist(field); var index = fieldPathsNoTypes.FindIndex(field); - if (fieldTypes[index] != typeof(Live)) - throw new Exception($"Arg transformer param mismatch for {this}: {fieldTypes[index]} != {typeof(Live)}"); + if (!skipTypeCheck && fieldTypes[index] != typeof(Live)) + throw new Exception($"Field transformer type mismatch for {this}: {fieldTypes[index]} != {typeof(Live)}"); fieldTransformers[index] = new(typeof(Live), typeof(Networked), serializer.Writer, serializer.Reader); return this; @@ -149,7 +155,7 @@ private void CheckFieldsExist(params string[] fields) throw new Exception($"Field with path {f} not found"); } - public static SyncDelegate Lambda(Type parentType, string parentMethod, int lambdaOrdinal, Type[] parentArgs = null, MethodType parentMethodType = MethodType.Normal) + public new static SyncDelegate Lambda(Type parentType, string parentMethod, int lambdaOrdinal, Type[] parentArgs = null, MethodType parentMethodType = MethodType.Normal) { return Sync.RegisterSyncDelegate( MpMethodUtil.GetLambda(parentType, parentMethod, parentMethodType, parentArgs, lambdaOrdinal), @@ -157,7 +163,7 @@ public static SyncDelegate Lambda(Type parentType, string parentMethod, int lamb ); } - public static SyncDelegate LambdaInGetter(Type parentType, string parentMethod, int lambdaOrdinal) + public new static SyncDelegate LambdaInGetter(Type parentType, string parentMethod, int lambdaOrdinal) { return Sync.RegisterSyncDelegate( MpMethodUtil.GetLambda(parentType, parentMethod, MethodType.Getter, null, lambdaOrdinal), @@ -221,6 +227,13 @@ public ISyncDelegate CancelIfNoSelectedObjects() return this; } + public ISyncDelegate ExposeFields(params string[] fields) + { + CheckFieldsExist(fields); + exposeFields = fields; + return this; + } + ISyncDelegate ISyncDelegate.SetContext(SyncContext context) { SetContext(context); @@ -232,6 +245,48 @@ ISyncDelegate ISyncDelegate.SetDebugOnly() SetDebugOnly(); return this; } + + ISyncDelegate ISyncDelegate.SetHostOnly() + { + SetHostOnly(); + return this; + } + + ISyncDelegate ISyncDelegate.SetPreInvoke(Action action) + { + SetPreInvoke(action); + return this; + } + + ISyncDelegate ISyncDelegate.SetPostInvoke(Action action) + { + SetPostInvoke(action); + return this; + } + + ISyncDelegate ISyncDelegate.TransformArgument(int index, Serializer serializer, bool skipTypeCheck) + { + TransformArgument(index, serializer, skipTypeCheck); + return this; + } + + ISyncDelegate ISyncDelegate.TransformTarget(Serializer serializer, bool skipTypeCheck) + { + TransformTarget(serializer, skipTypeCheck); + return this; + } + + ISyncDelegate ISyncDelegate.CancelIfNoSelectedMapObjects() + { + CancelIfNoSelectedMapObjects(); + return this; + } + + ISyncDelegate ISyncDelegate.CancelIfNoSelectedWorldObjects() + { + CancelIfNoSelectedWorldObjects(); + return this; + } } } diff --git a/Source/Client/Syncing/Handler/SyncMethod.cs b/Source/Client/Syncing/Handler/SyncMethod.cs index 7a8b1c92..17bbbe84 100644 --- a/Source/Client/Syncing/Handler/SyncMethod.cs +++ b/Source/Client/Syncing/Handler/SyncMethod.cs @@ -9,29 +9,6 @@ namespace Multiplayer.Client { - public record Serializer( - Func Writer, // (live, target, args) => networked - Func Reader // (networked) => live - ); - - public static class Serializer - { - public static Serializer New(Func writer, Func reader) - { - return new(writer, reader); - } - - public static Serializer New(Func writer, Func reader) - { - return new((live, _, _) => writer(live), reader); - } - - public static Serializer SimpleReader(Func reader) - { - return new((_, _, _) => null, _ => reader()); - } - } - public record SyncTransformer(Type LiveType, Type NetworkType, Delegate Writer, Delegate Reader); public delegate void SyncMethodWriter(object obj, SyncType type, string debugInfo); @@ -234,6 +211,12 @@ public ISyncMethod SetDebugOnly() return this; } + public ISyncMethod SetHostOnly() + { + hostOnly = true; + return this; + } + public ISyncMethod SetPreInvoke(Action action) { beforeCall = action; @@ -270,39 +253,33 @@ public ISyncMethod ExposeParameter(int index) return this; } - public SyncMethod TransformArgument(int index, Serializer serializer) + public ISyncMethod TransformArgument(int index, Serializer serializer, bool skipTypeCheck = false) { - if (argTypes[index].type != typeof(Live)) + if (!skipTypeCheck && argTypes[index].type != typeof(Live)) throw new Exception($"Arg transformer type mismatch for {this}: {argTypes[index].type} != {typeof(Live)}"); argTransformers[index] = new(typeof(Live), typeof(Networked), serializer.Writer, serializer.Reader); return this; } - public SyncMethod TransformTarget(Serializer serializer) + public ISyncMethod TransformTarget(Serializer serializer, bool skipTypeCheck = false) { - if (targetType != typeof(Live)) + if (!skipTypeCheck && targetType != typeof(Live)) throw new Exception($"Target transformer type mismatch for {this}: {targetType} != {typeof(Live)}"); targetTransformer = new(typeof(Live), typeof(Networked), serializer.Writer, serializer.Reader); return this; } - public SyncMethod SetHostOnly() - { - hostOnly = true; - return this; - } - public static SyncMethod Register(Type type, string methodOrPropertyName, SyncType[] argTypes = null) { return Sync.RegisterSyncMethod(type, methodOrPropertyName, argTypes); } - public static SyncMethod Lambda(Type parentType, string parentMethod, int lambdaOrdinal, Type[] parentArgs = null) + public static SyncMethod Lambda(Type parentType, string parentMethod, int lambdaOrdinal, Type[] parentArgs = null, MethodType parentMethodType = MethodType.Normal) { return Sync.RegisterSyncMethod( - MpMethodUtil.GetLambda(parentType, parentMethod, MethodType.Normal, parentArgs, lambdaOrdinal), + MpMethodUtil.GetLambda(parentType, parentMethod, parentMethodType, parentArgs, lambdaOrdinal), null ); } diff --git a/Source/Client/Util/MpMethodUtil.cs b/Source/Client/Util/MpMethodUtil.cs index 6b82b6ab..9d159bb4 100644 --- a/Source/Client/Util/MpMethodUtil.cs +++ b/Source/Client/Util/MpMethodUtil.cs @@ -157,6 +157,11 @@ public static MethodBase GetMethod(Type type, string methodName, MethodType meth return AccessTools .GetDeclaredConstructors(type) .FirstOrDefault(c => c.IsStatic); + + case MethodType.Enumerator: + if (methodName == null) + return null; + return AccessTools.EnumeratorMoveNext(AccessTools.DeclaredMethod(type, methodName, args)); } return null;