Skip to content

Commit

Permalink
WIP: Run replays in docker
Browse files Browse the repository at this point in the history
  • Loading branch information
TheEadie committed Aug 15, 2024
1 parent 6cf1926 commit 2b840b0
Show file tree
Hide file tree
Showing 11 changed files with 198 additions and 8 deletions.
2 changes: 2 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,8 @@ dotnet_diagnostic.CA1812.severity = none
dotnet_diagnostic.CA1848.severity = none
# CA1308 tries to make user facing string upper case
dotnet_diagnostic.CA1308.severity = none
# CA1303 wants localization of text - I'm unlikely to do this
dotnet_diagnostic.CA1303.severity = none
# Workaround for https://github.com/dotnet/roslyn/issues/41640
dotnet_diagnostic.IDE0005.severity = suggestion

Expand Down
6 changes: 6 additions & 0 deletions Worms.sln
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Worms.Cli", "src\Worms.Cli\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Worms.Armageddon.Files.Tests", "src\Worms.Armageddon.Files.Tests\Worms.Armageddon.Files.Tests.csproj", "{6233FC52-586A-40A0-B369-FA77ADE35E94}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Worms.Hub.ReplayProcessor", "src\Worms.Hub.ReplayProcessor\Worms.Hub.ReplayProcessor.csproj", "{F41B5B20-FDE9-4835-8282-7DB750F06992}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -48,6 +50,10 @@ Global
{6233FC52-586A-40A0-B369-FA77ADE35E94}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6233FC52-586A-40A0-B369-FA77ADE35E94}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6233FC52-586A-40A0-B369-FA77ADE35E94}.Release|Any CPU.Build.0 = Release|Any CPU
{F41B5B20-FDE9-4835-8282-7DB750F06992}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F41B5B20-FDE9-4835-8282-7DB750F06992}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F41B5B20-FDE9-4835-8282-7DB750F06992}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F41B5B20-FDE9-4835-8282-7DB750F06992}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
EndGlobalSection
Expand Down
4 changes: 3 additions & 1 deletion build/docker/makefile
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ $1.package: $1.version
--build-arg VERSION=$$($1_VERSION) \
--cache-from=type=gha,scope=package \
--cache-from=type=gha,scope=build \
--cache-to=type=gha,mode=max,scope=package
--cache-to=type=gha,mode=max,scope=package \
--progress=plain \
--load
@echo ""

## Release
Expand Down
79 changes: 79 additions & 0 deletions build/docker/replay-processor/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#### Build ####
FROM mcr.microsoft.com/dotnet/sdk:8.0.303@sha256:7d0ba26469267b563120456557e38eccef9972cb6b9cfbbd47a50d1218fa7b30 AS build
WORKDIR /app

COPY src/Directory.Build.props .
COPY .editorconfig .
COPY src/Worms.Armageddon.Game/Worms.Armageddon.Game.csproj ./src/Worms.Armageddon.Game/Worms.Armageddon.Game.csproj
COPY src/Worms.Hub.ReplayProcessor/Worms.Hub.ReplayProcessor.csproj ./src/Worms.Hub.ReplayProcessor/Worms.Hub.ReplayProcessor.csproj
RUN dotnet restore src/Worms.Hub.ReplayProcessor/Worms.Hub.ReplayProcessor.csproj

COPY src/Worms.Armageddon.Game ./src/Worms.Armageddon.Game
COPY src/Worms.Hub.ReplayProcessor ./src/Worms.Hub.ReplayProcessor
ARG VERSION=0.0.1
RUN dotnet publish \
src/Worms.Hub.ReplayProcessor/Worms.Hub.ReplayProcessor.csproj \
-c Release \
-o out \
--no-restore \
-p:AssemblyVersion=${VERSION} \
-p:Version=${VERSION}

#### Test ####
FROM build AS test
RUN dotnet test --no-restore --no-build --verbosity normal

#### Runtime ####
FROM ubuntu:22.04

RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
wget \
p7zip-full \
unshield \
dotnet-runtime-8.0

# Get key to Wine repo
RUN wget -nc https://dl.winehq.org/wine-builds/winehq.key -O /tmp/winehq.key

# Add Wine repo
RUN apt-get update \
&& apt-get install -y software-properties-common gnupg \
&& apt-key add /tmp/winehq.key \
&& add-apt-repository 'deb https://dl.winehq.org/wine-builds/ubuntu/ jammy main' \
&& rm /tmp/winehq.key

