コード例 #1
0
        public void Patch()
        {
            if (!File.Exists(_filePath))
            {
                throw new FileNotFoundException(_filePath);
            }

            var fileBytes = File.ReadAllBytes(_filePath);

            var buildSettingsStartIndex = BitConverter.ToInt32(fileBytes, BuildSettingsStartAddressIndex) + BlockAddressOffset;
            var buildSettingsSize       = BitConverter.ToInt32(fileBytes, BuildSettingsSizeIndex);
            var buildSettingsEndIndex   = buildSettingsStartIndex + buildSettingsSize;

            var patchStartIndex  = FindPatchStartIndex(fileBytes, buildSettingsStartIndex, buildSettingsEndIndex);
            var isAlreadyPatched = FindExistingPatch(fileBytes, patchStartIndex, buildSettingsEndIndex);

            if (isAlreadyPatched)
            {
                _writer.WriteLine("globalgamemanagers already patched.");
                return;
            }

            BackupFile(_filePath);
            var patchedBytes = CreatePatchedFileBytes(fileBytes, patchStartIndex);

            File.WriteAllBytes(_filePath, patchedBytes);
            _writer.WriteLine("Successfully patched globalgamemanagers.");
        }
コード例 #2
0
ファイル: ModMenu.cs プロジェクト: misternebula/owml
        public IModButton GetButton(string title)
        {
            var button = Buttons.FirstOrDefault(x => x.Title == title || x.Button.name == title);

            if (button == null)
            {
                _console.WriteLine("Warning: no button found with title or name: " + title);
            }
            return(button);
        }
コード例 #3
0
ファイル: ModMenu.cs プロジェクト: TAImatem/owml
        private T GetTitleButton <T>(string title, List <T> buttons) where T : IModButton
        {
            var button = buttons.FirstOrDefault(x => x.Title == title || x.Button.name == title);

            if (button == null)
            {
                OwmlConsole.WriteLine("Warning: no button found with title or name: " + title);
            }
            return(button);
        }
コード例 #4
0
ファイル: ModEvents.cs プロジェクト: misternebula/owml
        private void SubscribeToEvent <T>(Common.Events ev)
        {
            var type = typeof(T);

            if (IsSubscribedTo(type, ev))
            {
                _console.WriteLine($"Warning: already subscribed to {ev} of {type.Name}");
                return;
            }
            AddToEventList(_subscribedEvents, type, ev);
        }
コード例 #5
0
        public IModConfigMenu GetModMenu(IModBehaviour modBehaviour)
        {
            _console.WriteLine("Registering " + modBehaviour.ModHelper.Manifest.UniqueName);
            var modConfigMenu = _modConfigMenus.FirstOrDefault(x => x.Mod == modBehaviour);

            if (modConfigMenu == null)
            {
                _console.WriteLine($"Error: {modBehaviour.ModHelper.Manifest.UniqueName} isn't added.");
                return(null);
            }
            return(modConfigMenu);
        }
コード例 #6
0
        public AssetBundle LoadBundle(string filename)
        {
            var path = _manifest.ModFolderPath + filename;

            _console.WriteLine("Loading asset bundle from " + path);
            var bundle = AssetBundle.LoadFromFile(path);

            if (bundle == null)
            {
                _console.WriteLine("Bundle is null");
            }
            return(bundle);
        }
コード例 #7
0
ファイル: ModAssets.cs プロジェクト: kaikecarlos/owml
        public GameObject Load3DObject(ModBehaviour modBehaviour, string objectFilename, string imageFilename)
        {
            var objectPath = modBehaviour.ModManifest.FolderPath + objectFilename;
            var imagePath  = modBehaviour.ModManifest.FolderPath + imageFilename;

            _console.WriteLine("Loading object from " + objectPath);

            var go = new GameObject();

            go.AddComponent <DontDestroyOnLoad>();

            modBehaviour.StartCoroutine(LoadMesh(go, objectPath));
            modBehaviour.StartCoroutine(LoadTexture(go, imagePath));

            return(go);
        }
