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
11 changes: 10 additions & 1 deletion OpenDreamRuntime/DreamThread.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ public abstract class ProcState : IDisposable {

public bool WaitFor { get; set; } = true;

/// <summary> This stores our 'src' value. May be null!</summary>
public DreamObject? Instance;

public DreamObject? Usr;
public int ArgumentCount;
public abstract DreamProc? Proc { get; }

protected void Initialize(DreamThread thread, bool waitFor) {
Expand Down Expand Up @@ -173,6 +178,10 @@ public virtual void Dispose() {
WaitFor = true;
Id = -1;
}

public abstract ReadOnlySpan<DreamValue> GetArguments();

public abstract void SetArgument(int id, DreamValue value);
}

public sealed class DreamThread(string name) {
Expand Down Expand Up @@ -214,7 +223,7 @@ public static DreamValue Run(DreamProc proc, DreamObject src, DreamObject? usr,
return context.Resume();
}

public static DreamValue Run(string name, Func<AsyncNativeProc.State, Task<DreamValue>> anonymousFunc) {
public static DreamValue Run(string name, Func<AsyncNativeProc.AsyncNativeProcState, Task<DreamValue>> anonymousFunc) {
var context = new DreamThread(name);
var state = AsyncNativeProc.CreateAnonymousState(context, anonymousFunc);
context.PushProcState(state);
Expand Down
6 changes: 3 additions & 3 deletions OpenDreamRuntime/Objects/DreamObjectTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ internal NativeProc CreateNativeProc(TreeEntry owningType, NativeProc.HandlerFn
return proc;
}

private AsyncNativeProc CreateAsyncNativeProc(TreeEntry owningType, Func<AsyncNativeProc.State, Task<DreamValue>> func) {
private AsyncNativeProc CreateAsyncNativeProc(TreeEntry owningType, Func<AsyncNativeProc.AsyncNativeProcState, Task<DreamValue>> func) {
var (name, defaultArgumentValues, argumentNames) = NativeProc.GetNativeInfo(func);
var proc = new AsyncNativeProc(Procs.Count, owningType, name, argumentNames, defaultArgumentValues, func);

Expand All @@ -517,7 +517,7 @@ internal void SetGlobalNativeProc(NativeProc.HandlerFn func) {
Procs[proc.Id] = proc;
}

public void SetGlobalNativeProc(Func<AsyncNativeProc.State, Task<DreamValue>> func) {
public void SetGlobalNativeProc(Func<AsyncNativeProc.AsyncNativeProcState, Task<DreamValue>> func) {
var (name, defaultArgumentValues, argumentNames) = NativeProc.GetNativeInfo(func);
var proc = new AsyncNativeProc(_globalProcIds[name], Root, name, argumentNames, defaultArgumentValues, func);

Expand All @@ -530,7 +530,7 @@ internal void SetNativeProc(TreeEntry type, NativeProc.HandlerFn func) {
type.ObjectDefinition.SetProcDefinition(proc.Name, proc.Id);
}

public void SetNativeProc(TreeEntry type, Func<AsyncNativeProc.State, Task<DreamValue>> func) {
public void SetNativeProc(TreeEntry type, Func<AsyncNativeProc.AsyncNativeProcState, Task<DreamValue>> func) {
var proc = CreateAsyncNativeProc(type, func);

type.ObjectDefinition.SetProcDefinition(proc.Name, proc.Id);
Expand Down
2 changes: 1 addition & 1 deletion OpenDreamRuntime/Objects/Types/DreamList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1567,7 +1567,7 @@ public override int GetLength() {
}

// proc args list
internal sealed class ProcArgsList(DreamObjectDefinition listDef, DMProcState state) : DreamList(listDef, 0) {
internal sealed class ProcArgsList(DreamObjectDefinition listDef, ProcState state) : DreamList(listDef, 0) {
public override DreamValue GetValue(DreamValue key) {
if (!key.TryGetValueAsInteger(out var index))
throw new Exception($"Invalid index into args list: {key}");
Expand Down
66 changes: 38 additions & 28 deletions OpenDreamRuntime/Procs/AsyncNativeProc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,19 @@
using Dependency = Robust.Shared.IoC.DependencyAttribute;

namespace OpenDreamRuntime.Procs {
public sealed class AsyncNativeProc : DreamProc {
public sealed class State : ProcState {
public static readonly Stack<State> Pool = new();
public sealed class AsyncNativeProc(
int id,
TreeEntry owningType,
string name,
List<string> argumentNames,
Dictionary<string, DreamValue> defaultArgumentValues,
Func<AsyncNativeProc.AsyncNativeProcState, Task<DreamValue>> taskFunc)
: DreamProc(id, owningType, name, null, ProcAttributes.None, argumentNames, null, null, null, null, null, 0) {
/// <summary>
/// ProcState specifically for running native procs, not DM procs
/// </summary>
public sealed class AsyncNativeProcState : ProcState {
public static readonly Stack<AsyncNativeProcState> Pool = new();

#if TOOLS
public override (string SourceFile, int Line) TracyLocationId => ("Async Native Proc", 0);
Expand All @@ -21,16 +31,12 @@
[Dependency] public readonly DreamObjectTree ObjectTree = default!;
[Dependency] public readonly ProcScheduler ProcScheduler = default!;

public DreamObject? Src;
public DreamObject? Usr;

private readonly DreamValue[] _arguments = new DreamValue[128];
private int _argumentCount;

public override DreamProc? Proc => _proc;
private AsyncNativeProc? _proc;

private Func<State, Task<DreamValue>> _taskFunc;
private Func<AsyncNativeProcState, Task<DreamValue>> _taskFunc;
private Task? _task;

private ProcState? _callProcNotify;
Expand All @@ -39,19 +45,19 @@

private bool _inResume;

public State() {
public AsyncNativeProcState() {
IoCManager.InjectDependencies(this);
}

public void Initialize(AsyncNativeProc? proc, Func<State, Task<DreamValue>> taskFunc, DreamThread thread, DreamObject? src, DreamObject? usr, DreamProcArguments arguments) {
public void Initialize(AsyncNativeProc? proc, Func<AsyncNativeProcState, Task<DreamValue>> taskFunc, DreamThread thread, DreamObject? src, DreamObject? usr, DreamProcArguments arguments) {
base.Initialize(thread, true);

_proc = proc;
_taskFunc = taskFunc;
Src = src;
Instance = src;
Usr = usr;
arguments.Values.CopyTo(_arguments);
_argumentCount = arguments.Count;
ArgumentCount = arguments.Count;
}

// Used to avoid reentrant resumptions in our proc
Expand Down Expand Up @@ -96,9 +102,9 @@
public override void Dispose() {
base.Dispose();

Src = null!;
Instance = null!;
Usr = null!;
_argumentCount = 0;
ArgumentCount = 0;
_proc = null!;
_taskFunc = null!;
_task = null;
Expand Down Expand Up @@ -162,34 +168,38 @@

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public DreamValue GetArgument(int argumentPosition, string argumentName) {
if (argumentPosition < _argumentCount && _arguments[argumentPosition] != DreamValue.Null)
if (argumentPosition < ArgumentCount && _arguments[argumentPosition] != DreamValue.Null)
return _arguments[argumentPosition];

return _proc?._defaultArgumentValues?.TryGetValue(argumentName, out var argValue) == true ? argValue : DreamValue.Null;
}
}

private readonly Dictionary<string, DreamValue>? _defaultArgumentValues;
private readonly Func<State, Task<DreamValue>> _taskFunc;
public override ReadOnlySpan<DreamValue> GetArguments() {
return _arguments.AsSpan(0, ArgumentCount);
}

public override void SetArgument(int id, DreamValue value) {
if (id < 0 || id >= ArgumentCount)
throw new IndexOutOfRangeException($"Given argument id ({id}) was out of range");

public AsyncNativeProc(int id, TreeEntry owningType, string name, List<string> argumentNames, Dictionary<string, DreamValue> defaultArgumentValues, Func<State, Task<DreamValue>> taskFunc)
: base(id, owningType, name, null, ProcAttributes.None, argumentNames, null, null, null, null, null, 0) {
_defaultArgumentValues = defaultArgumentValues;
_taskFunc = taskFunc;
_arguments[id] = value;
}
}

private readonly Dictionary<string, DreamValue>? _defaultArgumentValues = defaultArgumentValues;

public override ProcState CreateState(DreamThread thread, DreamObject? src, DreamObject? usr, DreamProcArguments arguments) {
if (!State.Pool.TryPop(out var state)) {
state = new State();
if (!AsyncNativeProcState.Pool.TryPop(out var state)) {
state = new AsyncNativeProcState();
}

state.Initialize(this, _taskFunc, thread, src, usr, arguments);
state.Initialize(this, taskFunc, thread, src, usr, arguments);
return state;
}

public static ProcState CreateAnonymousState(DreamThread thread, Func<State, Task<DreamValue>> taskFunc) {
if (!State.Pool.TryPop(out var state)) {
state = new State();
public static ProcState CreateAnonymousState(DreamThread thread, Func<AsyncNativeProcState, Task<DreamValue>> taskFunc) {
if (!AsyncNativeProcState.Pool.TryPop(out var state)) {
state = new AsyncNativeProcState();
}

state.Initialize(null, taskFunc, thread, null, null, new DreamProcArguments());
Expand Down
17 changes: 10 additions & 7 deletions OpenDreamRuntime/Procs/DMProc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,14 @@ public override void Dispose() {
_proc = null;
Pool.Push(this);
}

public override ReadOnlySpan<DreamValue> GetArguments() {
throw new InvalidOperationException();
}

public override void SetArgument(int id, DreamValue value) {
throw new InvalidOperationException();
}
}

public sealed class DMProcState : ProcState {
Expand Down Expand Up @@ -352,11 +360,6 @@ public sealed class DMProcState : ProcState {
public ProcScheduler ProcScheduler => _proc.ProcScheduler;
public IDreamDebugManager DebugManager => _proc.DreamDebugManager;

/// <summary> This stores our 'src' value. May be null!</summary>
public DreamObject? Instance;

public DreamObject? Usr;
public int ArgumentCount;
public readonly IDreamValueEnumerator?[] Enumerators = new IDreamValueEnumerator?[16];

public int ProgramCounter => _pc;
Expand Down Expand Up @@ -581,11 +584,11 @@ public override void Dispose() {
Pool.Push(this);
}

public ReadOnlySpan<DreamValue> GetArguments() {
public override ReadOnlySpan<DreamValue> GetArguments() {
return _localVariables.AsSpan(0, ArgumentCount);
}

public void SetArgument(int id, DreamValue value) {
public override void SetArgument(int id, DreamValue value) {
if (id < 0 || id >= ArgumentCount)
throw new IndexOutOfRangeException($"Given argument id ({id}) was out of range");

Expand Down
11 changes: 11 additions & 0 deletions OpenDreamRuntime/Procs/InitDreamObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,17 @@ public override void AppendStackFrame(StringBuilder builder) {
builder.AppendLine($"new {_dreamObject.ObjectDefinition.Type}");
}

public override ReadOnlySpan<DreamValue> GetArguments() {
return _arguments.AsSpan(0, ArgumentCount);
}

public override void SetArgument(int id, DreamValue value) {
if (id < 0 || id >= ArgumentCount)
throw new IndexOutOfRangeException($"Given argument id ({id}) was out of range");

_arguments[id] = value;
}

public override void Dispose() {
base.Dispose();

Expand Down
4 changes: 2 additions & 2 deletions OpenDreamRuntime/Procs/Native/DreamProcNativeClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ namespace OpenDreamRuntime.Procs.Native;

internal static class DreamProcNativeClient {
[DreamProc("SoundQuery")]
public static async Task<DreamValue> NativeProc_SoundQuery(AsyncNativeProc.State state) {
var client = (DreamObjectClient)state.Src!;
public static async Task<DreamValue> NativeProc_SoundQuery(AsyncNativeProc.AsyncNativeProcState state) {
var client = (DreamObjectClient)state.Instance!;
return await client.Connection.SoundQuery();
}
}
8 changes: 4 additions & 4 deletions OpenDreamRuntime/Procs/Native/DreamProcNativeRoot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ internal static class DreamProcNativeRoot {
[DreamProcParameter("Button1", Type = DreamValueTypeFlag.String)]
[DreamProcParameter("Button2", Type = DreamValueTypeFlag.String)]
[DreamProcParameter("Button3", Type = DreamValueTypeFlag.String)]
public static async Task<DreamValue> NativeProc_alert(AsyncNativeProc.State state) {
public static async Task<DreamValue> NativeProc_alert(AsyncNativeProc.AsyncNativeProcState state) {
string message, title, button1, button2, button3;

DreamValue usrArgument = state.GetArgument(0, "Usr");
Expand Down Expand Up @@ -2332,7 +2332,7 @@ public static DreamValue NativeProc_sign(NativeProc.Bundle bundle, DreamObject?

[DreamProc("sleep")]
[DreamProcParameter("Delay", Type = DreamValueTypeFlag.Float)]
public static async Task<DreamValue> NativeProc_sleep(AsyncNativeProc.State state) {
public static async Task<DreamValue> NativeProc_sleep(AsyncNativeProc.AsyncNativeProcState state) {
state.GetArgument(0, "Delay").TryGetValueAsFloat(out float delay);

await state.ProcScheduler.CreateDelay(delay);
Expand Down Expand Up @@ -3337,7 +3337,7 @@ public static DreamValue NativeProc_winclone(NativeProc.Bundle bundle, DreamObje
[DreamProc("winexists")]
[DreamProcParameter("player", Type = DreamValueTypeFlag.DreamObject)]
[DreamProcParameter("control_id", Type = DreamValueTypeFlag.String)]
public static async Task<DreamValue> NativeProc_winexists(AsyncNativeProc.State state) {
public static async Task<DreamValue> NativeProc_winexists(AsyncNativeProc.AsyncNativeProcState state) {
DreamValue player = state.GetArgument(0, "player");
if (!state.GetArgument(1, "control_id").TryGetValueAsString(out var controlId)) {
return DreamValue.EmptyString;
Expand All @@ -3361,7 +3361,7 @@ public static async Task<DreamValue> NativeProc_winexists(AsyncNativeProc.State
[DreamProcParameter("player", Type = DreamValueTypeFlag.DreamObject)]
[DreamProcParameter("control_id", Type = DreamValueTypeFlag.String)]
[DreamProcParameter("params", Type = DreamValueTypeFlag.String)]
public static async Task<DreamValue> NativeProc_winget(AsyncNativeProc.State state) {
public static async Task<DreamValue> NativeProc_winget(AsyncNativeProc.AsyncNativeProcState state) {
DreamValue player = state.GetArgument(0, "player");
state.GetArgument(1, "control_id").TryGetValueAsString(out var controlId);
if (!state.GetArgument(2, "params").TryGetValueAsString(out var paramsValue))
Expand Down
2 changes: 1 addition & 1 deletion OpenDreamRuntime/Procs/Native/DreamProcNativeWorld.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ internal static class DreamProcNativeWorld {
[DreamProcParameter("File", Type = DreamValue.DreamValueTypeFlag.DreamObject)]
[DreamProcParameter("Persist", Type = DreamValue.DreamValueTypeFlag.Float, DefaultValue = 0)]
[DreamProcParameter("Clients", Type = DreamValue.DreamValueTypeFlag.DreamObject)]
public static async Task<DreamValue> NativeProc_Export(AsyncNativeProc.State state) {
public static async Task<DreamValue> NativeProc_Export(AsyncNativeProc.AsyncNativeProcState state) {
var addr = state.GetArgument(0, "Addr").Stringify();

if (!Uri.TryCreate(addr, UriKind.RelativeOrAbsolute, out var uri))
Expand Down
8 changes: 4 additions & 4 deletions OpenDreamRuntime/Procs/ProcScheduler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@
namespace OpenDreamRuntime.Procs;

public sealed partial class ProcScheduler {
private readonly HashSet<AsyncNativeProc.State> _sleeping = new();
private readonly Queue<AsyncNativeProc.State> _scheduled = new();
private AsyncNativeProc.State? _current;
private readonly HashSet<AsyncNativeProc.AsyncNativeProcState> _sleeping = new();
private readonly Queue<AsyncNativeProc.AsyncNativeProcState> _scheduled = new();
private AsyncNativeProc.AsyncNativeProcState? _current;

public Task Schedule(AsyncNativeProc.State state, Func<AsyncNativeProc.State, Task<DreamValue>> taskFunc) {
public Task Schedule(AsyncNativeProc.AsyncNativeProcState state, Func<AsyncNativeProc.AsyncNativeProcState, Task<DreamValue>> taskFunc) {
async Task Foo() {
state.Result = await taskFunc(state);
if (!_sleeping.Remove(state))
Expand Down
Loading