diff --git a/OpenDreamRuntime/DreamValue.cs b/OpenDreamRuntime/DreamValue.cs index 99102d0b6c..38b3be2ce0 100644 --- a/OpenDreamRuntime/DreamValue.cs +++ b/OpenDreamRuntime/DreamValue.cs @@ -501,7 +501,7 @@ public override DreamValue Read(ref Utf8JsonReader reader, Type typeToConvert, J DreamValue value; switch (type) { - case DreamValue.DreamValueType.String: value = new DreamValue(reader.GetString()); break; + case DreamValue.DreamValueType.String: value = new DreamValue(reader.GetString() ?? string.Empty); break; case DreamValue.DreamValueType.Float: value = new DreamValue(reader.GetSingle()); break; case DreamValue.DreamValueType.DreamObject: { string? objectTypePath = reader.GetString(); diff --git a/OpenDreamRuntime/Objects/DreamObjectTree.cs b/OpenDreamRuntime/Objects/DreamObjectTree.cs index f2492129f4..f54b130dc0 100644 --- a/OpenDreamRuntime/Objects/DreamObjectTree.cs +++ b/OpenDreamRuntime/Objects/DreamObjectTree.cs @@ -19,6 +19,8 @@ namespace OpenDreamRuntime.Objects; public sealed class DreamObjectTree { + // These all get set when the JSON is loaded so just disable the pragma +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. public TreeEntry[] Types { get; private set; } public List Procs { get; private set; } = new(); public List Strings { get; private set; } //TODO: Store this somewhere else @@ -50,6 +52,8 @@ public sealed class DreamObjectTree { private readonly Dictionary _pathToType = new(); private Dictionary _globalProcIds; +#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. + [Dependency] private readonly AtomManager _atomManager = default!; [Dependency] private readonly DreamManager _dreamManager = default!; [Dependency] private readonly IDreamMapManager _dreamMapManager = default!; @@ -498,7 +502,7 @@ public sealed class TreeEntry { public readonly string Path; public readonly int Id; public DreamObjectDefinition ObjectDefinition; - public TreeEntry ParentEntry; + public TreeEntry? ParentEntry; public readonly List InheritingTypes = new(); /// diff --git a/OpenDreamRuntime/Objects/Types/DreamObjectMob.cs b/OpenDreamRuntime/Objects/Types/DreamObjectMob.cs index ae5d9876d3..3eb2f23360 100644 --- a/OpenDreamRuntime/Objects/Types/DreamObjectMob.cs +++ b/OpenDreamRuntime/Objects/Types/DreamObjectMob.cs @@ -11,7 +11,7 @@ public int SeeInvisible { get => _sightComponent.SeeInvisibility; private set { _sightComponent.SeeInvisibility = (sbyte)value; - EntityManager.Dirty(_sightComponent); + EntityManager.Dirty(Entity, _sightComponent); } } @@ -19,7 +19,7 @@ public SightFlags Sight { get => _sightComponent.Sight; private set { _sightComponent.Sight = value; - EntityManager.Dirty(_sightComponent); + EntityManager.Dirty(Entity, _sightComponent); } } diff --git a/OpenDreamRuntime/Objects/Types/DreamObjectMovable.cs b/OpenDreamRuntime/Objects/Types/DreamObjectMovable.cs index 9b38720942..9649b3b69a 100644 --- a/OpenDreamRuntime/Objects/Types/DreamObjectMovable.cs +++ b/OpenDreamRuntime/Objects/Types/DreamObjectMovable.cs @@ -7,6 +7,7 @@ namespace OpenDreamRuntime.Objects.Types; [Virtual] public class DreamObjectMovable : DreamObjectAtom { + [Dependency] private readonly SharedMapSystem _mapSystem = default!; public EntityUid Entity; public readonly DMISpriteComponent SpriteComponent; public DreamObjectAtom? Loc; @@ -198,7 +199,8 @@ private void SetLoc(DreamObjectAtom? loc) { TransformSystem.SetLocalPosition(Entity, Vector2.Zero); break; case null: - TransformSystem.SetParent(Entity, MapManager.GetMapEntityId(MapId.Nullspace)); + _mapSystem.TryGetMap(MapId.Nullspace, out var mapId); + TransformSystem.SetParent(Entity, mapId!.Value); break; default: throw new ArgumentException($"Invalid loc {loc}"); diff --git a/OpenDreamRuntime/OpenDreamRuntime.csproj b/OpenDreamRuntime/OpenDreamRuntime.csproj index e6858df7e9..d7b8aa3cea 100644 --- a/OpenDreamRuntime/OpenDreamRuntime.csproj +++ b/OpenDreamRuntime/OpenDreamRuntime.csproj @@ -5,6 +5,7 @@ true Debug;Release;Tools AnyCPU + NU1507 diff --git a/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs b/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs index 29f372e2e1..c44bc5aff9 100644 --- a/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs +++ b/OpenDreamRuntime/Procs/DMOpcodeHandlers.cs @@ -220,7 +220,7 @@ public static ProcStatus CreateObject(DMProcState state) { if (!loc.TryGetValueAsDreamObject(out var turf)) ThrowInvalidTurfLoc(loc); - state.Proc.DreamMapManager.SetTurf(turf, objectDef, newArguments); + state.Proc.DreamMapManager.SetTurf(turf!, objectDef, newArguments); state.Push(loc); return ProcStatus.Continue; @@ -642,6 +642,7 @@ public static ProcStatus IsInList(DMProcState state) { } else { // BYOND ignores all floats, strings, types, etc. here and just returns 0. state.Push(DreamValue.False); + return ProcStatus.Continue; } } @@ -1414,8 +1415,8 @@ public static ProcStatus Call(DMProcState state) { DreamReference procRef = state.ReadReference(); var argumentInfo = state.ReadProcArguments(); - DreamObject instance; - DreamProc proc; + DreamObject? instance; + DreamProc? proc; switch (procRef.Type) { case DMReference.Type.Self: { instance = state.Instance; @@ -1442,8 +1443,8 @@ public static ProcStatus Call(DMProcState state) { } case DMReference.Type.SrcProc: { instance = state.Instance; - if (!instance.TryGetProc(state.ResolveString(procRef.Value), out proc)) - throw new Exception($"Type {instance.ObjectDefinition.Type} has no proc called \"{state.ResolveString(procRef.Value)}\""); + if (instance is null || !instance.TryGetProc(state.ResolveString(procRef.Value), out proc)) + throw new Exception($"Type {instance?.ObjectDefinition.Type ?? ""} has no proc called \"{state.ResolveString(procRef.Value)}\""); break; } @@ -2386,7 +2387,7 @@ public static ProcStatus BrowseResource(DMProcState state) { throw new Exception("Invalid browse_rsc() recipient"); } - connection?.BrowseResource(file, filename.IsNull ? Path.GetFileName(file.ResourcePath) : filename.GetValueAsString()); + connection?.BrowseResource(file, (filename.IsNull ? Path.GetFileName(file.ResourcePath) : filename.MustGetValueAsString())!); return ProcStatus.Continue; } diff --git a/OpenDreamRuntime/Procs/Native/DreamProcNativeRoot.cs b/OpenDreamRuntime/Procs/Native/DreamProcNativeRoot.cs index 8c24545377..84b6cc4e7b 100644 --- a/OpenDreamRuntime/Procs/Native/DreamProcNativeRoot.cs +++ b/OpenDreamRuntime/Procs/Native/DreamProcNativeRoot.cs @@ -29,7 +29,7 @@ namespace OpenDreamRuntime.Procs.Native; /// Note that this proc container also includes global procs which are used to create some DM objects, /// like filter(), matrix(), etc. /// -internal static class DreamProcNativeRoot { +internal static partial class DreamProcNativeRoot { private static readonly DreamResourceManager _resourceManager = IoCManager.Resolve(); [DreamProc("alert")] @@ -156,7 +156,7 @@ public static DreamValue NativeProc_animate(NativeProc.Bundle bundle, DreamObjec return DreamValue.Null; chainAnim = true; } - + bundle.LastAnimatedObject = new DreamValue(obj); if(obj.IsSubtypeOf(bundle.ObjectTree.Filter)) {//TODO animate filters return DreamValue.Null; @@ -466,7 +466,7 @@ public static DreamValue NativeProc_ckeyEx(NativeProc.Bundle bundle, DreamObject return DreamValue.Null; } - text = Regex.Replace(text, "[\\^]|[^A-z0-9@_-]", ""); //Remove all punctuation except - and _ + text = CkeyExRegex().Replace(text, ""); //Remove all punctuation except - and _ return new DreamValue(text); } @@ -803,7 +803,7 @@ public static DreamValue NativeProc_findtext(NativeProc.Bundle bundle, DreamObje return match.Success ? new DreamValue(match.Index + 1) : new DreamValue(0); } - int needleIndex = text.IndexOf(needle, start - 1, end - start, StringComparison.OrdinalIgnoreCase); + int needleIndex = text.IndexOf(needle!, start - 1, end - start, StringComparison.OrdinalIgnoreCase); return new DreamValue(needleIndex + 1); //1-indexed } @@ -846,7 +846,7 @@ public static DreamValue NativeProc_findtextEx(NativeProc.Bundle bundle, DreamOb return match.Success ? new DreamValue(match.Index + 1) : new DreamValue(0); } - int needleIndex = text.IndexOf(needle, start - 1, end - start, StringComparison.InvariantCulture); + int needleIndex = text.IndexOf(needle!, start - 1, end - start, StringComparison.InvariantCulture); if (needleIndex != -1) { return new DreamValue(needleIndex + 1); //1-indexed } else { @@ -3196,8 +3196,8 @@ public static async Task NativeProc_winget(AsyncNativeProc.State sta public static DreamValue NativeProc_winset(NativeProc.Bundle bundle, DreamObject? src, DreamObject? usr) { DreamValue player = bundle.GetArgument(0, "player"); DreamValue controlId = bundle.GetArgument(1, "control_id"); - string? winsetControlId = (!controlId.IsNull) ? controlId.GetValueAsString() : null; - string winsetParams = bundle.GetArgument(2, "params").GetValueAsString(); + string? winsetControlId = (!controlId.IsNull) ? controlId.MustGetValueAsString() : null; + string winsetParams = bundle.GetArgument(2, "params").MustGetValueAsString(); DreamConnection? connection = null; if (player.TryGetValueAsDreamObject(out var mob)) { @@ -3213,4 +3213,7 @@ public static DreamValue NativeProc_winset(NativeProc.Bundle bundle, DreamObject connection.WinSet(winsetControlId, winsetParams); return DreamValue.Null; } + + [GeneratedRegex("[\\^]|[^A-z0-9@_-]")] + private static partial Regex CkeyExRegex(); } diff --git a/OpenDreamRuntime/Procs/NativeProc.cs b/OpenDreamRuntime/Procs/NativeProc.cs index ae80f6895d..63d8a0a96d 100644 --- a/OpenDreamRuntime/Procs/NativeProc.cs +++ b/OpenDreamRuntime/Procs/NativeProc.cs @@ -8,7 +8,20 @@ namespace OpenDreamRuntime.Procs; -public sealed unsafe class NativeProc : DreamProc { +public sealed unsafe class NativeProc( + int id, + TreeEntry owningType, + string name, + List argumentNames, + Dictionary? defaultArgumentValues, + NativeProc.HandlerFn handler, + DreamManager dreamManager, + AtomManager atomManager, + IDreamMapManager mapManager, + DreamResourceManager resourceManager, + WalkManager walkManager, + DreamObjectTree objectTree) + : DreamProc(id, owningType, name, null, ProcAttributes.None, argumentNames, null, null, null, null, null, 0) { public delegate DreamValue HandlerFn(Bundle bundle, DreamObject? src, DreamObject? usr); public static (string, Dictionary?, List) GetNativeInfo(Delegate func) { @@ -40,12 +53,12 @@ public static (string, Dictionary?, List) GetNativeI return (procAttribute.Name, defaultArgumentValues, argumentNames); } - private readonly DreamManager _dreamManager; - private readonly AtomManager _atomManager; - private readonly IDreamMapManager _mapManager; - private readonly DreamResourceManager _resourceManager; - private readonly WalkManager _walkManager; - private readonly DreamObjectTree _objectTree; + private readonly DreamManager _dreamManager = dreamManager; + private readonly AtomManager _atomManager = atomManager; + private readonly IDreamMapManager _mapManager = mapManager; + private readonly DreamResourceManager _resourceManager = resourceManager; + private readonly WalkManager _walkManager = walkManager; + private readonly DreamObjectTree _objectTree = objectTree; public readonly ref struct Bundle { public readonly NativeProc Proc; @@ -86,21 +99,8 @@ private DreamValue GetArgumentFallback(string argumentName) { } } - private readonly Dictionary? _defaultArgumentValues; - private readonly delegate* _handler; - - public NativeProc(int id, TreeEntry owningType, string name, List argumentNames, Dictionary defaultArgumentValues, HandlerFn handler, DreamManager dreamManager, AtomManager atomManager, IDreamMapManager mapManager, DreamResourceManager resourceManager, WalkManager walkManager, DreamObjectTree objectTree) - : base(id, owningType, name, null, ProcAttributes.None, argumentNames, null, null, null, null, null, 0) { - _defaultArgumentValues = defaultArgumentValues; - _handler = (delegate*)handler.Method.MethodHandle.GetFunctionPointer(); - - _dreamManager = dreamManager; - _atomManager = atomManager; - _mapManager = mapManager; - _resourceManager = resourceManager; - _walkManager = walkManager; - _objectTree = objectTree; - } + private readonly Dictionary? _defaultArgumentValues = defaultArgumentValues; + private readonly delegate* _handler = (delegate*)handler.Method.MethodHandle.GetFunctionPointer(); public override ProcState CreateState(DreamThread thread, DreamObject? src, DreamObject? usr, DreamProcArguments arguments) { diff --git a/OpenDreamRuntime/Resources/ConsoleOutputResource.cs b/OpenDreamRuntime/Resources/ConsoleOutputResource.cs index 4d149862c9..364ea7a0ca 100644 --- a/OpenDreamRuntime/Resources/ConsoleOutputResource.cs +++ b/OpenDreamRuntime/Resources/ConsoleOutputResource.cs @@ -9,7 +9,7 @@ namespace OpenDreamRuntime.Resources; sealed class ConsoleOutputResource : DreamResource { public ConsoleOutputResource() : base(0, null, null) { } - public override string ReadAsString() { + public override string? ReadAsString() { return null; }