Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions OpenDreamRuntime/ByondApi/ByondApi.Functions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,10 @@ private static uint Byond_GetStrId(byte* cstr) {
return RunOnMainThread(() => {
var strId = _dreamManager!.FindString(str);
if (strId != null) {
return (uint)RefType.String | strId.Value;
} else {
return NONE;
return strId.Value;
}

return NONE;
});
}

Expand All @@ -138,7 +138,7 @@ private static uint Byond_AddGetStrId(byte* cstr) {

return RunOnMainThread(() => {
var strIdx = _dreamManager!.FindOrAddString(str);
return (uint)RefType.String | strIdx;
return strIdx;
});
}

Expand Down Expand Up @@ -195,9 +195,9 @@ private static byte Byond_ReadVarByStrId(CByondValue* loc, uint varname, CByondV

return RunOnMainThread<byte>(() => {
try {
DreamValue varNameVal = _dreamManager!.RefIdToValue((int)varname);
DreamValue varNameVal = _dreamManager!.RefToValue(RefType.String, (int)varname);
if (!varNameVal.TryGetValueAsString(out var varName))
return SetLastError("varname argument was not a reference to a string");
return SetLastError("varname argument was an invalid string ID");

DreamValue srcValue = ValueFromDreamApi(*loc);
if (!srcValue.TryGetValueAsDreamObject(out var srcObj))
Expand Down Expand Up @@ -264,9 +264,9 @@ private static byte Byond_WriteVar(CByondValue* loc, byte* varname, CByondValue*
private static byte Byond_WriteVarByStrId(CByondValue* loc, uint varname, CByondValue* val) {
return RunOnMainThread<byte>(() => {
try {
DreamValue varNameVal = _dreamManager!.RefIdToValue((int)varname);
DreamValue varNameVal = _dreamManager!.RefToValue(RefType.String, (int)varname);
if (!varNameVal.TryGetValueAsString(out var varName))
return SetLastError("varname argument was not a ref to a string");
return SetLastError("varname argument was an invalid string ID");

DreamValue srcValue = ValueFromDreamApi(*val);
DreamValue dstValue = ValueFromDreamApi(*loc);
Expand Down Expand Up @@ -590,9 +590,9 @@ private static byte Byond_CallProcByStrId(CByondValue* cSrc, uint name, CByondVa

return RunOnMainThread(() => {
try {
DreamValue procNameVal = _dreamManager!.RefIdToValue((int)name);
DreamValue procNameVal = _dreamManager!.RefToValue(RefType.String, (int)name);
if (!procNameVal.TryGetValueAsString(out var procName))
return SetLastError("name argument was not a ref to a string");
return SetLastError("name argument was an invalid string ID");

DreamValue src = ValueFromDreamApi(*cSrc);
if (!src.TryGetValueAsDreamObject(out var srcObj))
Expand Down Expand Up @@ -659,9 +659,9 @@ private static byte Byond_CallGlobalProcByStrId(uint name, CByondValue* cArgs, u

return RunOnMainThread<byte>(() => {
try {
DreamValue procNameVal = _dreamManager!.RefIdToValue((int)name);
DreamValue procNameVal = _dreamManager!.RefToValue(RefType.String, (int)name);
if (!procNameVal.TryGetValueAsString(out var procName))
return SetLastError("name argument was not a ref to a string");
return SetLastError("name argument was an invalid string ID");
if (!_dreamManager.TryGetGlobalProc(procName, out var proc))
return SetLastError($"no global proc named \"{procName}\"");

Expand Down Expand Up @@ -1068,13 +1068,13 @@ private static void ByondValue_DecTempRef(CByondValue* src) {
// This only applies to ref types, not null/num/string which are always valid.
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])]
private static byte Byond_TestRef(CByondValue* src) {
if (src == null) return SetLastError("src argument was a null pointer");
if (src->type == ByondValueType.Null) {
if (src == null)
return SetLastError("src argument was a null pointer");
if (src->type == ByondValueType.Null)
return 1;
}

return RunOnMainThread<byte>(() => {
var srcValue = _dreamManager!.RefIdToValue((int)src->data.@ref);
var srcValue = ValueFromDreamApi(*src);

if (srcValue == DreamValue.Null) {
src->type = 0;
Expand Down
32 changes: 28 additions & 4 deletions OpenDreamRuntime/ByondApi/ByondApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public static partial class ByondApi {
/// A failed ByondApi call will set this string. It can be retrieved with <see cref="Byond_LastError"/>.
/// </summary>
private static string _lastError = string.Empty;

private static IntPtr _lastErrorPtr = IntPtr.Zero;

public static void Initialize(DreamManager dreamManager, AtomManager atomManager, IDreamMapManager dreamMapManager, DreamObjectTree objectTree) {
Expand Down Expand Up @@ -90,8 +90,32 @@ public static DreamValue ValueFromDreamApi(CByondValue value) {
case ByondValueType.Appearance:
case ByondValueType.World:
case ByondValueType.Proc:
var refType = ctype switch {
ByondValueType.Turf => RefType.DreamObjectTurf,
ByondValueType.Obj => RefType.DreamObject,
ByondValueType.Mob => RefType.DreamObjectMob,
ByondValueType.Area => RefType.DreamObjectArea,
ByondValueType.Client => RefType.DreamObjectClient,
ByondValueType.Image => RefType.DreamObjectImage,
ByondValueType.List => RefType.DreamObjectList,
ByondValueType.Datum => RefType.DreamObjectDatum,
ByondValueType.World => RefType.DreamObjectDatum,
ByondValueType.String => RefType.String,
ByondValueType.Resource => RefType.DreamResource,
ByondValueType.Appearance => RefType.DreamAppearance,
ByondValueType.Proc => RefType.Proc,

ByondValueType.ObjTypePath or
ByondValueType.MobTypePath or
ByondValueType.TurfTypePath or
ByondValueType.DatumTypePath or
ByondValueType.AreaTypePath => RefType.DreamType,

_ => throw new Exception($"Invalid reference type for type {ctype.ToString()}")
};

int refId = (int)cdata.@ref;
return _dreamManager!.RefIdToValue(refId);
return _dreamManager!.RefToValue(refType, refId);
}
}

Expand All @@ -111,9 +135,9 @@ public static CByondValue ValueToByondApi(DreamValue value) {
case DreamValue.DreamValueType.DreamType:
case DreamValue.DreamValueType.Appearance:
case DreamValue.DreamValueType.DreamProc:
var refid = _dreamManager!.CreateRefInt(value, out RefType refType);
var refId = _dreamManager!.GetRefId(value, out var refType);
ByondValueType type;
ByondValueData data = new ByondValueData { @ref = refid };
ByondValueData data = new ByondValueData { @ref = refId };

switch (refType) {
default:
Expand Down
31 changes: 19 additions & 12 deletions OpenDreamRuntime/DreamManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,14 @@ public uint FindOrAddString(string str) {
}

public string CreateRef(DreamValue value) {
return $"[0x{CreateRefInt(value, out _):x}]";
var refId = GetRefId(value, out var refType);

// refType combines with the highest byte. This could produce an invalid ref, but that's BYOND behavior too.
var combined = (uint)refType | refId;
return $"[0x{combined:x}]";
}

public uint CreateRefInt(DreamValue value, out RefType refType) {
public uint GetRefId(DreamValue value, out RefType refType) {
int idx;

if (value.TryGetValueAsDreamObject(out var refObject)) {
Expand Down Expand Up @@ -309,8 +313,7 @@ public uint CreateRefInt(DreamValue value, out RefType refType) {
throw new NotImplementedException($"Ref for {value} is unimplemented");
}

// The highest byte is the type
return (uint)refType | (uint)idx;
return (uint)idx;
}

/// <summary>
Expand All @@ -333,12 +336,16 @@ public IEnumerable<DreamObject> IterateDatums() {
}
}

public DreamValue RefIdToValue(int rawRefId) {
public DreamValue RefToValue(int rawRef) {
// The first one/two digits give the type, the last 6 give the index
var typeId = (RefType)(rawRefId & 0xFF000000);
var refId = (rawRefId & 0x00FFFFFF); // The ref minus its ref type prefix
var refType = (RefType)(rawRef & 0xFF000000);
var refId = (rawRef & 0x00FFFFFF); // The ref minus its ref type prefix

return RefToValue(refType, refId);
}

switch (typeId) {
public DreamValue RefToValue(RefType refType, int refId) {
switch (refType) {
case RefType.Null:
return DreamValue.Null;
case RefType.DreamObjectArea:
Expand Down Expand Up @@ -380,7 +387,7 @@ public DreamValue RefIdToValue(int rawRefId) {
case RefType.Number: // For the oh so few numbers this works with (most numbers clobber the ref type)
return new(BitConverter.Int32BitsToSingle(refId));
default:
throw new Exception($"Invalid reference type for ref [0x{rawRefId:x}]");
throw new Exception($"Invalid reference type for ref [0x{refId:x}]");
}
}

Expand All @@ -396,7 +403,7 @@ public DreamValue LocateRef(string refString) {
}

if (canBePointer && int.TryParse(refString.Substring(2), System.Globalization.NumberStyles.HexNumber, null, out var refId)) {
return RefIdToValue(refId);
return RefToValue(refId);
}

// Search for an object with this ref as its tag
Expand Down Expand Up @@ -475,7 +482,6 @@ public enum RefType : uint {
DreamObjectMob = 0x3000000,
DreamObjectArea = 0x4000000,
DreamObjectClient = 0x5000000,
DreamObjectFilter = 0x5300000,
DreamResourceIcon = 0xC000000,
DreamObjectImage = 0xD000000,
DreamObjectList = 0xF000000,
Expand All @@ -485,5 +491,6 @@ public enum RefType : uint {
DreamResource = 0x27000000, //Equivalent to file
DreamAppearance = 0x3A000000,
Proc = 0x26000000,
Number = 0x2A000000
Number = 0x2A000000,
DreamObjectFilter = 0x53000000
}
Loading