mirror of
https://github.com/CommonLoon102/NBloodServerSupervisor.git
synced 2024-12-22 10:42:54 +01:00
Mods and home page (#3)
* add some mods * refactor * user friendly home page added * refactor * update readme * update readme
This commit is contained in:
parent
74b9946969
commit
a6dea8efbc
5
.gitignore
vendored
5
.gitignore
vendored
@ -337,4 +337,7 @@ ASALocalRun/
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
healthchecksdb
|
||||
/WebInterface/.config/dotnet-tools.json
|
||||
/output
|
||||
/publish
|
||||
|
@ -4,4 +4,8 @@
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Model\Model.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
@ -7,5 +8,13 @@ namespace Common
|
||||
public class Constants
|
||||
{
|
||||
public const string NBloodExecutable = "nblood_server";
|
||||
public static readonly IReadOnlyDictionary<string, Mod> SupportedMods = new Dictionary<string, Mod>()
|
||||
{
|
||||
{ "BLOOD", new Mod("BLOOD", "Blood", "") },
|
||||
{ "CRYPTIC", new Mod("CRYPTIC", "Cryptic Passage", "-ini CRYPTIC.INI") },
|
||||
{ "DW", new Mod("DW", "Death Wish", "-ini dw.ini") },
|
||||
{ "FO", new Mod("FO", "Fleshed Out", "-ini fo.ini") },
|
||||
{ "TWOIRA", new Mod("TWOIRA", "The Way of Ira", "-ini TWOIRA/twoira.ini -j=TWOIRA") },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
@ -12,9 +13,9 @@ namespace Common
|
||||
{
|
||||
private static readonly string workingDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "blood");
|
||||
|
||||
public static ProcessStartInfo Get(int maxPlayers, int port)
|
||||
public static ProcessStartInfo Get(int maxPlayers, int port, Mod mod)
|
||||
{
|
||||
var psi = new ProcessStartInfo(GetExecutable(), $"-server {maxPlayers} -port {port} -pname Server")
|
||||
var psi = new ProcessStartInfo(GetExecutable(), $"-server {maxPlayers} -port {port} -pname Server {mod.CommandLine}")
|
||||
{
|
||||
UseShellExecute = true,
|
||||
WorkingDirectory = workingDir
|
||||
|
21
Model/Mod.cs
Normal file
21
Model/Mod.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Model
|
||||
{
|
||||
[Serializable]
|
||||
public class Mod
|
||||
{
|
||||
public string Name { get; }
|
||||
public string FriendlyName { get; }
|
||||
public string CommandLine { get; }
|
||||
|
||||
public Mod(string name, string friendlyName, string cmdLine)
|
||||
{
|
||||
Name = name;
|
||||
FriendlyName = friendlyName;
|
||||
CommandLine = cmdLine;
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@ namespace Model
|
||||
public int CurrentPlayers { get; set; }
|
||||
public int MaximumPlayers { get; set; }
|
||||
public string GameType { get; set; }
|
||||
public Mod Mod { get; set; }
|
||||
public IList<Player> Players { get; set; } = new List<Player>();
|
||||
}
|
||||
}
|
||||
|
49
README.md
49
README.md
@ -25,21 +25,52 @@ After you start the container, the following will happen:
|
||||
6. Start `WebInterface.exe`
|
||||
7. Attach the debugger to `WebInterface.exe` and/or `Supervisor.exe`
|
||||
8. You can call the following URLs with your web browser or Postman:
|
||||
- http://localhost:5000/nblood/home
|
||||
- http://localhost:5000/nblood/api/listservers
|
||||
- http://localhost:5000/nblood/api/startserver?players=3&ApiKey=CHANGEME
|
||||
- http://localhost:5000/nblood/api/startserver?players=3&modName=cryptic&apiKey=CHANGEME
|
||||
|
||||
## Deploy the server onto GNU/Linux
|
||||
1. Install Docker and wget (if you don't have already), for example like this: `sudo snap install docker && sudo apt install wget -y`
|
||||
2. Download the Dockerfile: `wget https://raw.githubusercontent.com/CommonLoon102/NBloodServerSupervisor/master/Dockerfile --directory-prefix=supervisor`
|
||||
3. Build the Docker image: `sudo docker build -t nblood-supervisor:latest supervisor`
|
||||
4. Navigate to your Blood 1.21 directory where you have these files:
|
||||
4. Navigate to your Blood 1.21 directory where you have the below files.
|
||||
The files are from stock Blood 1.21, Cryptic Passage, Death Wish 1.6.10, The Way of Ira 1.0.1, Fleshed Out 1.3
|
||||
- BLOOD.INI
|
||||
- BLOOD.RFF
|
||||
- CP01.MAP-CP09.MAP
|
||||
- CPART07.AR_ (Fresh Supply owners need to copy tiles007.ART from `\addons\Cryptic Passage` and rename it)
|
||||
- CPART15.AR_ (Fresh Supply owners need to copy tiles015.ART from `\addons\Cryptic Passage` and rename it)
|
||||
- CPBB01.MAP-CPBB04.MAP
|
||||
- CPSL.MAP
|
||||
- CRYPTIC.INI
|
||||
- dw.ini
|
||||
- DWBB1.MAP-DWBB3.MAP
|
||||
- DWE1M1.MAP-DWE1M12.MAP
|
||||
- DWE2M1.MAP-DWE2M12.MAP
|
||||
- DWE3M1.MAP-DWE3M12.MAP
|
||||
- fo.INI
|
||||
- fo1m1.MAP-fo1m8.MAP
|
||||
- GUI.RFF
|
||||
- SOUNDS.RFF
|
||||
- SURFACE.DAT
|
||||
- TILES000.ART-TILES017.ART
|
||||
- TWOIRA (folder, see below)
|
||||
- VOXEL.DAT
|
||||
|
||||
You need a folder in your Blood folder, named `TWOIRA`, and inside that, these files:
|
||||
- IRA01.MAP
|
||||
- IRA02_A.MAP
|
||||
- IRA02_B.MAP
|
||||
- IRA03.MAP
|
||||
- IRA04.MAP
|
||||
- IRA05.MAP
|
||||
- IRA06.MAP
|
||||
- IRA07.MAP
|
||||
- IRA08.MAP
|
||||
- SURFACE.DAT
|
||||
- TILES18.ART
|
||||
- twoira.ini
|
||||
|
||||
5. Run a Docker container from there: `sudo docker run --volume "$PWD":/supervisor/publish/blood --network=host --detach nblood-supervisor`
|
||||
6. Optional: You can see the ApiKey here:
|
||||
- `sudo docker run -it nblood-supervisor /bin/bash`
|
||||
@ -47,12 +78,14 @@ After you start the container, the following will happen:
|
||||
- `exit`
|
||||
|
||||
## Usage
|
||||
You can list the currently running public servers via this URL:
|
||||
User friendly homepage:
|
||||
http://your.ip.goes.here:23580/nblood/home
|
||||
|
||||
You can list the currently running public servers via this API:
|
||||
http://your.ip.goes.here:23580/nblood/api/listservers
|
||||
|
||||
You can start new private servers via this URL:
|
||||
|
||||
http://your.ip.goes.here:23580/nblood/api/startserver?players=3&ApiKey=the_actual_apikey_here
|
||||
|
||||
The number of players must be at least 3 and maximum 8. The servers started with this URL won't be visible publicly via the `listservers` URL. You can see the port and the command line command to join in the response.
|
||||
You can start new private servers via this API:
|
||||
http://your.ip.goes.here:23580/nblood/api/startserver?players=3&modName=cryptic&apiKey=the_actual_apikey_here
|
||||
The number of players must be at least 3 and maximum 8. The servers started with this URL won't be visible publicly via the `listservers` URL.
|
||||
The modName parameter can be `cryptic`, `dw`, `fo`, `twoira` or it can be missing.
|
||||
You can see the port and the command line command to join in the response.
|
||||
|
@ -10,7 +10,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Supervisor
|
||||
{
|
||||
class PublicServerManager
|
||||
static class PublicServerManager
|
||||
{
|
||||
public static void Start()
|
||||
{
|
||||
@ -39,36 +39,43 @@ namespace Supervisor
|
||||
|
||||
private static void LaunchNewServersWhenNeeded()
|
||||
{
|
||||
const int maxPlayers = 8;
|
||||
|
||||
for (int i = 3; i <= maxPlayers; i++)
|
||||
foreach (Mod mod in Constants.SupportedMods.Values)
|
||||
{
|
||||
if (IsNewServerNeeded(i))
|
||||
const int maxPlayers = 8;
|
||||
for (int i = 3; i <= maxPlayers; i++)
|
||||
{
|
||||
int port = PortUtils.GetPort();
|
||||
var process = Process.Start(NBloodServerStartInfo.Get(i, port));
|
||||
Program.State.Servers.AddOrUpdate(port, new Server()
|
||||
if (IsNewServerNeeded(i, mod))
|
||||
{
|
||||
Port = port,
|
||||
ProcessId = process.Id,
|
||||
MaximumPlayers = i,
|
||||
CurrentPlayers = 1,
|
||||
},
|
||||
(prt, server) =>
|
||||
{
|
||||
server.ProcessId = process.Id;
|
||||
return server;
|
||||
});
|
||||
int port = PortUtils.GetPort();
|
||||
var process = Process.Start(NBloodServerStartInfo.Get(i, port, mod));
|
||||
Program.State.Servers.AddOrUpdate(port, new Server()
|
||||
{
|
||||
Port = port,
|
||||
ProcessId = process.Id,
|
||||
MaximumPlayers = i,
|
||||
CurrentPlayers = 1,
|
||||
Mod = mod,
|
||||
},
|
||||
(prt, server) =>
|
||||
{
|
||||
server.ProcessId = process.Id;
|
||||
server.MaximumPlayers = i;
|
||||
server.CurrentPlayers = 1;
|
||||
server.Mod = mod;
|
||||
return server;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Thread.Sleep(TimeSpan.FromSeconds(2));
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsNewServerNeeded(int i)
|
||||
private static bool IsNewServerNeeded(int i, Mod mod)
|
||||
{
|
||||
return !Program.State.Servers.Values.Any(s =>
|
||||
!s.IsPrivate && s.MaximumPlayers == i && s.CurrentPlayers < s.MaximumPlayers);
|
||||
!s.IsPrivate
|
||||
&& s.Mod.Name == mod.Name
|
||||
&& s.MaximumPlayers == i
|
||||
&& s.CurrentPlayers < s.MaximumPlayers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
17
WebInterface/CommandLineUtils.cs
Normal file
17
WebInterface/CommandLineUtils.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WebInterface
|
||||
{
|
||||
public static class CommandLineUtils
|
||||
{
|
||||
public static string GetLaunchCommand(string host, int port, Mod mod)
|
||||
{
|
||||
return $"nblood -client {host} -port {port} {mod.CommandLine}";
|
||||
}
|
||||
}
|
||||
}
|
26
WebInterface/Controllers/HomeController.cs
Normal file
26
WebInterface/Controllers/HomeController.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using WebInterface.Services;
|
||||
|
||||
namespace WebInterface.Controllers
|
||||
{
|
||||
public class HomeController : Controller
|
||||
{
|
||||
IListServersService _serversList;
|
||||
|
||||
public HomeController(IListServersService serversList)
|
||||
{
|
||||
_serversList = serversList;
|
||||
}
|
||||
|
||||
[Route("nblood/home")]
|
||||
public IActionResult Index()
|
||||
{
|
||||
var viewModel = _serversList.ListServers(HttpContext.Request.Host.Host).Servers;
|
||||
return View(viewModel);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,20 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Common;
|
||||
using Common;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Model;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using WebInterface.Services;
|
||||
|
||||
namespace WebInterface.Controllers
|
||||
{
|
||||
@ -24,22 +21,19 @@ namespace WebInterface.Controllers
|
||||
private static bool _isBusy = false;
|
||||
private static DateTime _lastRefresh = DateTime.MinValue;
|
||||
private static ListServersResponse _lastServerList = null;
|
||||
private static readonly object _locker = new object();
|
||||
|
||||
private readonly ILogger<NBloodController> _logger;
|
||||
private readonly IConfiguration _config;
|
||||
|
||||
private const int listenPort = 11029;
|
||||
private static readonly IPEndPoint remoteIP = new IPEndPoint(IPAddress.Loopback, listenPort);
|
||||
private static readonly UdpClient udpClient = new UdpClient(remoteIP);
|
||||
private readonly IListServersService _listServersService;
|
||||
|
||||
private static readonly Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||
private static readonly IPEndPoint webApiListenerEndPoint = new IPEndPoint(IPAddress.Loopback, 11028);
|
||||
|
||||
public NBloodController(ILogger<NBloodController> logger, IConfiguration config)
|
||||
public NBloodController(ILogger<NBloodController> logger, IConfiguration config, IListServersService listServersService)
|
||||
{
|
||||
_logger = logger;
|
||||
_config = config;
|
||||
_listServersService = listServersService;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
@ -69,9 +63,10 @@ namespace WebInterface.Controllers
|
||||
if (serversRunning >= _config.GetValue<int>("MaximumServers"))
|
||||
return new StartServerResponse("The maximum number of servers are already running.");
|
||||
|
||||
Mod mod = GetMod(parameters.ModName);
|
||||
int port = PortUtils.GetPort();
|
||||
|
||||
var process = Process.Start(NBloodServerStartInfo.Get(parameters.Players, port));
|
||||
var process = Process.Start(NBloodServerStartInfo.Get(parameters.Players, port, mod));
|
||||
byte[] payload = Encoding.ASCII.GetBytes($"B{port}\t{process.Id}\0");
|
||||
socket.SendTo(payload, webApiListenerEndPoint);
|
||||
|
||||
@ -79,7 +74,7 @@ namespace WebInterface.Controllers
|
||||
parameters.Players, port);
|
||||
|
||||
Thread.Sleep(TimeSpan.FromSeconds(2));
|
||||
return new StartServerResponse(port) { CommandLine = GetCommandLine(port) };
|
||||
return new StartServerResponse(port) { CommandLine = CommandLineUtils.GetLaunchCommand(HttpContext.Request.Host.Host, port, mod) };
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -98,32 +93,10 @@ namespace WebInterface.Controllers
|
||||
{
|
||||
try
|
||||
{
|
||||
if (DateTime.UtcNow - _lastRefresh > TimeSpan.FromSeconds(5)
|
||||
if (DateTime.UtcNow - _lastRefresh > TimeSpan.FromSeconds(1)
|
||||
|| _lastServerList == null)
|
||||
{
|
||||
byte[] payload = Encoding.ASCII.GetBytes($"A");
|
||||
byte[] response;
|
||||
lock (_locker)
|
||||
{
|
||||
socket.SendTo(payload, webApiListenerEndPoint);
|
||||
response = udpClient.ReceiveAsync().Result.Buffer;
|
||||
}
|
||||
|
||||
StateResponse stateResponse = (StateResponse)ByteArrayToObject(response);
|
||||
var webResponse = new ListServersResponse();
|
||||
webResponse.Servers = stateResponse.Servers.Where(s => !s.IsPrivate).Select(s => new Server()
|
||||
{
|
||||
Port = s.Port,
|
||||
IsStarted = s.IsStarted,
|
||||
CommandLine = s.CurrentPlayers == s.MaximumPlayers ? "Sorry, the game is already started." : GetCommandLine(s.Port),
|
||||
GameType = s.GameType,
|
||||
CurrentPlayers = s.CurrentPlayers,
|
||||
MaximumPlayers = s.MaximumPlayers,
|
||||
Players = s.Players.Select(p => new Player() { Name = p.Name, Score = p.Score }).ToList(),
|
||||
SpawnedAtUtc = s.SpawnedAtUtc
|
||||
}).OrderBy(s => s.MaximumPlayers).ToList();
|
||||
|
||||
_lastServerList = webResponse;
|
||||
_lastServerList = _listServersService.ListServers(HttpContext.Request.Host.Host);
|
||||
_lastRefresh = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
@ -136,21 +109,15 @@ namespace WebInterface.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
private static object ByteArrayToObject(byte[] arrBytes)
|
||||
private Mod GetMod(string modName)
|
||||
{
|
||||
using (var memStream = new MemoryStream())
|
||||
{
|
||||
var binForm = new BinaryFormatter();
|
||||
memStream.Write(arrBytes, 0, arrBytes.Length);
|
||||
memStream.Seek(0, SeekOrigin.Begin);
|
||||
var obj = binForm.Deserialize(memStream);
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(modName))
|
||||
return Constants.SupportedMods["BLOOD"];
|
||||
|
||||
private string GetCommandLine(int port)
|
||||
{
|
||||
return $"nblood -client {HttpContext.Request.Host.Host} -port {port}";
|
||||
if (!Constants.SupportedMods.ContainsKey(modName.ToUpper()))
|
||||
throw new Exception("This mod is not supported: " + modName);
|
||||
|
||||
return Constants.SupportedMods[modName.ToUpper()];
|
||||
}
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ namespace WebInterface
|
||||
public int CurrentPlayers { get; set; }
|
||||
public int MaximumPlayers { get; set; }
|
||||
public string GameType { get; set; }
|
||||
public string Mod { get; set; }
|
||||
public IList<Player> Players { get; set; } = new List<Player>();
|
||||
}
|
||||
}
|
@ -9,5 +9,6 @@ namespace WebInterface
|
||||
{
|
||||
public string ApiKey { get; set; }
|
||||
public int Players { get; set; }
|
||||
public string ModName { get; set; }
|
||||
}
|
||||
}
|
12
WebInterface/Services/IListServersService.cs
Normal file
12
WebInterface/Services/IListServersService.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WebInterface.Services
|
||||
{
|
||||
public interface IListServersService
|
||||
{
|
||||
ListServersResponse ListServers(string host);
|
||||
}
|
||||
}
|
64
WebInterface/Services/ListServersService.cs
Normal file
64
WebInterface/Services/ListServersService.cs
Normal file
@ -0,0 +1,64 @@
|
||||
using Model;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Text;
|
||||
|
||||
namespace WebInterface.Services
|
||||
{
|
||||
public class ListServersService : IListServersService
|
||||
{
|
||||
private const int listenPort = 11029;
|
||||
|
||||
private static readonly object _locker = new object();
|
||||
private static readonly IPEndPoint remoteIP = new IPEndPoint(IPAddress.Loopback, listenPort);
|
||||
private static readonly UdpClient udpClient = new UdpClient(remoteIP);
|
||||
|
||||
private static readonly Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||
private static readonly IPEndPoint webApiListenerEndPoint = new IPEndPoint(IPAddress.Loopback, 11028);
|
||||
|
||||
public ListServersResponse ListServers(string host)
|
||||
{
|
||||
byte[] payload = Encoding.ASCII.GetBytes($"A");
|
||||
byte[] response;
|
||||
lock (_locker)
|
||||
{
|
||||
socket.SendTo(payload, webApiListenerEndPoint);
|
||||
response = udpClient.ReceiveAsync().Result.Buffer;
|
||||
}
|
||||
|
||||
StateResponse stateResponse = (StateResponse)ByteArrayToObject(response);
|
||||
var serversResponse = new ListServersResponse
|
||||
{
|
||||
Servers = stateResponse.Servers.Where(s => !s.IsPrivate).Select(s => new Server()
|
||||
{
|
||||
Port = s.Port,
|
||||
IsStarted = s.IsStarted,
|
||||
CommandLine = s.CurrentPlayers == s.MaximumPlayers ? "Sorry, the game is already started." : CommandLineUtils.GetLaunchCommand(host, s.Port, s.Mod),
|
||||
GameType = s.GameType,
|
||||
Mod = s.Mod.FriendlyName,
|
||||
CurrentPlayers = s.CurrentPlayers,
|
||||
MaximumPlayers = s.MaximumPlayers,
|
||||
Players = s.Players.Select(p => new Player() { Name = p.Name, Score = p.Score }).ToList(),
|
||||
SpawnedAtUtc = s.SpawnedAtUtc
|
||||
}).OrderBy(s => s.MaximumPlayers).ToList()
|
||||
};
|
||||
|
||||
return serversResponse;
|
||||
}
|
||||
|
||||
private static object ByteArrayToObject(byte[] arrBytes)
|
||||
{
|
||||
using (var memStream = new MemoryStream())
|
||||
{
|
||||
var binForm = new BinaryFormatter();
|
||||
memStream.Write(arrBytes, 0, arrBytes.Length);
|
||||
memStream.Seek(0, SeekOrigin.Begin);
|
||||
var obj = binForm.Deserialize(memStream);
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using WebInterface.Services;
|
||||
|
||||
namespace WebInterface
|
||||
{
|
||||
@ -37,6 +38,8 @@ namespace WebInterface
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddControllers();
|
||||
services.AddControllersWithViews();
|
||||
services.Add(new ServiceDescriptor(typeof(IListServersService), typeof(ListServersService), ServiceLifetime.Singleton));
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
|
153
WebInterface/Views/Home/Index.cshtml
Normal file
153
WebInterface/Views/Home/Index.cshtml
Normal file
@ -0,0 +1,153 @@
|
||||
@model IEnumerable<WebInterface.Server>
|
||||
|
||||
@{
|
||||
Layout = null;
|
||||
string b = "Blood";
|
||||
string cp = "Cryptic Passage";
|
||||
string dw = "Death Wish";
|
||||
string fo = "Fleshed Out";
|
||||
string twoira = "The Way of Ira";
|
||||
|
||||
Func<string, Microsoft.AspNetCore.Html.IHtmlContent>
|
||||
ListServers = @<div>
|
||||
@foreach (var server in Model.Where(s => s.Mod == item).OrderBy(s => s.MaximumPlayers))
|
||||
{
|
||||
<div style="border:2px solid cornflowerblue;">
|
||||
<p style="font-weight:bold">Players: @(server.CurrentPlayers - 1)/@(server.MaximumPlayers - 1)</p>
|
||||
<div>
|
||||
@if (server.IsStarted)
|
||||
{
|
||||
<p>Game Type: @server.GameType</p>
|
||||
<div>
|
||||
@foreach (var player in server.Players.Skip(1))
|
||||
{
|
||||
<p>@player.Name: @player.Score</p>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
@if (server.CurrentPlayers < server.MaximumPlayers)
|
||||
{
|
||||
<p>Command to join: <span class="code">@server.CommandLine</span></p>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>;
|
||||
}
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>Blood servers</title>
|
||||
<style>
|
||||
.code {
|
||||
font-family: Consolas;
|
||||
background-color: black;
|
||||
color: whitesmoke;
|
||||
}
|
||||
.warning {
|
||||
border: dashed 4px red;
|
||||
font-weight: bold;
|
||||
}
|
||||
.version-text {
|
||||
font-weight: bolder;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style="background-color: cornsilk">
|
||||
<h1>The client EXE</h1>
|
||||
<p>Use this exe to connect: <a href="https://lerppu.net/wannabethesis/nblood/20200113-2073/">https://lerppu.net/wannabethesis/nblood/20200113-2073/</a></p>
|
||||
|
||||
<h2>@b 1.21</h2>
|
||||
<details>
|
||||
<summary>Show @b <span class="version-text">version 1.21</span> servers</summary>
|
||||
<p>The below files must be in your Blood directory.</p>
|
||||
<ul>
|
||||
<li>BLOOD.INI</li>
|
||||
<li>BLOOD.RFF</li>
|
||||
<li>GUI.RFF</li>
|
||||
<li>SOUNDS.RFF</li>
|
||||
<li>SURFACE.DAT</li>
|
||||
<li>TILES000.ART-TILES017.ART</li>
|
||||
<li>VOXEL.DAT</li>
|
||||
</ul>
|
||||
@ListServers(@b)
|
||||
</details>
|
||||
<br />
|
||||
<h2>@cp</h2>
|
||||
<details>
|
||||
<summary>Show @cp servers</summary>
|
||||
<p>The below files must be in your Blood directory.</p>
|
||||
<ul>
|
||||
<li>CP01-CP09.MAP</li>
|
||||
<li>CPART07.AR_ (Fresh Supply owners need to copy tiles007.ART from <span class="code">\addons\Cryptic Passage</span> and rename it</li>
|
||||
<li>CPART15.AR_ (Fresh Supply owners need to copy tiles015.ART from <span class="code">\addons\Cryptic Passage</span> and rename it</li>
|
||||
<li>CPBB01.MAP-CPBB04.MAP</li>
|
||||
<li>CPSL.MAP</li>
|
||||
<li>CRYPTIC.INI</li>
|
||||
</ul>
|
||||
<p class="warning">Don't forget to send back the ferry every time at the end of the last map, otherwise you cannot go back if the boss kills you!</p>
|
||||
@ListServers(@cp)
|
||||
</details>
|
||||
<br />
|
||||
<h2>@dw 1.6.10</h2>
|
||||
<details>
|
||||
<summary>Show @dw <span class="version-text">version 1.6.10</span> servers</summary>
|
||||
<p>The below files must be in your Blood directory.</p>
|
||||
<ul>
|
||||
<li>dw.ini</li>
|
||||
<li>DWBB1.MAP-DWBB3.MAP</li>
|
||||
<li>DWE1M1.MAP-DWE1M12.MAP</li>
|
||||
<li>DWE2M1.MAP-DWE2M12.MAP</li>
|
||||
<li>DWE3M1.MAP-DWE3M12.MAP</li>
|
||||
</ul>
|
||||
@ListServers(@dw)
|
||||
</details>
|
||||
<br />
|
||||
<h2>@twoira 1.0.1</h2>
|
||||
<details>
|
||||
<summary>Show @twoira <span class="version-text">version 1.0.1</span> servers</summary>
|
||||
<p>@twoira </p>
|
||||
<p>The below folder (TWOIRA) must be in your Blood directory, and inside that the other additional files.</p>
|
||||
<ul>
|
||||
<li>TWOIRA</li>
|
||||
<li>
|
||||
<ul>
|
||||
<li>IRA01.MAP</li>
|
||||
<li>IRA02_A.MAP</li>
|
||||
<li>IRA02_B.MAP</li>
|
||||
<li>IRA03.MAP</li>
|
||||
<li>IRA04.MAP</li>
|
||||
<li>IRA05.MAP</li>
|
||||
<li>IRA06.MAP</li>
|
||||
<li>IRA07.MAP</li>
|
||||
<li>IRA08.MAP</li>
|
||||
<li>SURFACE.DAT</li>
|
||||
<li>TILES18.ART</li>
|
||||
<li>twoira.ini</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@ListServers(twoira)
|
||||
</details>
|
||||
<h2>@fo 1.3</h2>
|
||||
<details>
|
||||
<summary>Show @fo <span class="version-text">version 1.3</span> servers</summary>
|
||||
<p>The below files must be in your Blood directory.</p>
|
||||
<ul>
|
||||
<li>fo.INI</li>
|
||||
<li>fo1m1.MAP-fo1m8.MAP</li>
|
||||
</ul>
|
||||
<p class="warning">Not tested in co-op! But I hope it works! :)</p>
|
||||
@ListServers(@fo)
|
||||
</details>
|
||||
<br />
|
||||
<hr />
|
||||
<p>Do you think this page is ugly? You are right! If you want to make it better, PRs are welcomed (but please, don't use any JavaScript, thanks): <a href="https://github.com/CommonLoon102/NBloodServerSupervisor">https://github.com/CommonLoon102/NBloodServerSupervisor</a></p>
|
||||
</body>
|
||||
</html>
|
@ -7,6 +7,6 @@
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"MaximumServers": 20,
|
||||
"MaximumServers": 80,
|
||||
"ApiKey": "CHANGEME"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user