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
13 changes: 13 additions & 0 deletions .config/dotnet-tools.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"version": 1,
"isRoot": true,
"tools": {
"csharpier": {
"version": "1.2.6",
"commands": [
"csharpier"
],
"rollForward": false
}
}
}
84 changes: 84 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# EditorConfig: https://editorconfig.org
root = true

##########################################
# All files
##########################################
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true

[*.{yml,yaml,json,md}]
indent_size = 2

[*.{csproj,props,targets,xml}]
indent_size = 2

##########################################
# C# files
##########################################
[*.cs]
indent_size = 4

# Organize usings
dotnet_sort_system_directives_first = true
dotnet_separate_import_directive_groups = false
csharp_using_directive_placement = outside_namespace:warning

# Namespace does not need to match folder structure.
# Also avoids a dotnet-format crash: its IDE0130 fixer attempts file moves that
# MSBuildWorkspace doesn't support (NotSupportedException: Changing document properties).
dotnet_diagnostic.IDE0130.severity = none

# this. qualification
dotnet_style_qualification_for_field = false:warning
dotnet_style_qualification_for_property = false:warning
dotnet_style_qualification_for_method = false:warning
dotnet_style_qualification_for_event = false:warning

# Language keywords vs BCL types
dotnet_style_predefined_type_for_locals_parameters_members = true:warning
dotnet_style_predefined_type_for_member_access = true:warning

# Modifier preferences
dotnet_style_require_accessibility_modifiers = for_non_interface_members:warning
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:warning

# var preferences
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
csharp_style_var_elsewhere = true:suggestion

# Expression-bodied members
csharp_style_expression_bodied_methods = when_on_single_line:suggestion
csharp_style_expression_bodied_properties = when_on_single_line:suggestion
csharp_style_expression_bodied_accessors = when_on_single_line:suggestion

# Newline preferences (Allman braces)
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true

# Indentation
csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_labels = flush_left

# Spacing
csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_parentheses = false

# Wrapping
csharp_preserve_single_line_statements = false
csharp_preserve_single_line_blocks = true
7 changes: 0 additions & 7 deletions .env.example

This file was deleted.

56 changes: 56 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: Build & Verify

on:
push:
branches:
- master
tags:
- '*'
pull_request:

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x

- name: Cache NuGet Packages
uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }}
restore-keys: |
${{ runner.os }}-nuget-

- name: Restore Main Project
run: dotnet restore ./PlatformSampleGameServer.csproj

- name: Restore Tools Project
run: dotnet restore ./tools/Ss58SelfTest/Ss58SelfTest.csproj

- name: Restore .NET Tools
run: dotnet tool restore

- name: Verify Formatting (CSharpier)
run: dotnet csharpier check .

- name: Verify Formatting (dotnet format - main)
run: dotnet format ./PlatformSampleGameServer.csproj --verify-no-changes --no-restore

- name: Verify Formatting (dotnet format - tools)
run: dotnet format ./tools/Ss58SelfTest/Ss58SelfTest.csproj --verify-no-changes --no-restore

- name: Build Main Project
run: dotnet build ./PlatformSampleGameServer.csproj --configuration Release --no-restore

- name: Build Tools Project
run: dotnet build ./tools/Ss58SelfTest/Ss58SelfTest.csproj --configuration Release --no-restore
18 changes: 14 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
node_modules/
.env
npm-debug.log
.DS_Store
.DS_Store

# .NET
bin/
obj/
*.user

# Local-only runtime state (persisted bootstrap collection id, etc.)
state.json

# Local-only secrets (URL, API key, JWT secret). Use appsettings.Development.json
# or environment variables.
appsettings.Development.json
appsettings.Local.json
69 changes: 69 additions & 0 deletions Endpoints/AuthEndpoints.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Mvc;
Comment thread
JayPavlina marked this conversation as resolved.
using PlatformSampleGameServer.Models;
using PlatformSampleGameServer.Services;

namespace PlatformSampleGameServer.Endpoints;

public static class AuthEndpoints
{
public static void MapAuthEndpoints(this IEndpointRouteBuilder app)
{
var group = app.MapGroup("/api/auth");

// Anonymous - the Unity client polls this to confirm connectivity.
group
.MapGet("/health-check", () => Results.Ok(new HealthCheckResponse("OK")))
.AllowAnonymous();

// Register-or-login. The Unity client uses this single endpoint for both
// first-time signup and returning sessions; behaviour matches the original
// Node.js sample (src/routes/auth.js).
group
.MapPost(
"/register",
async (
AuthRequest body,
AuthService auth,
EnjinService enjin,
ILoggerFactory loggerFactory,
CancellationToken ct
) =>
{
var log = loggerFactory.CreateLogger(
"PlatformSampleGameServer.Endpoints.AuthEndpoints"
);
try
{
var (token, email) = auth.RegisterOrLogin(body.Email, body.Password);

// Ensure a managed wallet exists for this player so subsequent
// operations (mint/melt/transfer) can target it immediately.
string? wallet = null;
try
{
wallet = await enjin.EnsureManagedWalletAsync(email, ct);
}
catch (Exception ex)
{
// Don't fail registration on a wallet-provisioning hiccup;
// the client can retry against /api/wallet/get-tokens later.
wallet = null;
log.LogWarning(ex, "EnsureManagedWallet failed for {Email}", email);
}

return Results.Ok(new AuthResponse(email, wallet, token));
}
catch (UnauthorizedAccessException ex)
{
return Results.Json(new BoolResponse(false, ex.Message), statusCode: 401);
}
catch (Exception ex)
{
return Results.Json(new BoolResponse(false, ex.Message), statusCode: 400);
}
Comment thread
JayPavlina marked this conversation as resolved.
}
)
.AllowAnonymous();
}
}
45 changes: 45 additions & 0 deletions Endpoints/SetupEndpoints.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using PlatformSampleGameServer.Models;
using PlatformSampleGameServer.Services;

namespace PlatformSampleGameServer.Endpoints;

/// <summary>
/// Setup-time endpoints. Called by the Unity Editor (and any other tooling)
/// once when standing the game up against a new server / new canary state, to
/// bake server-allocated identifiers into client-side configuration assets.
///
/// Intentionally unauthenticated: setup happens before any player account
/// exists, the values exposed here are not secret (they end up in shipped
/// client builds anyway), and gating this behind a JWT would be a chicken-
/// and-egg problem for fresh installs.
/// </summary>
public static class SetupEndpoints
{
public static void MapSetupEndpoints(this IEndpointRouteBuilder app)
{
var group = app.MapGroup("/api/setup");

// GET /api/setup/collection-id - returns the on-chain collection id
// this server has bootstrapped. The Unity Editor menu "Enjin > Stamp
// Collection ID onto EnjinItem Assets" calls this and writes the
// value onto every EnjinItem ScriptableObject.
group.MapGet(
"/collection-id",
(EnjinService enjin) =>
{
var id = enjin.CollectionId;
if (id is null)
{
return Results.Json(
new BoolResponse(
false,
"Collection id not initialised. " + "Did the server finish bootstrap?"
),
statusCode: 503
);
}
return Results.Ok(new CollectionIdResponse(id.Value.ToString()));
}
);
}
}
Loading
Loading