Skip to content

Instantly share code, notes, and snippets.

@pardeike
Last active October 6, 2018 20:43
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pardeike/ba995510a468c00ce54091183a2f4aca to your computer and use it in GitHub Desktop.
Save pardeike/ba995510a468c00ce54091183a2f4aca to your computer and use it in GitHub Desktop.
Add this class to your mod to make it 0.9 and 1.0 compatible and put 1.0 into the About.xml
using Harmony;
using RimWorld;
using Steamworks;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml;
using Verse;
using Verse.Steam;
// Prerequisites:
// - your project needs to use latest Harmony release
// - you mark your mod as 1.0 in the About.xml file
// - prepare Fluffy's Mod Manager's Manifest.xml file
// How to get started:
// - add this file to your project
// - update the About.xml
// - update Manifest.xml file with <targetVersions><li>0.19.0</li><li>1.0.0</li></targetVersions>
// - test with 0.19+ and 1.0
// - use MethodInvoker.GetHandler(methodInfo) to create dynamic calls for API that is different in both versions
// Whenever at least one mod has this code, all mods that have <targetVersions> define will be compatible with these versions
// Also, when you upload a mod to the workshop that has <targetVersions> defined, it will generate multiple version tags on steam
[StaticConstructorOnStartup]
static class MultiVersionModFix
{
const string _multiversionmodfix = "multiversionmodfix";
static readonly Dictionary<string, List<System.Version>> cachedVersions = new Dictionary<string, List<System.Version>>();
static MultiVersionModFix()
{
var instance = HarmonyInstance.Create(_multiversionmodfix);
var aBool = false;
var m_VersionCompatible = AccessTools.Property(typeof(ModMetaData), nameof(ModMetaData.VersionCompatible)).GetGetMethod();
var m_VersionCompatiblePostfix = SymbolExtensions.GetMethodInfo(() => VersionCompatible_Postfix(null, ref aBool));
instance.PostfixOnce(m_VersionCompatible, m_VersionCompatiblePostfix);
var m_SetWorkshopItemDataFrom = AccessTools.Method(typeof(Workshop), "SetWorkshopItemDataFrom");
var m_SetWorkshopItemDataFrom_Postfix = SymbolExtensions.GetMethodInfo(() => SetWorkshopItemDataFrom_Postfix(default(UGCUpdateHandle_t), null));
instance.PostfixOnce(m_SetWorkshopItemDataFrom, m_SetWorkshopItemDataFrom_Postfix);
}
static void PostfixOnce(this HarmonyInstance instance, MethodInfo original, MethodInfo postfix)
{
var postfixes = instance.GetPatchInfo(original)?.Postfixes;
if (postfixes == null || !postfixes.Any(patch => patch != null && patch.owner == _multiversionmodfix))
instance.Patch(original, postfix: new HarmonyMethod(postfix));
}
static List<System.Version> GetTaggedVersions(string rootDir)
{
if (cachedVersions.TryGetValue(rootDir, out var cached))
return cached;
try
{
var xml = new XmlDocument();
xml.Load(rootDir + Path.DirectorySeparatorChar + "About" + Path.DirectorySeparatorChar + "Manifest.xml");
var tags = xml.SelectNodes("/Manifest/targetVersions/li").Cast<XmlNode>().Select(node => node.InnerText);
var result = tags
.Where(tag => VersionControl.IsWellFormattedVersionString(tag))
.Select(tag => VersionControl.VersionFromString(tag)).ToList();
cachedVersions[rootDir] = result;
return result;
}
catch (System.Exception)
{
cachedVersions[rootDir] = null;
return null;
}
}
static void VersionCompatible_Postfix(ModMetaData __instance, ref bool __result)
{
var taggedVersions = GetTaggedVersions(__instance.RootDir.FullName);
if (taggedVersions.NullOrEmpty()) return;
var currentVersion = VersionControl.CurrentVersion;
__result = taggedVersions
.Any(version =>
version.Major == currentVersion.Major &&
version.Minor == currentVersion.Minor &&
(version.Build == 0 || version.Build == currentVersion.Build));
}
static void SetWorkshopItemDataFrom_Postfix(UGCUpdateHandle_t updateHandle, WorkshopItemHook hook)
{
var taggedVersions = GetTaggedVersions(hook.Directory.FullName);
if (!taggedVersions.NullOrEmpty())
{
var tags = taggedVersions.Select(version => version.Major + "." + version.Minor);
tags.Add("Mod");
SteamUGC.SetItemTags(updateHandle, tags.Distinct().ToList());
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment