using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("polymeric")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © polymeric. All rights reserved.")]
[assembly: AssemblyDescription("A mod assembly for TMfDS v1.2.1")]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: AssemblyInformationalVersion("1.0.2+8aa99e7c0c6c5bfe38b893c12027481c1f4856dc")]
[assembly: AssemblyProduct("Better Signal Compiler")]
[assembly: AssemblyTitle("Better Signal Compiler")]
[assembly: AssemblyVersion("1.0.2.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace polymeric.BetterSignalCompiler
{
public static class DelegatesAndRefs
{
public static readonly FieldRef<CompilerResult, string> CompilerResult__errorMsg = AccessTools.FieldRefAccess<CompilerResult, string>("errorMsg");
}
public static class HarmonyPatches
{
[HarmonyPatch(typeof(C_Reformatter), "CompileStringToSignal")]
public static class Patch__C_Reformatter__CompileStringToSignal
{
public static void Prefix(ref bool __runOriginal, ref SignalMessage __result, string input, ref CompilerResult cr)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
if (__runOriginal)
{
__runOriginal = false;
__result = MwisCompiler.CompileStringToSignal(input, ref cr);
}
}
}
public static void PatchInClassShallow(Harmony harmony, Type outerClass)
{
foreach (Type item in from type in outerClass.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic)
where HarmonyMethodExtensions.GetFromType(type).Count > 0
select type)
{
harmony.CreateClassProcessor(item).Patch();
}
}
}
public enum TokenizeResultKind
{
Word,
Numeral,
BareId,
BareIdBig
}
public class TokenizeResult
{
public readonly TokenizeResultKind kind;
public readonly int id;
public readonly int start;
public readonly int end;
public TokenizeResult(TokenizeResultKind kind, int id, int start, int end)
{
this.kind = kind;
this.id = id;
this.start = start;
this.end = end;
}
public static int PartitionPointEndLtEqNeedle(List<TokenizeResult> list, int first, int last, int needle)
{
int num = last - first;
while (num > 0)
{
int num2 = num / 2;
int num3 = first + num2;
if (list[num3].end <= needle)
{
first = num3 + 1;
num -= num2 + 1;
}
else
{
num = num2;
}
}
return first;
}
}
public class MwisWeight : IComparable<MwisWeight>
{
public readonly uint nonWhitespaceChars;
public readonly uint tokensPenalty;
public MwisWeight(uint nonWhitespaceChars, uint tokensPenalty)
{
this.nonWhitespaceChars = nonWhitespaceChars;
this.tokensPenalty = tokensPenalty;
}
public int CompareTo(MwisWeight other)
{
return (nonWhitespaceChars, other.tokensPenalty).CompareTo((other.nonWhitespaceChars, tokensPenalty));
}
public static MwisWeight operator +(MwisWeight x, MwisWeight y)
{
return new MwisWeight(x.nonWhitespaceChars + y.nonWhitespaceChars, x.tokensPenalty + y.tokensPenalty);
}
}
public enum CompileErrorTypeInternal
{
NaN,
EntryNotFound,
EmptyEntry,
Ambiguous,
BareIdIntegerTooWide
}
public static class CompileErrorTypeInternalExtensions
{
public static string GetString(this CompileErrorTypeInternal ceti)
{
return ceti switch
{
CompileErrorTypeInternal.NaN => "Not a Number",
CompileErrorTypeInternal.EntryNotFound => "Entry not found",
CompileErrorTypeInternal.EmptyEntry => "Null Input",
CompileErrorTypeInternal.Ambiguous => "Ambiguous",
CompileErrorTypeInternal.BareIdIntegerTooWide => "ID out of bounds",
_ => "Miscellaneous Error",
};
}
}
public static class MwisCompiler
{
private static readonly Regex BareIdRegex = new Regex("\\G\\|(-?[0-9]+)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
public static SignalMessage CompileStringToSignal(string input, ref CompilerResult cr)
{
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
//IL_0a27: Unknown result type (might be due to invalid IL or missing references)
//IL_0a36: Unknown result type (might be due to invalid IL or missing references)
//IL_0873: Unknown result type (might be due to invalid IL or missing references)
Plugin.Singleton.logger.LogDebug((object)("CompileStringToSignal input: " + input));
if (input.Trim() == "")
{
cr.compilerResultTag = (CompilerResultTag)1;
cr.LogError(input, (CompileErrorType)2);
Plugin.Singleton.logger.LogDebug((object)"CompileStringToSignal cr.LogError: EmptyEntry");
return new SignalMessage
{
signals = Array.Empty<int>()
};
}
Trie<int> trie = new Trie<int>();
foreach (var (id, word) in UserDictionary.Instance.terms)
{
trie.Insert(id, word);
}
List<TokenizeResult> list = new List<TokenizeResult>();
for (int i = 0; i < input.Length; i++)
{
foreach (TriePrefix<int> item7 in trie.Prefixes(input, i))
{
list.Add(new TokenizeResult(TokenizeResultKind.Word, item7.id, i, i + item7.length));
}
if (input[i] >= '0' && input[i] <= '9')
{
list.Add(new TokenizeResult(TokenizeResultKind.Numeral, input[i] - 48, i, i + 1));
}
if (!Plugin.Singleton.configParserParseBareIds.Value)
{
continue;
}
Match match = BareIdRegex.Match(input, i);
if (match.Success)
{
if (int.TryParse(match.Groups[1].Value, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out var result))
{
list.Add(new TokenizeResult(TokenizeResultKind.BareId, result, i, i + match.Length));
}
else
{
list.Add(new TokenizeResult(TokenizeResultKind.BareIdBig, 0, i, i + match.Length));
}
}
}
list.Sort((TokenizeResult x, TokenizeResult y) => (x.end, x.start).CompareTo((y.end, y.start)));
MwisWeight[] array = new MwisWeight[list.Count + 1];
int[] array2 = new int[list.Count + 1];
MwisWeight[] array3 = new MwisWeight[list.Count + 1];
array[0] = new MwisWeight(0u, 0u);
array2[0] = 0;
array3[0] = new MwisWeight(0u, 0u);
for (int num2 = 1; num2 <= list.Count; num2++)
{
TokenizeResult tokenizeResult = list[num2 - 1];
uint num3 = 0u;
string text2 = input;
int start = tokenizeResult.start;
string text3 = text2.Substring(start, tokenizeResult.end - start);
for (int num4 = 0; num4 < text3.Length; num4++)
{
if (!char.IsWhiteSpace(text3[num4]))
{
num3++;
}
}
array[num2] = new MwisWeight(num3, 1u);
array2[num2] = TokenizeResult.PartitionPointEndLtEqNeedle(list, 0, num2 - 1, tokenizeResult.start);
MwisWeight mwisWeight = array[num2] + array3[array2[num2]];
MwisWeight mwisWeight2 = array3[num2 - 1];
array3[num2] = ((mwisWeight.CompareTo(mwisWeight2) > 0) ? mwisWeight : mwisWeight2);
}
List<int> list2 = new List<int>();
List<int> list3 = new List<int>();
int num5 = list.Count;
while (num5 > 0)
{
int num6 = (array[num5] + array3[array2[num5]]).CompareTo(array3[num5 - 1]);
if (num6 == 0)
{
list3.Add(num5);
}
if (num6 >= 0)
{
list2.Add(num5);
num5 = array2[num5];
}
else
{
num5--;
}
}
list2.Reverse();
list3.Reverse();
int[] array4 = new int[list2.Count];
List<(string, CompileErrorTypeInternal)> list4 = new List<(string, CompileErrorTypeInternal)>();
SortedDictionary<(int, int), (string, bool)> sortedDictionary = new SortedDictionary<(int, int), (string, bool)>();
int num7 = 0;
for (int num8 = 0; num8 < list2.Count; num8++)
{
TokenizeResult tokenizeResult2 = list[list2[num8] - 1];
if (tokenizeResult2.kind != TokenizeResultKind.BareIdBig)
{
array4[num8] = tokenizeResult2.id;
sortedDictionary.Add((tokenizeResult2.start, tokenizeResult2.end), ($"|{tokenizeResult2.id}", true));
}
else
{
string text4 = input;
int num4 = tokenizeResult2.start;
list4.Add((text4.Substring(num4, tokenizeResult2.end - num4), CompileErrorTypeInternal.BareIdIntegerTooWide));
sortedDictionary.Add((tokenizeResult2.start, tokenizeResult2.end), ("|TOOBIG:(", false));
}
CheckUncoveredNonWhitespace(list4, sortedDictionary, input, num7, tokenizeResult2.start);
num7 = tokenizeResult2.end;
}
if (num7 < input.Length)
{
CheckUncoveredNonWhitespace(list4, sortedDictionary, input, num7, input.Length);
}
Plugin.Singleton.logger.LogDebug((object)("CompileStringToSignal signals: " + string.Join(", ", array4)));
foreach (int item8 in list3)
{
List<TokenizeResult> list5 = new List<TokenizeResult>();
List<TokenizeResult> list6 = new List<TokenizeResult>();
int num9 = array2[item8];
TokenizeResult item = list[item8 - 1];
list5.Add(item);
int num10 = item8 - 1;
while (num9 != num10)
{
if (num9 > num10)
{
if ((array[num9] + array3[array2[num9]]).CompareTo(array3[num9 - 1]) >= 0)
{
TokenizeResult item2 = list[num9 - 1];
list5.Add(item2);
num9 = array2[num9];
}
else
{
num9--;
}
}
else if ((array[num10] + array3[array2[num10]]).CompareTo(array3[num10 - 1]) >= 0)
{
TokenizeResult item3 = list[num10 - 1];
list6.Add(item3);
num10 = array2[num10];
}
else
{
num10--;
}
}
list5.Reverse();
list6.Reverse();
for (int num11 = 0; num11 < list5.Count; num11++)
{
TokenizeResult tokenizeResult3 = list5[num11];
if (list5.Count == list6.Count)
{
sortedDictionary[(tokenizeResult3.start, tokenizeResult3.end)] = ($"|{tokenizeResult3.id}?{list6[num11].id}", false);
}
else
{
sortedDictionary[(tokenizeResult3.start, tokenizeResult3.end)] = ($"|{tokenizeResult3.id}?", false);
}
}
string text5 = "";
text5 += string.Join(" ", list5.Select(delegate(TokenizeResult tk)
{
string text7 = input;
int start2 = tk.start;
return text7.Substring(start2, tk.end - start2);
}));
text5 += " ? ";
text5 += string.Join(" ", list6.Select(delegate(TokenizeResult tk)
{
string text7 = input;
int start2 = tk.start;
return text7.Substring(start2, tk.end - start2);
}));
list4.Add((text5, CompileErrorTypeInternal.Ambiguous));
}
string text6;
if (Plugin.Singleton.configErrorLogAbbreviateTrace.Value)
{
List<string> list7 = new List<string>();
bool flag = false;
foreach (var value2 in sortedDictionary.Values)
{
var (item4, _) = value2;
if (value2.Item2)
{
if (!flag)
{
list7.Add("|...");
flag = true;
}
}
else
{
list7.Add(item4);
flag = false;
}
}
text6 = string.Join(" ", list7);
}
else
{
text6 = string.Join(" ", sortedDictionary.Select((KeyValuePair<(int, int), (string, bool)> pair) => pair.Value.Item1));
}
Plugin.Singleton.logger.LogDebug((object)("CompileStringToSignal trace: " + text6));
if (list4.Count > 0)
{
cr.compilerResultTag = (CompilerResultTag)1;
ref string reference = ref DelegatesAndRefs.CompilerResult__errorMsg.Invoke(cr);
reference = "- Compilation Failed -" + Environment.NewLine;
ConfigErrorLogDisplayFormat value = Plugin.Singleton.configErrorLogDisplayFormat.Value;
if (value == ConfigErrorLogDisplayFormat.TraceAndCount || value == ConfigErrorLogDisplayFormat.TraceAndVerbose)
{
reference = reference + text6 + Environment.NewLine + Environment.NewLine;
}
if (value == ConfigErrorLogDisplayFormat.TraceAndCount)
{
foreach (IGrouping<CompileErrorTypeInternal, (string, CompileErrorTypeInternal)> item9 in from err in list4
group err by err.Item2 into grp
orderby grp.Key
select grp)
{
reference = reference + $"{item9.Key.GetString()}: {item9.Count()}" + Environment.NewLine;
}
}
if (value == ConfigErrorLogDisplayFormat.Verbose || value == ConfigErrorLogDisplayFormat.TraceAndVerbose)
{
int num12 = 1;
foreach (var item10 in list4)
{
string item5 = item10.Item1;
CompileErrorTypeInternal item6 = item10.Item2;
reference = reference + $"{num12} - {item6.GetString()}: " + Environment.NewLine + item5 + Environment.NewLine;
num12++;
}
}
Plugin.Singleton.logger.LogDebug((object)("CompileStringToSignal errorMsg: " + reference));
}
return new SignalMessage
{
signals = array4
};
}
private static void CheckUncoveredNonWhitespace(List<(string, CompileErrorTypeInternal)> errors, SortedDictionary<(int, int), (string, bool)> traces, string input, int endPrev, int start)
{
int? num = null;
for (int i = endPrev; i < start; i++)
{
if (!char.IsWhiteSpace(input[i]))
{
int valueOrDefault = num.GetValueOrDefault();
if (!num.HasValue)
{
valueOrDefault = i;
num = valueOrDefault;
}
}
else if (num.HasValue)
{
int valueOrDefault = num.GetValueOrDefault();
string item = input.Substring(valueOrDefault, i - valueOrDefault);
traces.Add((num.GetValueOrDefault(), i), (item, false));
errors.Add((item, CompileErrorTypeInternal.EntryNotFound));
num = null;
}
}
if (num.HasValue)
{
int valueOrDefault = num.GetValueOrDefault();
string item2 = input.Substring(valueOrDefault, start - valueOrDefault);
traces.Add((num.GetValueOrDefault(), start), (item2, false));
errors.Add((item2, CompileErrorTypeInternal.EntryNotFound));
}
}
}
public enum ConfigErrorLogDisplayFormat
{
TraceAndCount,
TraceAndVerbose,
Verbose
}
[BepInPlugin("polymeric.BetterSignalCompiler", "Better Signal Compiler", "1.0.2")]
public class Plugin : BaseUnityPlugin
{
internal static Plugin Singleton;
public ManualLogSource logger;
public Harmony harmony;
public ConfigEntry<bool> configParserParseBareIds;
public ConfigEntry<ConfigErrorLogDisplayFormat> configErrorLogDisplayFormat;
public ConfigEntry<bool> configErrorLogAbbreviateTrace;
private Plugin()
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Expected O, but got Unknown
logger = ((BaseUnityPlugin)this).Logger;
harmony = new Harmony("polymeric.BetterSignalCompiler");
configParserParseBareIds = ((BaseUnityPlugin)this).Config.Bind<bool>("Parser", "ParseBareIds", true, "Enables parsing expressions of the form '|<integer>' (e.g. '|5', '|-244'), which directly specify frequency offsets.\nfalse: Do not parse '|<integer>' expressions.\ntrue: Parse '|<integer>' expressions.");
configErrorLogDisplayFormat = ((BaseUnityPlugin)this).Config.Bind<ConfigErrorLogDisplayFormat>("ErrorLog", "DisplayFormat", ConfigErrorLogDisplayFormat.Verbose, "Selects a formatting style for displaying compilation errors.\nTraceAndCount: Shows a compile trace, followed by a count of each error type.\nTraceAndVerbose: Shows a compile trace, followed by every error.\nVerbose: Shows every error, like the base game compiler.");
configErrorLogAbbreviateTrace = ((BaseUnityPlugin)this).Config.Bind<bool>("ErrorLog", "AbbreviateTrace", false, "Controls whether compile traces print every parsed ID, or whether runs of IDs are collapsed with '|...'.\nfalse: Print every parsed signal ID interspersed with unparsed portions of the input.\ntrue: Collapse parsed signal IDs with '|...' and print unparsed portions of the input.");
}
private void Awake()
{
Singleton = this;
Singleton.logger.LogInfo((object)"Hello from polymeric.BetterSignalCompiler v1.0.2!");
HarmonyPatches.PatchInClassShallow(Singleton.harmony, typeof(HarmonyPatches));
}
}
internal class TrieNode<T>
{
public Dictionary<char, TrieNode<T>> children = new Dictionary<char, TrieNode<T>>();
public List<T> ids = new List<T>();
}
public class TriePrefix<T>
{
public readonly T id;
public readonly int length;
public TriePrefix(T id, int length)
{
this.id = id;
this.length = length;
}
}
public class Trie<T> where T : IComparable<T>
{
private readonly TrieNode<T> root = new TrieNode<T>();
public bool Insert(T id, string word)
{
TrieNode<T> trieNode = root;
foreach (char key in word)
{
if (trieNode.children.TryGetValue(key, out TrieNode<T> value))
{
trieNode = value;
continue;
}
TrieNode<T> trieNode2 = new TrieNode<T>();
trieNode.children[key] = trieNode2;
trieNode = trieNode2;
}
int num = trieNode.ids.BinarySearch(id);
if (num < 0)
{
trieNode.ids.Insert(~num, id);
return true;
}
return false;
}
public IReadOnlyList<T> Search(string word)
{
TrieNode<T> trieNode = root;
foreach (char key in word)
{
TrieNode<T> valueOrDefault = trieNode.children.GetValueOrDefault(key);
if (valueOrDefault != null)
{
trieNode = valueOrDefault;
continue;
}
return Array.Empty<T>();
}
return trieNode.ids;
}
public bool Delete(T id, string word)
{
TrieNode<T> trieNode = root;
TrieNode<T> trieNode2 = null;
char key = '\0';
if (word.Length > 0)
{
trieNode2 = root;
key = word[0];
}
foreach (char c in word)
{
TrieNode<T> valueOrDefault = trieNode.children.GetValueOrDefault(c);
if (valueOrDefault != null)
{
if (trieNode.ids.Count > 0 || trieNode.children.Count > 1)
{
trieNode2 = trieNode;
key = c;
}
trieNode = valueOrDefault;
continue;
}
return false;
}
int num = trieNode.ids.BinarySearch(id);
if (num >= 0)
{
if (trieNode2 != null && trieNode.ids.Count == 1 && trieNode.children.Count == 0)
{
trieNode2.children.Remove(key);
}
else
{
trieNode.ids.RemoveAt(num);
}
return true;
}
return false;
}
public List<TriePrefix<T>> Prefixes(string text, int offset)
{
List<TriePrefix<T>> list = new List<TriePrefix<T>>();
TrieNode<T> trieNode = root;
foreach (T id in trieNode.ids)
{
list.Add(new TriePrefix<T>(id, 0));
}
for (int i = offset; i < text.Length; i++)
{
char key = text[i];
TrieNode<T> valueOrDefault = trieNode.children.GetValueOrDefault(key);
if (valueOrDefault == null)
{
break;
}
trieNode = valueOrDefault;
foreach (T id2 in trieNode.ids)
{
list.Add(new TriePrefix<T>(id2, i - offset + 1));
}
}
return list;
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "polymeric.BetterSignalCompiler";
public const string PLUGIN_NAME = "Better Signal Compiler";
public const string PLUGIN_VERSION = "1.0.2";
}
}