Skip to content

Commit

Permalink
feat: Add C# scripting support
Browse files Browse the repository at this point in the history
- Added Roslyn to the project.
- Added an example of parsing game logic settings from a .csx file.
  • Loading branch information
pacampbell committed Dec 20, 2024
1 parent a0b4c4d commit 2f6360b
Show file tree
Hide file tree
Showing 11 changed files with 339 additions and 235 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ root = true
indent_style = space

# Code files
[*.{cs,sql,json}]
[*.{cs,sql,json,csx}]
indent_size = 4
insert_final_newline = true
charset = utf-8
1 change: 1 addition & 0 deletions Arrowgene.Ddon.Cli/Command/ServerCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Threading;
using Arrowgene.Ddon.Database;
using Arrowgene.Ddon.GameServer;
using Arrowgene.Ddon.GameServer.Scripting;
using Arrowgene.Ddon.LoginServer;
using Arrowgene.Ddon.Rpc.Web;
using Arrowgene.Ddon.Shared;
Expand Down
1 change: 1 addition & 0 deletions Arrowgene.Ddon.Cli/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
using System.Text;
using System.Threading;
using Arrowgene.Ddon.Cli.Command;
using Arrowgene.Ddon.GameServer.Scripting;
using Arrowgene.Ddon.Shared;
using Arrowgene.Ddon.Shared.Network;
using Arrowgene.Logging;
Expand Down
9 changes: 8 additions & 1 deletion Arrowgene.Ddon.GameServer/DdonGameServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
using Arrowgene.Ddon.GameServer.Dump;
using Arrowgene.Ddon.GameServer.Handler;
using Arrowgene.Ddon.GameServer.Party;
using Arrowgene.Ddon.GameServer.Scripting;
using Arrowgene.Ddon.GameServer.Shop;
using Arrowgene.Ddon.Server;
using Arrowgene.Ddon.Server.Handler;
Expand All @@ -52,7 +53,12 @@ public class DdonGameServer : DdonServer<GameClient>
public DdonGameServer(GameServerSetting setting, IDatabase database, AssetRepository assetRepository)
: base(ServerType.Game, setting.ServerSetting, database, assetRepository)
{
// This must be first
Setting = new GameServerSetting(setting);
// This must be second
ScriptManager = new ScriptManager(this);

// Rest of server managers
ClientLookup = new GameClientLookup();
ChatLogHandler = new ChatLogHandler();
ChatManager = new ChatManager(this);
Expand Down Expand Up @@ -91,6 +97,7 @@ public DdonGameServer(GameServerSetting setting, IDatabase database, AssetReposi

public event EventHandler<ClientConnectionChangeArgs> ClientConnectionChangeEvent;
public GameServerSetting Setting { get; }
public ScriptManager ScriptManager { get; }
public ChatManager ChatManager { get; }
public ItemManager ItemManager { get; }
public CraftManager CraftManager { get; }
Expand Down Expand Up @@ -136,7 +143,7 @@ public override void Start()
{
ScheduleManager.StartServerTasks();
}

LoadChatHandler();
LoadPacketHandler();
base.Start();
Expand Down
2 changes: 1 addition & 1 deletion Arrowgene.Ddon.GameServer/GameServerSetting.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Arrowgene.Ddon.GameServer
public class GameServerSetting
{
[DataMember(Order = 1)] public ServerSetting ServerSetting { get; set; }
[DataMember(Order = 2)] public GameLogicSetting GameLogicSetting { get; set; }
public GameLogicSetting GameLogicSetting { get; set; }

public GameServerSetting()
{
Expand Down
14 changes: 14 additions & 0 deletions Arrowgene.Ddon.GameServer/Scripting/DdonLibrary.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Arrowgene.Ddon.GameServer.Scripting
{
public class DdonLibrary
{
public DdonLibrary()
{
}

public static uint GetValue()
{
return 1;
}
}
}
91 changes: 91 additions & 0 deletions Arrowgene.Ddon.GameServer/Scripting/ScriptManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using Arrowgene.Ddon.Server;
using Arrowgene.Ddon.Shared;
using Arrowgene.Ddon.Shared.Model;
using Arrowgene.Logging;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
using System;
using System.Collections.Generic;
using System.IO;

namespace Arrowgene.Ddon.GameServer.Scripting
{
public class Globals
{
public DdonGameServer Server { get; set; }
public GameLogicSetting GameLogicSetting { get; set; }
}

public class ScriptManager
{
public string ScriptsRoot { get; private set; }
public string SettingsPath { get; private set; }

public Script Settings {
get {
return CompiledScripts["Settings"];
}
set
{
CompiledScripts["Settings"] = value;
}
}

private Dictionary<string, Script> CompiledScripts;
private static readonly ServerLogger Logger = LogProvider.Logger<ServerLogger>(typeof(ScriptManager));
private Globals Globals { get; }
private DdonGameServer Server { get; }

public event EventHandler<AssetChangedEventArgs> AssetChanged;
private readonly DirectoryInfo ScriptsDirectory;
private readonly Dictionary<string, FileSystemWatcher> FileSystemWatchers;

public ScriptManager(DdonGameServer server)
{
ScriptsRoot = $"{server.AssetRepository.AssetsPath}\\scripts";
SettingsPath = $"{ScriptsRoot}\\Settings.csx";

Server = server;
Globals = new Globals()
{
Server = server,
GameLogicSetting = server.Setting.GameLogicSetting
};

ScriptsDirectory = new DirectoryInfo(ScriptsRoot);
if (!ScriptsDirectory.Exists)
{
Logger.Error($"Could not compile scripts, unable to locate the path '{ScriptsRoot}'");
return;
}

FileSystemWatchers = new Dictionary<string, FileSystemWatcher>();

CompiledScripts = new Dictionary<string, Script>();

CompileScripts();
}

private void CompileScripts()
{
var options = ScriptOptions.Default
.WithReferences(MetadataReference.CreateFromFile(typeof(DdonGameServer).Assembly.Location))
.WithReferences(MetadataReference.CreateFromFile(typeof(GameLogicSetting).Assembly.Location))
.WithReferences(MetadataReference.CreateFromFile(typeof(WalletType).Assembly.Location))
.WithImports("System", "System.Collections", "System.Collections.Generic",
"Arrowgene", "Arrowgene.Ddon", "Arrowgene.Ddon.Shared", "Arrowgene.Ddon.Shared.Model");

// Load The Game Settings
Settings = CSharpScript.Create(
code: File.ReadAllText(SettingsPath),
options: options,
globalsType: typeof(Globals)
);
// Execute the script file to populate the settings
Settings.RunAsync(Globals);

// TODO: Load other game functionality we want to have scripted.
}
}
}
Loading

0 comments on commit 2f6360b

Please sign in to comment.