feat(a1): .NET 8 solution scaffold + Model + OpcodeTable loader
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -13,6 +13,11 @@ __pycache__/
|
|||||||
*.egg-info/
|
*.egg-info/
|
||||||
.venv/
|
.venv/
|
||||||
|
|
||||||
|
# .NET (engine/) build output
|
||||||
|
engine/**/bin/
|
||||||
|
engine/**/obj/
|
||||||
|
.vs/
|
||||||
|
|
||||||
# Godot / C# (future)
|
# Godot / C# (future)
|
||||||
.godot/
|
.godot/
|
||||||
*.import
|
*.import
|
||||||
|
|||||||
14
engine/Age.Cli/Age.Cli.csproj
Normal file
14
engine/Age.Cli/Age.Cli.csproj
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Age.Engine\Age.Engine.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
2
engine/Age.Cli/Program.cs
Normal file
2
engine/Age.Cli/Program.cs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
// See https://aka.ms/new-console-template for more information
|
||||||
|
Console.WriteLine("Hello, World!");
|
||||||
27
engine/Age.Engine.Tests/Age.Engine.Tests.csproj
Normal file
27
engine/Age.Engine.Tests/Age.Engine.Tests.csproj
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<IsTestProject>true</IsTestProject>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||||
|
<PackageReference Include="xunit" Version="2.5.3" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Using Include="Xunit" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Age.Engine\Age.Engine.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
18
engine/Age.Engine.Tests/OpcodeTableTests.cs
Normal file
18
engine/Age.Engine.Tests/OpcodeTableTests.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using Age.Engine.Sys4;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
public class OpcodeTableTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void LoadsAll248FromJson()
|
||||||
|
{
|
||||||
|
var t = OpcodeTableJson.Load(Paths.OpcodesJson);
|
||||||
|
Assert.Equal(248, t.Count);
|
||||||
|
Assert.True(t.TryGet(0x55, out var label, out var argc));
|
||||||
|
Assert.Equal("mov", label);
|
||||||
|
Assert.Equal(2, argc);
|
||||||
|
Assert.Equal("u0041BEB0", t.Label(0x90));
|
||||||
|
Assert.Equal(7, t.Argc(0x90));
|
||||||
|
Assert.Equal(-1, t.Argc(0x9999)); // absent -> -1
|
||||||
|
}
|
||||||
|
}
|
||||||
13
engine/Age.Engine/Age.Engine.csproj
Normal file
13
engine/Age.Engine/Age.Engine.csproj
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="System.Text.Encoding.CodePages" Version="10.0.9" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
2
engine/Age.Engine/Model/Instruction.cs
Normal file
2
engine/Age.Engine/Model/Instruction.cs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
namespace Age.Engine.Model;
|
||||||
|
public sealed record Instruction(int Offset, int Opcode, IReadOnlyList<Operand> Args);
|
||||||
14
engine/Age.Engine/Model/OpcodeTable.cs
Normal file
14
engine/Age.Engine/Model/OpcodeTable.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
namespace Age.Engine.Model;
|
||||||
|
public sealed class OpcodeTable
|
||||||
|
{
|
||||||
|
private readonly IReadOnlyDictionary<int, (string Label, int Argc)> _t;
|
||||||
|
public OpcodeTable(IReadOnlyDictionary<int, (string, int)> t) => _t = t;
|
||||||
|
public int Count => _t.Count;
|
||||||
|
public bool TryGet(int op, out string label, out int argc)
|
||||||
|
{
|
||||||
|
if (_t.TryGetValue(op, out var e)) { label = e.Label; argc = e.Argc; return true; }
|
||||||
|
label = ""; argc = -1; return false;
|
||||||
|
}
|
||||||
|
public string Label(int op) => _t.TryGetValue(op, out var e) ? e.Label : "";
|
||||||
|
public int Argc(int op) => _t.TryGetValue(op, out var e) ? e.Argc : -1;
|
||||||
|
}
|
||||||
2
engine/Age.Engine/Model/Operand.cs
Normal file
2
engine/Age.Engine/Model/Operand.cs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
namespace Age.Engine.Model;
|
||||||
|
public readonly record struct Operand(int Type, long Value);
|
||||||
9
engine/Age.Engine/Model/Script.cs
Normal file
9
engine/Age.Engine/Model/Script.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Age.Engine.Model;
|
||||||
|
public sealed class Script
|
||||||
|
{
|
||||||
|
public required ScriptHeader Header { get; init; }
|
||||||
|
public required IReadOnlyList<Instruction> Instructions { get; init; }
|
||||||
|
public required IReadOnlyDictionary<int, int> IndexByOffset { get; init; }
|
||||||
|
public required IReadOnlyDictionary<int, string> Strings { get; init; }
|
||||||
|
public string GetString(int offset) => Strings.TryGetValue(offset, out var s) ? s : "";
|
||||||
|
}
|
||||||
4
engine/Age.Engine/Model/ScriptHeader.cs
Normal file
4
engine/Age.Engine/Model/ScriptHeader.cs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
namespace Age.Engine.Model;
|
||||||
|
public sealed record ScriptHeader(
|
||||||
|
int LocalInt1, int LocalFloats, int LocalStrings1,
|
||||||
|
int LocalInt2, int Unknown, int LocalStrings2);
|
||||||
19
engine/Age.Engine/Sys4/OpcodeTableJson.cs
Normal file
19
engine/Age.Engine/Sys4/OpcodeTableJson.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using Age.Engine.Model;
|
||||||
|
namespace Age.Engine.Sys4;
|
||||||
|
public static class OpcodeTableJson
|
||||||
|
{
|
||||||
|
public static OpcodeTable Load(string path)
|
||||||
|
{
|
||||||
|
using var doc = JsonDocument.Parse(File.ReadAllText(path));
|
||||||
|
var dict = new Dictionary<int, (string, int)>();
|
||||||
|
foreach (var e in doc.RootElement.GetProperty("opcodes").EnumerateArray())
|
||||||
|
{
|
||||||
|
int op = Convert.ToInt32(e.GetProperty("op").GetString(), 16);
|
||||||
|
string label = e.GetProperty("label").GetString() ?? "";
|
||||||
|
int argc = e.GetProperty("argc").GetInt32();
|
||||||
|
dict[op] = (label, argc);
|
||||||
|
}
|
||||||
|
return new OpcodeTable(dict);
|
||||||
|
}
|
||||||
|
}
|
||||||
33
engine/Age.Engine/Sys4/Paths.cs
Normal file
33
engine/Age.Engine/Sys4/Paths.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
namespace Age.Engine.Sys4;
|
||||||
|
public static class Paths
|
||||||
|
{
|
||||||
|
public static string Repo { get; } = FindRepo();
|
||||||
|
public static string Workspace => Directory.GetParent(Repo)!.FullName;
|
||||||
|
public static string Extracted => Path.Combine(Workspace, "extracted");
|
||||||
|
public static string Data1 => Path.Combine(Extracted, "DATA1");
|
||||||
|
public static string GameDir => Path.Combine(Workspace, "姫狩りダンジョンマイスター");
|
||||||
|
public static string Build => Path.Combine(Repo, "build");
|
||||||
|
public static string OpcodesJson => Path.Combine(Build, "opcodes.json");
|
||||||
|
|
||||||
|
private static string FindRepo()
|
||||||
|
{
|
||||||
|
var d = new DirectoryInfo(AppContext.BaseDirectory);
|
||||||
|
while (d != null && d.Name != "age-reimpl") d = d.Parent;
|
||||||
|
if (d == null) throw new DirectoryNotFoundException(
|
||||||
|
"age-reimpl root not found above " + AppContext.BaseDirectory);
|
||||||
|
return d.FullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// name(UPPER).BIN -> path; game-dir loose overrides shadow extracted/DATA1 (mirrors paths.scripts()).
|
||||||
|
public static Dictionary<string, string> Scripts()
|
||||||
|
{
|
||||||
|
var d = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
if (Directory.Exists(Data1))
|
||||||
|
foreach (var p in Directory.EnumerateFiles(Data1, "*.BIN"))
|
||||||
|
d[Path.GetFileName(p).ToUpperInvariant()] = p;
|
||||||
|
if (Directory.Exists(GameDir))
|
||||||
|
foreach (var p in Directory.EnumerateFiles(GameDir, "*.BIN"))
|
||||||
|
d[Path.GetFileName(p).ToUpperInvariant()] = p;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
}
|
||||||
34
engine/AgeEngine.sln
Normal file
34
engine/AgeEngine.sln
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.0.31903.59
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Age.Engine", "Age.Engine\Age.Engine.csproj", "{DD04FB21-F83D-4547-BBEC-97295F30623A}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Age.Cli", "Age.Cli\Age.Cli.csproj", "{795573A0-A283-4A28-B26C-606C1AA5E1FE}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Age.Engine.Tests", "Age.Engine.Tests\Age.Engine.Tests.csproj", "{2ED171C8-DA87-40FD-A6FB-3B3F6501029F}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{DD04FB21-F83D-4547-BBEC-97295F30623A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{DD04FB21-F83D-4547-BBEC-97295F30623A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{DD04FB21-F83D-4547-BBEC-97295F30623A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{DD04FB21-F83D-4547-BBEC-97295F30623A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{795573A0-A283-4A28-B26C-606C1AA5E1FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{795573A0-A283-4A28-B26C-606C1AA5E1FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{795573A0-A283-4A28-B26C-606C1AA5E1FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{795573A0-A283-4A28-B26C-606C1AA5E1FE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2ED171C8-DA87-40FD-A6FB-3B3F6501029F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2ED171C8-DA87-40FD-A6FB-3B3F6501029F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2ED171C8-DA87-40FD-A6FB-3B3F6501029F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2ED171C8-DA87-40FD-A6FB-3B3F6501029F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
Reference in New Issue
Block a user