Giter VIP home page Giter VIP logo

omodframework's Introduction

OMODFramework

Nuget CI

The Oblivion Mod Manager by Timeslip was a utility tool for managing Oblivion mods and was the most prominent mod manager during it's time. One of the crazy features it has was .omod files and the multiple different ways of creating installation scripts for them. 10 years later and you still needed to use parts of the tool in order to install OMODs. This library solves the issue and pain involved when dealing with OMODs and is written in modern C# code targeting .NET Standard 2.1 and .NET 5.

Features

  • File Extraction
  • OMOD Creation (please don't create new OMODs, only use this for testing)
  • Script Execution (only OBMM and inlined C# scripts)

Usage

Extraction

//OMOD implements IDisposable
using var omod = new OMOD("path-to-file.omod");

/*
 * Use on of the different extraction methods:
 *  - ExtractFiles
 *  - ExtractFilesParallel (only for data files)
*/

omod.ExtractFiles(true, "output\\data");

//not every OMOD has plugin files so make sure to check before extracting
if (omod.HasEntryFile(OMODEntryFileType.PluginsCRC))
    omod.ExtractFiles(false, "output\\plugins");

Script Execution

Script Execution is very complex compared to simple extraction. You need the OMODFramework.Scripting library for this and have to use the OMODScriptRunner class. The important thing to understand is that there are multiple different types of scripts:

  • OBMM (custom scripting language of the Oblivion Mod Manager, see this for more infos)
  • C#
  • Python (using IronPython)
  • Visual Basic

The OMODFramework only supports OBMM scripts and inlined C# scripts. OBMM scripts are the most common with probably 95% of all scripts being in this language while the rest are C# scripts. I have yet to find any script in Python and Visual Basic. The OMODFramework only supports running inlined C# scripts, as opposed to the Oblivion Mod Manager which compiled the scripts and then used DI to make it run, because script compilation changed in newer .NET versions and also pose a huge security risk. There are also not many C# scripts out there and I included the biggset scripts:

If you found another C# script, create a new issue and I will look into inlining it as well. Now onto the actual script execution:

using var omod = new OMOD("path-to-file.omod");

IExternalScriptFunctions scriptFunctions = new MyExternalScriptFunctions();
var settings = new OMODScriptSettings(scriptFunctions);

var srd = OMODScriptRunner.RunScript(omod, settings);

You have to create a new class that implements IExternalScriptFunctions before you want to execute any script. This interface provides functions that can be called during script execution which this library can not do alone. You do not have to implement every function as some are never called depending on your settings (make sure to adjust OMODScriptSettings) but most of them like Select, Message or the Display* functions are very common in OBMM scripts.

OMODScriptRunner.RunScript will run the script and return ScriptReturnData which contains everything you need to do after script execution in order to install the mod. This library provides additional utility functions like ScriptReturnData.CopyAllDataFiles or ExecuteEdit functions for edits that need to be done after script execution.

omodframework's People

Contributors

anyoldname3 avatar dependabot-preview[bot] avatar erri120 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

anyoldname3

omodframework's Issues

Multithreaded extraction

We discussed this a little in the past, but I can't remember what came of it. As extracting OMODs takes so long, it would be nice if more than one thread could be used. I've not checked whether OBMM used multiple threads during extraction.

If the format isn't amenable to this, I feel like it's probably better to have a written record of it that can be referred to in the future.

System.ArgumentOutOfRangeException from Script Execution

Describe the bug
The animation installer OMOD script behaves inconsistently between OBMM and OMODFramework. This kills the OMOD.

To Reproduce

  • Download the 7z for non-Wrye Bash users.
  • Extract it.
  • Attempt to run the script in the animations installer OMOD with OMODFramework.
  • Observe a System.ArgumentOutOfRangeException when the script reaches line 87.

Versions
OMODFramework-Version: 2.0.1, master
.NET Framework-Version: .NET 4.8

Additional context
The script uses string functions to emulate arrays. I don't believe all the string functions behave the same way, although it could be that string interpolation isn't behaving consistently, too.

The offending line is

RemoveString vMapName "%vMapName%" 0 %vLen%

Using a tweaked version of the OMOD, adding the line

Message "Line is 'RemoveString vMapName \"%vMapName%\" 0 %vLen%'"

produces different results in OBMM and OMODFramework.

With OBMM:
image
With OMODFramework:
image

Extraction to disk fallback

Instead of having everything purely in Memory, offload to disk if desired or the system has not enough resources, goes hand in hand with #29

Scripted OMODs can't be installed without being extracted twice

As per https://discordapp.com/channels/265929299490635777/265929879718068224/730480596387758191, ScriptReturnData::RunScript calls omod.GetDataFiles and omod.GetPlugins as running the script uses them, but then these paths aren't remembered or made accessible to me, so I'm forced to extract them again.

Possible solutions include:

  • The OMOD object should remember where it's been extracted to and return that path if asked to extract itself again (and there should probably be some way of telling it that it's been meddled with and needs redoing).
  • The extracted paths should end up in the ScriptReturnData and be used automatically by Pretty.
  • The extracted paths should be given to me somehow so I can pass them to Pretty.
  • RunScript should let me pass in already-extracted data files and plugins paths.
  • The script should only work with the list of files from the .crc files, rather than the extracted files themselves.

No 2.0.1 Scripting package

#22 fixed a bug after the 2.0.0 release. The 2.0.1 release only happened for the main package, but this bug was in the scripting DLL, so the scripting package needs a 2.0.1 release, too.

2.0.1 package is missing PDB files

The 2.0.0 package included debugging symbols, but these have been excluded from the 2.0.1 package. I can't remember if you said you'd fixed whatever caused this when we discussed it before, but I thought it was better to have an issue for it so it wasn't forgotten.

Add Memory Limits

System can run out of memory during extraction on the dotnetcore branch if the system has low amount of resources.

C# script output path dependent on when scripting DLL gets loaded

The DotNetScriptHandler is static and its output path is set based on a static field called ScriptOutputPath. This means that it gets initialised when the scripting DLL gets loaded, and isn't updated if the temp path gets changed later. This is bad because it's hard to predict which path is actually going to get used - a user of the library can't control how eagerly the scripting DLL gets loaded, so it might happen before they've set a custom temp path, or after, or, if they change it several times, potentially between any two of those changes (which is how I discovered the issue - I was cheekily using a per-mod temp path so it definitely ended up on the right drive, making the final install process a rename rather than a copy-and-delete, and it would always try and build into the temp directory for the first scripted OMOD, which no longer existed).

As C# has properties, it's probably pretty simple to just update the temp path throughout whenever it gets changed. Alternatively, the main reason someone's likely to want a custom temp path is for the aforementioned reason of ensuring it's on the same drive as the final installation location, in which case there's no advantage to using anything other than the default.

I'm going to attempt to work around this in the MO2 OMOD installer by making sure the DLL gets loaded before the custom temp path is set.

C# scripts don't compile with default DllPath

Branch is master.

With DllPath left with its default value, the C# script compiler is told to link with OMODFramework.dll, but it's OMODFramework.Scripting.dll that exports the functions they need.

#23 is a hacky fix just to demonstrate what the problem was, but it's probably better to call into a function in the scripting DLL that calls GetExecutingAssembly to get the scripting DLL's path in a more reliable way.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.