コード例 #8
0
ファイル: ModInputHandler.cs プロジェクト: TAImatem/owml
        public IModInputCombination RegisterCombination(IModBehaviour mod, string name, string combination)
        {
            var combo = new ModInputCombination(mod.ModHelper.Manifest, _console, name, combination);

            switch (SwapCombination(combo, false))
            {
            case RegistrationCode.InvalidCombination:
                _console.WriteLine($"Failed to register \"{combo.FullName}\": invalid combination!");
                return(null);

            case RegistrationCode.CombinationTooLong:
                _console.WriteLine($"Failed to register \"{combo.FullName}\": too long!");
                return(null);

            case RegistrationCode.CombinationTaken:
                _console.WriteLine($"Failed to register \"{combo.FullName}\": already in use by following mods:");
                var collisions = GetCollisions(combo.Hashes);
                foreach (var collision in collisions)
                {
                    _console.WriteLine($"\"{collision}\"");
                }
                return(null);

            case RegistrationCode.AllNormal:
                return(combo);

            default:
                return(null);
            }
        }
コード例 #9
0
        private void AddConfigInput(string key, object value, int index)
        {
            if (value is bool)
            {
                AddToggleInput(key, index);
                return;
            }

            if (value is string)
            {
                AddTextInput(key, index);
                return;
            }

            if (new[] { typeof(long), typeof(int), typeof(float), typeof(double) }.Contains(value.GetType()))
            {
                AddNumberInput(key, index);
                return;
            }

            if (value is JObject obj)
            {
                var type = (string)obj["type"];
                if (type == "slider")
                {
                    AddSliderInput(key, obj, index);
                    return;
                }
                if (type == "toggle")
                {
                    AddToggleInput(key, obj, index);
                    return;
                }

                _console.WriteLine("Error: unrecognized complex setting: " + value);
                return;
            }

            _console.WriteLine("Error: unrecognized setting type: " + value.GetType());
        }
コード例 #10
0
ファイル: ModSorter.cs プロジェクト: misternebula/owml
        public IList <IModData> SortMods(IList <IModData> mods)
        {
            var modDict = new Dictionary <string, IModData>();
            var set     = new HashSet <Edge>();
            var modList = mods.Select(mod => mod.Manifest.UniqueName).ToList();

            foreach (var mod in mods)
            {
                modDict.Add(mod.Manifest.UniqueName, mod);

                foreach (var dependency in mod.Manifest.Dependencies)
                {
                    if (mod.Manifest.PriorityLoad && !modList.Contains(dependency))
                    {
                        _console.WriteLine($"Error! {mod.Manifest.UniqueName} (priority load) depends on a normal mod! Removing from load...");
                        modDict.Remove(mod.Manifest.UniqueName);
                        modList.Remove(mod.Manifest.UniqueName);
                    }
                    else
                    {
                        set.Add(new Edge(mod.Manifest.UniqueName, dependency));
                    }
                }
            }

            var sortedList = TopologicalSort(
                new HashSet <string>(modList),
                new HashSet <Edge>(set)
                );

            if (sortedList == null)
            {
                // Sorting has failed, return the original mod list
                _console.WriteLine("Error - Cyclic dependency found. Returning original load order...");
                return(mods);
            }

            sortedList.Reverse();
            return(sortedList.Select(mod => modDict[mod]).ToList());
        }
