From 986adcf685cf42433d8232a82bee307573e661ad Mon Sep 17 00:00:00 2001 From: ike709 Date: Sun, 30 Oct 2022 10:53:40 -0700 Subject: [PATCH] Implements icon.Insert() (#714) * Implements icon.Insert() * nuke a reminder comment * Update OpenDreamShared/Resources/DMIParser.cs Co-authored-by: wixoa * Update OpenDreamShared/Resources/DMIParser.cs Co-authored-by: wixoa * Update OpenDreamShared/Resources/DMIParser.cs Co-authored-by: wixoa * Update OpenDreamRuntime/Procs/Native/DreamProcNativeIcon.cs Co-authored-by: wixoa * review Co-authored-by: ike709 Co-authored-by: wixoa --- DMCompiler/DMStandard/Types/Icon.dm | 1 - .../Procs/Native/DreamProcNative.cs | 1 + .../Procs/Native/DreamProcNativeIcon.cs | 43 +++++++++++++ OpenDreamShared/Resources/DMIParser.cs | 60 +++++++++++++++++++ 4 files changed, 104 insertions(+), 1 deletion(-) diff --git a/DMCompiler/DMStandard/Types/Icon.dm b/DMCompiler/DMStandard/Types/Icon.dm index 6047aaa93b..5c332640a0 100644 --- a/DMCompiler/DMStandard/Types/Icon.dm +++ b/DMCompiler/DMStandard/Types/Icon.dm @@ -25,7 +25,6 @@ return icon_states(src, mode) proc/Insert(new_icon, icon_state, dir, frame, moving, delay) - set opendream_unimplemented = TRUE proc/MapColors(...) set opendream_unimplemented = TRUE diff --git a/OpenDreamRuntime/Procs/Native/DreamProcNative.cs b/OpenDreamRuntime/Procs/Native/DreamProcNative.cs index d2a36efea7..d1e8ceb4b2 100644 --- a/OpenDreamRuntime/Procs/Native/DreamProcNative.cs +++ b/OpenDreamRuntime/Procs/Native/DreamProcNative.cs @@ -120,6 +120,7 @@ public static void SetupNativeProcs(DreamObjectTree objectTree) { DreamObjectDefinition icon = objectTree.GetObjectDefinition(DreamPath.Icon); icon.SetNativeProc(DreamProcNativeIcon.NativeProc_Width); icon.SetNativeProc(DreamProcNativeIcon.NativeProc_Height); + icon.SetNativeProc(DreamProcNativeIcon.NativeProc_Insert); //DreamObjectDefinition savefile = objectTree.GetObjectDefinitionFromPath(DreamPath.Savefile); //savefile.SetNativeProc(DreamProcNativeSavefile.NativeProc_Flush); diff --git a/OpenDreamRuntime/Procs/Native/DreamProcNativeIcon.cs b/OpenDreamRuntime/Procs/Native/DreamProcNativeIcon.cs index ebaaf9806c..6f3fc21d24 100644 --- a/OpenDreamRuntime/Procs/Native/DreamProcNativeIcon.cs +++ b/OpenDreamRuntime/Procs/Native/DreamProcNativeIcon.cs @@ -1,5 +1,6 @@ using OpenDreamRuntime.Objects; using OpenDreamRuntime.Objects.MetaObjects; +using OpenDreamShared.Dream; namespace OpenDreamRuntime.Procs.Native { static class DreamProcNativeIcon { @@ -17,6 +18,48 @@ public static DreamValue NativeProc_Height(DreamObject instance, DreamObject usr return new DreamValue(dreamIconObject.Description.Height); } + [DreamProc("Insert")] + [DreamProcParameter("new_icon", Type = DreamValue.DreamValueType.DreamObject)] + [DreamProcParameter("icon_state", Type = DreamValue.DreamValueType.String)] + [DreamProcParameter("dir", Type = DreamValue.DreamValueType.Float)] + [DreamProcParameter("frame", Type = DreamValue.DreamValueType.Float)] + [DreamProcParameter("moving", Type = DreamValue.DreamValueType.Float)] + [DreamProcParameter("delay", Type = DreamValue.DreamValueType.Float)] + public static DreamValue NativeProc_Insert(DreamObject instance, DreamObject usr, DreamProcArguments arguments) { + //TODO Figure out what happens when you pass the wrong types as args + if (!arguments.GetArgument(0, "new_icon").TryGetValueAsDreamObject(out var new_icon)) + { + // TODO: Implement this + if (arguments.GetArgument(0, "new_icon").TryGetValueAsDreamResource(out _)) + { + throw new NotImplementedException("icon.Insert() doesn't support DreamResources yet"); + } + } + arguments.GetArgument(1, "icon_state").TryGetValueAsString(out var icon_state); + AtomDirection? dir = null; + if (arguments.GetArgument(2, "dir").TryGetValueAsInteger(out var dirNum)) + { + dir = (AtomDirection)dirNum; + } + int? frame = null; + if (arguments.GetArgument(3, "frame").TryGetValueAsInteger(out var frameNum)) + { + frame = frameNum; + } + bool moving = !(arguments.GetArgument(4, "moving").TryGetValueAsInteger(out var movingNum) && movingNum == 0); + int? delay = null; + if (arguments.GetArgument(5, "delay").TryGetValueAsInteger(out var delayNum)) + { + delay = delayNum; + } + + DreamMetaObjectIcon.DreamIconObject instanceIconObject = DreamMetaObjectIcon.ObjectToDreamIcon[instance]; + DreamMetaObjectIcon.DreamIconObject newIconObject = DreamMetaObjectIcon.ObjectToDreamIcon[new_icon]; + instanceIconObject.Description.InsertIcon(newIconObject.Description, icon_state, dir, frame, delay); + + instanceIconObject.Moving = moving ? DreamMetaObjectIcon.DreamIconMovingMode.Movement : DreamMetaObjectIcon.DreamIconMovingMode.NonMovement; + return DreamValue.Null; + } } } diff --git a/OpenDreamShared/Resources/DMIParser.cs b/OpenDreamShared/Resources/DMIParser.cs index fa46640f5e..5c707edb0c 100644 --- a/OpenDreamShared/Resources/DMIParser.cs +++ b/OpenDreamShared/Resources/DMIParser.cs @@ -7,6 +7,7 @@ using System.Text; using OpenDreamShared.Dream; using System.Globalization; +using JetBrains.Annotations; namespace OpenDreamShared.Resources { public static class DMIParser { @@ -44,6 +45,65 @@ public static ParsedDMIDescription CreateEmpty(int width, int height) { }; } + private static ParsedDMIDescription CloneDescription(ParsedDMIDescription original) + { + Dictionary stateCopy = new(original.States.Count); + foreach (var key in original.States.Keys) + { + stateCopy.Add(key, original.States[key]); + } + + return new ParsedDMIDescription() { + Source = original.Source, + Version = original.Version, + Width = original.Width, + Height = original.Height, + States = stateCopy + }; + } + + public void InsertIcon(ParsedDMIDescription original_icon, string icon_state, AtomDirection? dir, int? frame, float? delay) + { + var icon = CloneDescription(original_icon); + IEnumerable states; + if (icon_state is null) { + states = icon.States.Values; + } else { + states = new ParsedDMIState[] { icon.States[icon_state] }; + } + + foreach (var state in states) + { + if (dir is not null) + { + var goodDir = state.Directions[dir.Value]; + state.Directions.Clear(); + state.Directions = new Dictionary(1) { { dir.Value, goodDir } }; + } + + if (frame is not null) + { + // TODO Ref says it must start at 1, need to check behavior for when it's less. Manually validate it for now. + var goodFrame = Math.Max(frame.Value, 1); + foreach (var (direction, frames) in state.Directions) + { + state.Directions[direction] = new ParsedDMIFrame[1] { frames[goodFrame] }; + if (delay is not null or 0) { + state.Rewind = delay < 0; + frames[goodFrame].Delay = Math.Abs(delay.Value); + } + } + } + } + + // All of that above was just to adjust the inserted icon to match the args. Now we can actually insert it. + + foreach (var state in states) + { + States[state.Name] = state; + } + } + public bool HasState(string stateName = null) { return States.ContainsKey(stateName ?? ""); }