Skip to content

Commit

Permalink
First 1.0 (exp) compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
mgreter committed Jun 28, 2024
1 parent 8a8ac97 commit 4d2a6ab
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 110 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ jobs:

steps:
- name: Check out repository code
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Call 7D2D compiler action
uses: OCB7D2D/OcbModCompiler@master
with:
v7d2d: 'V1.0'
name: "OcbInventoryMouseWheel"
version: "${{ github.ref_name }}"
token: "${{ secrets.GITHUB_TOKEN }}"
Expand Down
146 changes: 96 additions & 50 deletions Harmony/ModXmlPatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ private static bool EvaluateConditions(string conditions, XmlFile xml)
foreach (string xpath in conditions.Split(','))
{
bool negate = false;
List<XElement> xmlNodeList;
List<System.Xml.Linq.XElement> xmlNodeList;
if (xpath.StartsWith("!"))
{
negate = true;
Expand Down Expand Up @@ -140,13 +140,59 @@ private static bool EvaluateConditions(string conditions, XmlFile xml)
return true;
}

// Static dictionary for templating
static Dictionary<string, string> dict =
new Dictionary<string, string>();

// Helper class to keep correct template dict scoping
// Add new keys when initialized, restores old on close
private class DictScopeHelper : IDisposable
{
Dictionary<string, string> prev = null;
public DictScopeHelper(XElement element) =>
dict = GetTemplateValues(prev = dict, element);
public void Dispose() => dict = prev;
}

// Add placeholder keys to our template dictionary
private static Dictionary<string, string> GetTemplateValues(
Dictionary<string, string> parent, XElement child)
{
// Make a copy of the parent dictionary
Dictionary<string, string> dict =
new Dictionary<string, string>(parent);
// Add new template values to dictionary
foreach (var attr in child.Attributes())
{
if (!attr.Name.LocalName.StartsWith("tmpl-")) continue;
dict[attr.Name.LocalName.Substring(5)] = attr.Value;
}
// Return new dict
return dict;
}

// Replace all placeholder the dictionary contains
private static void ReplaceTemplateOccurences(
Dictionary<string, string> dict, ref string text)
{
foreach (var kv in dict)
text = text.Replace(
"{{" + kv.Key + "}}",
kv.Value);
}

// We need to call into the private function to proceed with XML patching
private static readonly MethodInfo MethodSinglePatch = AccessTools.Method(typeof(XmlPatcher), "singlePatch");

// Function to load another XML file and basically call the same PatchXML function again
private static bool IncludeAnotherDocument(XmlFile target, XmlFile parent, XElement element, string modName)
private static bool IncludeAnotherDocument(XmlFile target, XmlFile parent, XElement element, Mod mod)
{
bool result = true;

var modName = mod.Name;

// Add template values to dictionary
using (var tmpls = new DictScopeHelper(element))
foreach (XAttribute attr in element.Attributes())
{
// Skip unknown attributes
Expand All @@ -160,6 +206,7 @@ private static bool IncludeAnotherDocument(XmlFile target, XmlFile parent, XElem
{
string _text = File.ReadAllText(path, Encoding.UTF8)
.Replace("@modfolder:", "@modfolder(" + modName + "):");
ReplaceTemplateOccurences(dict, ref _text);
XmlFile _patchXml;
try
{
Expand All @@ -176,7 +223,7 @@ private static bool IncludeAnotherDocument(XmlFile target, XmlFile parent, XElem
continue;
}
result &= XmlPatcher.PatchXml(
target, _patchXml, modName);
target, element, _patchXml, mod);
}
catch (Exception ex)
{
Expand All @@ -198,43 +245,40 @@ private static bool IncludeAnotherDocument(XmlFile target, XmlFile parent, XElem

static int count = 0;

public static bool PatchXml(XmlFile xmlFile, XmlFile patchXml, XElement node, string patchName)
public static bool PatchXml(XmlFile xmlFile,
XmlFile patchXml, XElement node, Mod mod)
{
bool result = true;
count++;
ParserStack stack = new ParserStack();
stack.count = count;
foreach (XElement child in node.Elements())
{
if (child.NodeType == XmlNodeType.Element)
// Patched to support includes
if (child.Name == "modinc")
{
if (!(child is XElement element)) continue;
// Patched to support includes
if (child.Name == "include")
{
// Will do the magic by calling our functions again
IncludeAnotherDocument(xmlFile, patchXml, element, patchName);
}
else if (child.Name == "echo")
{
foreach (XAttribute attr in child.Attributes())
{
if (attr.Name == "log") Log.Out("{1}: {0}", attr.Value, xmlFile.Filename);
if (attr.Name == "warn") Log.Warning("{1}: {0}", attr.Value, xmlFile.Filename);
if (attr.Name == "error") Log.Error("{1}: {0}", attr.Value, xmlFile.Filename);
if (attr.Name != "log" && attr.Name != "warn" && attr.Name != "error")
Log.Warning("Echo has no valid name (log, warn or error)");
}
}
// Otherwise try to apply the patches found in child element
else if (!ApplyPatchEntry(xmlFile, patchXml, element, patchName, ref stack))
// Will do the magic by calling our functions again
IncludeAnotherDocument(xmlFile, patchXml, child, mod);
}
else if (child.Name == "echo")
{
foreach (XAttribute attr in child.Attributes())
{
IXmlLineInfo lineInfo = (IXmlLineInfo)element;
Log.Warning(string.Format("XML patch for \"{0}\" from mod \"{1}\" did not apply: {2} (line {3} at pos {4})",
xmlFile.Filename, patchName, element.ToString(), lineInfo.LineNumber, lineInfo.LinePosition));
result = false;
if (attr.Name == "log") Log.Out("{1}: {0}", attr.Value, xmlFile.Filename);
if (attr.Name == "warn") Log.Warning("{1}: {0}", attr.Value, xmlFile.Filename);
if (attr.Name == "error") Log.Error("{1}: {0}", attr.Value, xmlFile.Filename);
if (attr.Name != "log" && attr.Name != "warn" && attr.Name != "error")
Log.Warning("Echo has no valid name (log, warn or error)");
}
}
// Otherwise try to apply the patches found in child element
else if (!ApplyPatchEntry(xmlFile, child, patchXml, mod, ref stack))
{
IXmlLineInfo lineInfo = child;
Log.Warning(string.Format("XML patch for \"{0}\" from mod \"{1}\" did not apply: {2} (line {3} at pos {4})",
xmlFile.Filename, mod.Name, child.ToString(), lineInfo.LineNumber, lineInfo.LinePosition));
result = false;
}
}
return result;
}
Expand All @@ -249,18 +293,19 @@ public struct ParserStack

// Entry point instead of (private) `XmlPatcher.singlePatch`
// Implements conditional patching and also allows includes
private static bool ApplyPatchEntry(XmlFile _xmlFile, XmlFile _patchXml, XElement _patchElement, string _patchName, ref ParserStack stack)
private static bool ApplyPatchEntry(XmlFile _targetFile, XElement _patchElement,
XmlFile _patchFile, Mod _patchingMod, ref ParserStack stack)
{

// Only support root level
switch (_patchElement.Name.ToString())
{

case "include":
case "modinc":

// Call out to our include handler
return IncludeAnotherDocument(_xmlFile, _patchXml,
_patchElement, _patchName);
return IncludeAnotherDocument(_targetFile, _patchFile,
_patchElement, _patchingMod);

case "modif":

Expand All @@ -278,11 +323,11 @@ private static bool ApplyPatchEntry(XmlFile _xmlFile, XmlFile _patchXml, XElemen
continue;
}
// Evaluate one or'ed condition
if (EvaluateConditions(attr.Value, _xmlFile))
if (EvaluateConditions(attr.Value, _targetFile))
{
stack.PreviousResult = true;
return PatchXml(_xmlFile, _patchXml,
_patchElement, _patchName);
return PatchXml(_targetFile, _patchFile,
_patchElement, _patchingMod);
}
}

Expand Down Expand Up @@ -311,11 +356,11 @@ private static bool ApplyPatchEntry(XmlFile _xmlFile, XmlFile _patchXml, XElemen
continue;
}
// Evaluate one or'ed condition
if (EvaluateConditions(attr.Value, _xmlFile))
if (EvaluateConditions(attr.Value, _targetFile))
{
stack.PreviousResult = true;
return PatchXml(_xmlFile, _patchXml,
_patchElement, _patchName);
return PatchXml(_targetFile, _patchFile,
_patchElement, _patchingMod);
}
}

Expand All @@ -328,16 +373,16 @@ private static bool ApplyPatchEntry(XmlFile _xmlFile, XmlFile _patchXml, XElemen
stack.IfClauseParsed = false;
// Abort else when last result was true
if (stack.PreviousResult) return true;
return PatchXml(_xmlFile, _patchXml,
_patchElement, _patchName);
return PatchXml(_targetFile, _patchFile,
_patchElement, _patchingMod);

default:
// Reset flags first
stack.IfClauseParsed = false;
stack.PreviousResult = true;
// Dispatch to original function
return (bool)MethodSinglePatch.Invoke(null,
new object[] { _xmlFile, _patchElement, _patchName });
new object[] { _targetFile, _patchElement, _patchFile, _patchingMod });
}
}

Expand All @@ -348,8 +393,9 @@ public class XmlPatcher_PatchXml
{
static bool Prefix(
ref XmlFile _xmlFile,
ref XmlFile _patchXml,
ref string _patchName,
ref XmlFile _patchFile,
XElement _containerElement,
ref Mod _patchingMod,
ref bool __result)
{
// According to Harmony docs, returning false on a prefix
Expand All @@ -360,21 +406,21 @@ static bool Prefix(
// Might also be something solved with latest versions,
// as the game uses a rather old HarmonyX version (2.2).
// To address this we simply "consume" one of the args.
if (_patchXml == null) return false;
XElement element = _patchXml.XmlDoc.Root;
if (_patchFile == null) return false;
XElement element = _patchFile.XmlDoc.Root;
if (element == null) return false;
string version = element.GetAttribute("patcher-version");
if (!string.IsNullOrEmpty(version))
{
// Check if version is too new for us
if (int.Parse(version) > 4) return true;
if (int.Parse(version) > 5) return true;
}
// Call out to static helper function
__result = PatchXml(
_xmlFile, _patchXml,
element, _patchName);
_xmlFile, _patchFile,
element, _patchingMod);
// First one wins
_patchXml = null;
_patchFile = null;
return false;
}
}
Expand Down
16 changes: 0 additions & 16 deletions Harmony/WheelItemStack.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,6 @@
public static class WheelItemStack
{

public static UIScrollView GetParentScrollView(XUiController ctr)
{
var parent = ctr.Parent;
while (parent != null)
{
var vp = parent.ViewComponent;
if (vp != null && vp.EventOnScroll)
{
var ui = vp.UiTransform?.GetComponent<UIScrollView>();
if (ui != null) return ui;
}
parent = parent.Parent;
}
return null;
}

public static int TransferItems(int amount,
ItemStack src, Action<ItemStack> setSrc,
ItemStack dst, Action<ItemStack> setDst)
Expand Down
16 changes: 2 additions & 14 deletions Harmony/XUiC_WheelItemStack.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,9 @@ public class XUiC_WheelItemStack : XUiC_ItemStack

protected bool IsOver = false;

protected UIScrollView ScrollView = null;

public override void Init()
{
base.Init();
ScrollView = WheelItemStack
.GetParentScrollView(this);
}

private ItemStack DnDStack => xui.dragAndDrop.CurrentStack;
Expand Down Expand Up @@ -43,22 +39,14 @@ protected virtual int TransferItems(int amount,
return amount;
}

protected override void OnHovered(bool _isOver)
public override void OnHovered(bool _isOver)
{
IsOver = _isOver;
base.OnHovered(_isOver);
}

protected override void OnScrolled(float _delta)
public override void OnScrolled(float _delta)
{
// Check for edge case where we are actually inside another
// Scrollable View (enforce shift key in that situation)
if (ScrollView != null && !Input.GetKey(KeyCode.LeftShift))
{
// Otherwise "bubble" event up
ScrollView.Scroll(_delta);
return;
}
// Process the item transfer
if (IsLocked || StackLock)
{
Expand Down
21 changes: 2 additions & 19 deletions Harmony/XUiC_WheelRequiredItemStack.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,6 @@ public class XUiC_WheelRequiredItemStack : XUiC_RequiredItemStack

protected bool IsOver = false;

protected UIScrollView ScrollView = null;

public override void Init()
{
base.Init();
ScrollView = WheelItemStack
.GetParentScrollView(this);
}

private ItemStack DnDStack => xui.dragAndDrop.CurrentStack;

private void SetSlot(ItemStack stack) => ItemStack = stack;
Expand Down Expand Up @@ -43,22 +34,14 @@ protected virtual int TransferItems(int amount,
return amount;
}

protected override void OnHovered(bool _isOver)
public override void OnHovered(bool _isOver)
{
IsOver = _isOver;
base.OnHovered(_isOver);
}

protected override void OnScrolled(float _delta)
public override void OnScrolled(float _delta)
{
// Check for edge case where we are actually inside another
// Scrollable View (enforce shift key in that situation)
if (ScrollView != null && !Input.GetKey(KeyCode.LeftShift))
{
// Otherwise "bubble" event up
ScrollView.Scroll(_delta);
return;
}
// Process the item transfer
if (IsLocked || StackLock)
{
Expand Down
Binary file modified InventoryMouseWheel.dll
Binary file not shown.
2 changes: 1 addition & 1 deletion ModInfo.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
<Description value="Use mouse scroll wheel to move inventory items." />
<Website value="https://github.com/OCB7D2D/OcbInventoryMouseWheel" />
<Author value="ocbMaurice" />
<Version value="0.2.2" />
<Version value="0.3.0" />
</xml>
Loading

0 comments on commit 4d2a6ab

Please sign in to comment.