# AMD 32-bit deps for Wine
RUN dpkg --add-architecture i386 \
&& apt-get update \
&& apt-get install -y --install-recommends winehq-stable wine32 xvfb \
&& rm -rf /var/lib/apt/lists/*

# Create WINEPREFIX
RUN WINEDLLOVERRIDES="mscoree,mshtml=" xvfb-run wineboot -i \
&& wineserver -k

# Copy game installation directory

# Some settings for WA
RUN wine reg add 'HKEY_CURRENT_USER\Software\Team17SoftwareLTD\WormsArmageddon\Options' /t REG_DWORD /v WineCompatibilitySuggested /d 0x7FFFFFFF /f \
&& wine reg add 'HKEY_CURRENT_USER\Software\Team17SoftwareLTD\WormsArmageddon\Options' /t REG_DWORD /v WindowedMode /d 0x00000001 /f \
&& wine reg add 'HKEY_CURRENT_USER\Software\Team17SoftwareLTD\WormsArmageddon\Options' /t REG_DWORD /v ChatPinned /d 0x00000001 /f \
&& wine reg add 'HKEY_CURRENT_USER\Software\Team17SoftwareLTD\WormsArmageddon\Options' /t REG_DWORD /v DetailLevel /d 0x00000005 /f \
&& wine reg add 'HKEY_CURRENT_USER\Software\Team17SoftwareLTD\WormsArmageddon\Options' /t REG_DWORD /v WindowedMode /d 0x00000001 /f \
&& wine reg add 'HKEY_CURRENT_USER\Software\Team17SoftwareLTD\WormsArmageddon\Options' /t REG_DWORD /v PinnedChatLines /d 0x00000007 /f \
&& wine reg add 'HKEY_CURRENT_USER\Software\Team17SoftwareLTD\WormsArmageddon\Options' /t REG_DWORD /v InfoTransparency /d 0x00000001 /f \
&& wine reg add 'HKEY_CURRENT_USER\Software\Team17SoftwareLTD\WormsArmageddon\Options' /t REG_DWORD /v InfoSpy /d 0x00000001 /f \
&& wine reg add 'HKEY_CURRENT_USER\Software\Team17SoftwareLTD\WormsArmageddon\Options' /t REG_DWORD /v DisableSmoothBackgroundGradient /d 0x00000000 /f \
&& wine reg add 'HKEY_CURRENT_USER\Software\Team17SoftwareLTD\WormsArmageddon\Options' /t REG_DWORD /v HardwareRendering /d 0x00000001 /f \
&& wine reg add 'HKEY_CURRENT_USER\Software\Team17SoftwareLTD\WormsArmageddon\Options' /t REG_DWORD /v LargerFonts /d 0x00000000 /f \
&& wine reg add 'HKEY_CURRENT_USER\Software\Team17SoftwareLTD\WormsArmageddon\Options' /t REG_DWORD /v AssistedVsync /d 0x00000000 /f \
&& wine reg add 'HKEY_CURRENT_USER\Software\Team17SoftwareLTD\WormsArmageddon\Options' /t REG_DWORD /v Vsync /d 0x00000000 /f \
&& wineserver -k

RUN Xvfb :1 & export DISPLAY=:1

WORKDIR /app
COPY --from=build /app/out .
ENTRYPOINT ["./Worms.Hub.ReplayProcessor"]
10 changes: 10 additions & 0 deletions build/docker/replay-processor/Dockerfile.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Ignore everything
**

# Except for these files
!/src
!/scripts
!.editorconfig

**/bin
**/obj
3 changes: 3 additions & 0 deletions build/docker/replay-processor/config.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
replay-processor_IMAGE_NAME := theeadie/worms-hub-replay-processor
replay-processor_NEXT_VERSION := 0.1
replay-processor_TAG_PREFIX := replay-processor/v
2 changes: 1 addition & 1 deletion src/Worms.Armageddon.Game/Linux/WormsLocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public GameInfo Find()
return GameInfo.NotInstalled;
}

