Пример #1
0
 public SyncField(Type targetType, string memberPath)
 {
     this.targetType = targetType;
     this.memberPath = targetType + "/" + memberPath;
     fieldType       = MpReflection.PathType(this.memberPath);
     indexType       = MpReflection.IndexType(this.memberPath);
 }
Пример #2
0
        public override void Handle(ByteReader data)
        {
            object target = null;

            if (targetType != null)
            {
                target = SyncSerialization.ReadSyncObject(data, targetType);
                if (target == null)
                {
                    return;
                }
            }

            object value = SyncSerialization.ReadSyncObject(data, fieldType);

            if (cancelIfValueNull && value == null)
            {
                return;
            }

            object index = null;

            if (indexType != null)
            {
                index = SyncSerialization.ReadSyncObject(data, indexType);
            }

            preApply?.Invoke(target, value);

            MpLog.Debug($"Set {memberPath} in {target} to {value}, map {data.MpContext().map}, index {index}");
            MpReflection.SetValue(target, memberPath, value, index);

            postApply?.Invoke(target, value);
        }
Пример #3
0
        public override void Bind(object obj, string name)
        {
            object value = MpReflection.GetValue(obj, name);
            Type   type  = value.GetType();

            SyncSerialization.WriteSyncObject(writer, value, type);
        }
Пример #4
0
        // todo support methods with arguments (currently there has been no need for it)
        public static SyncDelegate RegisterSyncDelegate(Type inType, string nestedType, string methodName, string[] fields, Type[] args = null)
        {
            string typeName = $"{inType}+{nestedType}";
            Type   type     = MpReflection.GetTypeByName(typeName);

            if (type == null)
            {
                throw new Exception($"Couldn't find type {typeName}");
            }

            MethodInfo method = AccessTools.Method(type, methodName, args);

            if (method == null)
            {
                throw new Exception($"Couldn't find method {typeName}::{methodName}");
            }

            MpUtil.MarkNoInlining(method);

            SyncDelegate handler = new SyncDelegate(type, method, fields);

            syncMethods[handler.method] = handler;
            handlers.Add(handler);

            PatchMethodForSync(method);

            return(handler);
        }
Пример #5
0
        public override void Handle(ByteReader data)
        {
            object target = Activator.CreateInstance(delegateType);

            for (int i = 0; i < fieldPaths.Length; i++)
            {
                string path       = fieldPaths[i];
                string noTypePath = MpReflection.RemoveType(path);
                Type   fieldType  = fieldTypes[i];
                object value;

                if (fieldType.IsCompilerGenerated())
                {
                    value = Activator.CreateInstance(fieldType);
                }
                else
                {
                    value = Sync.ReadSyncObject(data, fieldType);
                }

                if (value == null)
                {
                    if (cancelIfAnyNullBlacklist != null && !cancelIfAnyNullBlacklist.Contains(noTypePath))
                    {
                        return;
                    }

                    if (path.EndsWith("$this"))
                    {
                        return;
                    }

                    if (cancelIfNull != null && cancelIfNull.Contains(noTypePath))
                    {
                        return;
                    }
                }

                if (removeNullsFromLists != null && removeNullsFromLists.Contains(noTypePath) && value is IList list)
                {
                    list.RemoveNulls();
                }

                MpReflection.SetValue(target, path, value);
            }

            if (context.HasFlag(SyncContext.MapSelected) && cancelIfNoSelectedObjects && Find.Selector.selected.Count == 0)
            {
                return;
            }

            object[] parameters = Sync.ReadSyncObjects(data, argTypes);

            MpLog.Log("Invoked delegate method " + method + " " + delegateType);
            method.Invoke(target, parameters);
        }
Пример #6
0
        public override void Bind(object obj, string name)
        {
            object value = MpReflection.GetValue(obj, name);

            Type type = value.GetType();

            var res = SyncSerialization.ReadSyncObject(reader, type);

            MpReflection.SetValue(obj, name, res);
        }