コード例 #11
0
ファイル: OWPatcher.cs プロジェクト: misternebula/owml
        private void PatchAssembly()
        {
            var patcher = new dnpatch.Patcher($"{_owmlConfig.ManagedPath}/Assembly-CSharp.dll");

            var target = new Target
            {
                Class  = PatchClass,
                Method = PatchMethod
            };
            var instructions        = patcher.GetInstructions(target).ToList();
            var patchedInstructions = GetPatchedInstructions(instructions);

            if (patchedInstructions.Count == 1)
            {
                _writer.WriteLine($"{PatchClass}.{PatchMethod} is already patched.");
                return;
            }

            if (patchedInstructions.Count > 1)
            {
                _writer.WriteLine($"Removing corrupted patch from {PatchClass}.{PatchMethod}.");
                foreach (var patchedInstruction in patchedInstructions)
                {
                    instructions.Remove(patchedInstruction);
                }
            }

            _writer.WriteLine($"Adding patch in {PatchClass}.{PatchMethod}.");

            var newInstruction = Instruction.Create(OpCodes.Call, patcher.BuildCall(typeof(ModLoader.ModLoader), "LoadMods", typeof(void), new Type[] { }));

            instructions.Insert(instructions.Count - 1, newInstruction);

            target.Instructions = instructions.ToArray();

            Patch(patcher, target);

            Save(patcher);
        }
コード例 #12
0
ファイル: VrPatcher.cs プロジェクト: misternebula/owml
        private void PatchGlobalManager(bool enableVR)
        {
            var currentPath = _owmlConfig.DataPath + "/globalgamemanagers";

            if (!File.Exists(currentPath))
            {
                _writer.WriteLine("Error: can't find " + currentPath);
                return;
            }

            var currentChecksum = CalculateChecksum(currentPath);

            _writer.WriteLine("Current checksum: " + currentChecksum);

            var backupPath = $"{_owmlConfig.DataPath}/globalgamemanagers.{currentChecksum}.bak";

            if (!File.Exists(backupPath))
            {
                _writer.WriteLine("Taking backup of globalgamemanagers.");
                File.Copy(currentPath, backupPath, true);
            }

            var vrPath = $"{_owmlConfig.DataPath}/globalgamemanagers.{currentChecksum}.vr";

            if (enableVR && !File.Exists(vrPath))
            {
                _writer.WriteLine("Patching globalgamemanagers for VR...");
                if (PatchChecksums.Contains(currentChecksum))
                {
                    var patchPath = $"{_owmlConfig.OWMLPath}VR/{currentChecksum}";
                    ApplyPatch(currentPath, vrPath, patchPath);
                }
                else
                {
                    var patchedChecksum = PatchChecksums.FirstOrDefault(checksum =>
                                                                        CalculateChecksum($"{_owmlConfig.DataPath}/globalgamemanagers.{checksum}.vr") == currentChecksum);
                    if (!string.IsNullOrEmpty(patchedChecksum))
                    {
                        _writer.WriteLine("Already patched! Original checksum: " + patchedChecksum);
                        vrPath = $"{_owmlConfig.DataPath}/globalgamemanagers.{patchedChecksum}.vr";
                    }
                    else
                    {
                        _writer.WriteLine($"Error: invalid checksum: {currentChecksum}. " +
                                          "VR patch for this version of Outer Wilds is not yet supported by OWML.");
                        return;
                    }
                }
            }

            var copyFrom = enableVR ? vrPath : backupPath;

            File.Copy(copyFrom, currentPath, true);
        }
コード例 #13
0
        public void AddPrefix <T>(string methodName, Type patchType, string patchMethodName)
        {
            var prefix = patchType.GetAnyMethod(patchMethodName);

            if (prefix == null)
            {
                _logger.Log("prefix is null");
                _console.WriteLine("prefix is null");
                return;
            }
            Patch <T>(methodName, prefix, null, null);
        }