var rootLocation = Path.Combine(userHomeDirectory, "games", "worms");
var rootLocation = Path.Combine(userHomeDirectory, ".wine", "drive_c", "WA");
var exeLocation = Path.Combine(rootLocation, processName + ".exe");
var schemesFolder = Path.Combine(rootLocation, "User", "Schemes");
var gamesFolder = Path.Combine(rootLocation, "User", "Games");
Expand Down
41 changes: 36 additions & 5 deletions src/Worms.Armageddon.Game/Linux/WormsRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,55 @@ public Task RunWorms(params string[] wormsArgs)
async () =>
{
var gameInfo = wormsLocator.Find();
var args = string.Join(" ", wormsArgs);
Console.WriteLine("ARGS: " + args);
var processStartInfo = new ProcessStartInfo
{
FileName = "wine",
Arguments = gameInfo.ExeLocation + " " + args,
//FileName = "wine",
//Arguments = gameInfo.ExeLocation + " " + args,
FileName = "/bin/bash",
Arguments = $"""
-c "xvfb-run wine "{gameInfo.ExeLocation}" {args}"
""",
RedirectStandardOutput = true,
RedirectStandardError = true
RedirectStandardError = true,
WorkingDirectory = $"{gameInfo.ReplayFolder}",
};
processStartInfo.EnvironmentVariables["DISPLAY"] = Environment.GetEnvironmentVariable("DISPLAY");
processStartInfo.EnvironmentVariables["WINEDLLOVERRIDES"] = "mscoree,mshtml=";
using var process = Process.Start(processStartInfo);
if (process is not null)
{
await process.WaitForExitAsync().ConfigureAwait(false);
var processTask = Task.Run(() => process.WaitForExitAsync());
var output = Task.Run(() => PrintStdOut(process));
var errors = Task.Run(() => PrintStdErr(process));
await Task.WhenAll(processTask, errors, output).ConfigureAwait(false);
await Console.Error.WriteLineAsync("Exit code:" + process.ExitCode).ConfigureAwait(false);
}
return Task.CompletedTask;
});
}

private static async Task PrintStdOut(Process process)
{
while (!process.StandardOutput.EndOfStream)
{
var line = await process.StandardOutput.ReadLineAsync().ConfigureAwait(false);
await Console.Error.WriteLineAsync("StdOut: " + line).ConfigureAwait(false);
}
}

private static async Task PrintStdErr(Process process)
{
while (!process.StandardError.EndOfStream)
{
var line = await process.StandardError.ReadLineAsync().ConfigureAwait(false);
await Console.Error.WriteLineAsync("StdErr: " + line).ConfigureAwait(false);
}
}
}
2 changes: 1 addition & 1 deletion src/Worms.Armageddon.Game/Replays/ReplayFrameExtractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public Task ExtractReplayFrames(

return wormsRunner.RunWorms(
"/getvideo",
$"\"{replayPath}\"",
$"'{replayPath}'",
fps.ToString(CultureInfo.CurrentCulture),
start,
end,
Expand Down
39 changes: 39 additions & 0 deletions src/Worms.Hub.ReplayProcessor/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Microsoft.Extensions.DependencyInjection;
using Worms.Armageddon.Game;
using Worms.Armageddon.Game.Replays;

Console.WriteLine("Starting replay processor...");

var serviceCollection = new ServiceCollection().AddWormsArmageddonGameServices();
var serviceProvider = serviceCollection.BuildServiceProvider();

var gameLocator = serviceProvider.GetService<IWormsLocator>();
var logGenerator = serviceProvider.GetService<IReplayFrameExtractor>();

// Get message from queue
// Grab the replay path from the message
var replayPath = args[0];
var userHomeDirectory = Environment.GetEnvironmentVariable("HOME");
// Generate the replay log and save it
var gameInfo = gameLocator!.Find();

if (gameInfo.IsInstalled)
{
Console.WriteLine("Game found at: {0}", gameInfo.ExeLocation);
}
else
{
Console.WriteLine("Looking in {0}", userHomeDirectory);
Console.WriteLine("Game not found. Please install the game and try again.");
return;
}

// Set the DISPLAY environment variable
Environment.SetEnvironmentVariable("DISPLAY", ":99");

// Print the DISPLAY environment variable
Console.WriteLine("DISPLAY: {0}", Environment.GetEnvironmentVariable("DISPLAY"));

await logGenerator!.ExtractReplayFrames(replayPath, 5, TimeSpan.Zero, TimeSpan.FromSeconds(5)).ConfigureAwait(false);

Console.WriteLine("Replay processor finished.");
18 changes: 18 additions & 0 deletions src/Worms.Hub.ReplayProcessor/Worms.Hub.ReplayProcessor.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0"/>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Worms.Armageddon.Game\Worms.Armageddon.Game.csproj"/>
</ItemGroup>

</Project>

0 comments on commit 2b840b0

Please sign in to comment.