Пример #7
0
        // todo what happens on exceptions?
        public static void FieldWatchPostfix()
        {
            if (Multiplayer.Client == null)
            {
                return;
            }

            while (watchedStack.Count > 0)
            {
                FieldData data = watchedStack.Pop();

                if (data == null)
                {
                    break; // The marker
                }
                SyncField handler = data.handler;

                object newValue = MpReflection.GetValue(data.target, handler.memberPath, data.index);
                bool   changed  = !Equals(newValue, data.oldValue);
                var    cache    = (handler.bufferChanges && !Multiplayer.IsReplay) ? bufferedChanges.GetValueSafe(handler) : null;

                if (cache != null && cache.TryGetValue(new Pair <object, object>(data.target, data.index), out BufferData cached))
                {
                    if (changed && cached.sent)
                    {
                        cached.sent = false;
                    }

                    cached.toSend = newValue;
                    MpReflection.SetValue(data.target, handler.memberPath, cached.actualValue, data.index);
                    continue;
                }

                if (!changed)
                {
                    continue;
                }

                if (cache != null)
                {
                    BufferData bufferData = new BufferData(data.oldValue, newValue);
                    cache[new Pair <object, object>(data.target, data.index)] = bufferData;
                }
                else
                {
                    handler.DoSync(data.target, newValue, data.index);
                }

                MpReflection.SetValue(data.target, handler.memberPath, data.oldValue, data.index);
            }
        }
Пример #8
0
        protected override object ReadTarget(ByteReader data)
        {
            object target = Activator.CreateInstance(targetType);

            for (int i = 0; i < fieldPaths.Length; i++)
            {
                string path       = fieldPaths[i];
                string noTypePath = fieldPathsNoTypes[i];
                Type   fieldType  = fieldTypes[i];
                object value;

                if (fieldTransformers[i] is SyncTransformer tr)
                {
                    value = tr.Reader.DynamicInvoke(SyncSerialization.ReadSyncObject(data, tr.NetworkType));
                }
                else if (fieldType.IsCompilerGenerated())
                {
                    value = Activator.CreateInstance(fieldType);
                }
                else
                {
                    value = SyncSerialization.ReadSyncObject(data, fieldType);
                }

                if (value == null)
                {
                    if (allowedNull != null && !allowedNull.Contains(noTypePath))
                    {
                        return(null);
                    }
                    if (noTypePath.EndsWith(DELEGATE_THIS))
                    {
                        return(null);
                    }
                    if (cancelIfNull != null && cancelIfNull.Contains(noTypePath))
                    {
                        return(null);
                    }
                }

                if (removeNullsFromLists != null && removeNullsFromLists.Contains(noTypePath) && value is IList list)
                {
                    list.RemoveNulls();
                }

                MpReflection.SetValue(target, path, value);
            }

            return(target);
        }
Пример #9
0
        public SyncMethod(Type targetType, string instancePath, string methodName, SyncType[] argTypes)
        {
            this.targetType = targetType;

            Type instanceType = targetType;

            if (!instancePath.NullOrEmpty())
            {
                this.instancePath = instanceType + "/" + instancePath;
                instanceType      = MpReflection.PathType(this.instancePath);
            }

            method        = AccessTools.Method(instanceType, methodName, argTypes?.Select(t => t.type).ToArray()) ?? throw new Exception($"Couldn't find method {instanceType}::{methodName}");
            this.argTypes = CheckArgs(argTypes);
        }
        static void PatchIfExists(string typeName, string methodName, HarmonyMethod prefix = null, HarmonyMethod postfix = null, HarmonyMethod transpiler = null)
        {
            var type = MpReflection.GetTypeByName(typeName);

            if (type == null)
            {
                return;
            }

            var method = AccessTools.Method(type, methodName);

            if (method == null)
            {
                return;
            }

            Multiplayer.harmony.Patch(method, prefix, postfix, transpiler);
        }
        public static void Init()
        {
            var harmony = Multiplayer.harmony;

            // Compat with Fluffy's mod loader
            var fluffysModButtonType = MpReflection.GetTypeByName("ModManager.ModButton_Installed");

            if (fluffysModButtonType != null)
            {
                harmony.Patch(
                    fluffysModButtonType.GetMethod("DoModButton"),
                    new HarmonyMethod(typeof(PageModsPatch), nameof(PageModsPatch.ModManager_ButtonPrefix)),
                    new HarmonyMethod(typeof(PageModsPatch), nameof(PageModsPatch.Postfix))
                    );
            }

            var cancelForArbiter = new HarmonyMethod(typeof(CancelForArbiter), "Prefix");

            // Fix PrisonLabor breaking the arbiter
            {
                PatchIfExists("PrisonLabor.Behaviour_MotivationIcon", "Update", cancelForArbiter);
                PatchIfExists("PrisonLabor.Core.GUI_Components.PawnIcons", "MapComponentTick", cancelForArbiter);
                PatchIfExists("PrisonLabor.MapComponent_Icons", "MapComponentTick", cancelForArbiter);
            }

            // PawnsAreCapable compat
            // Replace workSettings.SetPriority(def, p) with (workSettings.priorities[def] = p)
            // Minimizes side effects and goes around syncing
            // Also cache the dictionary to improve performance
            {
                var pawnsAreCapablePatch = new HarmonyMethod(typeof(ModPatches), nameof(PawnsAreCapable_FloatMenu_Patch_Transpiler));
                PatchIfExists("PawnsAreCapable.FloatMenuMakerMap_ChoicesAtFor", "Prefix", transpiler: pawnsAreCapablePatch);
                PatchIfExists("PawnsAreCapable.FloatMenuMakerMap_ChoicesAtFor", "Postfix", transpiler: pawnsAreCapablePatch);
            }

            var randPatchPrefix  = new HarmonyMethod(typeof(RandPatches), "Prefix");
            var randPatchPostfix = new HarmonyMethod(typeof(RandPatches), "Postfix");

            // Facial Stuff compat
            {
                PatchIfExists("FacialStuff.Harmony.HarmonyPatchesFS", "TryInteractWith_Postfix", randPatchPrefix, randPatchPostfix);
            }
        }