コード例 #14
0
ファイル: Owo.cs プロジェクト: misternebula/owml
        public void LoadMods()
        {
            if (_owmlConfig.Verbose)
            {
                _console.WriteLine("Verbose mode is enabled");
                Application.logMessageReceived += OnLogMessageReceived;
            }
            var normalMods   = _modFinder.GetMods().Where(mod => !mod.Manifest.PriorityLoad).ToList();
            var sortedNormal = _sorter.SortMods(normalMods);

            var priorityMods   = _modFinder.GetMods().Where(mod => mod.Manifest.PriorityLoad).ToList();
            var sortedPriority = _sorter.SortMods(priorityMods);

            var modNames   = _modFinder.GetMods().Where(mod => mod.Config.Enabled).Select(mod => mod.Manifest.UniqueName).ToList();
            var sortedMods = sortedPriority.Concat(sortedNormal);

            foreach (var mod in sortedMods)
            {
                foreach (var dependency in mod.Manifest.Dependencies)
                {
                    if (!modNames.Contains(dependency))
                    {
                        _console.WriteLine($"Error! {mod.Manifest.UniqueName} needs {dependency}, but it's disabled!");
                    }
                }
                var modType = LoadMod(mod);
                if (modType == null)
                {
                    _logger.Log("Mod type is null, skipping");
                    _menus.ModsMenu.AddMod(mod, null);
                    continue;
                }
                var helper  = CreateModHelper(mod);
                var initMod = InitializeMod(modType, helper);
                _menus.ModsMenu.AddMod(mod, initMod);
                _modList.Add(initMod);
            }
        }
コード例 #15
0
ファイル: HarmonyHelper.cs プロジェクト: TAImatem/owml
        private HarmonyInstance CreateInstance()
        {
            HarmonyInstance harmony;

            try
            {
                _logger.Log("Creating harmony instance");
                harmony = HarmonyInstance.Create("com.alek.owml");
                _logger.Log("Created harmony instance");
            }
            catch (Exception ex)
            {
                _console.WriteLine($"Exception while creating harmony instance: {ex}");
                return(null);
            }
            if (harmony == null)
            {
                _console.WriteLine("Error: harmony instance is null");
            }
            return(harmony);
        }
コード例 #16
0
        public IList <IModData> GetMods()
        {
            if (!Directory.Exists(_config.ModsPath))
            {
                _console.WriteLine("Warning: Mods folder not found!");
                return(new List <IModData>());
            }
            var manifestFilenames = Directory.GetFiles(_config.ModsPath, "manifest.json", SearchOption.AllDirectories);
            var mods = new List <IModData>();

            foreach (var manifestFilename in manifestFilenames)
            {
                var json     = File.ReadAllText(manifestFilename);
                var manifest = JsonConvert.DeserializeObject <ModManifest>(json);
                manifest.ModFolderPath = manifestFilename.Substring(0, manifestFilename.IndexOf("manifest.json"));
                var modData = GetModData(manifest);
                mods.Add(modData);
            }
            return(mods);
        }
コード例 #17
0
        private List <long> StringToHashes(string combinations)
        {
            var hashes = new List <long>();

            foreach (var combo in combinations.Split('/'))
            {
                var hash = ModInputLibrary.StringToHash(combo);
                if (hash <= 0)
                {
                    _console.WriteLine($"Warning: Invalid part of combo in {FullName}: {combo}, " +
                                       ModInputLibrary.GetReadableMessage((RegistrationCode)hash));
                    continue;
                }
                hashes.Add(hash);
                if (hash < ModInputLibrary.MaxUsefulKey)
                {
                    _singles.Add((KeyCode)hash);
                }
            }
            return(hashes);
        }
コード例 #18
0
ファイル: App.cs プロジェクト: misternebula/owml
        public void Run(string[] args)
        {
            _writer.WriteLine($"Started OWML v{_owmlManifest.Version}");
            _writer.WriteLine("For detailed log, see Logs/OWML.Log.txt");

            LocateGamePath();

            CopyGameFiles();

            CreateLogsDirectory();

            var hasPortArgument = CommandLineArguments.HasArgument(Constants.ConsolePortArgument);

            if (!hasPortArgument)
            {
                ListenForOutput();
            }

            var mods = _modFinder.GetMods();

            ShowModList(mods);

            PatchGame(mods);

            StartGame(args);

            if (hasPortArgument)
            {
                ExitConsole();
            }

            Console.ReadLine();
        }