using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.Json.Serialization;
using GDWeave;
using GDWeave.Godot;
using GDWeave.Godot.Variants;
using GDWeave.Modding;
using patchlist;
using util.LexicalTransformer;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")]
[assembly: AssemblyCompany("SaruShinobie.ExploitPatches")]
[assembly: AssemblyConfiguration("release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0.0+8670b8bddc13550031e4ff8a4046035c07f9807a")]
[assembly: AssemblyProduct("SaruShinobie.ExploitPatches")]
[assembly: AssemblyTitle("SaruShinobie.ExploitPatches")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
[CompilerGenerated]
internal sealed class <>z__ReadOnlySingleElementList<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T>
{
private sealed class Enumerator : IDisposable, IEnumerator, IEnumerator<T>
{
object IEnumerator.Current => _item;
T IEnumerator<T>.Current => _item;
public Enumerator(T item)
{
_item = item;
}
bool IEnumerator.MoveNext()
{
if (!_moveNextCalled)
{
return _moveNextCalled = true;
}
return false;
}
void IEnumerator.Reset()
{
_moveNextCalled = false;
}
void IDisposable.Dispose()
{
}
}
int ICollection.Count => 1;
bool ICollection.IsSynchronized => false;
object ICollection.SyncRoot => this;
object? IList.this[int index]
{
get
{
if (index != 0)
{
throw new IndexOutOfRangeException();
}
return _item;
}
set
{
throw new NotSupportedException();
}
}
bool IList.IsFixedSize => true;
bool IList.IsReadOnly => true;
int IReadOnlyCollection<T>.Count => 1;
T IReadOnlyList<T>.this[int index]
{
get
{
if (index != 0)
{
throw new IndexOutOfRangeException();
}
return _item;
}
}
int ICollection<T>.Count => 1;
bool ICollection<T>.IsReadOnly => true;
T IList<T>.this[int index]
{
get
{
if (index != 0)
{
throw new IndexOutOfRangeException();
}
return _item;
}
set
{
throw new NotSupportedException();
}
}
public <>z__ReadOnlySingleElementList(T item)
{
_item = item;
}
IEnumerator IEnumerable.GetEnumerator()
{
return new Enumerator(_item);
}
void ICollection.CopyTo(Array array, int index)
{
array.SetValue(_item, index);
}
int IList.Add(object? value)
{
throw new NotSupportedException();
}
void IList.Clear()
{
throw new NotSupportedException();
}
bool IList.Contains(object? value)
{
return EqualityComparer<T>.Default.Equals(_item, (T)value);
}
int IList.IndexOf(object? value)
{
if (!EqualityComparer<T>.Default.Equals(_item, (T)value))
{
return -1;
}
return 0;
}
void IList.Insert(int index, object? value)
{
throw new NotSupportedException();
}
void IList.Remove(object? value)
{
throw new NotSupportedException();
}
void IList.RemoveAt(int index)
{
throw new NotSupportedException();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return new Enumerator(_item);
}
void ICollection<T>.Add(T item)
{
throw new NotSupportedException();
}
void ICollection<T>.Clear()
{
throw new NotSupportedException();
}
bool ICollection<T>.Contains(T item)
{
return EqualityComparer<T>.Default.Equals(_item, item);
}
void ICollection<T>.CopyTo(T[] array, int arrayIndex)
{
array[arrayIndex] = _item;
}
bool ICollection<T>.Remove(T item)
{
throw new NotSupportedException();
}
int IList<T>.IndexOf(T item)
{
if (!EqualityComparer<T>.Default.Equals(_item, item))
{
return -1;
}
return 0;
}
void IList<T>.Insert(int index, T item)
{
throw new NotSupportedException();
}
void IList<T>.RemoveAt(int index)
{
throw new NotSupportedException();
}
}
namespace util
{
public enum BuiltinFunc : uint
{
sin,
cos,
tan,
sinh,
cosh,
tanh,
asin,
acos,
atan,
atan2,
sqrt,
fmod,
fposmod,
posmod,
floor,
ceil,
round,
abs,
sign,
pow,
log,
exp,
is_nan,
is_inf,
is_equal_approx,
is_zero_approx,
ease,
decimals,
step_decimals,
stepify,
lerp,
lerp_angle,
inverse_lerp,
range_lerp,
smoothstep,
move_toward,
dectime,
randomize,
randi,
randf,
rand_range,
seed,
rand_seed,
deg2rad,
rad2deg,
linear2db,
db2linear,
polar2cartesian,
cartesian2polar,
wrapi,
wrapf,
max,
min,
clamp,
nearest_po2,
weakref,
funcref,
convert,
@typeof,
type_exists,
@char,
ord,
str,
print,
printt,
prints,
printerr,
printraw,
print_debug,
push_error,
push_warning,
var2str,
str2var,
var2bytes,
bytes2var,
range,
load,
inst2dict,
dict2inst,
validate_json,
parse_json,
to_json,
hash,
Color8,
ColorN,
print_stack,
get_stack,
instance_from_id,
len,
is_instance_valid,
deep_equal,
MAX
}
public static class ScriptTokenizer
{
private static readonly IReadOnlyDictionary<string, TokenType> Tokens = new Dictionary<string, TokenType>
{
{
"continue",
(TokenType)44
},
{
"return",
(TokenType)46
},
{
"break",
(TokenType)43
},
{
"match",
(TokenType)47
},
{
"while",
(TokenType)42
},
{
"elif",
(TokenType)39
},
{
"else",
(TokenType)40
},
{
"pass",
(TokenType)45
},
{
"for",
(TokenType)41
},
{
"if",
(TokenType)38
},
{
"const",
(TokenType)58
},
{
"var",
(TokenType)59
},
{
"func",
(TokenType)48
},
{
"class",
(TokenType)49
},
{
"extends",
(TokenType)51
},
{
"is",
(TokenType)52
},
{
"as",
(TokenType)60
},
{
"onready",
(TokenType)53
},
{
"@tool",
(TokenType)54
},
{
"@export",
(TokenType)56
},
{
"yield",
(TokenType)65
},
{
"setget",
(TokenType)57
},
{
"static",
(TokenType)55
},
{
"void",
(TokenType)61
},
{
"enum",
(TokenType)62
},
{
"preload",
(TokenType)63
},
{
"assert",
(TokenType)64
},
{
"signal",
(TokenType)66
},
{
"breakpoint",
(TokenType)67
},
{
"sync",
(TokenType)69
},
{
"remote",
(TokenType)68
},
{
"master",
(TokenType)70
},
{
"slave",
(TokenType)71
},
{
"puppet",
(TokenType)72
},
{
"remotesync",
(TokenType)73
},
{
"mastersync",
(TokenType)74
},
{
"puppetsync",
(TokenType)75
},
{
"\n",
(TokenType)89
},
{
"PI",
(TokenType)90
},
{
"TAU",
(TokenType)91
},
{
"INF",
(TokenType)93
},
{
"NAN",
(TokenType)94
},
{
"error",
(TokenType)95
},
{
"cursor",
(TokenType)97
},
{
"self",
(TokenType)3
},
{
"in",
(TokenType)6
},
{
"or",
(TokenType)14
},
{
"and",
(TokenType)13
},
{
"not",
(TokenType)15
},
{
"_",
(TokenType)92
},
{
"[",
(TokenType)76
},
{
"]",
(TokenType)77
},
{
"{",
(TokenType)78
},
{
"}",
(TokenType)79
},
{
"(",
(TokenType)80
},
{
")",
(TokenType)81
},
{
",",
(TokenType)82
},
{
";",
(TokenType)83
},
{
".",
(TokenType)84
},
{
"?",
(TokenType)85
},
{
":",
(TokenType)86
},
{
"$",
(TokenType)87
},
{
"->",
(TokenType)88
},
{
">>=",
(TokenType)30
},
{
"<<=",
(TokenType)29
},
{
">>",
(TokenType)22
},
{
"<<",
(TokenType)21
},
{
"==",
(TokenType)7
},
{
"!=",
(TokenType)8
},
{
"&&",
(TokenType)13
},
{
"||",
(TokenType)14
},
{
"!",
(TokenType)15
},
{
"+=",
(TokenType)24
},
{
"-=",
(TokenType)25
},
{
"*=",
(TokenType)26
},
{
"/=",
(TokenType)27
},
{
"%=",
(TokenType)28
},
{
"&=",
(TokenType)31
},
{
"|=",
(TokenType)32
},
{
"^=",
(TokenType)33
},
{
"+",
(TokenType)16
},
{
"-",
(TokenType)17
},
{
"*",
(TokenType)18
},
{
"/",
(TokenType)19
},
{
"%",
(TokenType)20
},
{
"~",
(TokenType)37
},
{
"&",
(TokenType)34
},
{
"|",
(TokenType)35
},
{
"^",
(TokenType)36
},
{
"<=",
(TokenType)10
},
{
">=",
(TokenType)12
},
{
"<",
(TokenType)9
},
{
">",
(TokenType)11
},
{
"=",
(TokenType)23
}
};
private static readonly IReadOnlySet<string> Symbols = new HashSet<string>
{
"->", ">>=", "<<=", ">>", "<<", "==", "!=", "&&", "||", "!",
"+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", "[", "]",
"{", "}", "(", ")", ",", ";", ".", "?", ":", "$",
"+", "-", "*", "/", "%", "~", "&", "|", "^", "<=",
">=", "<", ">", "="
};
private static readonly IReadOnlyDictionary<string, uint> BuiltinTypeIds = new Dictionary<string, uint>
{
{ "int", 2u },
{ "Vector3", 7u },
{ "Color", 14u }
};
private static void InsertNewLine(IEnumerator<string> enumerator, uint baseIndent, List<Token> toFlush)
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Expected O, but got Unknown
if (enumerator.MoveNext())
{
uint num = uint.Parse(enumerator.Current);
toFlush.Add(new Token((TokenType)89, (uint?)(num + baseIndent)));
}
}
private static void BuildNumber(IEnumerator<string> enumerator, List<Token> toFlush, out bool foundFull)
{
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Expected O, but got Unknown
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Expected O, but got Unknown
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: Expected O, but got Unknown
//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Expected O, but got Unknown
//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Expected O, but got Unknown
foundFull = true;
int num = 1;
if (enumerator.Current == "-")
{
num = -1;
if (!enumerator.MoveNext())
{
return;
}
}
if (!long.TryParse(enumerator.Current, out var result))
{
toFlush.Add(new Token((TokenType)17, (uint?)null));
foundFull = false;
}
else if (enumerator.MoveNext())
{
long result2;
if (enumerator.Current != ".")
{
toFlush.Add((Token)new ConstantToken((Variant)new IntVariant(result * num, false)));
foundFull = false;
}
else if (enumerator.MoveNext() && long.TryParse(enumerator.Current, out result2))
{
double num2 = (double)result + (double)result2 / Math.Pow(10.0, result2.ToString().Length);
toFlush.Add((Token)new ConstantToken((Variant)new RealVariant(num2 * (double)num, false)));
}
}
}
public static IEnumerable<Token> Tokenize(string gdScript, uint baseIndent = 0u)
{
//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ff: Expected O, but got Unknown
//IL_0128: Unknown result type (might be due to invalid IL or missing references)
//IL_0132: Expected O, but got Unknown
//IL_012d: Unknown result type (might be due to invalid IL or missing references)
//IL_0137: Expected O, but got Unknown
//IL_0165: Unknown result type (might be due to invalid IL or missing references)
//IL_016f: Expected O, but got Unknown
//IL_019a: Unknown result type (might be due to invalid IL or missing references)
//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
//IL_01b0: Expected O, but got Unknown
//IL_0208: Unknown result type (might be due to invalid IL or missing references)
//IL_0212: Expected O, but got Unknown
//IL_020d: Unknown result type (might be due to invalid IL or missing references)
//IL_0217: Expected O, but got Unknown
//IL_023c: Unknown result type (might be due to invalid IL or missing references)
//IL_0246: Expected O, but got Unknown
//IL_0241: Unknown result type (might be due to invalid IL or missing references)
//IL_024b: Expected O, but got Unknown
List<Token> finalTokens = new List<Token>();
IEnumerable<string> enumerable = SanitizeInput(TokenizeString(gdScript + " "));
string previous = string.Empty;
string idName = string.Empty;
List<Token> toFlush = new List<Token>(2);
IEnumerator<string> enumerator = enumerable.GetEnumerator();
bool flag = false;
while (flag || enumerator.MoveNext())
{
flag = false;
uint value;
BuiltinFunc result;
TokenType value2;
bool result2;
if (enumerator.Current == "\n")
{
InsertNewLine(enumerator, baseIndent, toFlush);
endAndFlushId();
}
else if (char.IsDigit(enumerator.Current[0]))
{
BuildNumber(enumerator, toFlush, out var foundFull);
flag = !foundFull;
endAndFlushId();
}
else if (BuiltinTypeIds.TryGetValue(enumerator.Current, out value))
{
toFlush.Add(new Token((TokenType)4, (uint?)value));
endAndFlushId();
}
else if (enumerator.Current == "null")
{
toFlush.Add((Token)new ConstantToken((Variant)new NilVariant()));
endAndFlushId();
}
else if (Enum.TryParse<BuiltinFunc>(enumerator.Current, out result))
{
toFlush.Add(new Token((TokenType)5, (uint?)(uint)result));
endAndFlushId();
}
else if (Tokens.TryGetValue(enumerator.Current, out value2))
{
toFlush.Add(new Token(value2, (uint?)null));
endAndFlushId();
}
else if (enumerator.Current.StartsWith('"') || enumerator.Current.StartsWith('\''))
{
string current = enumerator.Current;
toFlush.Add((Token)new ConstantToken((Variant)new StringVariant(current.Substring(1, current.Length - 2))));
endAndFlushId();
}
else if (bool.TryParse(enumerator.Current, out result2))
{
toFlush.Add((Token)new ConstantToken((Variant)new BoolVariant(result2)));
endAndFlushId();
}
else
{
idName += enumerator.Current;
end();
}
}
return finalTokens.ToArray();
void end()
{
previous = enumerator.Current;
finalTokens.AddRange(toFlush);
toFlush.Clear();
}
void endAndFlushId()
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Expected O, but got Unknown
if (idName == string.Empty)
{
end();
}
else
{
finalTokens.Add((Token)new IdentifierToken(idName.Trim()));
idName = string.Empty;
end();
}
}
}
private static IEnumerable<string> SanitizeInput(IEnumerable<string> tokens)
{
foreach (string token in tokens)
{
if (!(token != "\n") || !string.IsNullOrWhiteSpace(token))
{
yield return token;
}
}
}
private static IEnumerable<string> TokenizeString(string text)
{
StringBuilder builder = new StringBuilder(20);
for (int i = 0; i < text.Length; i++)
{
if (text[i] == '\'' || text[i] == '"')
{
char delimiter = text[i];
yield return ClearBuilder();
builder.Append(delimiter);
for (i++; i < text.Length; i++)
{
builder.Append(text[i]);
if (text[i] == delimiter)
{
break;
}
}
yield return ClearBuilder();
}
else
{
if (text[i] == '\r')
{
continue;
}
if (text[i] == '\n')
{
yield return ClearBuilder();
int start = i;
for (i++; i < text.Length && text[i] == '\t'; i++)
{
}
i--;
yield return "\n";
yield return $"{i - start}";
continue;
}
bool flag = false;
foreach (string delimiter2 in Symbols)
{
if (Match(text, i, delimiter2))
{
yield return ClearBuilder();
yield return delimiter2;
i += delimiter2.Length - 1;
flag = true;
break;
}
}
if (!flag)
{
if (text[i] == ' ')
{
yield return ClearBuilder();
}
else
{
builder.Append(text[i]);
}
}
}
}
yield return "\n";
string ClearBuilder()
{
string result = builder.ToString();
builder.Clear();
return result;
}
}
private static bool Match(string text, int index, string match)
{
if (index + match.Length > text.Length)
{
return false;
}
for (int i = 0; i < match.Length; i++)
{
if (text[index + i] != match[i])
{
return false;
}
}
return true;
}
}
}
namespace util.LexicalTransformer
{
public static class TransformationPatternFactory
{
public static Func<Token, bool>[] CreateGlobalsPattern()
{
return new Func<Token, bool>[3]
{
(Token t) => (int)t.Type == 51,
(Token t) => (int)t.Type == 1,
(Token t) => (int)t.Type == 89
};
}
public static Func<Token, bool>[] CreateFunctionDefinitionPattern(string name, string[]? args = null)
{
List<Func<Token, bool>> list = new List<Func<Token, bool>>();
list.Add((Token t) => (int)t.Type == 48);
list.Add(delegate(Token t)
{
IdentifierToken val = (IdentifierToken)(object)((t is IdentifierToken) ? t : null);
return val != null && val.Name == name;
});
list.Add((Token t) => (int)t.Type == 80);
if (args != null && args.Length > 0)
{
foreach (string arg in args)
{
list.Add(delegate(Token t)
{
IdentifierToken val = (IdentifierToken)(object)((t is IdentifierToken) ? t : null);
return val != null && val.Name == arg;
});
list.Add((Token t) => (int)t.Type == 82);
}
list.RemoveAt(list.Count - 1);
}
list.Add((Token t) => (int)t.Type == 81);
list.Add((Token t) => (int)t.Type == 86);
return list.ToArray();
}
public static Func<Token, bool>[] CreateGdSnippetPattern(string snippet, uint indent = 0u)
{
return ScriptTokenizer.Tokenize(snippet, indent).Select((Func<Token, Func<Token, bool>>)((Token snippetToken) => delegate(Token t)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Invalid comparison between Unknown and I4
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Invalid comparison between Unknown and I4
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
if ((int)t.Type == 1)
{
Token obj = snippetToken;
IdentifierToken val = (IdentifierToken)(object)((obj is IdentifierToken) ? obj : null);
if (val != null)
{
IdentifierToken val2 = (IdentifierToken)(object)((t is IdentifierToken) ? t : null);
if (val2 != null)
{
return val.Name == val2.Name;
}
}
return false;
}
if ((int)t.Type == 2)
{
Token obj2 = snippetToken;
ConstantToken val3 = (ConstantToken)(object)((obj2 is ConstantToken) ? obj2 : null);
if (val3 != null)
{
ConstantToken val4 = (ConstantToken)(object)((t is ConstantToken) ? t : null);
if (val4 != null)
{
return val3.Value.Equals(val4.Value);
}
}
return false;
}
return t.Type == snippetToken.Type;
})).ToArray();
}
}
public enum Operation
{
None,
ReplaceAll,
ReplaceLast,
Append,
Prepend
}
public static class OperationExtensions
{
public static bool RequiresBuffer(this Operation operation)
{
if (operation == Operation.ReplaceAll || operation == Operation.Prepend)
{
return true;
}
return false;
}
public static bool YieldTokenBeforeOperation(this Operation operation)
{
if (operation == Operation.None || operation == Operation.Append)
{
return true;
}
return false;
}
public static bool YieldTokenAfterOperation(this Operation operation)
{
if (!operation.RequiresBuffer() && !operation.YieldTokenBeforeOperation())
{
return operation != Operation.ReplaceLast;
}
return false;
}
}
public record TransformationRule(string Name, Func<Token, bool>[] Pattern, Func<Token, bool>[] ScopePattern, IEnumerable<Token> Tokens, Operation Operation, uint Times, Func<bool> Predicate)
{
public MultiTokenWaiter CreateMultiTokenWaiter()
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Expected O, but got Unknown
return new MultiTokenWaiter(Pattern, false, false);
}
public MultiTokenWaiter CreateMultiTokenWaiterForScope()
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Expected O, but got Unknown
return new MultiTokenWaiter(ScopePattern, false, false);
}
}
public class TransformationRuleBuilder
{
private string? _name;
private Func<Token, bool>[]? _pattern;
private Func<Token, bool>[] _scopePattern = Array.Empty<Func<Token, bool>>();
private IEnumerable<Token>? _tokens;
private uint _times = 1u;
private Operation _operation = Operation.Append;
private Func<bool> _predicate = () => true;
public TransformationRuleBuilder Named(string name)
{
_name = name;
return this;
}
public TransformationRuleBuilder Matching(Func<Token, bool>[] pattern)
{
_pattern = pattern;
return this;
}
public TransformationRuleBuilder With(IEnumerable<Token> tokens)
{
_tokens = tokens;
return this;
}
public TransformationRuleBuilder With(Token token)
{
_tokens = new <>z__ReadOnlySingleElementList<Token>(token);
return this;
}
public TransformationRuleBuilder With(string snippet, uint indent = 0u)
{
_tokens = ScriptTokenizer.Tokenize(snippet, indent);
return this;
}
public TransformationRuleBuilder Do(Operation operation)
{
_operation = operation;
return this;
}
public TransformationRuleBuilder ExpectTimes(uint times)
{
_times = times;
return this;
}
public TransformationRuleBuilder ScopedTo(Func<Token, bool>[] scopePattern)
{
_scopePattern = scopePattern;
return this;
}
public TransformationRuleBuilder When(Func<bool> predicate)
{
_predicate = predicate;
return this;
}
public TransformationRuleBuilder When(bool eligible)
{
_predicate = () => eligible;
return this;
}
public TransformationRule Build()
{
if (string.IsNullOrEmpty(_name))
{
throw new ArgumentNullException("_name", "Name cannot be null or empty");
}
if (_pattern == null)
{
throw new ArgumentNullException("_pattern", "Pattern cannot be null");
}
if (_tokens == null)
{
throw new ArgumentNullException("_tokens", "Tokens cannot be null");
}
return new TransformationRule(_name, _pattern, _scopePattern, _tokens, _operation, _times, _predicate);
}
}
public class TransformationRuleScriptMod(IModInterface mod, string name, string scriptPath, Func<bool> predicate, TransformationRule[] rules) : IScriptMod
{
public bool ShouldRun(string path)
{
if (path != scriptPath)
{
return false;
}
if (!predicate())
{
mod.Logger.Warning(string.Concat(Enumerable.Repeat("!", 15)));
mod.Logger.Warning("[" + name + "] Predicate failed!!!!!!, not patching.");
mod.Logger.Warning(string.Concat(Enumerable.Repeat("!", 15)));
return false;
}
return true;
}
public IEnumerable<Token> Modify(string path, IEnumerable<Token> tokens)
{
//IL_0134: Unknown result type (might be due to invalid IL or missing references)
//IL_013b: Invalid comparison between Unknown and I4
//IL_015d: Unknown result type (might be due to invalid IL or missing references)
//IL_0164: Invalid comparison between Unknown and I4
List<TransformationRule> source = rules.Where(delegate(TransformationRule rule)
{
bool num2 = rule.Predicate();
if (!num2)
{
mod.Logger.Information($"[{name}] Skipping patch {rule.Name}...");
}
return num2;
}).ToList();
List<(TransformationRule, MultiTokenWaiter, List<Token>)> list = source.Select((TransformationRule rule) => (Rule: rule, Waiter: rule.CreateMultiTokenWaiter(), Buffer: new List<Token>())).ToList();
mod.Logger.Information("[" + name + "] Patching " + path);
Dictionary<string, (int, uint)> dictionary = source.ToDictionary((TransformationRule r) => r.Name, (TransformationRule r) => (Occurred: 0, Expected: r.Times));
bool flag = true;
List<Token> list2 = new List<Token>();
list2.AddRange(tokens);
List<Token> list3 = new List<Token>();
foreach (var item in list)
{
bool flag2 = item.Item1.ScopePattern.Length != 0;
bool flag3 = !flag2;
uint? num = null;
MultiTokenWaiter val = item.Item1.CreateMultiTokenWaiterForScope();
foreach (Token item2 in list2)
{
if (flag3 && flag2)
{
if (!num.HasValue && (int)item2.Type == 89)
{
num = item2.AssociatedData.GetValueOrDefault();
}
else if (num.HasValue && (int)item2.Type == 89)
{
flag3 = item2.AssociatedData.GetValueOrDefault() >= num;
}
}
else if (flag2 && val.Check(item2))
{
val.Reset();
flag3 = true;
}
if (!flag3)
{
list3.Add(item2);
continue;
}
item.Item2.Check(item2);
if (item.Item2.Step == 0)
{
list3.AddRange(item.Item3);
item.Item3.Clear();
}
else
{
if (item.Item1.Operation.RequiresBuffer())
{
item.Item3.Add(item2);
flag = false;
}
if (item.Item2.Matched)
{
item.Item2.Reset();
if (item.Item1.Operation.YieldTokenBeforeOperation())
{
list3.Add(item2);
flag = false;
}
else
{
flag = item.Item1.Operation.YieldTokenAfterOperation();
}
switch (item.Item1.Operation)
{
case Operation.Prepend:
list3.AddRange(item.Item1.Tokens);
list3.AddRange(item.Item3);
item.Item3.Clear();
break;
case Operation.ReplaceAll:
case Operation.ReplaceLast:
case Operation.Append:
item.Item3.Clear();
list3.AddRange(item.Item1.Tokens);
break;
}
mod.Logger.Information($"[{name}] Patch {item.Item1.Name} OK!");
string name = item.Item1.Name;
(int, uint) value = dictionary[item.Item1.Name];
value.Item1 = dictionary[item.Item1.Name].Item1 + 1;
dictionary[name] = value;
}
}
if (flag)
{
list3.Add(item2);
}
else
{
flag = true;
}
}
list2.Clear();
list2.AddRange(list3);
list3.Clear();
}
foreach (KeyValuePair<string, (int, uint)> item3 in dictionary.Where<KeyValuePair<string, (int, uint)>>((KeyValuePair<string, (int Occurred, uint Expected)> result) => result.Value.Occurred != result.Value.Expected))
{
mod.Logger.Error($"[{name}] Patch {item3.Key} FAILED!!!!!!! Times expected={item3.Value.Item2}, actual={item3.Value.Item1}");
}
return list2;
}
}
public class TransformationRuleScriptModBuilder
{
private IModInterface? _mod;
private string? _name;
private string? _scriptPath;
private Func<bool> _predicate = () => true;
private List<TransformationRule> _rules = new List<TransformationRule>();
public TransformationRuleScriptModBuilder ForMod(IModInterface mod)
{
_mod = mod;
return this;
}
public TransformationRuleScriptModBuilder When(Func<bool> predicate)
{
_predicate = predicate;
return this;
}
public TransformationRuleScriptModBuilder Named(string name)
{
_name = name;
return this;
}
public TransformationRuleScriptModBuilder Patching(string scriptPath)
{
_scriptPath = scriptPath;
if (scriptPath.EndsWith(".gd"))
{
throw new ArgumentException("Your script path should end in gdc NOT gd");
}
return this;
}
public TransformationRuleScriptModBuilder AddRule(TransformationRule rule)
{
if (_rules.Select((TransformationRule r) => r.Name).Contains(rule.Name))
{
throw new InvalidOperationException("Another rule with the name '" + rule.Name + "' already exists!");
}
_rules.Add(rule);
return this;
}
public TransformationRuleScriptModBuilder AddRule(TransformationRuleBuilder rule)
{
return AddRule(rule.Build());
}
public TransformationRuleScriptMod Build()
{
if (_mod == null)
{
throw new ArgumentNullException("_mod", "Mod cannot be null");
}
if (string.IsNullOrEmpty(_name))
{
throw new ArgumentNullException("_name", "Name cannot be null or empty");
}
if (string.IsNullOrEmpty(_scriptPath))
{
throw new ArgumentNullException("_scriptPath", "Script path cannot be null or empty");
}
return new TransformationRuleScriptMod(_mod, _name, _scriptPath, _predicate, _rules.ToArray());
}
}
}
namespace patchlist
{
public static class networkPatch
{
public static IScriptMod Create(IModInterface modInterface)
{
return (IScriptMod)(object)new TransformationRuleScriptModBuilder().ForMod(modInterface).Named("zoe's shitty patches (network exploits)").Patching("res://Scenes/Singletons/SteamNetwork.gdc")
.AddRule(new TransformationRuleBuilder().Named("Define crash checker node, add debounce vars").Matching(TransformationPatternFactory.CreateGlobalsPattern()).With("\nvar lastLetterAcceptedTime = 0\nvar lastLetterDeniedTime = 0\n\nvar naughty_list = {}\n\nfunc arraySafetyCheck(arr = []):\n\tfor c in arr:\n\t\tif typeof(c) == TYPE_NIL or (typeof(c) == TYPE_REAL and is_nan(c)):\n\t\t\treturn false\n\n\t\tif typeof(c) == TYPE_ARRAY:\n\t\t\treturn arraySafetyCheck(c)\n\n\treturn true\n\nfunc packetSafetyCheck(type, DATA):\n\tvar safe = true\n\n\tif type == \"actor_action\" and DATA.get(\"action\") == \"_play_sfx\":\n\t\treturn true\n\n\tvar parameters = DATA.get(\"params\")\n\n\tif typeof(parameters) == TYPE_ARRAY:\n\t\tsafe = arraySafetyCheck(parameters)\n\telif typeof(parameters) == TYPE_DICTIONARY:\n\t\tsafe = arraySafetyCheck(parameters.values())\n\n\treturn safe\n"))
.AddRule(new TransformationRuleBuilder().Named("Adjust default packet timeout limits").Do(Operation.ReplaceAll).Matching(TransformationPatternFactory.CreateGdSnippetPattern("const MAX_PACKET_TIMEOUT_LIMIT = 1500\nconst MAX_MAJOR_PACKET_TIMEOUT_LIMIT = 3000"))
.With("const MAX_PACKET_TIMEOUT_LIMIT = 1000\nconst MAX_MAJOR_PACKET_TIMEOUT_LIMIT = 2000"))
.AddRule(new TransformationRuleBuilder().Named("Throttling for letter notifications").Do(Operation.ReplaceAll).Matching(TransformationPatternFactory.CreateGdSnippetPattern("\"letter_was_accepted\":\n\tPlayerData._letter_was_accepted()\n\"letter_was_denied\":\n\tPlayerData._letter_was_denied()"))
.With("\"letter_was_accepted\":\n\tif Time.get_ticks_msec() - lastLetterAcceptedTime > 1000:\n\t\tlastLetterAcceptedTime = Time.get_ticks_msec()\n\t\tPlayerData._letter_was_accepted()\n\"letter_was_denied\":\n\tif Time.get_ticks_msec() - lastLetterDeniedTime > 1000:\n\t\tlastLetterDeniedTime = Time.get_ticks_msec()\n\t\tPlayerData._letter_was_denied()", 3u))
.AddRule(new TransformationRuleBuilder().Named("Packet validation and early return for invalid packets").Do(Operation.ReplaceAll).Matching(TransformationPatternFactory.CreateGdSnippetPattern("FLUSH_PACKET_INFORMATION[PACKET_SENDER] += 1"))
.With("FLUSH_PACKET_INFORMATION[PACKET_SENDER] += 1\n\nif DATA.has(\"parameters\"):\n\tvar safe = packetSafetyCheck(type, DATA)\n\n\tif not safe:\n\t\treturn", 2u))
.AddRule(new TransformationRuleBuilder().Named("Drop message packets over 480 chars hopefully (base game limit)").Do(Operation.ReplaceAll).Matching(TransformationPatternFactory.CreateGdSnippetPattern("if not _message_cap(PACKET_SENDER): return"))
.With("if not _message_cap(PACKET_SENDER): return\n\nif DATA[\"message\"].length() > 484:\n\tprint(\"message blocked, too long, sent by:\", PACKET_SENDER)\n\treturn", 4u))
.AddRule(new TransformationRuleBuilder().Named("Peer rate limit for large packets").Do(Operation.ReplaceAll).Matching(TransformationPatternFactory.CreateGdSnippetPattern("if not PACKET.keys().has(\"identity\") or not PACKET.keys().has(\"payload\"):\n\tprint(\"Packet Disregarded! Invalid Packet Structure\")\n\treturn\n\nvar PACKET_SENDER: int = int(PACKET[\"identity\"])"))
.With("if not PACKET.keys().has(\"identity\") or not PACKET.keys().has(\"payload\"):\n\tprint(\"Packet Disregarded! Invalid Packet Structure\")\n\treturn\n\nvar PACKET_SENDER: int = int(PACKET[\"identity\"])\n\nif naughty_list.has(PACKET_SENDER):\n\tprint(PACKET_SENDER, \"is on the naughty list, packet blocked\")\n\nif PACKET_SIZE > 8000 and not naughty_list.has(PACKET_SENDER):\n\tnaughty_list[PACKET_SENDER] = 0\n\tprint(PACKET_SENDER, \"added to the naughty list. :c\")\n\treturn\n", 2u))
.AddRule(new TransformationRuleBuilder().Named("Prevent bad *packet arrays* from being logged maybe hopefully").Do(Operation.ReplaceAll).Matching(TransformationPatternFactory.CreateGdSnippetPattern("if not valid:\n\tprint(array)\n\tprint(\"Array is invalid.\")\n"))
.With("if not valid:\n\tprint(\"Array is invalid. Packet dump bypassed by ExploitPatches.\")\n\t\t", 1u))
.AddRule(new TransformationRuleBuilder().Named("Prevent bad *packets* from being logged maybe hopefully").Do(Operation.ReplaceAll).Matching(TransformationPatternFactory.CreateGdSnippetPattern("if not valid:\n\tprint(data)\n\tprint(\"Packet is invalid.\")\n"))
.With("if not valid:\n\tprint(\"Packet is invalid. Packet dump bypassed by ExploitPatches.\")\n", 1u))
.AddRule(new TransformationRuleBuilder().Named("Prevent bad *actor action packets* from being logged maybe hopefully").Do(Operation.ReplaceAll).Matching(TransformationPatternFactory.CreateGdSnippetPattern("if ACTOR_ACTIONS[DATA[\"actor_id\"]].size() > 128:\n\tprint(DATA[\"actor_id\"], \" Too many actor actions queued. Disregarding.\")\n\tprint(\"Packet Dump: \", ACTOR_ACTIONS[DATA[\"actor_id\"]])\n\treturn"))
.With("if ACTOR_ACTIONS[DATA[\"actor_id\"]].size() > 128:\n\tprint(\"Too many actor actions. Dump bypassed by ExploitPatches.\")\n\treturn", 4u))
.Build();
}
}
}
namespace SaruShinobie.ExploitPatches
{
public class Config
{
[JsonInclude]
public bool SomeSetting = true;
}
public class Mod : IMod, IDisposable
{
public Mod(IModInterface modInterface)
{
modInterface.RegisterScriptMod(networkPatch.Create(modInterface));
}
public void Dispose()
{
}
}
}