Skip to content

Commit

Permalink
Implements DreamMetaObjectIcon, Width(), Height() (#650)
Browse files Browse the repository at this point in the history
* Implements DreamMetaObjectIcon, Width(), Height()

* Cleanup

* Clean it up but do it well

* Update OpenDreamRuntime/Objects/MetaObjects/DreamMetaObjectIcon.cs

Co-authored-by: wixoa <[email protected]>

* Update OpenDreamRuntime/Objects/MetaObjects/DreamMetaObjectIcon.cs

Co-authored-by: wixoa <[email protected]>

* Update OpenDreamRuntime/Objects/MetaObjects/DreamMetaObjectIcon.cs

Co-authored-by: wixoa <[email protected]>

* de-nullify

* fix

Co-authored-by: ike709 <[email protected]>
Co-authored-by: wixoa <[email protected]>
  • Loading branch information
3 people authored May 11, 2022
1 parent 323acbb commit c362445
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 11 deletions.
11 changes: 4 additions & 7 deletions DMCompiler/DMStandard/Types/Icon.dm
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
/icon
parent_type = /datum
var/icon

New(icon, icon_state, dir, frame, moving)

proc/Blend(icon, function = ICON_ADD, x = 1, y = 1)
set opendream_unimplemented = TRUE
CRASH("/icon.Blend() is not implemented")

proc/Crop(x1, y1, x2, y2)
set opendream_unimplemented = TRUE
CRASH("/icon.Crop() is not implemented")
Expand All @@ -18,14 +19,12 @@
proc/Flip(dir)
set opendream_unimplemented = TRUE
CRASH("/icon.Flip() is not implemented")

proc/GetPixel(x, y, icon_state, dir = 0, frame = 0, moving = -1)
set opendream_unimplemented = TRUE
CRASH("/icon.GetPixel() is not implemented")

proc/Height()
set opendream_unimplemented = TRUE
CRASH("/icon.Height() is not implemented")

proc/IconStates(mode = 0)
return icon_states(src, mode)
Expand Down Expand Up @@ -59,8 +58,6 @@
CRASH("/icon.Turn() is not implemented")

proc/Width()
set opendream_unimplemented = TRUE
CRASH("/icon.Width() is not implemented")

proc/icon(...)
return new /icon(arglist(args))
return new /icon(arglist(args))
1 change: 1 addition & 0 deletions OpenDreamRuntime/DreamManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ private void SetMetaObjects() {
ObjectTree.SetMetaObject(DreamPath.Turf, new DreamMetaObjectTurf());
ObjectTree.SetMetaObject(DreamPath.Movable, new DreamMetaObjectMovable());
ObjectTree.SetMetaObject(DreamPath.Mob, new DreamMetaObjectMob());
ObjectTree.SetMetaObject(DreamPath.Icon, new DreamMetaObjectIcon());
}

public void SetGlobalNativeProc(NativeProc.HandlerFn func) {
Expand Down
140 changes: 140 additions & 0 deletions OpenDreamRuntime/Objects/MetaObjects/DreamMetaObjectIcon.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
using System.Collections.Generic;
using System.IO;
using OpenDreamRuntime.Procs;
using OpenDreamRuntime.Resources;
using OpenDreamShared.Dream;
using OpenDreamShared.Resources;

namespace OpenDreamRuntime.Objects.MetaObjects {
sealed class DreamMetaObjectIcon : DreamMetaObjectDatum
{
[Dependency] private readonly DreamResourceManager _rscMan = default!;

public enum DreamIconMovingMode : byte
{
Both = 0,
Movement = 1,
NonMovement = 2,

}

public static Dictionary<DreamObject, DreamIconObject> ObjectToDreamIcon = new();

public struct DreamIconObject {
// Actual DMI data
public DMIParser.ParsedDMIDescription Description; // TODO Eventually this should probably be removed in favor of just directly storing the data for the subset of the DMI that we actually care about

// These vars correspond to the args in icon/new() and the resulting /icon obj, not the actual DMI data
public string Icon;
public string? State; // Specific icon_state. Null is all states.
public AtomDirection? Direction; // Specific dir. Null is all dirs.
public byte? Frame; //1-indexed. Specific frame. Null is all frames.
public DreamIconMovingMode Moving;

public DreamIconObject(DreamResource rsc, DreamValue state, DreamValue dir, DreamValue frame, DreamValue moving)
{
if (Path.GetExtension(rsc.ResourcePath) != ".dmi")
{
throw new Exception("Invalid icon file");
}

Description = DMIParser.ParseDMI(new MemoryStream(rsc.ResourceData));
Icon = rsc.ResourcePath;

// TODO confirm BYOND behavior of invalid args for icon, dir, and frame

if (state.TryGetValueAsString(out var iconState))
{
State = iconState;
}
else
{
State = null;
}

if (dir.TryGetValueAsInteger(out var dirVal) && (AtomDirection)dirVal != AtomDirection.None)
{
Direction = (AtomDirection)dirVal;
}
else
{
Direction = null;
}

if (frame.TryGetValueAsInteger(out var frameVal))
{
//TODO: Figure out how many frames an icon can have and see if this needs to be bigger than a byte
Frame = Convert.ToByte(frameVal - 1); //1-indexed
}
else
{
Frame = null;
}

if (moving != DreamValue.Null)
{
if (moving.TryGetValueAsInteger(out var movingVal) && movingVal == 0)
{
Moving = DreamIconMovingMode.NonMovement;
}
else
{
Moving = DreamIconMovingMode.Movement;
}
}
else
{
Moving = DreamIconMovingMode.Both;
}
}
}

public override void OnObjectCreated(DreamObject dreamObject, DreamProcArguments creationArguments) {
base.OnObjectCreated(dreamObject, creationArguments);

DreamValue icon = creationArguments.GetArgument(0, "icon");
DreamValue state = creationArguments.GetArgument(1, "icon_state");
DreamValue dir = creationArguments.GetArgument(2, "dir");
DreamValue frame = creationArguments.GetArgument(3, "frame");
DreamValue moving = creationArguments.GetArgument(4, "moving");

DreamIconObject dreamIconObject;

if (icon.TryGetValueAsDreamObjectOfType(DreamPath.Icon, out DreamObject copyFrom)) {
dreamIconObject = ObjectToDreamIcon[copyFrom];
} else if (icon.TryGetValueAsString(out string fileString))
{
var ext = Path.GetExtension(fileString);
switch (ext) // TODO implement other icon file types
{
case ".dmi":
dreamIconObject = new DreamIconObject(_rscMan.LoadResource(fileString), state, dir, frame, moving);
break;
case ".png":
case ".jpg":
case ".rsi": // RT-specific, not in BYOND
case ".gif":
case ".bmp":
throw new NotImplementedException($"Unimplemented icon type '{ext}'");
default:
throw new Exception($"Invalid icon file {fileString}");
}

} else if (icon.TryGetValueAsDreamResource(out var rsc))
{
dreamIconObject = new DreamIconObject(rsc, state, dir, frame, moving);
} else {
throw new Exception("Invalid icon file " + icon);
}

ObjectToDreamIcon.Add(dreamObject, dreamIconObject);

}

public override void OnObjectDeleted(DreamObject dreamObject) {
ObjectToDreamIcon.Remove(dreamObject);

base.OnObjectDeleted(dreamObject);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using OpenDreamShared.Dream;

namespace OpenDreamRuntime.Objects.MetaObjects {
class DreamMetaObjectRegex : DreamMetaObjectDatum {
sealed class DreamMetaObjectRegex : DreamMetaObjectDatum {
public struct DreamRegex {
public Regex Regex;
public bool IsGlobal;
Expand Down
4 changes: 4 additions & 0 deletions OpenDreamRuntime/Procs/Native/DreamProcNative.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ public static void SetupNativeProcs(DreamObjectTree objectTree) {
regex.SetNativeProc(DreamProcNativeRegex.NativeProc_Find);
regex.SetNativeProc(DreamProcNativeRegex.NativeProc_Replace);

DreamObjectDefinition icon = objectTree.GetObjectDefinition(DreamPath.Icon);
icon.SetNativeProc(DreamProcNativeIcon.NativeProc_Width);
icon.SetNativeProc(DreamProcNativeIcon.NativeProc_Height);

//DreamObjectDefinition savefile = objectTree.GetObjectDefinitionFromPath(DreamPath.Savefile);
//savefile.SetNativeProc(DreamProcNativeSavefile.NativeProc_Flush);

Expand Down
23 changes: 23 additions & 0 deletions OpenDreamRuntime/Procs/Native/DreamProcNativeIcon.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using OpenDreamRuntime.Objects;
using OpenDreamRuntime.Objects.MetaObjects;

namespace OpenDreamRuntime.Procs.Native {
static class DreamProcNativeIcon {
[DreamProc("Width")]
public static DreamValue NativeProc_Width(DreamObject instance, DreamObject usr, DreamProcArguments arguments) {
DreamMetaObjectIcon.DreamIconObject dreamIconObject = DreamMetaObjectIcon.ObjectToDreamIcon[instance];

return new DreamValue(dreamIconObject.Description.Width);
}

[DreamProc("Height")]
public static DreamValue NativeProc_Height(DreamObject instance, DreamObject usr, DreamProcArguments arguments) {
DreamMetaObjectIcon.DreamIconObject dreamIconObject = DreamMetaObjectIcon.ObjectToDreamIcon[instance];

return new DreamValue(dreamIconObject.Description.Height);
}


}
}
6 changes: 3 additions & 3 deletions OpenDreamShared/Resources/DMIParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static class DMIParser {
AtomDirection.Northwest
};

public class ParsedDMIDescription {
public sealed class ParsedDMIDescription {
public string Source;
public float Version;
public int Width, Height;
Expand Down Expand Up @@ -55,7 +55,7 @@ public ParsedDMIState GetState(string stateName = null) {
}
}

public class ParsedDMIState {
public sealed class ParsedDMIState {
public string Name;
public Dictionary<AtomDirection, ParsedDMIFrame[]> Directions = new();
public bool Loop = true;
Expand All @@ -68,7 +68,7 @@ public ParsedDMIFrame[] GetFrames(AtomDirection direction = AtomDirection.South)
}
}

public class ParsedDMIFrame {
public sealed class ParsedDMIFrame {
public int X, Y;
public float Delay;
}
Expand Down

0 comments on commit c362445

Please sign in to comment.