Skip to content

Commit

Permalink
Implement usr << link() (#2166)
Browse files Browse the repository at this point in the history
  • Loading branch information
wixoaGit authored Jan 14, 2025
1 parent 788b84b commit b7a1c57
Show file tree
Hide file tree
Showing 14 changed files with 108 additions and 3 deletions.
3 changes: 2 additions & 1 deletion DMCompiler/Bytecode/DreamProcOpcode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ public enum DreamProcOpcode : byte {
[OpcodeMetadata(-1)]
Power = 0x42,
//0x43,
//0x44
[OpcodeMetadata(-2)]
Link = 0x44,
[OpcodeMetadata(-3, OpcodeArgType.TypeId)]
Prompt = 0x45,
[OpcodeMetadata(-3)]
Expand Down
8 changes: 8 additions & 0 deletions DMCompiler/Compiler/DM/AST/DMAST.ProcStatements.cs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,14 @@ public sealed class DMASTProcStatementOutputControl(
public DMASTExpression Control = control;
}

public sealed class DMASTProcStatementLink(
Location location,
DMASTExpression receiver,
DMASTExpression url) : DMASTProcStatement(location) {
public readonly DMASTExpression Receiver = receiver;
public readonly DMASTExpression Url = url;
}

public sealed class DMASTProcStatementFtp(
Location location,
DMASTExpression receiver,
Expand Down
10 changes: 10 additions & 0 deletions DMCompiler/Compiler/DM/DMParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,16 @@ public DMASTFile File() {
DMASTExpression control = procCall.Parameters[1].Value;
return new DMASTProcStatementOutputControl(loc, leftShift.LHS, msg, control);
}
case "link": {
if (procCall.Parameters.Length != 1) {
Emit(WarningCode.InvalidArgumentCount, procCall.Location,
"link() requires 1 parameter");
return new DMASTInvalidProcStatement(procCall.Location);
}

DMASTExpression url = procCall.Parameters[0].Value;
return new DMASTProcStatementLink(loc, leftShift.LHS, url);
}
case "ftp": {
if (procCall.Parameters.Length is not 1 and not 2) {
Emit(WarningCode.InvalidArgumentCount, procCall.Location,
Expand Down
7 changes: 7 additions & 0 deletions DMCompiler/DM/Builders/DMProcBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ public void ProcessStatement(DMASTProcStatement statement) {
case DMASTProcStatementBrowse statementBrowse: ProcessStatementBrowse(statementBrowse); break;
case DMASTProcStatementBrowseResource statementBrowseResource: ProcessStatementBrowseResource(statementBrowseResource); break;
case DMASTProcStatementOutputControl statementOutputControl: ProcessStatementOutputControl(statementOutputControl); break;
case DMASTProcStatementLink statementLink: ProcessStatementLink(statementLink); break;
case DMASTProcStatementFtp statementFtp: ProcessStatementFtp(statementFtp); break;
case DMASTProcStatementOutput statementOutput: ProcessStatementOutput(statementOutput); break;
case DMASTProcStatementInput statementInput: ProcessStatementInput(statementInput); break;
Expand Down Expand Up @@ -893,6 +894,12 @@ public void ProcessStatementOutputControl(DMASTProcStatementOutputControl statem
proc.OutputControl();
}

public void ProcessStatementLink(DMASTProcStatementLink statementLink) {
_exprBuilder.Emit(statementLink.Receiver);
_exprBuilder.Emit(statementLink.Url);
proc.Link();
}

public void ProcessStatementFtp(DMASTProcStatementFtp statementFtp) {
_exprBuilder.Emit(statementFtp.Receiver);
_exprBuilder.Emit(statementFtp.File);
Expand Down
4 changes: 4 additions & 0 deletions DMCompiler/DM/DMProc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,10 @@ public void OutputControl() {
WriteOpcode(DreamProcOpcode.OutputControl);
}

public void Link() {
WriteOpcode(DreamProcOpcode.Link);
}

public void Ftp() {
WriteOpcode(DreamProcOpcode.Ftp);
}
Expand Down
2 changes: 0 additions & 2 deletions DMCompiler/DMStandard/UnsortedAdditions.dm
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@
set opendream_unimplemented = TRUE
/proc/issaved(v)
set opendream_unimplemented = TRUE
/proc/link(url)
set opendream_unimplemented = TRUE
/proc/load_resource(File)
set opendream_unimplemented = TRUE
proc/missile(Type, Start, End)
Expand Down
1 change: 1 addition & 0 deletions OpenDream.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=MissingBlankLines/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantBlankLines/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UseCollectionExpression/@EntryIndexedValue">NONE</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=PreferConcreteValueOverDefault/@EntryIndexedValue">NONE</s:String>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AROUND_SINGLE_LINE_TYPE/@EntryValue">0</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_CODE/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue">1</s:Int64>
Expand Down
19 changes: 19 additions & 0 deletions OpenDreamClient/Interface/DreamInterfaceManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ internal sealed class DreamInterfaceManager : IDreamInterfaceManager {
[Dependency] private readonly IUserInterfaceManager _uiManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ITimerManager _timerManager = default!;
[Dependency] private readonly IUriOpener _uriOpener = default!;

private readonly ISawmill _sawmill = Logger.GetSawmill("opendream.interface");

Expand Down Expand Up @@ -117,6 +118,7 @@ public void Initialize() {
_netManager.RegisterNetMessage<MsgWinClone>(RxWinClone);
_netManager.RegisterNetMessage<MsgWinExists>(RxWinExists);
_netManager.RegisterNetMessage<MsgWinGet>(RxWinGet);
_netManager.RegisterNetMessage<MsgLink>(RxLink);
_netManager.RegisterNetMessage<MsgFtp>(RxFtp);
_netManager.RegisterNetMessage<MsgLoadInterface>(RxLoadInterface);
_netManager.RegisterNetMessage<MsgAckLoadInterface>();
Expand Down Expand Up @@ -256,6 +258,23 @@ private void RxWinGet(MsgWinGet message) {
}));
}

private void RxLink(MsgLink message) {
Uri uri;
try {
uri = new Uri(message.Url);
} catch (Exception e) {
_sawmill.Error($"Received link \"{message.Url}\" which failed to parse as a valid URI: {e.Message}");
return;
}

// TODO: This can be a topic call or a connection to another server
if (uri.Scheme is "http" or "https") {
_uriOpener.OpenUri(message.Url);
} else {
_sawmill.Warning($"Received link \"{message.Url}\" which is being ignored because it's not http or https");
}
}

private void RxFtp(MsgFtp message) {
_dreamResource.LoadResourceAsync<DreamResource>(message.ResourceId, async resource => {
// TODO: Default the filename to message.SuggestedName
Expand Down
13 changes: 13 additions & 0 deletions OpenDreamRuntime/DreamConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,19 @@ public void WinClone(string controlId, string cloneId) {
Session?.Channel.SendMessage(msg);
}

/// <summary>
/// Sends a URL to the client to open.
/// Can be a website, a topic call, or another server to connect to.
/// </summary>
/// <param name="url">URL to open on the client's side</param>
public void SendLink(string url) {
var msg = new MsgLink {
Url = url
};

Session?.Channel.SendMessage(msg);
}

/// <summary>
/// Prompts the user to save a file to disk
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions OpenDreamRuntime/DreamManager.Connections.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ private void InitializeConnectionManager() {
_netManager.RegisterNetMessage<MsgWinClone>();
_netManager.RegisterNetMessage<MsgWinExists>();
_netManager.RegisterNetMessage<MsgWinGet>();
_netManager.RegisterNetMessage<MsgLink>();
_netManager.RegisterNetMessage<MsgFtp>();
_netManager.RegisterNetMessage<MsgLoadInterface>();
_netManager.RegisterNetMessage<MsgAckLoadInterface>(RxAckLoadInterface);
Expand Down
21 changes: 21 additions & 0 deletions OpenDreamRuntime/Procs/DMOpcodeHandlers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2512,6 +2512,27 @@ public static ProcStatus Prompt(DMProcState state) {
return ProcStatus.Called;
}

public static ProcStatus Link(DMProcState state) {
DreamValue url = state.Pop();
if (!state.Pop().TryGetValueAsDreamObject(out var receiver) || receiver == null)
return ProcStatus.Continue;

DreamConnection? connection = receiver switch {
DreamObjectMob receiverMob => receiverMob.Connection,
DreamObjectClient receiverClient => receiverClient.Connection,
_ => throw new Exception("Invalid link() recipient")
};

if (!url.TryGetValueAsString(out var urlStr)) {
throw new Exception($"Invalid link() url: {url}");
} else if (string.IsNullOrWhiteSpace(urlStr)) {
return ProcStatus.Continue;
}

connection?.SendLink(urlStr);
return ProcStatus.Continue;
}

public static ProcStatus Ftp(DMProcState state) {
DreamValue name = state.Pop();
DreamValue file = state.Pop();
Expand Down
1 change: 1 addition & 0 deletions OpenDreamRuntime/Procs/DMProc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ public sealed class DMProcState : ProcState {
{DreamProcOpcode.CreateFilteredListEnumerator, DMOpcodeHandlers.CreateFilteredListEnumerator},
{DreamProcOpcode.Power, DMOpcodeHandlers.Power},
{DreamProcOpcode.Prompt, DMOpcodeHandlers.Prompt},
{DreamProcOpcode.Link, DMOpcodeHandlers.Link},
{DreamProcOpcode.Ftp, DMOpcodeHandlers.Ftp},
{DreamProcOpcode.Initial, DMOpcodeHandlers.Initial},
{DreamProcOpcode.IsType, DMOpcodeHandlers.IsType},
Expand Down
1 change: 1 addition & 0 deletions OpenDreamShared/Network/Messages/MsgFtp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace OpenDreamShared.Network.Messages;

public sealed class MsgFtp : NetMessage {
public override MsgGroups MsgGroup => MsgGroups.EntityEvent;
public override NetDeliveryMethod DeliveryMethod => NetDeliveryMethod.ReliableUnordered;

public int ResourceId;
public string SuggestedName = string.Empty;
Expand Down
20 changes: 20 additions & 0 deletions OpenDreamShared/Network/Messages/MsgLink.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Lidgren.Network;
using Robust.Shared.Network;
using Robust.Shared.Serialization;

namespace OpenDreamShared.Network.Messages;

public sealed class MsgLink : NetMessage {
public override MsgGroups MsgGroup => MsgGroups.EntityEvent;
public override NetDeliveryMethod DeliveryMethod => NetDeliveryMethod.ReliableUnordered;

public string Url = string.Empty;

public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer) {
Url = buffer.ReadString();
}

public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer) {
buffer.Write(Url);
}
}

0 comments on commit b7a1c57

Please sign in to comment.