mirror of
https://gitea.tendokyu.moe/ppc/amnet.git
synced 2026-10-14 02:09:04 +03:00
create game-side .dll (initial commit)
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<PublishAot>true</PublishAot>
|
||||
<OutputType>Library</OutputType>
|
||||
<EventSourceSupport>false</EventSourceSupport>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<OptimizationPreference>Size</OptimizationPreference>
|
||||
<NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<DebugType>None</DebugType>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
<MetricsSupport>false</MetricsSupport>
|
||||
<DebuggerSupport>false</DebuggerSupport>
|
||||
<EventSourceSupport>false</EventSourceSupport>
|
||||
<InvariantGlobalization>true</InvariantGlobalization>
|
||||
<MetadataUpdaterSupport>false</MetadataUpdaterSupport>
|
||||
<EnableUnsafeUTF7Encoding>false</EnableUnsafeUTF7Encoding>
|
||||
<HttpActivityPropagationSupport>false</HttpActivityPropagationSupport>
|
||||
<EnableUnsafeBinaryFormatterSerialization>false</EnableUnsafeBinaryFormatterSerialization>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.106">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Properties\launchSettings.json" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace AimeNet;
|
||||
|
||||
public record SystemState(
|
||||
[property: JsonPropertyName("api_ver")] int ApiVersion,
|
||||
[property: JsonPropertyName("server_name")] string ServerName);
|
||||
|
||||
public record CardReadRequest(
|
||||
[property: JsonPropertyName("card_id")] string MatrixCode);
|
||||
|
||||
[JsonSerializable(typeof(SystemState))]
|
||||
[JsonSerializable(typeof(CardReadRequest))]
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
public partial class AppJsonSerializerContext : JsonSerializerContext;
|
||||
@@ -0,0 +1,196 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace AimeNet;
|
||||
|
||||
public static class DllMain
|
||||
{
|
||||
private const int ApiVersion = 1;
|
||||
private const string WebAddress = "http://amnet.ppc.moe";
|
||||
|
||||
private static ILogger _serverLogger;
|
||||
|
||||
private static string[] _serverAddresses;
|
||||
private static string _serverName;
|
||||
|
||||
private static (byte[] IdBytes, string OriginalId, long Expires)? _currentCard;
|
||||
|
||||
private static readonly object CardLock = new();
|
||||
|
||||
static DllMain()
|
||||
{
|
||||
PInvoke.AllocConsole();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "aime_io_get_api_version")]
|
||||
public static ushort GetApiVersion() => 0x0100;
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "aime_io_init")]
|
||||
public static int Init()
|
||||
{
|
||||
LoadConfiguration();
|
||||
|
||||
var builder = WebApplication.CreateSlimBuilder([]);
|
||||
|
||||
builder.Logging.ClearProviders();
|
||||
builder.Logging.AddSimpleConsole(o =>
|
||||
{
|
||||
o.SingleLine = true;
|
||||
o.IncludeScopes = false;
|
||||
});
|
||||
|
||||
builder.Logging.SetMinimumLevel(LogLevel.Information);
|
||||
builder.Logging.AddFilter("Microsoft.AspNetCore.Http.Result", LogLevel.None);
|
||||
builder.Logging.AddFilter("Microsoft.AspNetCore.Routing.EndpointMiddleware", LogLevel.Error);
|
||||
|
||||
builder.WebHost.UseUrls(_serverAddresses);
|
||||
builder.Services.ConfigureHttpJsonOptions(options =>
|
||||
{
|
||||
options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
app.MapGet("/", () => Results.Ok(new SystemState(ApiVersion, _serverName)));
|
||||
app.MapPost("/card", async ctx =>
|
||||
{
|
||||
CardReadRequest request;
|
||||
|
||||
try
|
||||
{
|
||||
request = await ctx.Request.ReadFromJsonAsync<CardReadRequest>();
|
||||
}
|
||||
catch (JsonException e)
|
||||
{
|
||||
await using var writer = new StreamWriter(ctx.Response.Body, Encoding.UTF8, leaveOpen: true);
|
||||
await writer.WriteLineAsync(e.Message);
|
||||
|
||||
ctx.Response.StatusCode = 400;
|
||||
return;
|
||||
}
|
||||
|
||||
lock (CardLock)
|
||||
{
|
||||
// don't allow multiple writes in quick succession
|
||||
if (_currentCard?.Expires > Environment.TickCount64)
|
||||
{
|
||||
ctx.Response.StatusCode = 429;
|
||||
ctx.Response.Headers.RetryAfter = ((int)TimeSpan.FromTicks(_currentCard.Value.Expires - Environment.TickCount64).TotalSeconds).ToString();
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.MatrixCode.Length < 20)
|
||||
{
|
||||
ctx.Response.StatusCode = 400;
|
||||
return;
|
||||
}
|
||||
|
||||
// ensure the matrix code is 20-digits long, otherwise pad with zeros
|
||||
var matrixCode = request.MatrixCode.PadLeft(20, '0');
|
||||
var bytes = new byte[10];
|
||||
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
var value = matrixCode.Substring(i * 2, 2);
|
||||
bytes[i] = byte.Parse(value, NumberStyles.HexNumber);
|
||||
}
|
||||
|
||||
_currentCard = (bytes, matrixCode, Environment.TickCount64 + 5000000);
|
||||
}
|
||||
|
||||
ctx.Response.StatusCode = 204;
|
||||
});
|
||||
|
||||
_serverLogger = app.Logger;
|
||||
|
||||
CancellationTokenRegistration cancellationRegistration = default;
|
||||
cancellationRegistration = app.Lifetime.ApplicationStarted.Register(() =>
|
||||
{
|
||||
_serverLogger.LogInformation("AimeNet started successfully.");
|
||||
_serverLogger.LogInformation("Visit {addr} from a mobile device on the same network to get started.", WebAddress);
|
||||
|
||||
cancellationRegistration.Dispose();
|
||||
});
|
||||
|
||||
app.RunAsync();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "aime_io_nfc_poll")]
|
||||
public static int NfcPoll(byte unitNo)
|
||||
{
|
||||
if (_currentCard.HasValue && _currentCard.Value.Expires < Environment.TickCount64)
|
||||
{
|
||||
lock (CardLock)
|
||||
{
|
||||
_currentCard = null;
|
||||
}
|
||||
}
|
||||
|
||||
// there's no polling here (handled by the webserver)
|
||||
return 0;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "aime_io_nfc_get_aime_id")]
|
||||
public static int GetAimeId(byte unitNo, nint luid, nint luidSize)
|
||||
{
|
||||
lock (CardLock)
|
||||
{
|
||||
if (unitNo != 0 || _currentCard == null)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
Marshal.Copy(_currentCard.Value.IdBytes, 0, luid, (int)luidSize);
|
||||
|
||||
_serverLogger.LogInformation("Aime Card read: {0}", string.Join(" ", Enumerable.Range(0, 5).Select(x => _currentCard.Value.OriginalId.Substring(x * 4, 4))));
|
||||
_currentCard = null;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "aime_io_nfc_get_felica_id")]
|
||||
public static unsafe int GetFelicaId(byte unitNo, ulong* idm)
|
||||
{
|
||||
// felica not supported
|
||||
return 1;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "aime_io_led_set_color")]
|
||||
public static void SetLedColour(byte unitNo, byte r, byte g, byte b)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
private static unsafe void LoadConfiguration()
|
||||
{
|
||||
const string configFileName = @".\segatools.ini";
|
||||
|
||||
var serverName = stackalloc char[64];
|
||||
var serverNameStr = new PWSTR(serverName);
|
||||
|
||||
var serverAddress = stackalloc char[1024];
|
||||
var serverAddressStr = new PWSTR(serverAddress);
|
||||
|
||||
PInvoke.GetPrivateProfileString("aimeio", "serverName", Environment.MachineName, serverNameStr, 64, configFileName);
|
||||
PInvoke.GetPrivateProfileString("aimeio", "serverAddress", "http://+:6070", serverAddressStr, 1024, configFileName);
|
||||
|
||||
_serverName = serverNameStr.ToString();
|
||||
_serverAddresses = serverAddressStr.ToString().Split(';');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
GetPrivateProfileStringW
|
||||
GetPrivateProfileInt
|
||||
AllocConsole
|
||||
Reference in New Issue
Block a user