Skip to content
14 changes: 11 additions & 3 deletions RNSReloaded.Interfaces/IBattlePatterns.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ public void gravity_fall_temporary(
);

public void gravity_pull(
CInstance* self, CInstance* other, double? mult = null
CInstance* self, CInstance* other, double? mult = null, Position? position = null
);

public void gravity_pull_temporary(
Expand Down Expand Up @@ -243,6 +243,10 @@ public void prsline_v(

public void setgamespeed(CInstance* self, CInstance* other, int? spawnDelay = null, double? timeMult = null);

public void setgamespeed_temp(CInstance* self, CInstance* other, int? spawnDelay = null, int? eraseDelay = null, double? timeMult = null);

public void setzoom(CInstance* self, CInstance* other, double? zoom = null);

public void showgroups(
CInstance* self, CInstance* other, int? spawnDelay = null, int? eraseDelay = null, (int, int, int, int)? groupMasks = null
);
Expand All @@ -252,11 +256,15 @@ public void showorder(
);

public void tailwind(
CInstance* self, CInstance* other, int? eraseDelay = null
CInstance* self, CInstance* other, int? eraseDelay = null, int? spawnDelay = null, int? trgBinary = null, double? mult = null
);

public void tailwind_permanent(
CInstance* self, CInstance* other
CInstance* self, CInstance* other, int? spawnDelay = null, int? trgBinary = null, double? mult = null
);

public void teleport_dist(
CInstance* self, CInstance* other, int? spawnDelay = null, int? eraseDelay = null, int? type = null, Position[]? offsets = null
);

public void tether(
Expand Down
2 changes: 2 additions & 0 deletions RNSReloaded.Interfaces/IRNSReloaded.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public unsafe interface IRNSReloaded {
public RFunctionStringRef GetTheFunction(int id);
public CInstance* GetGlobalInstance();
public RValue* FindValue(CInstance* instance, string name);
public RValue* FindAllocValue(CInstance* instance, string name);
public RValue* FindGlobalValue(string name);
public RValue* ArrayGetEntry(RValue* array, int index);
public RValue? ArrayGetLength(RValue* array);
public string GetString(RValue* value);
Expand Down
167 changes: 161 additions & 6 deletions RNSReloaded.Interfaces/Structs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
// ReSharper disable InconsistentNaming
namespace RNSReloaded.Interfaces.Structs;

public unsafe interface ILinkedListElement<T> where T : unmanaged {
T* GetNext();
T* GetPrev();
}

public unsafe delegate RValue* ScriptDelegate(
CInstance* self, CInstance* other, RValue* returnValue, int argc, RValue** argv
);
Expand Down Expand Up @@ -69,16 +74,80 @@ public unsafe struct RValue {
return IRNSReloaded.Instance.FindValue(this.Object, key);
}

public RValue* Set(string key, RValue value) {
if (this.Type != RValueType.Object) return null;
Comment thread
babit56 marked this conversation as resolved.
Outdated
var retVal = IRNSReloaded.Instance.FindAllocValue(this.Object, key);
*retVal = value;
return retVal;
}

// Thanks C# for making indexing a pointer with a number impossible lol
public RValue* this[int index] => this.Get(index);
public RValue* this[string key] => this.Get(key);
public RValue* this[string key] {
get => this.Get(key);
set => this.Set(key, *value);
}

public override string ToString() {
fixed (RValue* ptr = &this) {
return IRNSReloaded.Instance.GetString(ptr);
}
}

// Technically this should cast ints to uint and return long
public int ToInt(int defaultValue = 0) {
return this.Type switch {
RValueType.Real => (int) this.Real,
RValueType.Int32 => this.Int32,
RValueType.Int64 => this.Int32,
RValueType.Bool => (int) this.Real,
_ => defaultValue,
};
}

// See INT64_RValue in a YYC decompilation (might need debug symbols)
private static long RealToLong(double value) {
if (Double.IsNaN(value)) {
return 0;
} else if (Double.IsPositiveInfinity(value)) {
return long.MaxValue;
} else if (Double.IsNegativeInfinity(value)) {
return long.MinValue;
} else {
return (int)value;
}
}

public long ToLong(long defaultValue = 0) {
return this.Type switch {
RValueType.Real => RealToLong(this.Real),
RValueType.Int32 => this.Int32,
RValueType.Int64 => this.Int64,
RValueType.Bool => RealToLong(this.Real),
_ => defaultValue,
};
}

public double ToDouble(double defaultValue = 0) {
return this.Type switch {
RValueType.Real => this.Real,
RValueType.Int32 => (double) this.Int32,
RValueType.Int64 => (double)(int) this.Int64,
RValueType.Bool => this.Real,
_ => defaultValue,
};
}

public bool ToBool(bool defaultValue = false) {
return this.Type switch {
RValueType.Real => this.Real > 0.5,
RValueType.Int32 => this.Int32 > 0,
RValueType.Int64 => this.Int64 > 0,
RValueType.Bool => this.Real > 0.5,
_ => defaultValue,
};
}

// Constructors
public RValue(CInstance* obj) {
this.Type = RValueType.Object;
Expand All @@ -92,6 +161,12 @@ public RValue(int value) {
this.Flags = 0;
}

public RValue(long value) {
this.Type = RValueType.Int64;
this.Int64 = value;
this.Flags = 0;
}

public RValue(double value) {
this.Type = RValueType.Real;
this.Real = value;
Expand All @@ -104,13 +179,40 @@ public RValue(bool value) {
this.Flags = 0;
}

public RValue() {
this.Type = RValueType.Undefined;
this.Int64 = 0;
this.Flags = 0;
}

public RValue(string value) {
this = IRNSReloaded.Instance.utils.CreateString(value) switch {
{ } strR => strR,
null => new RValue(),
};
}

public static implicit operator RValue(CInstance* obj) => new(obj);
public static implicit operator RValue(int value) => new(value);
public static implicit operator RValue(long value) => new(value);
public static implicit operator RValue(double value) => new(value);
public static implicit operator RValue(bool value) => new(value);

public static explicit operator int(RValue value) => value.ToInt();
public static explicit operator long(RValue value) => value.ToLong();
public static explicit operator double(RValue value) => value.ToDouble();
public static explicit operator bool(RValue value) => value.ToBool();

// TODO: creating other primitives, new objects, and new arrays
}

[StructLayout(LayoutKind.Sequential, Pack = 8)]
public unsafe struct CInstance; // TODO
public unsafe struct CInstance : ILinkedListElement<CInstance> {
// TODO

public CInstance* GetNext() => throw new NotImplementedException();
public CInstance* GetPrev() => throw new NotImplementedException();
}

[StructLayout(LayoutKind.Sequential, Pack = 8)]
public unsafe struct CScript {
Expand All @@ -134,12 +236,42 @@ public unsafe struct RFunctionStringRef {
}

[StructLayout(LayoutKind.Sequential, Pack = 8)]
public unsafe struct LinkedList<T> where T : unmanaged {
public unsafe struct LinkedList<T> where T : unmanaged, ILinkedListElement<T> {
public T* First;
public T* Last;
public int Count;

// TODO: enumerator
public Enumerator GetEnumerator() => new Enumerator(this);

public struct Enumerator {
private LinkedList<T> list;
private T* curr;
private bool first;

internal Enumerator(LinkedList<T> list) {
this.list = list;
this.curr = list.First;
this.first = true;
}

public T* Current => this.curr;

// Contract says it should be run once before it points to first element
public bool MoveNext() {
if (!this.first) {
this.curr = this.curr->GetNext();
}
this.first = false;
return this.curr != null;
}

public void Reset() {
this.curr = this.list.First;
this.first = true;
}

public void Dispose() { }
}
}

[StructLayout(LayoutKind.Sequential, Pack = 8)]
Expand Down Expand Up @@ -222,7 +354,7 @@ public unsafe struct CRoom {
}

[StructLayout(LayoutKind.Sequential, Pack = 8)]
public unsafe struct CLayer {
public unsafe struct CLayer : ILinkedListElement<CLayer> {
public int ID;
public int Depth;
public float XOffset;
Expand Down Expand Up @@ -251,14 +383,34 @@ public unsafe struct CLayer {
public CLayer* Next;
public CLayer* Previous;
public nint GCProxy;

public CLayer* GetNext() => this.Next;
public CLayer* GetPrev() => this.Previous;

public List<RValue> GetInstances() {
RValue[] instances = [];
foreach (var element in this.Elements) {
if (element->Type != LayerElementType.Instance) { continue; }
var instance = (CLayerInstanceElement*) element;
instances = [..instances, instance->Instance];
}
return instances.ToList();
}

public string GetName() {
if (this.Name == null) {
return "Unnamed";
}
return Marshal.PtrToStringAnsi((nint) this.Name) ?? "Unnamed";
}
}

public enum LayerElementType {
Instance = 2
}

[StructLayout(LayoutKind.Sequential, Pack = 8)]
public unsafe struct CLayerElementBase {
public unsafe struct CLayerElementBase : ILinkedListElement<CLayerElementBase> {
public LayerElementType Type;
public int ID;
public byte RuntimeDataInitialized;
Expand All @@ -269,6 +421,9 @@ public unsafe struct CLayerElementBase {
public CLayerElementBase* Next;
public CLayerElementBase* Previous;
// Random 3 bytes of data, then 5 of pack, then another pointer. Who knows what that is though.

public CLayerElementBase* GetNext() => this.Next;
public CLayerElementBase* GetPrev() => this.Previous;
}

[StructLayout(LayoutKind.Sequential, Pack = 8)]
Expand Down
Loading