private static void patchSerializerTwo(SandboxLayoutData __instance, List <byte> bytes)
        {
            ptfInstance.ptfLogger.LogMessage($"Layout post version: {__instance.m_Version}");

            // add number of mods stored
            //bytes.AddRange(ByteSerializer.SerializeInt(noncheatMods.Where(x => x.shouldSaveData).Count() + cheatMods.Where(x => x.shouldSaveData).Count()));

            // add mod data for each mod

            // make sure to be backwards compatible!
            List <string> modData = cheatMods.Where(x => x.isEnabled).Select(x => $"{x.Info.Metadata.Name}\u058D{x.Info.Metadata.Version}\u058D{x.getSettings()}").ToList();

            modData.AddRange(noncheatMods.Where(x => x.shouldSaveData && x.isEnabled).Select(x => $"{x.Info.Metadata.Name}\u058D{x.Info.Metadata.Version}\u058D{x.getSettings()}").ToList());
            string[] mods = modData.ToArray();

            if (__instance.m_Version >= 0)
            {
                return;
            }
            bytes.AddRange(ByteSerializer.SerializeStrings(mods));

            // add an int indicating the number of mods that will save binary data
            int modsSavingBinary = noncheatMods.Where(x => x.shouldSaveData).Count() + cheatMods.Where(x => x.shouldSaveData).Count();

            bytes.AddRange(ByteSerializer.SerializeInt(modsSavingBinary));

            foreach (var mod in noncheatMods)
            {
                if (mod.isEnabled && mod.shouldSaveData)
                {
                    bytes.AddRange(ByteSerializer.SerializeString(
                                       $"{mod.Info.Metadata.Name}\u058D{mod.Info.Metadata.Version}"
                                       ));
                    bytes.AddRange(ByteSerializer.SerializeByteArray(
                                       mod.saveData()
                                       ));
                }
            }
            foreach (var mod in cheatMods)
            {
                if (mod.isEnabled && mod.shouldSaveData)
                {
                    bytes.AddRange(ByteSerializer.SerializeString(
                                       $"{mod.Info.Metadata.Name}\u058D{mod.Info.Metadata.Version}"
                                       ));
                    bytes.AddRange(ByteSerializer.SerializeByteArray(
                                       mod.saveData()
                                       ));
                }
            }
            ptfInstance.ptfLogger.LogMessage($"Serialized {mods.Length.ToString()} Mod Names");
        }
 static void patchSerializerOne(SandboxLayoutData __instance, List <byte> bytes)
 {
     ptfInstance.ptfLogger.LogMessage($"Layout pre version: {__instance.m_Version}");
     if (GameStateManager.GetState() != GameState.BUILD && GameStateManager.GetState() != GameState.SANDBOX)
     {
         return;
     }
     if (noncheatMods.Where(x => x.shouldSaveData).Count() + cheatMods.Where(x => x.isEnabled).Count() == 0)
     {
         return;
     }
     __instance.m_Version *= -1;
     //PopUpMessage.Display("You have cheat mods enabled, do you want to store them?\n(This will make the layout incompatible with vanilla PB2)", yes, no);
     ptfInstance.ptfLogger.LogMessage($"Version after cheat question: {__instance.m_Version.ToString()}");
 }
        public void AddThisLevel(string cPath, SandboxLayoutData data, CampaignLayoutData cData, int num)
        {
            data.m_Workshop.m_Id = data.m_Workshop.m_Title + "CampaignMod";
            byte[] layoutData = data.SerializeBinary();

            List <byte> bytes = new List <byte>();

            WorkshopPreview.Create();
            bytes.AddRange(ByteSerializer.SerializeByteArray(layoutData));
            bytes.AddRange(ByteSerializer.SerializeByteArray(WorkshopPreview.m_PreviewBytes));
            bytes.AddRange(ByteSerializer.SerializeString(mName.Value));

            File.WriteAllBytes(cPath + "/" + data.m_Workshop.m_Title + ".level", bytes.ToArray());

            if (cData.m_ItemIds.Contains(data.m_Workshop.m_Id))
            {
                cData.m_ItemIds.Remove(data.m_Workshop.m_Id);
            }
            if (num == -1)
            {
                cData.m_ItemIds.Add(data.m_Workshop.m_Id);
            }
            else
            {
                if (cData.m_ItemIds.Count < num)
                {
                    cData.m_ItemIds.Add(data.m_Workshop.m_Id);
                }
                else
                {
                    cData.m_ItemIds.Insert(num - 1, data.m_Workshop.m_Id);
                }
            }

            try
            {
                string json = JsonUtility.ToJson(cData);
                File.WriteAllText(cPath + "/CampaignData.json", json);
            }
            catch (Exception e)
            {
                uConsole.Log("Something went wrong:\n" + e);
                return;
            }
            uConsole.Log("Level added to campaign at position " + (cData.m_ItemIds.IndexOf(data.m_Workshop.m_Id) + 1));
        }
        public static void patchDeserializerPrefix(SandboxLayoutData __instance, byte[] bytes, ref int offset, ref bool __state)
        {
            __state = false;
            var startOffset = offset;

            __instance.m_Version = ByteSerializer.DeserializeInt(bytes, ref offset);
            offset = startOffset;
            //ptfInstance.ptfLogger.LogMessage($"Layout version pre-modcheck: {__instance.m_Version}");
            if (__instance.m_Version > 0)
            {
                return;
            }
            __instance.m_Version *= -1;
            __state = true;
            byte[] new_ver = ByteSerializer.SerializeInt(__instance.m_Version);
            for (int i = 0; i < new_ver.Length; i++)
            {
                bytes[i] = new_ver[i];
            }
            //ptfInstance.ptfLogger.LogMessage($"Layout version post-modcheck: {__instance.m_Version}");
        }
        public static void patchDeserializerPostfix(SandboxLayoutData __instance, byte[] bytes, ref int offset, bool __state)
        {
            //ptfInstance.ptfLogger.LogMessage($"Layout version pre-load: {__instance.m_Version}");
            if (!__state)
            {
                return;
            }
            string[] strings = ByteSerializer.DeserializeStrings(bytes, ref offset);
            ptfInstance.ptfLogger.LogInfo($"Layout created with mod{(strings.Length > 1 ? "s" : "")}: ");
            foreach (string str in strings)
            {
                string[] partsOfMod = str.Split('\u058D');
                string   name       = partsOfMod.Length >= 1 ? partsOfMod[0] : null;
                string   version    = partsOfMod.Length >= 2 ? partsOfMod[1] : null;
                string   settings   = partsOfMod.Length >= 3 ? partsOfMod[2] : null;

                ptfInstance.ptfLogger.LogInfo($" -- {str.Replace("\u058D", " - v")}");

                var currMod = cheatMods.Where(p => p.Info.Metadata.Name == name).FirstOrDefault();
                if (currMod == null)
                {
                    currMod = noncheatMods.Where(p => p.Info.Metadata.Name == name).FirstOrDefault();
                }

                ptfInstance.checkMods(0, name, version, settings, currMod);
            }
            if (offset == bytes.Length)
            {
                return;
            }
            int extraSaveDataCount = ByteSerializer.DeserializeInt(bytes, ref offset);

            if (extraSaveDataCount == 0)
            {
                return;
            }

            ptfInstance.Logger.LogInfo($"Layout created with custom data from mods: ");

            for (int i = 0; i < extraSaveDataCount; i++)
            {
                string modIdentifier     = ByteSerializer.DeserializeString(bytes, ref offset);
                byte[] customModSaveData = ByteSerializer.DeserializeByteArray(bytes, ref offset);

                string[] partsOfMod = modIdentifier.Split('\u058D');
                string   name       = partsOfMod.Length >= 1 ? partsOfMod[0] : null;
                string   version    = partsOfMod.Length >= 2 ? partsOfMod[1] : null;

                ptfInstance.Logger.LogInfo($" -- {name} - v{version}");

                var currMod = cheatMods.Where(p => p.Info.Metadata.Name == name).FirstOrDefault();
                if (currMod == null)
                {
                    currMod = noncheatMods.Where(p => p.Info.Metadata.Name == name).FirstOrDefault();
                }

                if (currMod == null)
                {
                    return;
                }
                if (currMod.Info.Metadata.Version.ToString() != version)
                {
                    return;
                }

                currMod.loadData(customModSaveData);
            }
        }
        public static SandboxLayoutData DeserializeLayoutBytes(byte[] bytes, ref int offset)
        {
            SandboxLayoutData layoutData = new SandboxLayoutData();

            layoutData.m_Version = ByteSerializer.DeserializeInt(bytes, ref offset);
            if (layoutData.m_Version < 0)
            {
                layoutData.m_Version *= -1;
            }
            layoutData.m_ThemeStubKey = ByteSerializer.DeserializeString(bytes, ref offset);
            if (layoutData.m_Version >= 19)
            {
                int num1 = ByteSerializer.DeserializeInt(bytes, ref offset);
                for (int i = 0; i < num1; i++)
                {
                    layoutData.m_Anchors.Add(new BridgeJointProxy(layoutData.m_Version, bytes, ref offset));
                }
            }
            if (layoutData.m_Version >= 5)
            {
                int num2 = ByteSerializer.DeserializeInt(bytes, ref offset);
                for (int i = 0; i < num2; i++)
                {
                    layoutData.m_HydraulicsPhases.Add(new HydraulicsPhaseProxy(bytes, ref offset));
                }
            }
            if (layoutData.m_Version > 4)
            {
                layoutData.m_Bridge.DeserializeBinary(bytes, ref offset);
                goto LABEL;
            }
            int num3 = ByteSerializer.DeserializeInt(bytes, ref offset);

            for (int i = 0; i < num3; i++)
            {
                layoutData.m_BridgeJoints.Add(new BridgeJointProxy(1, bytes, ref offset));
            }
            int num4 = ByteSerializer.DeserializeInt(bytes, ref offset);

            for (int i = 0; i < num4; i++)
            {
                layoutData.m_BridgeEdges.Add(new BridgeEdgeProxy(bytes, ref offset));
            }
            int num5 = ByteSerializer.DeserializeInt(bytes, ref offset);

            for (int i = 0; i < num5; i++)
            {
                layoutData.m_Pistons.Add(new PistonProxy(layoutData.m_Version, bytes, ref offset));
            }
LABEL:
            if (layoutData.m_Version >= 7)
            {
                int num6 = ByteSerializer.DeserializeInt(bytes, ref offset);
                for (int i = 0; i < num6; i++)
                {
                    layoutData.m_ZedAxisVehicles.Add(new ZedAxisVehicleProxy(layoutData.m_Version, bytes, ref offset));
                }
            }
            int num7 = ByteSerializer.DeserializeInt(bytes, ref offset);

            for (int i = 0; i < num7; i++)
            {
                layoutData.m_Vehicles.Add(new VehicleProxy(bytes, ref offset));
            }
            int num8 = ByteSerializer.DeserializeInt(bytes, ref offset);

            for (int i = 0; i < num8; i++)
            {
                layoutData.m_VehicleStopTriggers.Add(new VehicleStopTriggerProxy(bytes, ref offset));
            }
            if (layoutData.m_Version < 20)
            {
                int num9 = ByteSerializer.DeserializeInt(bytes, ref offset);
                for (int i = 0; i < num9; i++)
                {
                    ByteSerializer.DeserializeVector2(bytes, ref offset);
                    ByteSerializer.DeserializeString(bytes, ref offset);
                    ByteSerializer.DeserializeBool(bytes, ref offset);
                }
            }
            int num10 = ByteSerializer.DeserializeInt(bytes, ref offset);

            for (int i = 0; i < num10; i++)
            {
                layoutData.m_EventTimelines.Add(new EventTimelineProxy(layoutData.m_Version, bytes, ref offset));
            }
            int num11 = ByteSerializer.DeserializeInt(bytes, ref offset);

            for (int i = 0; i < num11; i++)
            {
                layoutData.m_Checkpoints.Add(new CheckpointProxy(bytes, ref offset));
            }
            int num12 = ByteSerializer.DeserializeInt(bytes, ref offset);

            for (int i = 0; i < num12; i++)
            {
                layoutData.m_TerrainStretches.Add(new TerrainIslandProxy(layoutData.m_Version, bytes, ref offset));
            }
            int num13 = ByteSerializer.DeserializeInt(bytes, ref offset);

            for (int i = 0; i < num13; i++)
            {
                layoutData.m_Platforms.Add(new PlatformProxy(layoutData.m_Version, bytes, ref offset));
            }
            int num14 = ByteSerializer.DeserializeInt(bytes, ref offset);

            for (int i = 0; i < num14; i++)
            {
                layoutData.m_Ramps.Add(new RampProxy(layoutData.m_Version, bytes, ref offset));
            }
            if (layoutData.m_Version < 5)
            {
                int num15 = ByteSerializer.DeserializeInt(bytes, ref offset);
                for (int i = 0; i < num15; i++)
                {
                    layoutData.m_HydraulicsPhases.Add(new HydraulicsPhaseProxy(bytes, ref offset));
                }
            }
            int num16 = ByteSerializer.DeserializeInt(bytes, ref offset);

            for (int i = 0; i < num16; i++)
            {
                layoutData.m_VehicleRestartPhases.Add(new VehicleRestartPhaseProxy(bytes, ref offset));
            }
            int num17 = ByteSerializer.DeserializeInt(bytes, ref offset);

            for (int i = 0; i < num17; i++)
            {
                layoutData.m_FlyingObjects.Add(new FlyingObjectProxy(bytes, ref offset));
            }
            int num18 = ByteSerializer.DeserializeInt(bytes, ref offset);

            for (int i = 0; i < num18; i++)
            {
                layoutData.m_Rocks.Add(new RockProxy(bytes, ref offset));
            }
            int num19 = ByteSerializer.DeserializeInt(bytes, ref offset);

            for (int i = 0; i < num19; i++)
            {
                layoutData.m_WaterBlocks.Add(new WaterBlockProxy(layoutData.m_Version, bytes, ref offset));
            }
            if (layoutData.m_Version < 5)
            {
                int num20 = ByteSerializer.DeserializeInt(bytes, ref offset);
                for (int i = 0; i < num20; i++)
                {
                    ByteSerializer.DeserializeString(bytes, ref offset);
                    int num21 = ByteSerializer.DeserializeInt(bytes, ref offset);
                    for (int j = 0; j < num21; j++)
                    {
                        ByteSerializer.DeserializeString(bytes, ref offset);
                    }
                }
            }
            layoutData.m_Budget.DeserializeBinary(bytes, ref offset);
            layoutData.m_Settings.DeserializeBinary(bytes, ref offset);
            if (layoutData.m_Version >= 9)
            {
                int num22 = ByteSerializer.DeserializeInt(bytes, ref offset);
                for (int i = 0; i < num22; i++)
                {
                    layoutData.m_CustomShapes.Add(new CustomShapeProxy(layoutData.m_Version, bytes, ref offset));
                }
            }
            if (layoutData.m_Version >= 15)
            {
                layoutData.m_Workshop.DeserializeBinary(layoutData.m_Version, bytes, ref offset);
            }
            if (layoutData.m_Version >= 17)
            {
                int num23 = ByteSerializer.DeserializeInt(bytes, ref offset);
                for (int i = 0; i < num23; i++)
                {
                    layoutData.m_SupportPillars.Add(new SupportPillarProxy(bytes, ref offset));
                }
            }
            if (layoutData.m_Version >= 18)
            {
                int num24 = ByteSerializer.DeserializeInt(bytes, ref offset);
                for (int i = 0; i < num24; i++)
                {
                    layoutData.m_Pillars.Add(new PillarProxy(bytes, ref offset));
                }
            }
            return(layoutData);
        }
        public void AddThisLevelCommand()
        {
            if (!instance.CheckForCheating())
            {
                uConsole.Log("Campaign Mod is not enabled!");
                return;
            }
            if (GameStateManager.GetState() != GameState.SANDBOX)
            {
                uConsole.Log("You have to be in sandbox mode to use this command!");
                return;
            }
            int Args = uConsole.GetNumParameters();

            if (Args == 0)
            {
                uConsole.Log("Usage: add_this_level <campaign> [num]");
            }
            else
            {
                string Name  = uConsole.GetString();
                string cPath = MainPath + "Campaigns/" + Name;

                if (!Directory.Exists(cPath))
                {
                    uConsole.Log(Name + " does not exist!");
                    return;
                }
                else if (!File.Exists(cPath + "/CampaignData.json"))
                {
                    uConsole.Log(Name + " is missing CampaignData.json!");
                    return;
                }
                else if (mName.Value.IsNullOrWhiteSpace())
                {
                    uConsole.Log("Your name can't be empty!");
                    return;
                }

                GameUI.m_Instance.m_WorkshopSubmit.gameObject.SetActive(true);
                GameUI.m_Instance.m_WorkshopSubmit.gameObject.SetActive(false);

                SandboxLayoutData data  = SandboxLayout.SerializeToProxies();
                string            Title = data.m_Workshop.m_Title;
                if (Title.IsNullOrWhiteSpace())
                {
                    uConsole.Log("Level doesn't have a name!");
                    return;
                }
                else
                if (Title.Contains("/") || Title.Contains("\\") || Title.Contains("?") || Title.Contains("%") || Title.Contains("*") ||
                    Title.Contains(":") || Title.Contains("|") || Title.Contains("\"") || Title.Contains("<") || Title.Contains(">") ||
                    Title.Contains(".") || Title.Contains(",") || Title.Contains(";") || Title.Contains("="))
                {
                    uConsole.Log("Level title contains prhobited characters!");
                    return;
                }

                CampaignLayoutData cData = JsonUtility.FromJson <CampaignLayoutData>(File.ReadAllText(cPath + "/CampaignData.json"));
                if (cData.m_ItemIds.Count >= 16)
                {
                    uConsole.Log("Campaign already has max levels");
                    return;
                }

                int num = -1;
                if (Args > 1)
                {
                    num = uConsole.GetInt();
                    if (num < 1 || num > 16)
                    {
                        uConsole.Log("Position has to be within 1 and 16!");
                        return;
                    }
                }

                if (File.Exists(cPath + "/" + Title + ".level"))
                {
                    PopUpMessage.Display("Level already exists!\nOverwrite level?", delegate { AddThisLevel(cPath, data, cData, num); });
                }
                else
                {
                    AddThisLevel(cPath, data, cData, num);
                }
            }
        }