Пример #12
0
        public SyncDelegate(Type delegateType, MethodInfo method, string[] fieldPaths)
        {
            this.delegateType = delegateType;
            this.method       = method;

            argTypes = method.GetParameters().Types();

            if (fieldPaths == null)
            {
                List <string> fieldList = new List <string>();
                Sync.AllDelegateFieldsRecursive(delegateType, path => { fieldList.Add(path); return(false); });
                this.fieldPaths = fieldList.ToArray();
            }
            else
            {
                var temp = new UniqueList <string>();
                foreach (string path in fieldPaths.Select(p => MpReflection.AppendType(p, delegateType)))
                {
                    string[] parts     = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
                    string   increment = parts[0] + "/" + parts[1];
                    for (int i = 2; i < parts.Length; i++)
                    {
                        if (!MpReflection.PathType(increment).IsCompilerGenerated())
                        {
                            break;
                        }
                        temp.Add(increment);
                        increment += "/" + parts[i];
                    }

                    temp.Add(path);
                }

                this.fieldPaths = temp.ToArray();
            }

            fieldTypes = this.fieldPaths.Select(path => MpReflection.PathType(path)).ToArray();
        }
Пример #13
0
        public SyncDelegate(Type delegateType, MethodInfo method, string[] inPaths) :
            base(delegateType, null, method, null)
        {
            if (inPaths == null)
            {
                List <string> fieldList = new List <string>();
                AllDelegateFieldsRecursive(delegateType, path => { fieldList.Add(path); return(false); });
                fieldPaths = fieldList.ToArray();
            }
            else
            {
                var temp = new UniqueList <string>();
                foreach (string path in inPaths.Select(p => MpReflection.AppendType(p, delegateType)))
                {
                    string[] parts     = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
                    string   increment = parts[0] + "/" + parts[1];
                    for (int i = 2; i < parts.Length; i++)
                    {
                        if (!MpReflection.PathType(increment).IsCompilerGenerated())
                        {
                            break;
                        }
                        temp.Add(increment);
                        increment += "/" + parts[i];
                    }

                    temp.Add(path);
                }

                fieldPaths = temp.ToArray();
            }

            fieldTypes        = fieldPaths.Select(path => MpReflection.PathType(path)).ToArray();
            fieldPathsNoTypes = fieldPaths.Select(path => MpReflection.RemoveType(path)).ToArray();
            fieldTransformers = new SyncTransformer[fieldTypes.Length];
        }
Пример #14
0
 public static void SetPropertyOrField(this object obj, string memberPath, object value, object index = null)
 {
     MpReflection.SetValue(obj, memberPath, value, index);
 }
Пример #15
0
 public static object GetPropertyOrField(this object obj, string memberPath, object index = null)
 {
     return(MpReflection.GetValue(obj, memberPath, index));
 }