Compare commits
No commits in common. "4666eb31ece7ab5e313efd4f4910de7d860c67d8" and "e4d2ad4a14e27bdd4487aa9359923789f041be48" have entirely different histories.
4666eb31ec
...
e4d2ad4a14
9 changed files with 53 additions and 125 deletions
85
README.md
85
README.md
|
|
@ -2,56 +2,7 @@
|
||||||
|
|
||||||
<!-- TODO: image -->
|
<!-- TODO: image -->
|
||||||
|
|
||||||
## Building and running
|
### Backend
|
||||||
|
|
||||||
### With Nix
|
|
||||||
|
|
||||||
Using the power of nix, you can just `nix run git+https://git.berlin.ccc.de/vinzenz/servicepoint-tanks`!
|
|
||||||
|
|
||||||
To build from local source:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# no submodules required
|
|
||||||
git clone https://github.com/kaesaecracker/servicepoint-tanks.git
|
|
||||||
cd servicepoint-tanks
|
|
||||||
nix build .#
|
|
||||||
result/bin/TanksServer
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also use the provided devShells (`nix develop .#`) and follow the manual steps.
|
|
||||||
|
|
||||||
For proper IDE suggestions, you may need to initialize the submodules. They are not used for building by Nix though.
|
|
||||||
|
|
||||||
### The hard way
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# initialize the submodules
|
|
||||||
git clone https://github.com/kaesaecracker/servicepoint-tanks.git
|
|
||||||
cd servicepoint-tanks
|
|
||||||
git submodule update --init --recursive
|
|
||||||
|
|
||||||
# build
|
|
||||||
cd tank-frontent
|
|
||||||
npm install
|
|
||||||
npm run build
|
|
||||||
cd ../tanks-backend
|
|
||||||
dotnet build
|
|
||||||
```
|
|
||||||
|
|
||||||
The Docker builds are currently broken and need some updates for the new library repo structure.
|
|
||||||
<!-- TODO currently broken
|
|
||||||
|
|
||||||
# build with docker/podman - probably broken rifht
|
|
||||||
cd tanks-backend
|
|
||||||
docker build .
|
|
||||||
cd ../tank-frontend
|
|
||||||
docker build .
|
|
||||||
cd ..
|
|
||||||
docker build .
|
|
||||||
```
|
|
||||||
-->
|
|
||||||
|
|
||||||
## Backend
|
|
||||||
|
|
||||||
<!-- TODO: image -->
|
<!-- TODO: image -->
|
||||||
|
|
||||||
|
|
@ -67,7 +18,7 @@ docker build .
|
||||||
- some values (like tank speed) can be configured but are fixed at run time
|
- some values (like tank speed) can be configured but are fixed at run time
|
||||||
- By default, the backend also hosts the frontend
|
- By default, the backend also hosts the frontend
|
||||||
|
|
||||||
## Frontend
|
### Frontend
|
||||||
|
|
||||||
<!-- TODO: image -->
|
<!-- TODO: image -->
|
||||||
|
|
||||||
|
|
@ -77,9 +28,9 @@ docker build .
|
||||||
- Sends user input to server
|
- Sends user input to server
|
||||||
- real time communication via WebSockets, HTTP for the REST
|
- real time communication via WebSockets, HTTP for the REST
|
||||||
|
|
||||||
## Binary formats
|
### Binary formats
|
||||||
|
|
||||||
### Controls WebSocket
|
#### Controls WebSocket
|
||||||
|
|
||||||
- Client sends 2 byte messages.
|
- Client sends 2 byte messages.
|
||||||
- on or off: `0x01` or `0x02`
|
- on or off: `0x01` or `0x02`
|
||||||
|
|
@ -104,3 +55,31 @@ docker build .
|
||||||
- 10: bullet
|
- 10: bullet
|
||||||
- 11: (reserved)
|
- 11: (reserved)
|
||||||
- client responds with empty message to request the next frame
|
- client responds with empty message to request the next frame
|
||||||
|
|
||||||
|
# Building
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# checkout repo and submodules
|
||||||
|
git clone https://github.com/kaesaecracker/servicepoint-tanks.git
|
||||||
|
cd servicepoint-tanks
|
||||||
|
git submodule update --init
|
||||||
|
cd tanks-backend/servicepoint
|
||||||
|
git submodule update --init
|
||||||
|
cd ../..
|
||||||
|
|
||||||
|
# build with nix-shell
|
||||||
|
nix-shell
|
||||||
|
cd tank-frontent
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
cd ../tanks-backend
|
||||||
|
dotnet build
|
||||||
|
|
||||||
|
# build with docker/podman
|
||||||
|
cd tanks-backend
|
||||||
|
docker build .
|
||||||
|
cd ../tank-frontend
|
||||||
|
docker build .
|
||||||
|
cd ..
|
||||||
|
docker build .
|
||||||
|
```
|
||||||
|
|
|
||||||
43
flake.nix
43
flake.nix
|
|
@ -5,17 +5,13 @@
|
||||||
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-25.05";
|
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-25.05";
|
||||||
|
|
||||||
binding = {
|
binding = {
|
||||||
url = "git+https://git.berlin.ccc.de/servicepoint/servicepoint-binding-csharp.git";
|
url = "git+https://git.berlin.ccc.de/servicepoint/servicepoint-binding-csharp.git";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs =
|
outputs =
|
||||||
{
|
{ self, nixpkgs, binding }:
|
||||||
self,
|
|
||||||
nixpkgs,
|
|
||||||
binding,
|
|
||||||
}:
|
|
||||||
let
|
let
|
||||||
supported-systems = [
|
supported-systems = [
|
||||||
"x86_64-linux"
|
"x86_64-linux"
|
||||||
|
|
@ -35,20 +31,6 @@
|
||||||
);
|
);
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
apps = forAllSystems (
|
|
||||||
{
|
|
||||||
pkgs,
|
|
||||||
lib,
|
|
||||||
selfPkgs,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
{
|
|
||||||
default = {
|
|
||||||
type = "app";
|
|
||||||
program = "${lib.getBin selfPkgs.servicepoint-tanks}/bin/TanksServer";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
devShells = forAllSystems (
|
devShells = forAllSystems (
|
||||||
{
|
{
|
||||||
pkgs,
|
pkgs,
|
||||||
|
|
@ -65,7 +47,7 @@
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
backend-set = {
|
backend-set = {
|
||||||
inputsFrom = [ selfPkgs.servicepoint-tanks ];
|
inputsFrom = [ selfPkgs.servicepoint-tanks-backend ];
|
||||||
packages = with pkgs; [
|
packages = with pkgs; [
|
||||||
nuget-to-json
|
nuget-to-json
|
||||||
cargo-tarpaulin
|
cargo-tarpaulin
|
||||||
|
|
@ -89,7 +71,7 @@
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
servicepoint-tanks-frontend = pkgs.buildNpmPackage (finalAttrs: {
|
servicepoint-tanks-frontend = pkgs.buildNpmPackage (finalAttrs: {
|
||||||
pname = "servicepoint-tanks-frontend";
|
pname = "tank-frontend";
|
||||||
version = "0.0.0";
|
version = "0.0.0";
|
||||||
|
|
||||||
src = ./tank-frontend;
|
src = ./tank-frontend;
|
||||||
|
|
@ -100,29 +82,20 @@
|
||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
|
|
||||||
servicepoint-tanks-assets = ./tanks-backend/TanksServer/assets;
|
servicepoint-tanks-backend = pkgs.buildDotnetModule {
|
||||||
|
pname = "servicepoint-tanks-backend";
|
||||||
servicepoint-tanks = pkgs.buildDotnetModule {
|
|
||||||
pname = "servicepoint-tanks";
|
|
||||||
version = "0.0.0";
|
version = "0.0.0";
|
||||||
|
|
||||||
dotnet-sdk = pkgs.dotnetCorePackages.sdk_8_0;
|
dotnet-sdk = pkgs.dotnetCorePackages.sdk_8_0;
|
||||||
dotnet-runtime = pkgs.dotnetCorePackages.runtime_8_0;
|
dotnet-runtime = pkgs.dotnetCorePackages.runtime_8_0;
|
||||||
|
|
||||||
src = ./tanks-backend;
|
src = ./tanks-backend;
|
||||||
projectFile = "TanksServer/TanksServer.csproj";
|
projectFile = "TanksServer/TanksServer.csproj";
|
||||||
nugetDeps = ./tanks-backend/deps.json;
|
nugetDeps = ./tanks-backend/deps.json;
|
||||||
|
|
||||||
selfContainedBuild = true;
|
selfContainedBuild = true;
|
||||||
|
|
||||||
buildInputs = [ bindingPkgs.servicepoint-binding-csharp ];
|
buildInputs = [ bindingPkgs.servicepoint-binding-csharp ];
|
||||||
|
|
||||||
runtimeDeps = [ bindingPkgs.servicepoint-binding-uniffi ];
|
|
||||||
|
|
||||||
makeWrapperArgs = [
|
|
||||||
"--set-default TANKSSERVER_CLIENT ${selfPkgs.servicepoint-tanks-frontend}"
|
|
||||||
"--set-default TANKSSERVER_ASSETS ${selfPkgs.servicepoint-tanks-assets}"
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ namespace TanksServer.GameLogic;
|
||||||
|
|
||||||
internal sealed class CollideBullets : ITickStep
|
internal sealed class CollideBullets : ITickStep
|
||||||
{
|
{
|
||||||
private readonly Sprite _explosiveSprite = Sprite.FromImageFile(Path.Combine(Program.AssetsDir, "explosion.png"));
|
private readonly Sprite _explosiveSprite = Sprite.FromImageFile("assets/explosion.png");
|
||||||
private readonly Predicate<Bullet> _removeBulletsPredicate;
|
private readonly Predicate<Bullet> _removeBulletsPredicate;
|
||||||
private readonly MapEntityManager _entityManager;
|
private readonly MapEntityManager _entityManager;
|
||||||
private readonly MapService _map;
|
private readonly MapService _map;
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,9 @@ internal sealed class MapService
|
||||||
|
|
||||||
public MapService()
|
public MapService()
|
||||||
{
|
{
|
||||||
var dir = Path.Combine(Program.AssetsDir, "maps");
|
foreach (var file in Directory.EnumerateFiles("./assets/maps/", "*.txt"))
|
||||||
foreach (var file in Directory.EnumerateFiles(dir, "*.txt"))
|
|
||||||
LoadMapString(file);
|
LoadMapString(file);
|
||||||
foreach (var file in Directory.EnumerateFiles(dir, "*.png"))
|
foreach (var file in Directory.EnumerateFiles("./assets/maps/", "*.png"))
|
||||||
LoadMapPng(file);
|
LoadMapPng(file);
|
||||||
Current = GetRandomMap();
|
Current = GetRandomMap();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
global using System;
|
global using System;
|
||||||
global using System.Collections.Concurrent;
|
global using System.Collections.Concurrent;
|
||||||
global using System.Collections.Generic;
|
global using System.Collections.Generic;
|
||||||
global using System.IO;
|
|
||||||
global using System.Linq;
|
global using System.Linq;
|
||||||
global using System.Threading;
|
global using System.Threading;
|
||||||
global using System.Threading.Tasks;
|
global using System.Threading.Tasks;
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ namespace TanksServer.Graphics;
|
||||||
|
|
||||||
internal sealed class DrawPowerUpsStep(MapEntityManager entityManager) : IDrawStep
|
internal sealed class DrawPowerUpsStep(MapEntityManager entityManager) : IDrawStep
|
||||||
{
|
{
|
||||||
private readonly Sprite _genericSprite = Sprite.FromImageFile(Path.Combine(Program.AssetsDir, "powerup_generic.png"));
|
private readonly Sprite _genericSprite = Sprite.FromImageFile("assets/powerup_generic.png");
|
||||||
private readonly Sprite _smartSprite = Sprite.FromImageFile(Path.Combine(Program.AssetsDir, "powerup_smart.png"));
|
private readonly Sprite _smartSprite = Sprite.FromImageFile("assets/powerup_smart.png");
|
||||||
private readonly Sprite _magazineSprite = Sprite.FromImageFile(Path.Combine(Program.AssetsDir, "powerup_magazine.png"));
|
private readonly Sprite _magazineSprite = Sprite.FromImageFile("assets/powerup_magazine.png");
|
||||||
private readonly Sprite _explosiveSprite = Sprite.FromImageFile(Path.Combine(Program.AssetsDir, "powerup_explosive.png"));
|
private readonly Sprite _explosiveSprite = Sprite.FromImageFile("assets/powerup_explosive.png");
|
||||||
private readonly Sprite _fastSprite = Sprite.FromImageFile(Path.Combine(Program.AssetsDir, "powerup_fastbullet.png"));
|
private readonly Sprite _fastSprite = Sprite.FromImageFile("assets/powerup_fastbullet.png");
|
||||||
|
|
||||||
public void Draw(GamePixelGrid pixels)
|
public void Draw(GamePixelGrid pixels)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ namespace TanksServer.Graphics;
|
||||||
internal sealed class DrawTanksStep(MapEntityManager entityManager) : IDrawStep
|
internal sealed class DrawTanksStep(MapEntityManager entityManager) : IDrawStep
|
||||||
{
|
{
|
||||||
private readonly SpriteSheet _tankSprites =
|
private readonly SpriteSheet _tankSprites =
|
||||||
SpriteSheet.FromImageFile(Path.Combine(Program.AssetsDir, "tank.png"), (int)MapService.TileSize, (int)MapService.TileSize);
|
SpriteSheet.FromImageFile("assets/tank.png", (int)MapService.TileSize, (int)MapService.TileSize);
|
||||||
|
|
||||||
public void Draw(GamePixelGrid pixels)
|
public void Draw(GamePixelGrid pixels)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -11,44 +11,22 @@ namespace TanksServer;
|
||||||
|
|
||||||
public static class Program
|
public static class Program
|
||||||
{
|
{
|
||||||
internal static string AssetsDir = (Environment.GetEnvironmentVariable("TANKSSERVER_ASSETS") ?? "./assets") + "/";
|
|
||||||
|
|
||||||
[RequiresUnreferencedCode("Calls Endpoints.Map")]
|
[RequiresUnreferencedCode("Calls Endpoints.Map")]
|
||||||
[RequiresDynamicCode("Calls Endpoints.Map")]
|
[RequiresDynamicCode("Calls Endpoints.Map")]
|
||||||
public static async Task Main(string[] args)
|
public static async Task Main(string[] args)
|
||||||
{
|
{
|
||||||
var app = Configure(args);
|
var app = Configure(args);
|
||||||
|
|
||||||
app.Logger.LogInformation("Running in {}", app.Environment.ContentRootPath);
|
var clientFileProvider = new PhysicalFileProvider(Path.Combine(app.Environment.ContentRootPath, "client"));
|
||||||
|
|
||||||
AddStaticClientHost(app);
|
app.UseDefaultFiles(new DefaultFilesOptions { FileProvider = clientFileProvider });
|
||||||
|
app.UseStaticFiles(new StaticFileOptions { FileProvider = clientFileProvider });
|
||||||
|
|
||||||
app.Services.GetRequiredService<Endpoints>().Map(app);
|
app.Services.GetRequiredService<Endpoints>().Map(app);
|
||||||
|
|
||||||
await app.RunAsync();
|
await app.RunAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AddStaticClientHost(WebApplication app)
|
|
||||||
{
|
|
||||||
var clientDir = Environment.GetEnvironmentVariable("TANKSSERVER_CLIENT");
|
|
||||||
bool required = clientDir != null;
|
|
||||||
|
|
||||||
clientDir ??= Path.Combine(app.Environment.ContentRootPath, "client");
|
|
||||||
bool available = Directory.Exists(clientDir);
|
|
||||||
|
|
||||||
if (!available)
|
|
||||||
{
|
|
||||||
if (required)
|
|
||||||
throw new InvalidOperationException($"The environment variable TANKSSERVER_CLIENT is set, but the specified directory {clientDir} does not exist.");
|
|
||||||
app.Logger.LogError("Not providing static file host for client because {} does not exist", clientDir);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var clientFileProvider = new PhysicalFileProvider(clientDir);
|
|
||||||
app.UseDefaultFiles(new DefaultFilesOptions { FileProvider = clientFileProvider });
|
|
||||||
app.UseStaticFiles(new StaticFileOptions { FileProvider = clientFileProvider });
|
|
||||||
}
|
|
||||||
|
|
||||||
[RequiresUnreferencedCode("Calls Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionExtensions.Configure<TOptions>(IConfiguration)")]
|
[RequiresUnreferencedCode("Calls Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionExtensions.Configure<TOptions>(IConfiguration)")]
|
||||||
[RequiresDynamicCode("Calls Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionExtensions.Configure<TOptions>(IConfiguration)")]
|
[RequiresDynamicCode("Calls Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionExtensions.Configure<TOptions>(IConfiguration)")]
|
||||||
private static WebApplication Configure(string[] args)
|
private static WebApplication Configure(string[] args)
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="./assets/**" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="Always" Condition="'$(ContinuousIntegrationBuild)'!='true'" />
|
<None Include="./assets/**" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="Always"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue